authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2023-10-21 15:30:20+02:00
committergravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2023-10-21 17:46:53+02:00
log1deec09f03d07aefcff1f886085c929c93669b5d
treeb8ceeaa4aef003c3c701252f5b5d4238be8a748e
parent5090d75e48ba0a044997b93b0c5cf1f7dcec60f1
signaturebadge-check Signed by SSH key SHA256:CQ99aPxq+RueiL9u7z0FEki5Fm7V6T8q4PrEGmINrA4

spirv: improve union operations

This removes the strategy where union with different active fields would be generated, and instead simply pointer casts the active field type where required. This also allows removing spv.ptrType and using self.ptrType instead, and allows caching all union types (because there is only the canonical one).

3 files changed, 104 insertions(+), 137 deletions(-)

src/codegen/spirv.zig+104-126
......@@ -874,12 +874,12 @@ const DeclGen = struct {
874874 },
875875 .un => |un| {
876876 const active_field = ty.unionTagFieldIndex(un.tag.toValue(), mod).?;
877 const layout = self.unionLayout(ty, active_field);
878 const payload = if (layout.active_field_size != 0)
879 try self.constant(layout.active_field_ty, un.val.toValue(), .direct)
877 const union_obj = mod.typeToUnion(ty).?;
878 const field_ty = union_obj.field_types.get(ip)[active_field].toType();
879 const payload = if (field_ty.hasRuntimeBitsIgnoreComptime(mod))
880 try self.constant(field_ty, un.val.toValue(), .direct)
880881 else
881882 null;
882
883883 return try self.unionInit(ty, active_field, payload);
884884 },
885885 .memoized_call => unreachable,
......@@ -1105,29 +1105,25 @@ const DeclGen = struct {
11051105 return try self.spv.ptrType(child_ty_ref, storage_class);
11061106 }
11071107
1108 /// Generate a union type, optionally with a known field. If the tag alignment is greater
1109 /// than that of the payload, a regular union (non-packed, with both tag and payload), will
1110 /// be generated as follows:
1111 /// If the active field is known:
1108 /// Generate a union type. Union types are always generated with the
1109 /// most aligned field active. If the tag alignment is greater
1110 /// than that of the payload, a regular union (non-packed, with both tag and
1111 /// payload), will be generated as follows:
11121112 /// struct {
11131113 /// tag: TagType,
1114 /// payload: ActivePayloadType,
1115 /// payload_padding: [payload_size - @sizeOf(ActivePayloadType)]u8,
1114 /// payload: MostAlignedFieldType,
1115 /// payload_padding: [payload_size - @sizeOf(MostAlignedFieldType)]u8,
11161116 /// padding: [padding_size]u8,
11171117 /// }
11181118 /// If the payload alignment is greater than that of the tag:
11191119 /// struct {
1120 /// payload: ActivePayloadType,
1121 /// payload_padding: [payload_size - @sizeOf(ActivePayloadType)]u8,
1120 /// payload: MostAlignedFieldType,
1121 /// payload_padding: [payload_size - @sizeOf(MostAlignedFieldType)]u8,
11221122 /// tag: TagType,
11231123 /// padding: [padding_size]u8,
11241124 /// }
1125 /// If the active payload is unknown, it will default back to the most aligned field. This is
1126 /// to make sure that the overal struct has the correct alignment in spir-v.
11271125 /// If any of the fields' size is 0, it will be omitted.
1128 /// NOTE: When the active field is set to something other than the most aligned field, the
1129 /// resulting struct will be *underaligned*.
1130 fn resolveUnionType(self: *DeclGen, ty: Type, maybe_active_field: ?usize) !CacheRef {
1126 fn resolveUnionType(self: *DeclGen, ty: Type) !CacheRef {
11311127 const mod = self.module;
11321128 const ip = &mod.intern_pool;
11331129 const union_obj = mod.typeToUnion(ty).?;
......@@ -1136,17 +1132,13 @@ const DeclGen = struct {
11361132 return self.todo("packed union types", .{});
11371133 }
11381134
1139 const layout = self.unionLayout(ty, maybe_active_field);
1140
1141 if (layout.payload_size == 0) {
1135 const layout = self.unionLayout(ty);
1136 if (!layout.has_payload) {
11421137 // No payload, so represent this as just the tag type.
11431138 return try self.resolveType(union_obj.enum_tag_ty.toType(), .indirect);
11441139 }
11451140
1146 // TODO: We need to add the active field to the key, somehow.
1147 if (maybe_active_field == null) {
1148 if (self.type_map.get(ty.toIntern())) |info| return info.ty_ref;
1149 }
1141 if (self.type_map.get(ty.toIntern())) |info| return info.ty_ref;
11501142
11511143 var member_types: [4]CacheRef = undefined;
11521144 var member_names: [4]CacheString = undefined;
......@@ -1159,10 +1151,10 @@ const DeclGen = struct {
11591151 member_names[layout.tag_index] = try self.spv.resolveString("(tag)");
11601152 }
11611153
1162 if (layout.active_field_size != 0) {
1163 const active_payload_ty_ref = try self.resolveType(layout.active_field_ty, .indirect);
1164 member_types[layout.active_field_index] = active_payload_ty_ref;
1165 member_names[layout.active_field_index] = try self.spv.resolveString("(payload)");
1154 if (layout.payload_size != 0) {
1155 const payload_ty_ref = try self.resolveType(layout.payload_ty, .indirect);
1156 member_types[layout.payload_index] = payload_ty_ref;
1157 member_names[layout.payload_index] = try self.spv.resolveString("(payload)");
11661158 }
11671159
11681160 if (layout.payload_padding_size != 0) {
......@@ -1183,9 +1175,7 @@ const DeclGen = struct {
11831175 .member_names = member_names[0..layout.total_fields],
11841176 } });
11851177
1186 if (maybe_active_field == null) {
1187 try self.type_map.put(self.gpa, ty.toIntern(), .{ .ty_ref = ty_ref });
1188 }
1178 try self.type_map.put(self.gpa, ty.toIntern(), .{ .ty_ref = ty_ref });
11891179 return ty_ref;
11901180 }
11911181
......@@ -1453,7 +1443,7 @@ const DeclGen = struct {
14531443 try self.type_map.put(self.gpa, ty.toIntern(), .{ .ty_ref = ty_ref });
14541444 return ty_ref;
14551445 },
1456 .Union => return try self.resolveUnionType(ty, null),
1446 .Union => return try self.resolveUnionType(ty),
14571447 .ErrorSet => return try self.intType(.unsigned, 16),
14581448 .ErrorUnion => {
14591449 const payload_ty = ty.errorUnionPayload(mod);
......@@ -1567,14 +1557,16 @@ const DeclGen = struct {
15671557 }
15681558
15691559 const UnionLayout = struct {
1570 active_field: u32,
1571 active_field_ty: Type,
1572 payload_size: u32,
1573
1560 /// If false, this union is represented
1561 /// by only an integer of the tag type.
1562 has_payload: bool,
15741563 tag_size: u32,
15751564 tag_index: u32,
1576 active_field_size: u32,
1577 active_field_index: u32,
1565 /// Note: This is the size of the payload type itself, NOT the size of the ENTIRE payload.
1566 /// Use `has_payload` instead!!
1567 payload_ty: Type,
1568 payload_size: u32,
1569 payload_index: u32,
15781570 payload_padding_size: u32,
15791571 payload_padding_index: u32,
15801572 padding_size: u32,
......@@ -1582,23 +1574,19 @@ const DeclGen = struct {
15821574 total_fields: u32,
15831575 };
15841576
1585 fn unionLayout(self: *DeclGen, ty: Type, maybe_active_field: ?usize) UnionLayout {
1577 fn unionLayout(self: *DeclGen, ty: Type) UnionLayout {
15861578 const mod = self.module;
15871579 const ip = &mod.intern_pool;
15881580 const layout = ty.unionGetLayout(self.module);
15891581 const union_obj = mod.typeToUnion(ty).?;
15901582
1591 const active_field = maybe_active_field orelse layout.most_aligned_field;
1592 const active_field_ty = union_obj.field_types.get(ip)[active_field].toType();
1593
15941583 var union_layout = UnionLayout{
1595 .active_field = @intCast(active_field),
1596 .active_field_ty = active_field_ty,
1597 .payload_size = @intCast(layout.payload_size),
1584 .has_payload = layout.payload_size != 0,
15981585 .tag_size = @intCast(layout.tag_size),
15991586 .tag_index = undefined,
1600 .active_field_size = undefined,
1601 .active_field_index = undefined,
1587 .payload_ty = undefined,
1588 .payload_size = undefined,
1589 .payload_index = undefined,
16021590 .payload_padding_size = undefined,
16031591 .payload_padding_index = undefined,
16041592 .padding_size = @intCast(layout.padding),
......@@ -1606,11 +1594,16 @@ const DeclGen = struct {
16061594 .total_fields = undefined,
16071595 };
16081596
1609 union_layout.active_field_size = if (active_field_ty.hasRuntimeBitsIgnoreComptime(mod))
1610 @intCast(active_field_ty.abiSize(mod))
1611 else
1612 0;
1613 union_layout.payload_padding_size = @intCast(layout.payload_size - union_layout.active_field_size);
1597 if (union_layout.has_payload) {
1598 const most_aligned_field = layout.most_aligned_field;
1599 const most_aligned_field_ty = union_obj.field_types.get(ip)[most_aligned_field].toType();
1600 union_layout.payload_ty = most_aligned_field_ty;
1601 union_layout.payload_size = @intCast(most_aligned_field_ty.abiSize(mod));
1602 } else {
1603 union_layout.payload_size = 0;
1604 }
1605
1606 union_layout.payload_padding_size = @intCast(layout.payload_size - union_layout.payload_size);
16141607
16151608 const tag_first = layout.tag_align.compare(.gte, layout.payload_align);
16161609 var field_index: u32 = 0;
......@@ -1620,8 +1613,8 @@ const DeclGen = struct {
16201613 field_index += 1;
16211614 }
16221615
1623 if (union_layout.active_field_size != 0) {
1624 union_layout.active_field_index = field_index;
1616 if (union_layout.payload_size != 0) {
1617 union_layout.payload_index = field_index;
16251618 field_index += 1;
16261619 }
16271620
......@@ -3300,7 +3293,7 @@ const DeclGen = struct {
33003293 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
33013294 const un_ptr_ty = self.typeOf(bin_op.lhs);
33023295 const un_ty = un_ptr_ty.childType(mod);
3303 const layout = self.unionLayout(un_ty, null);
3296 const layout = self.unionLayout(un_ty);
33043297
33053298 if (layout.tag_size == 0) return;
33063299
......@@ -3310,7 +3303,7 @@ const DeclGen = struct {
33103303 const union_ptr_id = try self.resolve(bin_op.lhs);
33113304 const new_tag_id = try self.resolve(bin_op.rhs);
33123305
3313 if (layout.payload_size == 0) {
3306 if (!layout.has_payload) {
33143307 try self.store(tag_ty, union_ptr_id, new_tag_id, .{ .is_volatile = un_ptr_ty.isVolatilePtr(mod) });
33153308 } else {
33163309 const ptr_id = try self.accessChain(tag_ptr_ty_ref, union_ptr_id, &.{layout.tag_index});
......@@ -3325,11 +3318,11 @@ const DeclGen = struct {
33253318 const un_ty = self.typeOf(ty_op.operand);
33263319
33273320 const mod = self.module;
3328 const layout = self.unionLayout(un_ty, null);
3321 const layout = self.unionLayout(un_ty);
33293322 if (layout.tag_size == 0) return null;
33303323
33313324 const union_handle = try self.resolve(ty_op.operand);
3332 if (layout.payload_size == 0) return union_handle;
3325 if (!layout.has_payload) return union_handle;
33333326
33343327 const tag_ty = un_ty.unionTagTypeSafety(mod).?;
33353328 return try self.extractField(tag_ty, union_handle, layout.tag_index);
......@@ -3342,8 +3335,8 @@ const DeclGen = struct {
33423335 payload: ?IdRef,
33433336 ) !IdRef {
33443337 // To initialize a union, generate a temporary variable with the
3345 // type that has the right field active, then pointer-cast and store
3346 // the active field, and finally load and return the entire union.
3338 // union type, then get the field pointer and pointer-cast it to the
3339 // right type to store it. Finally load the entire union.
33473340
33483341 const mod = self.module;
33493342 const ip = &mod.intern_pool;
......@@ -3354,7 +3347,7 @@ const DeclGen = struct {
33543347 }
33553348
33563349 const maybe_tag_ty = ty.unionTagTypeSafety(mod);
3357 const layout = self.unionLayout(ty, active_field);
3350 const layout = self.unionLayout(ty);
33583351
33593352 const tag_int = if (layout.tag_size != 0) blk: {
33603353 const tag_ty = maybe_tag_ty.?;
......@@ -3365,23 +3358,12 @@ const DeclGen = struct {
33653358 break :blk tag_int_val.toUnsignedInt(mod);
33663359 } else 0;
33673360
3368 if (layout.payload_size == 0) {
3361 if (!layout.has_payload) {
33693362 const tag_ty_ref = try self.resolveType(maybe_tag_ty.?, .direct);
33703363 return try self.constInt(tag_ty_ref, tag_int);
33713364 }
33723365
3373 // TODO: Make this use self.ptrType
3374 const un_active_ty_ref = try self.resolveUnionType(ty, active_field);
3375 const un_active_ptr_ty_ref = try self.spv.ptrType(un_active_ty_ref, .Function);
3376 const un_general_ty_ref = try self.resolveType(ty, .direct);
3377 const un_general_ptr_ty_ref = try self.spv.ptrType(un_general_ty_ref, .Function);
3378
3379 const tmp_id = self.spv.allocId();
3380 try self.func.prologue.emit(self.spv.gpa, .OpVariable, .{
3381 .id_result_type = self.typeId(un_active_ptr_ty_ref),
3382 .id_result = tmp_id,
3383 .storage_class = .Function,
3384 });
3366 const tmp_id = try self.alloc(ty, .{ .storage_class = .Function });
33853367
33863368 if (layout.tag_size != 0) {
33873369 const tag_ty_ref = try self.resolveType(maybe_tag_ty.?, .direct);
......@@ -3391,10 +3373,19 @@ const DeclGen = struct {
33913373 try self.store(maybe_tag_ty.?, ptr_id, tag_id, .{});
33923374 }
33933375
3394 if (layout.active_field_size != 0) {
3395 const active_field_ptr_ty_ref = try self.ptrType(layout.active_field_ty, .Function);
3396 const ptr_id = try self.accessChain(active_field_ptr_ty_ref, tmp_id, &.{@as(u32, @intCast(layout.active_field_index))});
3397 try self.store(layout.active_field_ty, ptr_id, payload.?, .{});
3376 const payload_ty = union_ty.field_types.get(ip)[active_field].toType();
3377 if (payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
3378 const pl_ptr_ty_ref = try self.ptrType(layout.payload_ty, .Function);
3379 const pl_ptr_id = try self.accessChain(pl_ptr_ty_ref, tmp_id, &.{layout.payload_index});
3380 const active_pl_ptr_ty_ref = try self.ptrType(payload_ty, .Function);
3381 const active_pl_ptr_id = self.spv.allocId();
3382 try self.func.body.emit(self.spv.gpa, .OpBitcast, .{
3383 .id_result_type = self.typeId(active_pl_ptr_ty_ref),
3384 .id_result = active_pl_ptr_id,
3385 .operand = pl_ptr_id,
3386 });
3387
3388 try self.store(payload_ty, active_pl_ptr_id, payload.?, .{});
33983389 } else {
33993390 assert(payload == null);
34003391 }
......@@ -3402,34 +3393,21 @@ const DeclGen = struct {
34023393 // Just leave the padding fields uninitialized...
34033394 // TODO: Or should we initialize them with undef explicitly?
34043395
3405 // Now cast the pointer and load it as the 'generic' union type.
3406
3407 const casted_var_id = self.spv.allocId();
3408 try self.func.body.emit(self.spv.gpa, .OpBitcast, .{
3409 .id_result_type = self.typeId(un_general_ptr_ty_ref),
3410 .id_result = casted_var_id,
3411 .operand = tmp_id,
3412 });
3413
3414 const result_id = self.spv.allocId();
3415 try self.func.body.emit(self.spv.gpa, .OpLoad, .{
3416 .id_result_type = self.typeId(un_general_ty_ref),
3417 .id_result = result_id,
3418 .pointer = casted_var_id,
3419 });
3420
3421 return result_id;
3396 return try self.load(ty, tmp_id, .{});
34223397 }
34233398
34243399 fn airUnionInit(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
34253400 if (self.liveness.isUnused(inst)) return null;
34263401
3402 const mod = self.module;
3403 const ip = &mod.intern_pool;
34273404 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
34283405 const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data;
34293406 const ty = self.typeOfIndex(inst);
3430 const layout = self.unionLayout(ty, extra.field_index);
34313407
3432 const payload = if (layout.active_field_size != 0)
3408 const union_obj = mod.typeToUnion(ty).?;
3409 const field_ty = union_obj.field_types.get(ip)[extra.field_index].toType();
3410 const payload = if (field_ty.hasRuntimeBitsIgnoreComptime(mod))
34333411 try self.resolve(extra.init)
34343412 else
34353413 null;
......@@ -3458,30 +3436,24 @@ const DeclGen = struct {
34583436 .Union => switch (object_ty.containerLayout(mod)) {
34593437 .Packed => unreachable, // TODO
34603438 else => {
3461 // Store, pointer-cast, load
3462 const un_general_ty_ref = try self.resolveType(object_ty, .indirect);
3463 const un_general_ptr_ty_ref = try self.spv.ptrType(un_general_ty_ref, .Function);
3464 const un_active_ty_ref = try self.resolveUnionType(object_ty, field_index);
3465 const un_active_ptr_ty_ref = try self.spv.ptrType(un_active_ty_ref, .Function);
3466 const field_ty_ref = try self.resolveType(field_ty, .indirect);
3467 const field_ptr_ty_ref = try self.spv.ptrType(field_ty_ref, .Function);
3468
3469 const tmp_id = self.spv.allocId();
3470 try self.func.prologue.emit(self.spv.gpa, .OpVariable, .{
3471 .id_result_type = self.typeId(un_general_ptr_ty_ref),
3472 .id_result = tmp_id,
3473 .storage_class = .Function,
3474 });
3439 // Store, ptr-elem-ptr, pointer-cast, load
3440 const layout = self.unionLayout(object_ty);
3441 assert(layout.has_payload);
3442
3443 const tmp_id = try self.alloc(object_ty, .{ .storage_class = .Function });
34753444 try self.store(object_ty, tmp_id, object_id, .{});
3476 const casted_tmp_id = self.spv.allocId();
3445
3446 const pl_ptr_ty_ref = try self.ptrType(layout.payload_ty, .Function);
3447 const pl_ptr_id = try self.accessChain(pl_ptr_ty_ref, tmp_id, &.{layout.payload_index});
3448
3449 const active_pl_ptr_ty_ref = try self.ptrType(field_ty, .Function);
3450 const active_pl_ptr_id = self.spv.allocId();
34773451 try self.func.body.emit(self.spv.gpa, .OpBitcast, .{
3478 .id_result_type = self.typeId(un_active_ptr_ty_ref),
3479 .id_result = casted_tmp_id,
3480 .operand = tmp_id,
3452 .id_result_type = self.typeId(active_pl_ptr_ty_ref),
3453 .id_result = active_pl_ptr_id,
3454 .operand = pl_ptr_id,
34813455 });
3482 const layout = self.unionLayout(object_ty, field_index);
3483 const field_ptr_id = try self.accessChain(field_ptr_ty_ref, casted_tmp_id, &.{layout.active_field_index});
3484 return try self.load(field_ty, field_ptr_id, .{});
3456 return try self.load(field_ty, active_pl_ptr_id, .{});
34853457 },
34863458 },
34873459 else => unreachable,
......@@ -3540,18 +3512,24 @@ const DeclGen = struct {
35403512 .Union => switch (object_ty.containerLayout(mod)) {
35413513 .Packed => unreachable, // TODO
35423514 else => {
3515 const layout = self.unionLayout(object_ty);
3516 if (!layout.has_payload) {
3517 // Asked to get a pointer to a zero-sized field. Just lower this
3518 // to undefined, there is no reason to make it be a valid pointer.
3519 return try self.spv.constUndef(result_ty_ref);
3520 }
3521
35433522 const storage_class = spvStorageClass(object_ptr_ty.ptrAddressSpace(mod));
3544 const un_active_ty_ref = try self.resolveUnionType(object_ty, field_index);
3545 const un_active_ptr_ty_ref = try self.spv.ptrType(un_active_ty_ref, storage_class);
3523 const pl_ptr_ty_ref = try self.ptrType(layout.payload_ty, storage_class);
3524 const pl_ptr_id = try self.accessChain(pl_ptr_ty_ref, object_ptr, &.{layout.payload_index});
35463525
3547 const casted_id = self.spv.allocId();
3526 const active_pl_ptr_id = self.spv.allocId();
35483527 try self.func.body.emit(self.spv.gpa, .OpBitcast, .{
3549 .id_result_type = self.typeId(un_active_ptr_ty_ref),
3550 .id_result = casted_id,
3551 .operand = object_ptr,
3528 .id_result_type = self.typeId(result_ty_ref),
3529 .id_result = active_pl_ptr_id,
3530 .operand = pl_ptr_id,
35523531 });
3553 const layout = self.unionLayout(object_ty, field_index);
3554 return try self.accessChain(result_ty_ref, casted_id, &.{layout.active_field_index});
3532 return active_pl_ptr_id;
35553533 },
35563534 },
35573535 else => unreachable,
test/behavior/struct.zig-1
......@@ -736,7 +736,6 @@ test "packed struct with u0 field access" {
736736test "access to global struct fields" {
737737 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
738738 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
739 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
740739
741740 g_foo.bar.value = 42;
742741 try expect(g_foo.bar.value == 42);
test/behavior/union.zig-10
......@@ -399,7 +399,6 @@ test "tagged union with no payloads" {
399399 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
400400 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
401401 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
402 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
403402
404403 const a = UnionEnumNoPayloads{ .B = {} };
405404 switch (a) {
......@@ -474,7 +473,6 @@ test "update the tag value for zero-sized unions" {
474473 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
475474 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
476475 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
477 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
478476
479477 const S = union(enum) {
480478 U0: void,
......@@ -515,7 +513,6 @@ test "method call on an empty union" {
515513 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
516514 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
517515 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
518 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
519516
520517 const S = struct {
521518 const MyUnion = union(MyUnionTag) {
......@@ -593,7 +590,6 @@ test "tagged union with all void fields but a meaningful tag" {
593590 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
594591 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
595592 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
596 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
597593
598594 const S = struct {
599595 const B = union(enum) {
......@@ -795,7 +791,6 @@ test "@unionInit stored to a const" {
795791 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
796792 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
797793 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
798 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
799794
800795 const S = struct {
801796 const U = union(enum) {
......@@ -867,7 +862,6 @@ test "union no tag with struct member" {
867862 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
868863 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
869864 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
870 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
871865
872866 const Struct = struct {};
873867 const Union = union {
......@@ -1079,7 +1073,6 @@ test "@unionInit on union with tag but no fields" {
10791073 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10801074 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10811075 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1082 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
10831076
10841077 const S = struct {
10851078 const Type = enum(u8) { no_op = 105 };
......@@ -1128,7 +1121,6 @@ test "global variable struct contains union initialized to non-most-aligned fiel
11281121 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11291122 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11301123 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1131 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
11321124
11331125 const T = struct {
11341126 const U = union(enum) {
......@@ -1348,7 +1340,6 @@ test "union field ptr - zero sized payload" {
13481340 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13491341 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13501342 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1351 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
13521343
13531344 const U = union {
13541345 foo: void,
......@@ -1363,7 +1354,6 @@ test "union field ptr - zero sized field" {
13631354 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13641355 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13651356 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1366 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
13671357
13681358 const U = union {
13691359 foo: void,