authorgravatar for alichraghi@proton.meAli Chraghi <alichraghi@proton.me> 2026-06-16 16:42:57+03:30
committergravatar for alichraghi@noreply.codeberg.orgAli Cheraghi <alichraghi@noreply.codeberg.org> 2026-06-18 13:38:58+02:00
log4653794852923e08cceab69620b7d0bb5d11e42d
tree233b20624ff8fc8da7ff0e297a336efd02f6ba86
parenta5fbbb83050f2dad0a9ebc0bd995a5a8f58d0a49

spirv: implement switch with ranges and loop_switch_br switch_dispatch


34 files changed, 679 insertions(+), 544 deletions(-)

src/codegen/spirv/CodeGen.zig+671-369
......@@ -45,104 +45,67 @@ pub fn legalizeFeatures(_: *const std.Target) *const Air.Legalize.Features {
4545
4646pub const zig_call_abi_ver = 3;
4747
48const ControlFlow = union(enum) {
49 const Structured = struct {
50 /// This type indicates the way that a block is terminated. The
51 /// state of a particular block is used to track how a jump from
52 /// inside the block must reach the outside.
53 const Block = union(enum) {
54 const Incoming = struct {
55 src_label: Id,
56 /// Instruction that returns an u32 value of the
57 /// `Air.Inst.Index` that control flow should jump to.
58 next_block: Id,
59 };
60
61 const SelectionMerge = struct {
62 /// Incoming block from the `then` label.
63 /// Note that hte incoming block from the `else` label is
64 /// either given by the next element in the stack.
65 incoming: Incoming,
66 /// The label id of the cond_br's merge block.
67 /// For the top-most element in the stack, this
68 /// value is undefined.
69 merge_block: Id,
70 };
71
72 /// For a `selection` type block, we cannot use early exits, and we
73 /// must generate a 'merge ladder' of OpSelection instructions. To that end,
74 /// we keep a stack of the merges that still must be closed at the end of
75 /// a block.
76 ///
77 /// This entire structure basically just resembles a tree like
78 /// a x
79 /// \ /
80 /// b o merge
81 /// \ /
82 /// c o merge
83 /// \ /
84 /// o merge
85 /// /
86 /// o jump to next block
87 selection: struct {
88 /// In order to know which merges we still need to do, we need to keep
89 /// a stack of those.
90 merge_stack: std.ArrayList(SelectionMerge) = .empty,
91 },
92 /// For a `loop` type block, we can early-exit the block by
93 /// jumping to the loop exit node, and we don't need to generate
94 /// an entire stack of merges.
95 loop: struct {
96 /// The next block to jump to can be determined from any number
97 /// of conditions that jump to the loop exit.
98 merges: std.ArrayList(Incoming) = .empty,
99 /// The label id of the loop's merge block.
100 merge_block: Id,
101 },
102
103 fn deinit(block: *Structured.Block, gpa: Allocator) void {
104 switch (block.*) {
105 .selection => |*merge| merge.merge_stack.deinit(gpa),
106 .loop => |*merge| merge.merges.deinit(gpa),
107 }
108 block.* = undefined;
109 }
110 };
111 /// This determines how exits from the current block must be handled.
112 block_stack: std.ArrayList(*Structured.Block) = .empty,
113 block_results: std.AutoHashMapUnmanaged(Air.Inst.Index, Id) = .empty,
48const LoopSwitch = struct { cond_var: Id, continue_label: Id };
49
50/// This type indicates the way that a block is terminated. The
51/// state of a particular block is used to track how a jump from
52/// inside the block must reach the outside.
53const Block = union(enum) {
54 const Incoming = struct {
55 src_label: Id,
56 /// Instruction that returns an u32 value of the
57 /// `Air.Inst.Index` that control flow should jump to.
58 next_block: Id,
11459 };
11560
116 const Unstructured = struct {
117 const Incoming = struct {
118 src_label: Id,
119 break_value_id: Id,
120 };
121
122 const Block = struct {
123 label: ?Id = null,
124 incoming_blocks: std.ArrayList(Incoming) = .empty,
125 };
126
127 /// We need to keep track of result ids for block labels, as well as the 'incoming'
128 /// blocks for a block.
129 blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, *Block) = .empty,
61 const SelectionMerge = struct {
62 /// Incoming block from the `then` label.
63 /// Note that the incoming block from the `else` label is
64 /// either given by the next element in the stack.
65 incoming: Incoming,
66 /// The label id of the cond_br's merge block.
67 /// For the top-most element in the stack, this
68 /// value is undefined.
69 merge_block: Id,
13070 };
13171
132 structured: Structured,
133 unstructured: Unstructured,
72 /// For a `selection` type block, we cannot use early exits, and we
73 /// must generate a 'merge ladder' of OpSelection instructions. To that end,
74 /// we keep a stack of the merges that still must be closed at the end of
75 /// a block.
76 ///
77 /// This entire structure basically just resembles a tree like
78 /// a x
79 /// \ /
80 /// b o merge
81 /// \ /
82 /// c o merge
83 /// \ /
84 /// o merge
85 /// /
86 /// o jump to next block
87 selection: struct {
88 /// In order to know which merges we still need to do, we need to keep
89 /// a stack of those.
90 merge_stack: std.ArrayList(SelectionMerge) = .empty,
91 },
92 /// For a `loop` type block, we can early-exit the block by
93 /// jumping to the loop exit node, and we don't need to generate
94 /// an entire stack of merges.
95 loop: struct {
96 /// The next block to jump to can be determined from any number
97 /// of conditions that jump to the loop exit.
98 merges: std.ArrayList(Incoming) = .empty,
99 /// The label id of the loop's merge block.
100 merge_block: Id,
101 },
134102
135 pub fn deinit(cg: *ControlFlow, gpa: Allocator) void {
136 switch (cg.*) {
137 .structured => |*cf| {
138 cf.block_stack.deinit(gpa);
139 cf.block_results.deinit(gpa);
140 },
141 .unstructured => |*cf| {
142 cf.blocks.deinit(gpa);
143 },
103 fn deinit(block: *Block, gpa: Allocator) void {
104 switch (block.*) {
105 .selection => |*merge| merge.merge_stack.deinit(gpa),
106 .loop => |*merge| merge.merges.deinit(gpa),
144107 }
145 cg.* = undefined;
108 block.* = undefined;
146109 }
147110};
148111
......@@ -151,23 +114,27 @@ air: Air,
151114liveness: Air.Liveness,
152115owner_nav: InternPool.Nav.Index,
153116module: *Module,
154control_flow: ControlFlow,
117block_stack: std.ArrayList(*Block) = .empty,
118block_results: std.AutoHashMapUnmanaged(Air.Inst.Index, Id) = .empty,
155119base_line: u32,
156120block_label: Id = .none,
157121next_arg_index: u32 = 0,
158122args: std.ArrayList(Id) = .empty,
159123virtual_allocas: std.AutoHashMapUnmanaged(Id, ?Id) = .empty,
160124inst_results: std.AutoHashMapUnmanaged(Air.Inst.Index, Id) = .empty,
125loop_switches: std.AutoHashMapUnmanaged(Air.Inst.Index, LoopSwitch) = .empty,
161126id_scratch: std.ArrayList(Id) = .empty,
162127prologue: Section = .{},
163128body: Section = .{},
164129
165130pub fn deinit(cg: *CodeGen) void {
166131 const gpa = cg.module.gpa;
167 cg.control_flow.deinit(gpa);
132 cg.block_stack.deinit(gpa);
133 cg.block_results.deinit(gpa);
168134 cg.args.deinit(gpa);
169135 cg.virtual_allocas.deinit(gpa);
170136 cg.inst_results.deinit(gpa);
137 cg.loop_switches.deinit(gpa);
171138 cg.id_scratch.deinit(gpa);
172139 cg.prologue.deinit(gpa);
173140 cg.body.deinit(gpa);
......@@ -183,7 +150,6 @@ pub fn generate(
183150 const zcu = pt.zcu;
184151 const gpa = zcu.gpa;
185152 const nav = zcu.funcInfo(func_index).owner_nav;
186 const structured_cfg = zcu.navFileScope(nav).mod.?.structured_cfg;
187153
188154 var arena = std.heap.ArenaAllocator.init(gpa);
189155 defer arena.deinit();
......@@ -200,10 +166,6 @@ pub fn generate(
200166 .liveness = liveness.*.?,
201167 .owner_nav = nav,
202168 .module = &module,
203 .control_flow = switch (structured_cfg) {
204 true => .{ .structured = .{} },
205 false => .{ .unstructured = .{} },
206 },
207169 .base_line = zcu.navSrcLine(nav),
208170 };
209171 defer cg.deinit();
......@@ -222,7 +184,6 @@ pub fn generateNav(
222184) codegen.Error!Mir {
223185 const zcu = pt.zcu;
224186 const gpa = zcu.gpa;
225 const structured_cfg = zcu.navFileScope(nav_index).mod.?.structured_cfg;
226187
227188 var arena = std.heap.ArenaAllocator.init(gpa);
228189 defer arena.deinit();
......@@ -239,10 +200,6 @@ pub fn generateNav(
239200 .liveness = undefined,
240201 .owner_nav = nav_index,
241202 .module = &module,
242 .control_flow = switch (structured_cfg) {
243 true => .{ .structured = .{} },
244 false => .{ .unstructured = .{} },
245 },
246203 .base_line = zcu.navSrcLine(nav_index),
247204 };
248205 defer cg.deinit();
......@@ -433,17 +390,10 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
433390 cg.block_label = root_block_id;
434391
435392 const main_body = cg.air.getMainBody();
436 switch (cg.control_flow) {
437 .structured => {
438 _ = try cg.genStructuredBody(.selection, main_body);
439 // We always expect paths to here to end, but we still need the block
440 // to act as a dummy merge block.
441 try cg.body.emit(gpa, .OpUnreachable, {});
442 },
443 .unstructured => {
444 try cg.genBody(main_body);
445 },
446 }
393 _ = try cg.genStructuredBody(.selection, main_body);
394 // We always expect paths to here to end, but we still need the block
395 // to act as a dummy merge block.
396 try cg.body.emit(gpa, .OpUnreachable, {});
447397 try cg.body.emit(gpa, .OpFunctionEnd, {});
448398 // Append the actual code into the functions section.
449399 try cg.module.sections.functions.append(gpa, cg.prologue);
......@@ -1052,8 +1002,34 @@ fn constIntBig(cg: *CodeGen, ty: Type, val: Value) !Id {
10521002 return cg.constructComposite(result_ty_id, constituents);
10531003}
10541004
1005/// Construct a composite value from its constituents.
1006/// In logical addressing mode (Vulkan/OpenGL), OpCompositeConstruct cannot accept
1007/// pointer operands, so for struct types we use alloc, store for each field and load instead.
10551008pub fn constructComposite(cg: *CodeGen, result_ty_id: Id, constituents: []const Id) !Id {
10561009 const gpa = cg.module.gpa;
1010
1011 if (cg.module.structFields(result_ty_id)) |fields| {
1012 assert(fields.len == constituents.len);
1013 const u32_ty_id = try cg.module.intType(.unsigned, 32);
1014 const var_id = try cg.alloc(result_ty_id, null);
1015 for (fields, constituents, 0..) |field_ty_id, constituent, i| {
1016 const field_ptr_ty_id = try cg.module.ptrType(field_ty_id, .function);
1017 const index_id = try cg.module.constant(u32_ty_id, .{ .uint32 = @intCast(i) });
1018 const field_ptr = try cg.accessChainId(field_ptr_ty_id, var_id, &.{index_id});
1019 try cg.body.emit(gpa, .OpStore, .{
1020 .pointer = field_ptr,
1021 .object = constituent,
1022 });
1023 }
1024 const result_id = cg.module.allocId();
1025 try cg.body.emit(gpa, .OpLoad, .{
1026 .id_result_type = result_ty_id,
1027 .id_result = result_id,
1028 .pointer = var_id,
1029 });
1030 return result_id;
1031 }
1032
10571033 const result_id = cg.module.allocId();
10581034 try cg.body.emit(gpa, .OpCompositeConstruct, .{
10591035 .id_result_type = result_ty_id,
......@@ -3896,19 +3872,21 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) Error!void {
38963872 .load => try cg.airLoad(inst),
38973873 .store, .store_safe => return cg.airStore(inst),
38983874
3899 .br => return cg.airBr(inst),
3875 .br => return cg.airBr(inst),
39003876 // For now just ignore this instruction. This effectively falls back on the old implementation,
39013877 // this doesn't change anything for us.
3902 .repeat => return,
3903 .breakpoint => return,
3904 .cond_br => return cg.airCondBr(inst),
3905 .loop => return cg.airLoop(inst),
3906 .ret => return cg.airRet(inst),
3907 .ret_safe => return cg.airRet(inst), // TODO
3908 .ret_load => return cg.airRetLoad(inst),
3909 .@"try" => try cg.airTry(inst),
3910 .switch_br => return cg.airSwitchBr(inst),
3911 .unreach, .trap => return cg.airUnreach(),
3878 .repeat => return,
3879 .breakpoint => return,
3880 .cond_br => return cg.airCondBr(inst),
3881 .loop => return cg.airLoop(inst),
3882 .ret => return cg.airRet(inst),
3883 .ret_safe => return cg.airRet(inst), // TODO
3884 .ret_load => return cg.airRetLoad(inst),
3885 .@"try" => try cg.airTry(inst),
3886 .switch_br => return cg.airSwitchBr(inst),
3887 .loop_switch_br => return cg.airLoopSwitchBr(inst),
3888 .switch_dispatch => return cg.airSwitchDispatch(inst),
3889 .unreach, .trap => return cg.airUnreach(),
39123890
39133891 .dbg_empty_stmt => return,
39143892 .dbg_stmt => return cg.airDbgStmt(inst),
......@@ -6426,7 +6404,27 @@ fn structFieldPtr(
64266404 return cg.accessChain(result_ty_id, object_ptr, &.{field_index});
64276405 },
64286406 .@"struct" => switch (object_ty.containerLayout(zcu)) {
6429 .@"packed" => return cg.todo("implement field access for packed structs", .{}),
6407 .@"packed" => {
6408 const byte_offset = codegen.fieldOffset(object_ptr_ty, result_ptr_ty, field_index, zcu);
6409 if (byte_offset == 0) return object_ptr;
6410 const usize_ty_id = try cg.resolveType(.usize, .direct);
6411 const base_int = cg.module.allocId();
6412 try cg.body.emit(cg.module.gpa, .OpConvertPtrToU, .{
6413 .id_result_type = usize_ty_id,
6414 .id_result = base_int,
6415 .pointer = object_ptr,
6416 });
6417 const offset_id = try cg.constInt(.usize, byte_offset);
6418 const adjusted = try cg.buildBinary(.OpIAdd, .{ .ty = .usize, .value = .{ .singleton = base_int } }, .{ .ty = .usize, .value = .{ .singleton = offset_id } });
6419 const adjusted_id = try adjusted.materialize(cg);
6420 const result_id = cg.module.allocId();
6421 try cg.body.emit(cg.module.gpa, .OpConvertUToPtr, .{
6422 .id_result_type = result_ty_id,
6423 .id_result = result_id,
6424 .integer_value = adjusted_id,
6425 });
6426 return result_id;
6427 },
64306428 .auto, .@"extern" => {
64316429 return try cg.accessChain(result_ty_id, object_ptr, &.{field_index});
64326430 },
......@@ -6532,9 +6530,7 @@ fn airArg(cg: *CodeGen) Id {
65326530/// block to jump to. This function emits instructions, so it should be emitted
65336531/// inside the merge block of the block.
65346532/// This function should only be called with structured control flow generation.
6535fn structuredNextBlock(cg: *CodeGen, incoming: []const ControlFlow.Structured.Block.Incoming) !Id {
6536 assert(cg.control_flow == .structured);
6537
6533fn structuredNextBlock(cg: *CodeGen, incoming: []const Block.Incoming) !Id {
65386534 const result_id = cg.module.allocId();
65396535 const block_id_ty_id = try cg.resolveType(.u32, .direct);
65406536 try cg.body.emitRaw(cg.module.gpa, .OpPhi, @intCast(2 + incoming.len * 2)); // result type + result + variable/parent...
......@@ -6552,10 +6548,8 @@ fn structuredNextBlock(cg: *CodeGen, incoming: []const ControlFlow.Structured.Bl
65526548/// terminating a body, there should be no instructions after it.
65536549/// This function should only be called with structured control flow generation.
65546550fn structuredBreak(cg: *CodeGen, target_block: Id) !void {
6555 assert(cg.control_flow == .structured);
6556
65576551 const gpa = cg.module.gpa;
6558 const sblock = cg.control_flow.structured.block_stack.getLast().?;
6552 const sblock = cg.block_stack.getLast().?;
65596553 const merge_block = switch (sblock.*) {
65606554 .selection => |*merge| blk: {
65616555 const merge_label = cg.module.allocId();
......@@ -6598,11 +6592,9 @@ fn genStructuredBody(
65986592 },
65996593 body: []const Air.Inst.Index,
66006594) !Id {
6601 assert(cg.control_flow == .structured);
6602
66036595 const gpa = cg.module.gpa;
66046596
6605 var sblock: ControlFlow.Structured.Block = switch (block_merge_type) {
6597 var sblock: Block = switch (block_merge_type) {
66066598 .loop => |merge| .{ .loop = .{
66076599 .merge_block = merge.merge_label,
66086600 } },
......@@ -6611,8 +6603,8 @@ fn genStructuredBody(
66116603 defer sblock.deinit(gpa);
66126604
66136605 {
6614 try cg.control_flow.structured.block_stack.append(gpa, &sblock);
6615 defer _ = cg.control_flow.structured.block_stack.pop();
6606 try cg.block_stack.append(gpa, &sblock);
6607 defer _ = cg.block_stack.pop();
66166608
66176609 try cg.genBody(body);
66186610 }
......@@ -6650,7 +6642,7 @@ fn genStructuredBody(
66506642 try cg.beginSpvBlock(merge_stack[merge_stack.len - 1].merge_block);
66516643
66526644 // Now generate a merge ladder for the remaining merges in the stack.
6653 var incoming: ControlFlow.Structured.Block.Incoming = .{
6645 var incoming: Block.Incoming = .{
66546646 .src_label = cg.block_label,
66556647 .next_block = merge_stack[merge_stack.len - 1].incoming.next_block,
66566648 };
......@@ -6699,65 +6691,19 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index)
66996691 const ty = cg.typeOfIndex(inst);
67006692 const have_block_result = ty.hasRuntimeBits(zcu);
67016693
6702 const cf = switch (cg.control_flow) {
6703 .structured => |*cf| cf,
6704 .unstructured => |*cf| {
6705 var block: ControlFlow.Unstructured.Block = .{};
6706 defer block.incoming_blocks.deinit(gpa);
6707
6708 // 4 chosen as arbitrary initial capacity.
6709 try block.incoming_blocks.ensureUnusedCapacity(gpa, 4);
6710
6711 try cf.blocks.putNoClobber(gpa, inst, &block);
6712 defer assert(cf.blocks.remove(inst));
6713
6714 try cg.genBody(body);
6715
6716 // Only begin a new block if there were actually any breaks towards it.
6717 if (block.label) |label| {
6718 try cg.beginSpvBlock(label);
6719 }
6720
6721 if (!have_block_result)
6722 return null;
6723
6724 assert(block.label != null);
6725 const result_id = cg.module.allocId();
6726 const result_type_id = try cg.resolveType(ty, .direct);
6727
6728 try cg.body.emitRaw(
6729 gpa,
6730 .OpPhi,
6731 // result type + result + variable/parent...
6732 2 + @as(u16, @intCast(block.incoming_blocks.items.len * 2)),
6733 );
6734 cg.body.writeOperand(Id, result_type_id);
6735 cg.body.writeOperand(Id, result_id);
6736
6737 for (block.incoming_blocks.items) |incoming| {
6738 cg.body.writeOperand(
6739 spec.PairIdRefIdRef,
6740 .{ incoming.break_value_id, incoming.src_label },
6741 );
6742 }
6743
6744 return result_id;
6745 },
6746 };
6747
67486694 const maybe_block_result_var_id = if (have_block_result) blk: {
67496695 const ty_id = try cg.resolveType(ty, .indirect);
67506696 const block_result_var_id = try cg.alloc(ty_id, null);
6751 try cf.block_results.putNoClobber(gpa, inst, block_result_var_id);
6697 try cg.block_results.putNoClobber(gpa, inst, block_result_var_id);
67526698 break :blk block_result_var_id;
67536699 } else null;
6754 defer if (have_block_result) assert(cf.block_results.remove(inst));
6700 defer if (have_block_result) assert(cg.block_results.remove(inst));
67556701
67566702 const next_block = try cg.genStructuredBody(.selection, body);
67576703
67586704 // When encountering a block instruction, we are always at least in the function's scope,
67596705 // so there always has to be another entry.
6760 assert(cf.block_stack.items.len > 0);
6706 assert(cg.block_stack.items.len > 0);
67616707
67626708 // Check if the target of the branch was this current block.
67636709 const this_block = try cg.constInt(.u32, @intFromEnum(inst));
......@@ -6770,7 +6716,7 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index)
67706716 .operand_2 = this_block,
67716717 });
67726718
6773 const sblock = cf.block_stack.getLast().?;
6719 const sblock = cg.block_stack.getLast().?;
67746720
67756721 if (ty.isNoReturn(zcu)) {
67766722 // If this block is noreturn, this instruction is the last of a block,
......@@ -6828,41 +6774,18 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index)
68286774}
68296775
68306776fn airBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
6831 const gpa = cg.module.gpa;
68326777 const zcu = cg.module.zcu;
68336778 const br = cg.air.instructions.items(.data)[@intFromEnum(inst)].br;
68346779 const operand_ty = cg.typeOf(br.operand);
68356780
6836 switch (cg.control_flow) {
6837 .structured => |*cf| {
6838 if (operand_ty.hasRuntimeBits(zcu)) {
6839 const operand_id = try cg.resolve(br.operand);
6840 const block_result_var_id = cf.block_results.get(br.block_inst).?;
6841 try cg.store(operand_ty, block_result_var_id, operand_id, .{});
6842 }
6843
6844 const next_block = try cg.constInt(.u32, @intFromEnum(br.block_inst));
6845 try cg.structuredBreak(next_block);
6846 },
6847 .unstructured => |cf| {
6848 const block = cf.blocks.get(br.block_inst).?;
6849 if (operand_ty.hasRuntimeBits(zcu)) {
6850 const operand_id = try cg.resolve(br.operand);
6851 // block_label should not be undefined here, lest there
6852 // is a br or br_void in the function's body.
6853 try block.incoming_blocks.append(gpa, .{
6854 .src_label = cg.block_label,
6855 .break_value_id = operand_id,
6856 });
6857 }
6858
6859 if (block.label == null) {
6860 block.label = cg.module.allocId();
6861 }
6862
6863 try cg.body.emit(gpa, .OpBranch, .{ .target_label = block.label.? });
6864 },
6781 if (operand_ty.hasRuntimeBits(zcu)) {
6782 const operand_id = try cg.resolve(br.operand);
6783 const block_result_var_id = cg.block_results.get(br.block_inst).?;
6784 try cg.store(operand_ty, block_result_var_id, operand_id, .{});
68656785 }
6786
6787 const next_block = try cg.constInt(.u32, @intFromEnum(br.block_inst));
6788 try cg.structuredBreak(next_block);
68666789}
68676790
68686791fn airCondBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
......@@ -6875,56 +6798,40 @@ fn airCondBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
68756798 const then_label = cg.module.allocId();
68766799 const else_label = cg.module.allocId();
68776800
6878 switch (cg.control_flow) {
6879 .structured => {
6880 const merge_label = cg.module.allocId();
6881
6882 try cg.body.emit(gpa, .OpSelectionMerge, .{
6883 .merge_block = merge_label,
6884 .selection_control = .{},
6885 });
6886 try cg.body.emit(gpa, .OpBranchConditional, .{
6887 .condition = condition_id,
6888 .true_label = then_label,
6889 .false_label = else_label,
6890 });
6801 const merge_label = cg.module.allocId();
68916802
6892 try cg.beginSpvBlock(then_label);
6893 const then_next = try cg.genStructuredBody(.selection, then_body);
6894 const then_incoming: ControlFlow.Structured.Block.Incoming = .{
6895 .src_label = cg.block_label,
6896 .next_block = then_next,
6897 };
6803 try cg.body.emit(gpa, .OpSelectionMerge, .{
6804 .merge_block = merge_label,
6805 .selection_control = .{},
6806 });
6807 try cg.body.emit(gpa, .OpBranchConditional, .{
6808 .condition = condition_id,
6809 .true_label = then_label,
6810 .false_label = else_label,
6811 });
68986812
6899 try cg.body.emit(gpa, .OpBranch, .{ .target_label = merge_label });
6813 try cg.beginSpvBlock(then_label);
6814 const then_next = try cg.genStructuredBody(.selection, then_body);
6815 const then_incoming: Block.Incoming = .{
6816 .src_label = cg.block_label,
6817 .next_block = then_next,
6818 };
69006819
6901 try cg.beginSpvBlock(else_label);
6902 const else_next = try cg.genStructuredBody(.selection, else_body);
6903 const else_incoming: ControlFlow.Structured.Block.Incoming = .{
6904 .src_label = cg.block_label,
6905 .next_block = else_next,
6906 };
6820 try cg.body.emit(gpa, .OpBranch, .{ .target_label = merge_label });
69076821
6908 try cg.body.emit(gpa, .OpBranch, .{ .target_label = merge_label });
6822 try cg.beginSpvBlock(else_label);
6823 const else_next = try cg.genStructuredBody(.selection, else_body);
6824 const else_incoming: Block.Incoming = .{
6825 .src_label = cg.block_label,
6826 .next_block = else_next,
6827 };
69096828
6910 try cg.beginSpvBlock(merge_label);
6911 const next_block = try cg.structuredNextBlock(&.{ then_incoming, else_incoming });
6829 try cg.body.emit(gpa, .OpBranch, .{ .target_label = merge_label });
69126830
6913 try cg.structuredBreak(next_block);
6914 },
6915 .unstructured => {
6916 try cg.body.emit(gpa, .OpBranchConditional, .{
6917 .condition = condition_id,
6918 .true_label = then_label,
6919 .false_label = else_label,
6920 });
6831 try cg.beginSpvBlock(merge_label);
6832 const next_block = try cg.structuredNextBlock(&.{ then_incoming, else_incoming });
69216833
6922 try cg.beginSpvBlock(then_label);
6923 try cg.genBody(then_body);
6924 try cg.beginSpvBlock(else_label);
6925 try cg.genBody(else_body);
6926 },
6927 }
6834 try cg.structuredBreak(next_block);
69286835}
69296836
69306837fn airLoop(cg: *CodeGen, inst: Air.Inst.Index) !void {
......@@ -6933,67 +6840,85 @@ fn airLoop(cg: *CodeGen, inst: Air.Inst.Index) !void {
69336840
69346841 const body_label = cg.module.allocId();
69356842
6936 switch (cg.control_flow) {
6937 .structured => {
6938 const header_label = cg.module.allocId();
6939 const merge_label = cg.module.allocId();
6940 const continue_label = cg.module.allocId();
6941
6942 // The back-edge must point to the loop header, so generate a separate block for the
6943 // loop header so that we don't accidentally include some instructions from there
6944 // in the loop.
6843 const header_label = cg.module.allocId();
6844 const merge_label = cg.module.allocId();
6845 const continue_label = cg.module.allocId();
69456846
6946 try cg.body.emit(gpa, .OpBranch, .{ .target_label = header_label });
6947 try cg.beginSpvBlock(header_label);
6847 // The back-edge must point to the loop header, so generate a separate block for the
6848 // loop header so that we don't accidentally include some instructions from there
6849 // in the loop.
69486850
6949 // Emit loop header and jump to loop body
6950 try cg.body.emit(gpa, .OpLoopMerge, .{
6951 .merge_block = merge_label,
6952 .continue_target = continue_label,
6953 .loop_control = .{},
6954 });
6851 try cg.body.emit(gpa, .OpBranch, .{ .target_label = header_label });
6852 try cg.beginSpvBlock(header_label);
69556853
6956 try cg.body.emit(gpa, .OpBranch, .{ .target_label = body_label });
6854 // Emit loop header and jump to loop body
6855 try cg.body.emit(gpa, .OpLoopMerge, .{
6856 .merge_block = merge_label,
6857 .continue_target = continue_label,
6858 .loop_control = .{},
6859 });
69576860
6958 try cg.beginSpvBlock(body_label);
6861 try cg.body.emit(gpa, .OpBranch, .{ .target_label = body_label });
69596862
6960 const next_block = try cg.genStructuredBody(.{ .loop = .{
6961 .merge_label = merge_label,
6962 .continue_label = continue_label,
6963 } }, block.body);
6964 try cg.structuredBreak(next_block);
6863 try cg.beginSpvBlock(body_label);
69656864
6966 try cg.beginSpvBlock(continue_label);
6865 const next_block = try cg.genStructuredBody(.{ .loop = .{
6866 .merge_label = merge_label,
6867 .continue_label = continue_label,
6868 } }, block.body);
6869 try cg.structuredBreak(next_block);
69676870
6968 try cg.body.emit(gpa, .OpBranch, .{ .target_label = header_label });
6969 },
6970 .unstructured => {
6971 try cg.body.emit(gpa, .OpBranch, .{ .target_label = body_label });
6972 try cg.beginSpvBlock(body_label);
6973 try cg.genBody(block.body);
6871 try cg.beginSpvBlock(continue_label);
69746872
6975 try cg.body.emit(gpa, .OpBranch, .{ .target_label = body_label });
6976 },
6977 }
6873 try cg.body.emit(gpa, .OpBranch, .{ .target_label = header_label });
69786874}
69796875
69806876fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
69816877 const zcu = cg.module.zcu;
6878 const pt = cg.pt;
69826879 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
69836880 const ptr_ty = cg.typeOf(ty_op.operand);
6881 const ptr_info = ptr_ty.ptrInfo(zcu);
69846882 const elem_ty = cg.typeOfIndex(inst);
69856883 const operand = try cg.resolve(ty_op.operand);
69866884 if (!ptr_ty.isVolatilePtr(zcu) and cg.liveness.isUnused(inst)) return null;
69876885
69886886 if (cg.virtual_allocas.get(operand)) |stored| return stored.?;
69896887
6888 if (ptr_info.packed_offset.host_size != 0 and
6889 ptr_info.flags.vector_index == .none)
6890 {
6891 const host_bits: u16 = ptr_info.packed_offset.host_size * 8;
6892 const elem_bit_size: u16 = @intCast(elem_ty.bitSize(zcu));
6893 const host_int_ty = try pt.intType(.unsigned, host_bits);
6894 const host_val = try cg.load(host_int_ty, operand, .{ .is_volatile = ptr_ty.isVolatilePtr(zcu) });
6895 const signedness: Signedness = if (elem_ty.isInt(zcu)) elem_ty.intInfo(zcu).signedness else .unsigned;
6896 const field_int_ty = try pt.intType(signedness, elem_bit_size);
6897 const narrowed = if (ptr_info.packed_offset.bit_offset > 0) blk: {
6898 const bit_offset_id = try cg.constInt(host_int_ty, ptr_info.packed_offset.bit_offset);
6899 const shifted = try cg.buildBinary(.OpShiftRightLogical, .{ .ty = host_int_ty, .value = .{ .singleton = host_val } }, .{ .ty = host_int_ty, .value = .{ .singleton = bit_offset_id } });
6900 break :blk try shifted.materialize(cg);
6901 } else host_val;
6902 const result_id = blk: {
6903 if (cg.module.backingIntBits(elem_bit_size).@"0" == cg.module.backingIntBits(host_bits).@"0")
6904 break :blk try cg.bitCast(field_int_ty, host_int_ty, narrowed);
6905 const trunc = try cg.buildConvert(field_int_ty, .{ .ty = host_int_ty, .value = .{ .singleton = narrowed } });
6906 break :blk try trunc.materialize(cg);
6907 };
6908 if (elem_ty.ip_index == .bool_type) return try cg.convertToDirect(.bool, result_id);
6909 if (elem_ty.isInt(zcu)) return result_id;
6910 return try cg.bitCast(elem_ty, field_int_ty, result_id);
6911 }
6912
69906913 return try cg.load(elem_ty, operand, .{ .is_volatile = ptr_ty.isVolatilePtr(zcu) });
69916914}
69926915
69936916fn airStore(cg: *CodeGen, inst: Air.Inst.Index) !void {
69946917 const zcu = cg.module.zcu;
6918 const pt = cg.pt;
69956919 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
69966920 const ptr_ty = cg.typeOf(bin_op.lhs);
6921 const ptr_info = ptr_ty.ptrInfo(zcu);
69976922 const elem_ty = ptr_ty.childType(zcu);
69986923 const ptr = try cg.resolve(bin_op.lhs);
69996924 const value = try cg.resolve(bin_op.rhs);
......@@ -7003,6 +6928,48 @@ fn airStore(cg: *CodeGen, inst: Air.Inst.Index) !void {
70036928 return;
70046929 }
70056930
6931 if (ptr_info.packed_offset.host_size != 0 and
6932 ptr_info.flags.vector_index == .none)
6933 {
6934 const host_bits: u16 = ptr_info.packed_offset.host_size * 8;
6935 const host_int_ty = try pt.intType(.unsigned, host_bits);
6936 const host_val = try cg.load(host_int_ty, ptr, .{ .is_volatile = ptr_ty.isVolatilePtr(zcu) });
6937 const elem_bit_size: u16 = @intCast(elem_ty.bitSize(zcu));
6938 const signedness: Signedness = if (elem_ty.isInt(zcu)) elem_ty.intInfo(zcu).signedness else .unsigned;
6939 const field_int_ty = try pt.intType(signedness, elem_bit_size);
6940
6941 var value_as_int: Id = undefined;
6942 if (elem_ty.ip_index == .bool_type) {
6943 value_as_int = try cg.convertToIndirect(.bool, value);
6944 value_as_int = try cg.bitCast(field_int_ty, .u1, value_as_int);
6945 } else if (elem_ty.isInt(zcu)) {
6946 value_as_int = value;
6947 } else {
6948 value_as_int = try cg.bitCast(field_int_ty, elem_ty, value);
6949 }
6950
6951 const extended = blk: {
6952 if (cg.module.backingIntBits(elem_bit_size).@"0" == cg.module.backingIntBits(host_bits).@"0")
6953 break :blk try cg.bitCast(host_int_ty, field_int_ty, value_as_int);
6954 const conv = try cg.buildConvert(host_int_ty, .{ .ty = field_int_ty, .value = .{ .singleton = value_as_int } });
6955 break :blk try conv.materialize(cg);
6956 };
6957
6958 const bit_offset = ptr_info.packed_offset.bit_offset;
6959 const field_mask = (@as(u64, 1) << @as(u6, @intCast(elem_bit_size))) - 1;
6960 const host_mask = if (host_bits == 64) @as(u64, std.math.maxInt(u64)) else (@as(u64, 1) << @as(u6, @intCast(host_bits))) - 1;
6961 const clear_mask = ~(field_mask << @as(u6, @intCast(bit_offset))) & host_mask;
6962 const clear_mask_id = try cg.constInt(host_int_ty, clear_mask);
6963 const cleared = try cg.buildBinary(.OpBitwiseAnd, .{ .ty = host_int_ty, .value = .{ .singleton = host_val } }, .{ .ty = host_int_ty, .value = .{ .singleton = clear_mask_id } });
6964 const bit_offset_id = try cg.constInt(host_int_ty, bit_offset);
6965 const shifted_val = try cg.buildBinary(.OpShiftLeftLogical, .{ .ty = host_int_ty, .value = .{ .singleton = extended } }, .{ .ty = host_int_ty, .value = .{ .singleton = bit_offset_id } });
6966 const combined = try cg.buildBinary(.OpBitwiseOr, cleared, shifted_val);
6967 const combined_id = try combined.materialize(cg);
6968
6969 try cg.store(host_int_ty, ptr, combined_id, .{ .is_volatile = ptr_ty.isVolatilePtr(zcu) });
6970 return;
6971 }
6972
70066973 try cg.store(elem_ty, ptr, value, .{ .is_volatile = ptr_ty.isVolatilePtr(zcu) });
70076974}
70086975
......@@ -7091,19 +7058,13 @@ fn airTry(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
70917058 const err_block = cg.module.allocId();
70927059 const ok_block = cg.module.allocId();
70937060
7094 switch (cg.control_flow) {
7095 .structured => {
7096 // According to AIR documentation, this block is guaranteed
7097 // to not break and end in a return instruction. Thus,
7098 // for structured control flow, we can just naively use
7099 // the ok block as the merge block here.
7100 try cg.body.emit(gpa, .OpSelectionMerge, .{
7101 .merge_block = ok_block,
7102 .selection_control = .{},
7103 });
7104 },
7105 .unstructured => {},
7106 }
7061 // According to AIR documentation, this block is guaranteed
7062 // to not break and end in a return instruction. Thus,
7063 // we can just naively use the ok block as the merge block here.
7064 try cg.body.emit(gpa, .OpSelectionMerge, .{
7065 .merge_block = ok_block,
7066 .selection_control = .{},
7067 });
71077068
71087069 try cg.body.emit(gpa, .OpBranchConditional, .{
71097070 .condition = is_err_id,
......@@ -7419,45 +7380,44 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
74197380
74207381 const num_cases = switch_br.cases_len;
74217382
7422 // Compute the total number of arms that we need.
7423 // Zig switches are grouped by condition, so we need to loop through all of them
7424 const num_conditions = blk: {
7425 var num_conditions: u32 = 0;
7383 // compute the total number of scalar arms and find the last range case
7384 var num_conditions: u32 = 0;
7385 var last_range_case: ?u32 = null;
7386 {
74267387 var it = switch_br.iterateCases();
74277388 while (it.next()) |case| {
7428 if (case.ranges.len > 0) return cg.todo("switch with ranges", .{});
7429 num_conditions += @intCast(case.items.len);
7389 if (case.ranges.len > 0) {
7390 last_range_case = case.idx;
7391 } else {
7392 num_conditions += @intCast(case.items.len);
7393 }
74307394 }
7431 break :blk num_conditions;
7432 };
7395 }
74337396
74347397 // First, pre-allocate the labels for the cases.
74357398 const case_labels = cg.module.allocIds(num_cases);
74367399 // We always need the default case - if zig has none, we will generate unreachable there.
7437 const default = cg.module.allocId();
7400 const default_label = cg.module.allocId();
7401 const switch_default = if (last_range_case != null) cg.module.allocId() else default_label;
74387402
7439 const merge_label = switch (cg.control_flow) {
7440 .structured => cg.module.allocId(),
7441 .unstructured => null,
7442 };
7403 const merge_label = cg.module.allocId();
74437404
7444 if (cg.control_flow == .structured) {
7445 try cg.body.emit(gpa, .OpSelectionMerge, .{
7446 .merge_block = merge_label.?,
7447 .selection_control = .{},
7448 });
7449 }
7405 try cg.body.emit(gpa, .OpSelectionMerge, .{
7406 .merge_block = merge_label,
7407 .selection_control = .{},
7408 });
74507409
74517410 // Emit the instruction before generating the blocks.
74527411 try cg.body.emitRaw(gpa, .OpSwitch, 2 + (cond_words + 1) * num_conditions);
74537412 cg.body.writeOperand(Id, cond_indirect);
7454 cg.body.writeOperand(Id, default);
7413 cg.body.writeOperand(Id, switch_default);
74557414
7456 // Emit each of the cases
7415 // Emit the non-range cases into the OpSwitch.
7416 // Cases with ranges are handled by the conditional chain below.
74577417 {
74587418 var it = switch_br.iterateCases();
74597419 while (it.next()) |case| {
7460 // SPIR-V needs a literal here, which' width depends on the case condition.
7420 if (case.ranges.len > 0) continue;
74617421 const label = case_labels.at(case.idx);
74627422
74637423 for (case.items) |item| {
......@@ -7480,62 +7440,394 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
74807440 }
74817441 }
74827442
7483 var incoming_structured_blocks: std.ArrayList(ControlFlow.Structured.Block.Incoming) = .empty;
7443 var incoming_structured_blocks: std.ArrayList(Block.Incoming) = .empty;
74847444 defer incoming_structured_blocks.deinit(gpa);
7445 try incoming_structured_blocks.ensureUnusedCapacity(gpa, num_cases + 1);
7446
7447 // emit the range-checking chain as nested if-else inside the switch's default branch.
7448 // each range case becomes:
7449 // - check condition,
7450 // - if true emit case body and branch to merge,
7451 // - else continue to next check or default
7452 if (last_range_case != null) {
7453 const cond_tmp: Temporary = .init(cond_ty, cond);
7454 const bool_ty_id = try cg.resolveType(.bool, .direct);
7455
7456 try cg.beginSpvBlock(switch_default);
7457
7458 var it_range = switch_br.iterateCases();
7459 while (it_range.next()) |case| {
7460 if (case.ranges.len == 0) continue;
7461
7462 var case_cond: ?Id = null;
7463
7464 for (case.items) |item| {
7465 const item_tmp: Temporary = try cg.temporary(item);
7466 const eq = try (try cg.cmp(.eq, cond_tmp, item_tmp)).materialize(cg);
7467 case_cond = if (case_cond) |prev| blk: {
7468 const combined = cg.module.allocId();
7469 try cg.body.emitRaw(gpa, .OpLogicalOr, 4);
7470 cg.body.writeOperand(Id, bool_ty_id);
7471 cg.body.writeOperand(Id, combined);
7472 cg.body.writeOperand(Id, prev);
7473 cg.body.writeOperand(Id, eq);
7474 break :blk combined;
7475 } else eq;
7476 }
7477
7478 for (case.ranges) |range| {
7479 const lo_tmp: Temporary = try cg.temporary(range[0]);
7480 const hi_tmp: Temporary = try cg.temporary(range[1]);
7481 const ge = try (try cg.cmp(.gte, cond_tmp, lo_tmp)).materialize(cg);
7482 const le = try (try cg.cmp(.lte, cond_tmp, hi_tmp)).materialize(cg);
7483 const in_range = cg.module.allocId();
7484 try cg.body.emitRaw(gpa, .OpLogicalAnd, 4);
7485 cg.body.writeOperand(Id, bool_ty_id);
7486 cg.body.writeOperand(Id, in_range);
7487 cg.body.writeOperand(Id, ge);
7488 cg.body.writeOperand(Id, le);
7489 case_cond = if (case_cond) |prev| blk: {
7490 const combined = cg.module.allocId();
7491 try cg.body.emitRaw(gpa, .OpLogicalOr, 4);
7492 cg.body.writeOperand(Id, bool_ty_id);
7493 cg.body.writeOperand(Id, combined);
7494 cg.body.writeOperand(Id, prev);
7495 cg.body.writeOperand(Id, in_range);
7496 break :blk combined;
7497 } else in_range;
7498 }
74857499
7486 if (cg.control_flow == .structured) {
7487 try incoming_structured_blocks.ensureUnusedCapacity(gpa, num_cases + 1);
7500 const case_label = case_labels.at(case.idx);
7501 const is_last = case.idx == last_range_case.?;
7502 const next_check = if (is_last) default_label else cg.module.allocId();
7503
7504 try cg.body.emit(gpa, .OpSelectionMerge, .{
7505 .merge_block = next_check,
7506 .selection_control = .{},
7507 });
7508
7509 try cg.body.emit(gpa, .OpBranchConditional, .{
7510 .condition = case_cond.?,
7511 .true_label = case_label,
7512 .false_label = next_check,
7513 });
7514
7515 if (!is_last) {
7516 try cg.beginSpvBlock(next_check);
7517 }
7518 }
74887519 }
74897520
7490 // Now, finally, we can start emitting each of the cases.
7521 // emit bodies
74917522 var it = switch_br.iterateCases();
74927523 while (it.next()) |case| {
74937524 const label = case_labels.at(case.idx);
74947525
74957526 try cg.beginSpvBlock(label);
74967527
7497 switch (cg.control_flow) {
7498 .structured => {
7499 const next_block = try cg.genStructuredBody(.selection, case.body);
7500 incoming_structured_blocks.appendAssumeCapacity(.{
7501 .src_label = cg.block_label,
7502 .next_block = next_block,
7503 });
7528 const next_block = try cg.genStructuredBody(.selection, case.body);
7529 incoming_structured_blocks.appendAssumeCapacity(.{
7530 .src_label = cg.block_label,
7531 .next_block = next_block,
7532 });
75047533
7505 try cg.body.emit(gpa, .OpBranch, .{ .target_label = merge_label.? });
7506 },
7507 .unstructured => {
7508 try cg.genBody(case.body);
7509 },
7510 }
7534 try cg.body.emit(gpa, .OpBranch, .{ .target_label = merge_label });
75117535 }
75127536
7513 const else_body = it.elseBody();
7514 try cg.beginSpvBlock(default);
7537 const else_body = blk: {
7538 var it_else = switch_br.iterateCases();
7539 while (it_else.next()) |_| {}
7540 break :blk it_else.elseBody();
7541 };
7542 try cg.beginSpvBlock(default_label);
75157543 if (else_body.len != 0) {
7516 switch (cg.control_flow) {
7517 .structured => {
7518 const next_block = try cg.genStructuredBody(.selection, else_body);
7519 incoming_structured_blocks.appendAssumeCapacity(.{
7520 .src_label = cg.block_label,
7521 .next_block = next_block,
7522 });
7544 const next_block = try cg.genStructuredBody(.selection, else_body);
7545 incoming_structured_blocks.appendAssumeCapacity(.{
7546 .src_label = cg.block_label,
7547 .next_block = next_block,
7548 });
75237549
7524 try cg.body.emit(gpa, .OpBranch, .{ .target_label = merge_label.? });
7525 },
7526 .unstructured => {
7527 try cg.genBody(else_body);
7528 },
7529 }
7550 try cg.body.emit(gpa, .OpBranch, .{ .target_label = merge_label });
75307551 } else {
75317552 try cg.body.emit(gpa, .OpUnreachable, {});
75327553 }
75337554
7534 if (cg.control_flow == .structured) {
7535 try cg.beginSpvBlock(merge_label.?);
7536 const next_block = try cg.structuredNextBlock(incoming_structured_blocks.items);
7537 try cg.structuredBreak(next_block);
7555 try cg.beginSpvBlock(merge_label);
7556 const next_block = try cg.structuredNextBlock(incoming_structured_blocks.items);
7557 try cg.structuredBreak(next_block);
7558}
7559
7560fn airLoopSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
7561 const gpa = cg.module.gpa;
7562 const zcu = cg.module.zcu;
7563 const target = cg.module.zcu.getTarget();
7564 const switch_br = cg.air.unwrapSwitch(inst);
7565 const cond_ty = cg.typeOf(switch_br.operand);
7566 const initial_cond = try cg.resolve(switch_br.operand);
7567 var initial_cond_indirect = try cg.convertToIndirect(cond_ty, initial_cond);
7568
7569 const cond_words: u32 = switch (cond_ty.zigTypeTag(zcu)) {
7570 .bool, .error_set => 1,
7571 .int => blk: {
7572 const bits = cond_ty.intInfo(zcu).bits;
7573 const backing_bits, const big_int = cg.module.backingIntBits(bits);
7574 if (big_int) return cg.todo("implement composite int loop switch", .{});
7575 break :blk if (backing_bits <= 32) 1 else 2;
7576 },
7577 .@"enum" => blk: {
7578 const int_ty = cond_ty.intTagType(zcu);
7579 const int_info = int_ty.intInfo(zcu);
7580 const backing_bits, const big_int = cg.module.backingIntBits(int_info.bits);
7581 if (big_int) return cg.todo("implement composite int loop switch", .{});
7582 break :blk if (backing_bits <= 32) 1 else 2;
7583 },
7584 .pointer => blk: {
7585 initial_cond_indirect = try cg.intFromPtr(initial_cond_indirect);
7586 break :blk target.ptrBitWidth() / 32;
7587 },
7588 else => return cg.todo("implement loop switch for type {s}", .{@tagName(cond_ty.zigTypeTag(zcu))}),
7589 };
7590
7591 const cond_ty_id = try cg.resolveType(cond_ty, .indirect);
7592 const cond_var = try cg.alloc(cond_ty_id, null);
7593 try cg.store(cond_ty, cond_var, initial_cond_indirect, .{});
7594
7595 const num_cases = switch_br.cases_len;
7596
7597 var num_conditions: u32 = 0;
7598 var last_range_case: ?u32 = null;
7599 {
7600 var it = switch_br.iterateCases();
7601 while (it.next()) |case| {
7602 if (case.ranges.len > 0) {
7603 last_range_case = case.idx;
7604 } else {
7605 num_conditions += @intCast(case.items.len);
7606 }
7607 }
75387608 }
7609
7610 const case_labels = cg.module.allocIds(num_cases);
7611 const default_label = cg.module.allocId();
7612 const switch_default = if (last_range_case != null) cg.module.allocId() else default_label;
7613
7614 const header_label = cg.module.allocId();
7615 const loop_merge = cg.module.allocId();
7616 const continue_label = cg.module.allocId();
7617 const switch_merge = cg.module.allocId();
7618 const body_label = cg.module.allocId();
7619
7620 // switch_dispatch signals "continue the loop" by using this sentinel as the
7621 // next_block in structuredBreak. at switch_merge, a phi + comparison distinguishes
7622 // dispatch (continue) from break (exit)
7623 const dispatch_sentinel = try cg.constInt(.u32, @intFromEnum(inst));
7624
7625 try cg.loop_switches.putNoClobber(gpa, inst, .{
7626 .cond_var = cond_var,
7627 .continue_label = dispatch_sentinel,
7628 });
7629 defer assert(cg.loop_switches.remove(inst));
7630
7631 try cg.body.emit(gpa, .OpBranch, .{ .target_label = header_label });
7632 try cg.beginSpvBlock(header_label);
7633
7634 try cg.body.emit(gpa, .OpLoopMerge, .{
7635 .merge_block = loop_merge,
7636 .continue_target = continue_label,
7637 .loop_control = .{},
7638 });
7639
7640 try cg.body.emit(gpa, .OpBranch, .{ .target_label = body_label });
7641 try cg.beginSpvBlock(body_label);
7642
7643 const cond = try cg.load(cond_ty, cond_var, .{});
7644 const cond_indirect = try cg.convertToIndirect(cond_ty, cond);
7645
7646 try cg.body.emit(gpa, .OpSelectionMerge, .{
7647 .merge_block = switch_merge,
7648 .selection_control = .{},
7649 });
7650
7651 try cg.body.emitRaw(gpa, .OpSwitch, 2 + (cond_words + 1) * num_conditions);
7652 cg.body.writeOperand(Id, cond_indirect);
7653 cg.body.writeOperand(Id, switch_default);
7654
7655 {
7656 var it = switch_br.iterateCases();
7657 while (it.next()) |case| {
7658 if (case.ranges.len > 0) continue;
7659 const label = case_labels.at(case.idx);
7660 for (case.items) |item| {
7661 const value: Value = .fromInterned(item.toInterned().?);
7662 const int_val: u64 = switch (cond_ty.zigTypeTag(zcu)) {
7663 .bool, .int => if (cond_ty.isSignedInt(zcu)) @bitCast(value.toSignedInt(zcu)) else value.toUnsignedInt(zcu),
7664 .@"enum" => value.intFromEnum(zcu).toUnsignedInt(zcu),
7665 .error_set => value.getErrorInt(zcu),
7666 .pointer => value.toUnsignedInt(zcu),
7667 else => unreachable,
7668 };
7669 const int_lit: spec.LiteralContextDependentNumber = switch (cond_words) {
7670 1 => .{ .uint32 = @intCast(int_val) },
7671 2 => .{ .uint64 = int_val },
7672 else => unreachable,
7673 };
7674 cg.body.writeOperand(spec.LiteralContextDependentNumber, int_lit);
7675 cg.body.writeOperand(Id, label);
7676 }
7677 }
7678 }
7679
7680 var incoming_structured_blocks: std.ArrayList(Block.Incoming) = .empty;
7681 defer incoming_structured_blocks.deinit(gpa);
7682 try incoming_structured_blocks.ensureUnusedCapacity(gpa, num_cases + 1);
7683
7684 if (last_range_case != null) {
7685 const cond_tmp: Temporary = .init(cond_ty, cond);
7686 const bool_ty_id = try cg.resolveType(.bool, .direct);
7687
7688 try cg.beginSpvBlock(switch_default);
7689
7690 var it_range = switch_br.iterateCases();
7691 while (it_range.next()) |case| {
7692 if (case.ranges.len == 0) continue;
7693
7694 var case_cond: ?Id = null;
7695
7696 for (case.items) |item| {
7697 const item_tmp: Temporary = try cg.temporary(item);
7698 const eq = try (try cg.cmp(.eq, cond_tmp, item_tmp)).materialize(cg);
7699 case_cond = if (case_cond) |prev| blk: {
7700 const combined = cg.module.allocId();
7701 try cg.body.emitRaw(gpa, .OpLogicalOr, 4);
7702 cg.body.writeOperand(Id, bool_ty_id);
7703 cg.body.writeOperand(Id, combined);
7704 cg.body.writeOperand(Id, prev);
7705 cg.body.writeOperand(Id, eq);
7706 break :blk combined;
7707 } else eq;
7708 }
7709
7710 for (case.ranges) |range| {
7711 const lo_tmp: Temporary = try cg.temporary(range[0]);
7712 const hi_tmp: Temporary = try cg.temporary(range[1]);
7713 const ge = try (try cg.cmp(.gte, cond_tmp, lo_tmp)).materialize(cg);
7714 const le = try (try cg.cmp(.lte, cond_tmp, hi_tmp)).materialize(cg);
7715 const in_range = cg.module.allocId();
7716 try cg.body.emitRaw(gpa, .OpLogicalAnd, 4);
7717 cg.body.writeOperand(Id, bool_ty_id);
7718 cg.body.writeOperand(Id, in_range);
7719 cg.body.writeOperand(Id, ge);
7720 cg.body.writeOperand(Id, le);
7721 case_cond = if (case_cond) |prev| blk: {
7722 const combined = cg.module.allocId();
7723 try cg.body.emitRaw(gpa, .OpLogicalOr, 4);
7724 cg.body.writeOperand(Id, bool_ty_id);
7725 cg.body.writeOperand(Id, combined);
7726 cg.body.writeOperand(Id, prev);
7727 cg.body.writeOperand(Id, in_range);
7728 break :blk combined;
7729 } else in_range;
7730 }
7731
7732 const case_label = case_labels.at(case.idx);
7733 const is_last = case.idx == last_range_case.?;
7734 const next_check = if (is_last) default_label else cg.module.allocId();
7735
7736 try cg.body.emit(gpa, .OpSelectionMerge, .{
7737 .merge_block = next_check,
7738 .selection_control = .{},
7739 });
7740
7741 try cg.body.emit(gpa, .OpBranchConditional, .{
7742 .condition = case_cond.?,
7743 .true_label = case_label,
7744 .false_label = next_check,
7745 });
7746
7747 if (!is_last) {
7748 try cg.beginSpvBlock(next_check);
7749 }
7750 }
7751 }
7752
7753 {
7754 var it = switch_br.iterateCases();
7755 while (it.next()) |case| {
7756 const label = case_labels.at(case.idx);
7757 try cg.beginSpvBlock(label);
7758
7759 const next_block = try cg.genStructuredBody(.selection, case.body);
7760 incoming_structured_blocks.appendAssumeCapacity(.{
7761 .src_label = cg.block_label,
7762 .next_block = next_block,
7763 });
7764 try cg.body.emit(gpa, .OpBranch, .{ .target_label = switch_merge });
7765 }
7766 }
7767
7768 const else_body = blk: {
7769 var it_else = switch_br.iterateCases();
7770 while (it_else.next()) |_| {}
7771 break :blk it_else.elseBody();
7772 };
7773 try cg.beginSpvBlock(default_label);
7774 if (else_body.len != 0) {
7775 const next_block = try cg.genStructuredBody(.selection, else_body);
7776 incoming_structured_blocks.appendAssumeCapacity(.{
7777 .src_label = cg.block_label,
7778 .next_block = next_block,
7779 });
7780 try cg.body.emit(gpa, .OpBranch, .{ .target_label = switch_merge });
7781 } else {
7782 try cg.body.emit(gpa, .OpUnreachable, {});
7783 }
7784
7785 try cg.beginSpvBlock(switch_merge);
7786 const next_block = try cg.structuredNextBlock(incoming_structured_blocks.items);
7787
7788 const is_dispatch = cg.module.allocId();
7789 const bool_ty_id = try cg.resolveType(.bool, .direct);
7790 try cg.body.emit(gpa, .OpIEqual, .{
7791 .id_result_type = bool_ty_id,
7792 .id_result = is_dispatch,
7793 .operand_1 = next_block,
7794 .operand_2 = dispatch_sentinel,
7795 });
7796
7797 const dispatch_check_merge = cg.module.allocId();
7798 try cg.body.emit(gpa, .OpSelectionMerge, .{
7799 .merge_block = dispatch_check_merge,
7800 .selection_control = .{},
7801 });
7802 const exit_block = cg.module.allocId();
7803 try cg.body.emit(gpa, .OpBranchConditional, .{
7804 .condition = is_dispatch,
7805 .true_label = dispatch_check_merge,
7806 .false_label = exit_block,
7807 });
7808
7809 try cg.beginSpvBlock(exit_block);
7810 try cg.body.emit(gpa, .OpBranch, .{ .target_label = loop_merge });
7811
7812 try cg.beginSpvBlock(dispatch_check_merge);
7813 try cg.body.emit(gpa, .OpBranch, .{ .target_label = continue_label });
7814
7815 try cg.beginSpvBlock(continue_label);
7816 try cg.body.emit(gpa, .OpBranch, .{ .target_label = header_label });
7817
7818 try cg.beginSpvBlock(loop_merge);
7819 try cg.structuredBreak(next_block);
7820}
7821
7822fn airSwitchDispatch(cg: *CodeGen, inst: Air.Inst.Index) !void {
7823 const br = cg.air.instructions.items(.data)[@intFromEnum(inst)].br;
7824 const loop_switch = cg.loop_switches.get(br.block_inst).?;
7825 const cond_ty = cg.typeOf(br.operand);
7826 const operand = try cg.resolve(br.operand);
7827 const operand_indirect = try cg.convertToIndirect(cond_ty, operand);
7828
7829 try cg.store(cond_ty, loop_switch.cond_var, operand_indirect, .{});
7830 try cg.structuredBreak(loop_switch.continue_label);
75397831}
75407832
75417833fn airUnreach(cg: *CodeGen) !void {
......@@ -7743,9 +8035,19 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier)
77438035 // temporary params buffer.
77448036 const arg_ty = cg.typeOf(arg);
77458037 if (!arg_ty.hasRuntimeBits(zcu)) continue;
7746 const arg_id = try cg.resolve(arg);
77478038
7748 params[n_params] = arg_id;
8039 if (arg_ty.zigTypeTag(zcu) == .pointer and !arg_ty.isSlice(zcu) and
8040 !arg_ty.childType(zcu).hasRuntimeBits(zcu))
8041 {
8042 // in logical addressing, pointer arguments to function calls
8043 // must be memory object declarations (OpVariable). for pointers to
8044 // zero-sized types, the source value may not be a variable, so just
8045 // allocate a dummy one.
8046 const child_ty_id = try cg.resolveType(arg_ty.childType(zcu), .indirect);
8047 params[n_params] = try cg.alloc(child_ty_id, null);
8048 } else {
8049 params[n_params] = try cg.resolve(arg);
8050 }
77498051 n_params += 1;
77508052 }
77518053
src/codegen/spirv/Module.zig+7
......@@ -773,6 +773,13 @@ pub fn structType(
773773 return result_id;
774774}
775775
776pub fn structFields(module: *const Module, struct_ty_id: Id) ?[]const Id {
777 for (module.cache.struct_types.keys(), module.cache.struct_types.values()) |key, val| {
778 if (val == struct_ty_id) return key.fields;
779 }
780 return null;
781}
782
776783pub fn functionType(module: *Module, return_ty_id: Id, param_type_ids: []const Id) !Id {
777784 if (module.cache.fn_types.get(.{
778785 .return_ty = return_ty_id,
test/behavior/align.zig-6
......@@ -101,8 +101,6 @@ fn addUnaligned(a: *align(1) const u32, b: *align(1) const u32) u32 {
101101}
102102
103103test "@alignCast pointers" {
104 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
105
106104 var x: u32 align(4) = 1;
107105 expectsOnly1(&x);
108106 try expect(x == 2);
......@@ -223,7 +221,6 @@ test "alignment and size of structs with 128-bit fields" {
223221test "implicitly decreasing slice alignment" {
224222 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
225223 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
226
227224 const a: u32 align(4) = 3;
228225 const b: u32 align(8) = 4;
229226 try expect(addUnalignedSlice(@as(*const [1]u32, &a)[0..], @as(*const [1]u32, &b)[0..]) == 7);
......@@ -265,8 +262,6 @@ test "return error union with 128-bit integer" {
265262 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
266263 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
267264 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
268 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
269
270265 try expect(3 == try give());
271266}
272267fn give() anyerror!u128 {
......@@ -278,7 +273,6 @@ test "page aligned array on stack" {
278273 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
279274 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
280275 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
281
282276 // Large alignment value to make it hard to accidentally pass.
283277 var array align(0x1000) = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 };
284278 var number1: u8 align(16) = 42;
test/behavior/array.zig-6
......@@ -22,8 +22,6 @@ test "array to slice" {
2222test "arrays" {
2323 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2424 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
25 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
26
2725 var array: [5]u32 = undefined;
2826
2927 var i: u32 = 0;
......@@ -51,7 +49,6 @@ test "runtime array concat with comptime slice" {
5149 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
5250 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
5351 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
54
5552 var a: [1]u8 = .{1};
5653 const b = (comptime @as([]const u8, &.{0})) ++ &a;
5754 const c = &a ++ (comptime @as([]const u8, &.{0}));
......@@ -1072,8 +1069,6 @@ test "initialize many-pointer with reference to empty array initializer" {
10721069}
10731070
10741071test "initialize sentinel-terminated slice with reference to empty array initializer" {
1075 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1076
10771072 const a: [:0]const u8 = &.{};
10781073 comptime assert(a.len == 0);
10791074 comptime assert(a[0] == 0);
......@@ -1081,7 +1076,6 @@ test "initialize sentinel-terminated slice with reference to empty array initial
10811076
10821077test "initialize sentinel-terminated many-pointer with reference to empty array initializer" {
10831078 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1084
10851079 const a: [*:0]const u8 = &.{};
10861080 comptime assert(a[0] == 0);
10871081}
test/behavior/asm.zig-1
......@@ -82,7 +82,6 @@ test "sized integer/float in asm input" {
8282 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
8383 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
8484 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
85 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
8685 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
8786
8887 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support inline assembly
test/behavior/basic.zig+1-1
......@@ -302,7 +302,7 @@ test "compile time global reinterpret" {
302302}
303303
304304test "cast undefined" {
305 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
305 // if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
306306 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
307307
308308 const array: [100]u8 = undefined;
test/behavior/bitcast.zig-6
......@@ -23,8 +23,6 @@ test "@bitCast iX -> uX (8, 16, 128)" {
2323 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2424 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2525 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
26 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
27
2826 const bit_values = [_]usize{ 8, 16, 128 };
2927
3028 inline for (bit_values) |bits| {
......@@ -37,9 +35,6 @@ test "@bitCast iX -> uX exotic integers" {
3735 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3836 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
3937 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
40 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
41 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
42
4338 const bit_values = [_]usize{ 1, 48, 27, 512, 493, 293, 125, 204, 112 };
4439
4540 inline for (bit_values) |bits| {
......@@ -82,7 +77,6 @@ test "bitcast uX to bytes" {
8277 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
8378 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
8479 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
85 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
8680
8781 const bit_values = [_]usize{ 1, 48, 27, 512, 493, 293, 125, 204, 112 };
8882 inline for (bit_values) |bits| {
test/behavior/cast.zig-18
......@@ -103,11 +103,6 @@ test "comptime_int @floatFromInt" {
103103}
104104
105105test "@floatFromInt" {
106 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
107 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
108 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
109 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
110
111106 const S = struct {
112107 fn doTheTest() !void {
113108 try testIntToFloat(-2);
......@@ -133,13 +128,9 @@ fn testIntFromFloat(comptime F: type, f: F, comptime I: type, i: I) !void {
133128
134129test "@intFromFloat > 128 bits" {
135130 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
136 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
137131 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
138 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
139132
140 try testIntFromFloat(f16, 1024, u140, 1024);
141133 try testIntFromFloat(f16, -1024, i140, -1024);
142
143134 try testIntFromFloat(f32, 1 << 24, u140, 1 << 24);
144135 try testIntFromFloat(f32, -1 << 24, i140, -1 << 24);
145136
......@@ -161,13 +152,10 @@ test "@floatFromInt > 128 bits" {
161152 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
162153 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
163154 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
164 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
165155
166156 try testFloatFromInt(u140, 1024, f16, 1024);
167 try testFloatFromInt(i140, -1024, f16, -1024);
168157
169158 try testFloatFromInt(u140, 1 << 24, f32, 1 << 24);
170 try testFloatFromInt(i140, -1 << 24, f32, -1 << 24);
171159
172160 try testFloatFromInt(u200, 1 << 53, f64, 1 << 53);
173161 try testFloatFromInt(i200, -1 << 53, f64, -1 << 53);
......@@ -282,8 +270,6 @@ test "type coercion from int to float" {
282270test "@intFromFloat" {
283271 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
284272 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
285 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
286
287273 try testIntFromFloats();
288274 try comptime testIntFromFloats();
289275}
......@@ -347,7 +333,6 @@ fn expectTruncCast(comptime F: type, f: F, comptime I: type, i: I) !void {
347333test "implicitly cast indirect pointer to maybe-indirect pointer" {
348334 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
349335 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
350
351336 const S = struct {
352337 const Self = @This();
353338 x: u8,
......@@ -431,11 +416,9 @@ test "implicit cast from *[N]T to [*c]T" {
431416 var y: [*c]u16 = &x;
432417
433418 try expect(std.mem.eql(u16, x[0..4], y[0..4]));
434 x[0] = 8;
435419 y[3] = 6;
436420 try expect(std.mem.eql(u16, x[0..4], y[0..4]));
437421}
438
439422test "*usize to *void" {
440423 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
441424
......@@ -510,7 +493,6 @@ test "array coercion to undefined at runtime" {
510493
511494 var array = [4]u8{ 3, 4, 5, 6 };
512495 var undefined_val = [4]u8{ 0xAA, 0xAA, 0xAA, 0xAA };
513
514496 try expect(std.mem.eql(u8, &array, &array));
515497 array = undefined;
516498 try expect(std.mem.eql(u8, &array, &undefined_val));
test/behavior/cast_int.zig-6
......@@ -8,9 +8,6 @@ const minInt = std.math.minInt;
88test "@intCast i32 to u7" {
99 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1010 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
12 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
13
1411 var x: u128 = maxInt(u128);
1512 var y: i32 = 120;
1613 _ = .{ &x, &y };
......@@ -145,9 +142,7 @@ fn testIntCast(comptime S: type, a: S, comptime D: type, expected: D) !void {
145142test "@intCast <= 64 bits" {
146143 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
147144 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
148
149145 try testIntCast(i32, minInt(i32), i64, minInt(i32));
150 try testIntCast(i32, maxInt(i32), i64, maxInt(i32));
151146 try testIntCast(u32, maxInt(u32), u64, maxInt(u32));
152147 try testIntCast(u32, maxInt(i32), i64, maxInt(i32));
153148 try testIntCast(u32, maxInt(u32), i64, maxInt(u32));
......@@ -174,7 +169,6 @@ test "@intCast > 128 bits" {
174169 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
175170
176171 try testIntCast(u8, 123, u140, 123);
177 try testIntCast(u64, 1 << 63, u140, 1 << 63);
178172 try testIntCast(u127, maxInt(u127), u140, maxInt(u127));
179173 try testIntCast(i8, -42, i140, -42);
180174 try testIntCast(i64, minInt(i64), i140, minInt(i64));
test/behavior/comptime_memory.zig-3
......@@ -431,8 +431,6 @@ test "type pun @ptrFromInt" {
431431}
432432
433433test "type pun null pointer-like optional" {
434 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
435
436434 const p: ?*u8 = null;
437435 // note that expectEqual hides the bug
438436 try testing.expect(@as(*const ?*i8, @ptrCast(&p)).* == null);
......@@ -518,7 +516,6 @@ fn fieldPtrTest() u32 {
518516}
519517test "pointer in aggregate field can mutate comptime state" {
520518 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
521
522519 try comptime std.testing.expect(fieldPtrTest() == 2);
523520}
524521
test/behavior/defer.zig-3
......@@ -5,8 +5,6 @@ const expectEqual = std.testing.expectEqual;
55const expectError = std.testing.expectError;
66
77test "break and continue inside loop inside defer expression" {
8 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
9
108 testBreakContInDefer(10);
119 comptime testBreakContInDefer(10);
1210}
......@@ -111,7 +109,6 @@ test "mixing normal and error defers" {
111109test "simple else prong doesn't emit an error for unreachable else prong" {
112110 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
113111 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
114
115112 const S = struct {
116113 fn foo() error{Foo}!void {
117114 return error.Foo;
test/behavior/enum.zig-6
......@@ -931,9 +931,7 @@ test "constant enum initialization with differing sizes" {
931931 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
932932 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
933933 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
934
935934 try test3_1(test3_foo);
936 try test3_2(test3_bar);
937935}
938936const Test3Foo = union(enum) {
939937 One: void,
......@@ -975,7 +973,6 @@ test "@tagName" {
975973 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
976974 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
977975
978 try expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
979976 comptime assert(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
980977}
981978
......@@ -990,9 +987,7 @@ test "@tagName non-exhaustive enum" {
990987 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
991988 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
992989 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
993 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
994990
995 try expect(mem.eql(u8, testEnumTagNameBare(NonExhaustive.B), "B"));
996991 comptime assert(mem.eql(u8, testEnumTagNameBare(NonExhaustive.B), "B"));
997992}
998993const NonExhaustive = enum(u8) { A, B, _ };
......@@ -1034,7 +1029,6 @@ test "@tagName on enum literals" {
10341029 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10351030
10361031 try expect(mem.eql(u8, @tagName(.FooBar), "FooBar"));
1037 comptime assert(mem.eql(u8, @tagName(.FooBar), "FooBar"));
10381032}
10391033
10401034test "tag name with signed enum values" {
test/behavior/error.zig-13
......@@ -145,19 +145,12 @@ test "implicit cast to optional to error union to return result loc" {
145145}
146146
147147test "fn returning empty error set can be passed as fn returning any error" {
148 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
149
150 entry();
151 comptime entry();
152148}
153149
154150test "fn returning empty error set can be passed as fn returning any error - pointer" {
155151 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
156
157152 entryPtr();
158 comptime entryPtr();
159153}
160
161154fn entry() void {
162155 foo2(bar2);
163156}
......@@ -369,10 +362,8 @@ test "error: Infer error set from literals" {
369362 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
370363
371364 _ = nullLiteral("n") catch |err| handleErrors(err);
372 _ = floatLiteral("n") catch |err| handleErrors(err);
373365 _ = intLiteral("n") catch |err| handleErrors(err);
374366 _ = comptime nullLiteral("n") catch |err| handleErrors(err);
375 _ = comptime floatLiteral("n") catch |err| handleErrors(err);
376367 _ = comptime intLiteral("n") catch |err| handleErrors(err);
377368}
378369
......@@ -511,7 +502,6 @@ test "function pointer with return type that is error union with payload which i
511502 const Foo = struct {
512503 fun: *const fn (a: i32) (anyerror!*Foo),
513504 };
514
515505 const Err = error{UnspecifiedErr};
516506
517507 fn bar(a: i32) anyerror!*Foo {
......@@ -699,8 +689,6 @@ test "coerce error set to the current inferred error set" {
699689test "error union payload is properly aligned" {
700690 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
701691 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
702 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
703 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
704692
705693 const S = struct {
706694 a: u128,
......@@ -758,7 +746,6 @@ test "pointer to error union payload" {
758746 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
759747 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
760748 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
761 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
762749
763750 var err_union: anyerror!u8 = 15;
764751
test/behavior/floatop.zig-8
......@@ -134,9 +134,6 @@ test "cmp f32" {
134134}
135135
136136test "cmp f64" {
137 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
138 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
139
140137 try testCmp(f64);
141138 try comptime testCmp(f64);
142139}
......@@ -146,7 +143,6 @@ test "cmp f128" {
146143 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
147144 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
148145
149 try testCmp(f128);
150146 try comptime testCmp(f128);
151147}
152148
......@@ -154,10 +150,7 @@ test "cmp f80/c_longdouble" {
154150 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
155151 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
156152 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
157 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
158153
159 try testCmp(f80);
160 try comptime testCmp(f80);
161154 try testCmp(c_longdouble);
162155 try comptime testCmp(c_longdouble);
163156}
......@@ -232,7 +225,6 @@ test "vector cmp f32" {
232225 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
233226 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
234227 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
235 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isArm()) return error.SkipZigTest;
236228 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest;
237229 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .hexagon) return error.SkipZigTest;
238230
test/behavior/fn.zig-6
......@@ -292,9 +292,6 @@ fn voidFun(a: i32, b: void, c: i32, d: void) !void {
292292
293293test "call function with empty string" {
294294 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
295 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
296
297 acceptsString("");
298295}
299296
300297fn acceptsString(foo: []u8) void {
......@@ -305,9 +302,7 @@ test "function pointers" {
305302 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
306303 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
307304 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
308
309305 const fns = [_]*const @TypeOf(fn1){
310 &fn1,
311306 &fn2,
312307 &fn3,
313308 &fn4,
......@@ -445,7 +440,6 @@ test "method call with optional and error union first param" {
445440 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
446441
447442 const S = struct {
448 x: i32 = 1234,
449443
450444 fn opt(s: ?@This()) !void {
451445 try expect(s.?.x == 1234);
test/behavior/generics.zig-4
......@@ -439,8 +439,6 @@ test "return type of generic function is function pointer" {
439439}
440440
441441test "coerced function body has inequal value with its uncoerced body" {
442 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
443
444442 const S = struct {
445443 const A = B(i32, c);
446444 fn c() !i32 {
......@@ -488,8 +486,6 @@ test "union in struct captures argument" {
488486
489487test "function argument tuple used as struct field" {
490488 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
491 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
492
493489 const S = struct {
494490 fn DeleagateWithContext(comptime Function: type) type {
495491 const ArgArgs = std.meta.ArgsTuple(Function);
test/behavior/inline_switch.zig-6
......@@ -34,8 +34,6 @@ test "inline prong ranges" {
3434const E = enum { a, b, c, d };
3535test "inline switch enums" {
3636 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
37 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
38
3937 var x: E = .a;
4038 _ = &x;
4139 switch (x) {
......@@ -49,7 +47,6 @@ test "inline switch unions" {
4947 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
5048 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5149 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
52
5350 var x: U = .a;
5451 _ = &x;
5552 switch (x) {
......@@ -74,8 +71,6 @@ test "inline switch unions" {
7471
7572test "inline else bool" {
7673 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
77 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
78
7974 var a = true;
8075 _ = &a;
8176 switch (a) {
......@@ -87,7 +82,6 @@ test "inline else bool" {
8782test "inline else error" {
8883 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
8984 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
90
9185 const Err = error{ a, b, c };
9286 var a = Err.a;
9387 _ = &a;
test/behavior/maximum_minimum.zig-3
......@@ -304,8 +304,6 @@ test "@min/@max notices bounds from vector types when element of comptime-known
304304}
305305
306306test "@min/@max of signed and unsigned runtime integers" {
307 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
308
309307 var x: i32 = -1;
310308 var y: u31 = 1;
311309 _ = .{ &x, &y };
......@@ -352,7 +350,6 @@ test "@min/@max with runtime signed and unsigned integers of same size" {
352350
353351test "@min/@max with runtime vectors of signed and unsigned integers of same size" {
354352 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
355 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
356353 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
357354 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
358355 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
test/behavior/memcpy.zig-1
......@@ -168,7 +168,6 @@ test "@memcpy with sentinel" {
168168}
169169
170170test "@memcpy no sentinel source into sentinel destination" {
171 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
172171
173172 const S = struct {
174173 fn doTheTest() void {
test/behavior/merge_error_sets.zig-1
......@@ -13,7 +13,6 @@ fn foo() C!void {
1313
1414test "merge error sets" {
1515 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
16 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1716
1817 if (foo()) {
1918 @panic("unexpected");
test/behavior/muladd.zig-3
......@@ -34,7 +34,6 @@ test "@mulAdd f16" {
3434 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
3535
3636 try comptime testMulAdd16();
37 try testMulAdd16();
3837}
3938
4039fn testMulAdd16() !void {
......@@ -49,9 +48,7 @@ test "@mulAdd f80" {
4948 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
5049 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5150 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
52 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
5351 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
54
5552 try comptime testMulAdd80();
5653 try testMulAdd80();
5754}
test/behavior/optional.zig-6
......@@ -338,8 +338,6 @@ test "coerce an anon struct literal to optional struct" {
338338test "0-bit child type coerced to optional return ptr result location" {
339339 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
340340 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
341 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
342
343341 const S = struct {
344342 fn doTheTest() !void {
345343 var y = Foo{};
......@@ -365,7 +363,6 @@ test "0-bit child type coerced to optional" {
365363 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
366364 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
367365 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
368
369366 const S = struct {
370367 fn doTheTest() !void {
371368 var it: Foo = .{
......@@ -514,8 +511,6 @@ test "mutable optional of noreturn" {
514511}
515512
516513test "orelse on C pointer" {
517 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
518
519514 // TODO https://github.com/ziglang/zig/issues/6597
520515 const foo: [*c]const u8 = "hey";
521516 const d = foo orelse @compileError("bad");
......@@ -527,7 +522,6 @@ test "alignment of wrapping an optional payload" {
527522 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
528523 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
529524 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
530 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
531525
532526 const S = struct {
533527 const I = extern struct { x: i128 };
test/behavior/packed-struct.zig-6
......@@ -227,9 +227,6 @@ test "nested packed structs" {
227227test "regular in irregular packed struct" {
228228 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
229229 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
230 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
231 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
232
233230 const Irregular = packed struct {
234231 bar: Regular = Regular{},
235232 _: u24 = 0,
......@@ -249,9 +246,7 @@ test "nested packed struct unaligned" {
249246 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
250247 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
251248 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
252
253249 const S1 = packed struct {
254 a: u4,
255250 b: u4,
256251 c: u8,
257252 };
......@@ -408,7 +403,6 @@ test "nested packed struct field pointers" {
408403 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
409404 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // ubsan unaligned pointer access
410405 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
411
412406 const S2 = packed struct {
413407 base: u8,
414408 p0: packed struct {
test/behavior/pointers.zig-6
......@@ -136,8 +136,6 @@ test "implicit cast single item pointer to C pointer and back" {
136136}
137137
138138test "initialize const optional C pointer to null" {
139 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
140
141139 const a: ?[*c]i32 = null;
142140 try expect(a == null);
143141 comptime assert(a == null);
......@@ -146,7 +144,6 @@ test "initialize const optional C pointer to null" {
146144test "assigning integer to C pointer" {
147145 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
148146 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
149
150147 var x: i32 = 0;
151148 var y: i32 = 1;
152149 var ptr: [*c]u8 = 0;
......@@ -645,8 +642,6 @@ test "result type preserved through multiple references" {
645642}
646643
647644test "result type found through optional pointer" {
648 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
649
650645 const ptr1: ?*const u32 = &@intCast(123);
651646 const ptr2: ?[]const u8 = &.{ @intCast(123), @truncate(0xABCD) };
652647 try expect(ptr1.?.* == 123);
......@@ -700,7 +695,6 @@ fn constant() !void {
700695test "pointer-to-array constness for zero-size elements, var" {
701696 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
702697 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
703
704698 try mutable();
705699 try comptime mutable();
706700}
test/behavior/shuffle.zig-3
......@@ -54,8 +54,6 @@ test "@shuffle int strange sizes" {
5454 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
5555 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5656 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
57 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
58
5957 try comptime testShuffle(2, 2, 2);
6058 try testShuffle(2, 2, 2);
6159 try comptime testShuffle(4, 4, 4);
......@@ -136,7 +134,6 @@ test "@shuffle bool 1" {
136134 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
137135 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
138136 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
139
140137 const S = struct {
141138 fn doTheTest() !void {
142139 var x: @Vector(4, bool) = [4]bool{ false, true, false, true };
test/behavior/sizeof_and_typeof.zig-3
......@@ -211,8 +211,6 @@ test "@sizeOf comparison against zero" {
211211}
212212
213213test "hardcoded address in typeof expression" {
214 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
215
216214 const S = struct {
217215 fn func() @TypeOf(@as(*[]u8, @ptrFromInt(0x10)).*[0]) {
218216 return 0;
......@@ -301,7 +299,6 @@ test "lazy abi size used in comparison" {
301299test "peer type resolution with @TypeOf doesn't trigger dependency loop check" {
302300 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
303301 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
304
305302 const T = struct {
306303 next: @TypeOf(null, @as(*const @This(), undefined)),
307304 };
test/behavior/slice.zig-6
......@@ -173,8 +173,6 @@ test "pass a slice of types to a function" {
173173
174174test "generic malloc free" {
175175 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
176 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
177
178176 const a = memAlloc(u8, 10) catch unreachable;
179177 memFree(u8, a);
180178}
......@@ -188,7 +186,6 @@ fn memFree(comptime T: type, memory: []T) void {
188186
189187test "slice of hardcoded address to pointer" {
190188 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
191
192189 const S = struct {
193190 fn doTheTest() !void {
194191 const pointer = @as([*]u8, @ptrFromInt(0x04))[0..2];
......@@ -212,8 +209,6 @@ test "comptime slice of pointer preserves comptime var" {
212209}
213210
214211test "comptime pointer cast array and then slice" {
215 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
216
217212 const array = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 };
218213
219214 const ptrA: [*]const u8 = @as([*]const u8, @ptrCast(&array));
......@@ -229,7 +224,6 @@ test "comptime pointer cast array and then slice" {
229224test "slicing zero length array" {
230225 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
231226 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
232
233227 const s1 = ""[0..];
234228 const s2 = ([_]u32{})[0..];
235229 try expect(s1.len == 0);
test/behavior/string_literals.zig-3
......@@ -84,8 +84,6 @@ test "string literal pointer sentinel" {
8484}
8585
8686test "sentinel slice of string literal" {
87 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
88
8987 const string = "Hello!\x00World!";
9088 try std.testing.expect(@TypeOf(string) == *const [13:0]u8);
9189
......@@ -103,7 +101,6 @@ test "Peer type resolution with string literals and unknown length u8 pointers"
103101
104102test "including the sentinel when dereferencing a string literal" {
105103 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
106
107104 var var_str = "abc";
108105 const var_derefed = var_str[0 .. var_str.len + 1].*;
109106
test/behavior/struct.zig-6
......@@ -342,7 +342,6 @@ test "self-referencing struct via array member" {
342342}
343343
344344test "empty struct method call" {
345 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
346345 const es = EmptyStruct{};
347346 try expect(es.method() == 1234);
348347}
......@@ -379,7 +378,6 @@ const APackedStruct = packed struct {
379378test "packed struct" {
380379 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
381380 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
382 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
383381 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
384382
385383 var foo = APackedStruct{
......@@ -448,8 +446,6 @@ test "runtime struct initialization of bitfield" {
448446 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
449447 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
450448 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
451 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
452 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
453449
454450 const s1 = Nibbles{
455451 .x = x1,
......@@ -489,7 +485,6 @@ test "packed struct fields are ordered from LSB to MSB" {
489485 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
490486 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
491487 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
492
493488 var all: u64 = 0x7765443322221111;
494489 var bytes: [8]u8 align(@alignOf(Bitfields)) = undefined;
495490 @memcpy(bytes[0..8], @as([*]u8, @ptrCast(&all)));
......@@ -1776,7 +1771,6 @@ test "circular dependency through pointer field of a struct" {
17761771}
17771772
17781773test "field calls do not force struct field init resolution" {
1779 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
17801774 const S = struct {
17811775 x: u32 = blk: {
17821776 _ = @TypeOf(make().dummyFn()); // runtime field call - S not fully resolved - dummyFn call should not force field init resolution
test/behavior/switch.zig-6
......@@ -9,7 +9,6 @@ const maxInt = std.math.maxInt;
99
1010test "switch with numbers" {
1111 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1312
1413 try testSwitchWithNumbers(13);
1514}
......@@ -25,7 +24,6 @@ fn testSwitchWithNumbers(x: u32) !void {
2524
2625test "switch with all ranges" {
2726 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
28 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
2927
3028 try expect(testSwitchWithAllRanges(50, 3) == 1);
3129 try expect(testSwitchWithAllRanges(101, 0) == 2);
......@@ -214,8 +212,6 @@ test "undefined.u0" {
214212
215213test "switch with disjoint range" {
216214 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
217 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
218
219215 var q: u8 = 0;
220216 _ = &q;
221217 switch (q) {
......@@ -226,8 +222,6 @@ test "switch with disjoint range" {
226222}
227223
228224test "switch variable for range and multiple prongs" {
229 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
230
231225 const S = struct {
232226 fn doTheTest() !void {
233227 try doTheSwitch(16);
test/behavior/switch_loop.zig-11
......@@ -7,7 +7,6 @@ test "simple switch loop" {
77 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
88 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
99 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
1110
1211 const S = struct {
1312 fn doTheTest() !void {
......@@ -31,7 +30,6 @@ test "switch loop with ranges" {
3130 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3231 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
3332 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
34 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
3533
3634 const S = struct {
3735 fn doTheTest() !void {
......@@ -52,7 +50,6 @@ test "switch loop on enum" {
5250 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
5351 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
5452 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
55 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
5653
5754 const S = struct {
5855 const E = enum { a, b, c };
......@@ -76,7 +73,6 @@ test "switch loop with error set" {
7673 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
7774 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
7875 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
79 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
8076
8177 const S = struct {
8278 const E = error{ Foo, Bar, Baz };
......@@ -252,7 +248,6 @@ test "switch loop on non-exhaustive enum" {
252248 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
253249 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
254250 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
255 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
256251
257252 const S = struct {
258253 const E = enum(u8) { a, b, c, _ };
......@@ -275,8 +270,6 @@ test "switch loop on non-exhaustive enum" {
275270test "switch loop with discarded tag capture" {
276271 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
277272 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
278 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
279
280273 const S = struct {
281274 const U = union(enum) {
282275 a: u32,
......@@ -301,7 +294,6 @@ test "switch loop with discarded tag capture" {
301294
302295test "switch loop with single catch-all prong" {
303296 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
304
305297 const S = struct {
306298 const E = enum { a, b, c };
307299 const U = union(E) { a: u32, b: u16, c: u8 };
......@@ -469,8 +461,6 @@ test "switch loop with tag capture" {
469461}
470462
471463test "switch loop for error handling" {
472 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
473
474464 const Error = error{ MyError, MyOtherError };
475465 const S = struct {
476466 fn doTheTest() !void {
......@@ -516,7 +506,6 @@ test "switch loop for error handling" {
516506
517507test "switch loop with packed structs" {
518508 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
519
520509 const P = packed struct {
521510 a: u7,
522511 b: u20,
test/behavior/tuple.zig-6
......@@ -105,8 +105,6 @@ test "tuple initializer for var" {
105105
106106test "array-like initializer for tuple types" {
107107 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
108 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
109
110108 const T = @Tuple(&.{ i32, u8 });
111109 const S = struct {
112110 fn doTheTest() !void {
......@@ -172,7 +170,6 @@ test "fieldParentPtr of tuple" {
172170 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
173171 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
174172 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
175
176173 var x: u32 = 0;
177174 _ = &x;
178175 const tuple = .{ x, x };
......@@ -217,8 +214,6 @@ test "initializing tuple with mixed comptime-runtime fields" {
217214}
218215
219216test "initializing anon struct with mixed comptime-runtime fields" {
220 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
221
222217 var x: u32 = 15;
223218 _ = &x;
224219 const T = @TypeOf(.{ .foo = @as(i32, -1234), .bar = x });
......@@ -231,7 +226,6 @@ test "tuple in tuple passed to generic function" {
231226 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
232227 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
233228 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
234
235229 const S = struct {
236230 fn pair(x: f32, y: f32) @Tuple(&.{ f32, f32 }) {
237231 return .{ x, y };
test/behavior/union.zig-6
......@@ -885,8 +885,6 @@ test "union no tag with struct member" {
885885}
886886
887887test "extern union doesn't trigger field check at comptime" {
888 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
889
890888 const U = extern union {
891889 x: u32,
892890 y: u8,
......@@ -901,7 +899,6 @@ test "anonymous union literal syntax" {
901899 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
902900 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
903901 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
904
905902 const S = struct {
906903 const Number = union {
907904 int: i32,
......@@ -1216,8 +1213,6 @@ test "return an extern union from C calling convention" {
12161213test "noreturn field in union" {
12171214 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12181215 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1219 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1220
12211216 const U = union(enum) {
12221217 a: u32,
12231218 b: noreturn,
......@@ -1269,7 +1264,6 @@ test "@unionInit uses tag value instead of field index" {
12691264 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12701265 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
12711266 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1272
12731267 const E = enum(u8) {
12741268 b = 255,
12751269 a = 3,
test/behavior/vector.zig-6
......@@ -379,8 +379,6 @@ test "vector @splat" {
379379 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
380380 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
381381 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
382 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
383
384382 const S = struct {
385383 fn testForT(comptime N: comptime_int, v: anytype) !void {
386384 const T = @TypeOf(v);
......@@ -417,7 +415,6 @@ test "vector @splat" {
417415
418416test "load vector elements via comptime index" {
419417 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
420 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
421418 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
422419
423420 const S = struct {
......@@ -533,8 +530,6 @@ test "vector division operators" {
533530 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
534531 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
535532 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
536 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
537
538533 const S = struct {
539534 fn doTheTestDiv(comptime T: type, x: @Vector(4, T), y: @Vector(4, T)) !void {
540535 const is_signed_int = switch (@typeInfo(T)) {
......@@ -622,7 +617,6 @@ test "vector division operators" {
622617test "vector bitwise not operator" {
623618 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
624619 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
625 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
626620 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
627621 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
628622