Commit caf8461af8

Robin Voetter <robin@voetter.nl>
2022-11-30 23:28:07
spirv: make locals generic pointers
Taking the address of a local variable should result in a generic pointer - too much code breaks if we do not do this. We cannot lower locals into the generic storage class directly though, so instead, lower the variables into the Function storage class implicitly, and convert the pointer to a generic pointer. Also Correct OpInboundsAccessChain generation (we only need the one index).
1 parent 2a8e784
Changed files (1)
src
codegen
src/codegen/spirv.zig
@@ -1306,12 +1306,11 @@ pub const DeclGen = struct {
         };
 
         const result_id = self.spv.allocId();
-        const indexes = [_]IdRef{index};
-        try self.func.body.emit(self.spv.gpa, .OpInBoundsAccessChain, .{
+        try self.func.body.emit(self.spv.gpa, .OpInBoundsPtrAccessChain, .{
             .id_result_type = spv_ptr_ty,
             .id_result = result_id,
             .base = slice_ptr,
-            .indexes = &indexes,
+            .element = index,
         });
         return result_id;
     }
@@ -1340,12 +1339,11 @@ pub const DeclGen = struct {
 
         const elem_ptr = blk: {
             const result_id = self.spv.allocId();
-            const indexes = [_]IdRef{index};
-            try self.func.body.emit(self.spv.gpa, .OpInBoundsAccessChain, .{
+            try self.func.body.emit(self.spv.gpa, .OpInBoundsPtrAccessChain, .{
                 .id_result_type = ptr_ty_id,
                 .id_result = result_id,
                 .base = slice_ptr,
-                .indexes = &indexes,
+                .element = index,
             });
             break :blk result_id;
         };
@@ -1448,22 +1446,45 @@ pub const DeclGen = struct {
     fn airAlloc(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
         if (self.liveness.isUnused(inst)) return null;
         const ty = self.air.typeOfIndex(inst);
-        const result_type_id = try self.resolveTypeId(ty);
+        const result_ty_ref = try self.resolveType(ty, .direct);
+        const result_ty_id = self.typeId(result_ty_ref);
         const result_id = self.spv.allocId();
 
-        // Rather than generating into code here, we're just going to generate directly into the functions section so that
-        // variable declarations appear in the first block of the function.
         const storage_class = spirvStorageClass(ty.ptrAddressSpace());
-        const section = if (storage_class == .Function or storage_class == .Generic)
-            &self.func.prologue
-        else
-            &self.spv.sections.types_globals_constants;
 
+        const ptr_ty_id = switch (storage_class) {
+            .Generic => blk: {
+                const payload = try self.spv.arena.create(SpvType.Payload.Pointer);
+                payload.* = self.spv.typeRefType(result_ty_ref).payload(.pointer).*;
+                payload.storage_class = .Function;
+                break :blk try self.spv.resolveTypeId(SpvType.initPayload(&payload.base));
+            },
+            else => result_ty_id,
+        };
+        const actual_storage_class = switch (storage_class) {
+            .Generic, .Function => .Function,
+            else => storage_class,
+        };
+        const section = switch (storage_class) {
+            // SPIR-V requires that OpVariable declarations for locals go into the first block, so we are just going to
+            // directly generate them into func.prologue instead of the body.
+            .Generic, .Function => &self.func.prologue,
+            else => &self.spv.sections.types_globals_constants,
+        };
         try section.emit(self.spv.gpa, .OpVariable, .{
-            .id_result_type = result_type_id,
+            .id_result_type = ptr_ty_id,
             .id_result = result_id,
-            .storage_class = storage_class,
+            .storage_class = actual_storage_class,
         });
+        if (storage_class == .Generic) {
+            const casted_result_id = self.spv.allocId();
+            try self.func.body.emit(self.spv.gpa, .OpPtrCastToGeneric, .{
+                .id_result_type = result_ty_id,
+                .id_result = casted_result_id,
+                .pointer = result_id,
+            });
+            return casted_result_id;
+        }
         return result_id;
     }