Commit 89b1dafa78

Robin Voetter <robin@voetter.nl>
2023-10-07 18:53:33
spirv: aggregate_init for structs
1 parent 28dda3b
Changed files (3)
src
codegen
test
src/codegen/spirv.zig
@@ -2725,6 +2725,7 @@ const DeclGen = struct {
         if (self.liveness.isUnused(inst)) return null;
 
         const mod = self.module;
+        const ip = &mod.intern_pool;
         const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
         const result_ty = self.typeOfIndex(inst);
         const result_ty_ref = try self.resolveType(result_ty, .direct);
@@ -2733,15 +2734,53 @@ const DeclGen = struct {
 
         switch (result_ty.zigTypeTag(mod)) {
             .Vector => unreachable, // TODO
-            .Struct => unreachable, // TODO
+            .Struct => {
+                if (mod.typeToPackedStruct(result_ty)) |struct_type| {
+                    _ = struct_type;
+                    unreachable; // TODO
+                }
+
+                const constituents = try self.gpa.alloc(IdRef, elements.len);
+                defer self.gpa.free(constituents);
+                var index: usize = 0;
+
+                switch (ip.indexToKey(result_ty.toIntern())) {
+                    .anon_struct_type => |tuple| {
+                        for (tuple.types.get(ip), elements, 0..) |field_ty, element, i| {
+                            if ((try result_ty.structFieldValueComptime(mod, i)) != null) continue;
+                            assert(field_ty.toType().hasRuntimeBits(mod));
+
+                            const id = try self.resolve(element);
+                            constituents[index] = try self.convertToIndirect(field_ty.toType(), id);
+                            index += 1;
+                        }
+                    },
+                    .struct_type => |struct_type| {
+                        var it = struct_type.iterateRuntimeOrder(ip);
+                        for (elements, 0..) |element, i| {
+                            const field_index = it.next().?;
+                            if ((try result_ty.structFieldValueComptime(mod, i)) != null) continue;
+                            const field_ty = struct_type.field_types.get(ip)[field_index].toType();
+                            assert(field_ty.hasRuntimeBitsIgnoreComptime(mod));
+
+                            const id = try self.resolve(element);
+                            constituents[index] = try self.convertToIndirect(field_ty, id);
+                            index += 1;
+                        }
+                    },
+                    else => unreachable,
+                }
+
+                return try self.constructStruct(result_ty_ref, constituents[0..index]);
+            },
             .Array => {
                 const array_info = result_ty.arrayInfo(mod);
                 const n_elems: usize = @intCast(result_ty.arrayLenIncludingSentinel(mod));
                 const elem_ids = try self.gpa.alloc(IdRef, n_elems);
                 defer self.gpa.free(elem_ids);
 
-                for (elements, 0..) |elem_inst, i| {
-                    const id = try self.resolve(elem_inst);
+                for (elements, 0..) |element, i| {
+                    const id = try self.resolve(element);
                     elem_ids[i] = try self.convertToIndirect(array_info.elem_type, id);
                 }
 
test/behavior/basic.zig
@@ -357,8 +357,6 @@ fn f2(x: bool) []const u8 {
 }
 
 test "variable is allowed to be a pointer to an opaque type" {
-    if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
-
     var x: i32 = 1234;
     _ = hereIsAnOpaqueType(@as(*OpaqueA, @ptrCast(&x)));
 }
@@ -397,7 +395,6 @@ test "array 2D const double ptr" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
 
     const rect_2d_vertexes = [_][1]f32{
         [_]f32{1.0},
@@ -410,7 +407,6 @@ test "array 2D const double ptr with offset" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
 
     const rect_2d_vertexes = [_][2]f32{
         [_]f32{ 3.0, 4.239 },
@@ -423,7 +419,6 @@ test "array 3D const double ptr with offset" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
 
     const rect_3d_vertexes = [_][2][2]f32{
         [_][2]f32{
test/behavior/struct.zig
@@ -311,7 +311,6 @@ test "struct point to self" {
 test "void struct fields" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
 
     const foo = VoidStructFieldsFoo{
         .a = void{},
@@ -340,7 +339,6 @@ fn testReturnEmptyStructFromFn() EmptyStruct2 {
 
 test "pass slice of empty struct to fn" {
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
 
     try expect(testPassSliceOfEmptyStructToFn(&[_]EmptyStruct2{EmptyStruct2{}}) == 1);
 }
@@ -1229,7 +1227,6 @@ test "typed init through error unions and optionals" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
 
     const S = struct {
         a: u32,
@@ -1550,7 +1547,6 @@ test "no dependency loop on optional field wrapped in generic function" {
 test "optional field init with tuple" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
 
     const S = struct {
         a: ?struct { b: u32 },
@@ -1652,7 +1648,6 @@ test "struct field pointer has correct alignment" {
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
 
     const S = struct {
         fn doTheTest() !void {
@@ -1683,7 +1678,6 @@ test "extern struct field pointer has correct alignment" {
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
 
     const S = struct {
         fn doTheTest() !void {