authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-07-27 20:24:33+02:00
committergravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-07-28 20:44:32+00:00
log0fc79d602bf9b3a5c97cfc28b59193b005692cb2
tree0fafad0932696ef5ab18032605f2197d35a16ac0
parente863292fe2f280945d914e7e98fbc704b68f1004

stage2 ARM: more support for switch statements


2 files changed, 34 insertions(+), 36 deletions(-)

src/arch/arm/CodeGen.zig+34-27
......@@ -4300,17 +4300,6 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
43004300 );
43014301 defer self.gpa.free(liveness.deaths);
43024302
4303 // If the condition dies here in this switch instruction, process
4304 // that death now instead of later as this has an effect on
4305 // whether it needs to be spilled in the branches
4306 if (self.liveness.operandDies(inst, 0)) {
4307 const op_int = @enumToInt(pl_op.operand);
4308 if (op_int >= Air.Inst.Ref.typed_value_map.len) {
4309 const op_index = @intCast(Air.Inst.Index, op_int - Air.Inst.Ref.typed_value_map.len);
4310 self.processDeath(op_index);
4311 }
4312 }
4313
43144303 var extra_index: usize = switch_br.end;
43154304 var case_i: u32 = 0;
43164305 while (case_i < switch_br.data.cases_len) : (case_i += 1) {
......@@ -4320,21 +4309,43 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
43204309 const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len];
43214310 extra_index = case.end + items.len + case_body.len;
43224311
4323 var relocs = try self.gpa.alloc(u32, items.len);
4324 defer self.gpa.free(relocs);
4325
4326 if (items.len == 1) {
4312 // For every item, we compare it to condition and branch into
4313 // the prong if they are equal. After we compared to all
4314 // items, we branch into the next prong (or if no other prongs
4315 // exist out of the switch statement).
4316 //
4317 // cmp condition, item1
4318 // beq prong
4319 // cmp condition, item2
4320 // beq prong
4321 // cmp condition, item3
4322 // beq prong
4323 // b out
4324 // prong: ...
4325 // ...
4326 // out: ...
4327 const branch_into_prong_relocs = try self.gpa.alloc(u32, items.len);
4328 defer self.gpa.free(branch_into_prong_relocs);
4329
4330 for (items) |item, idx| {
43274331 const condition = try self.resolveInst(pl_op.operand);
4328 const item = try self.resolveInst(items[0]);
4332 const item_mcv = try self.resolveInst(item);
43294333
43304334 const operands: BinOpOperands = .{ .mcv = .{
43314335 .lhs = condition,
4332 .rhs = item,
4336 .rhs = item_mcv,
43334337 } };
4334 const cmp_result = try self.cmp(operands, condition_ty, .eq);
4335 relocs[0] = try self.condBr(cmp_result);
4336 } else {
4337 return self.fail("TODO switch with multiple items", .{});
4338 const cmp_result = try self.cmp(operands, condition_ty, .neq);
4339 branch_into_prong_relocs[idx] = try self.condBr(cmp_result);
4340 }
4341
4342 const branch_away_from_prong_reloc = try self.addInst(.{
4343 .tag = .b,
4344 .data = .{ .inst = undefined }, // populated later through performReloc
4345 });
4346
4347 for (branch_into_prong_relocs) |reloc| {
4348 try self.performReloc(reloc);
43384349 }
43394350
43404351 // Capture the state of register and stack allocation state so that we can revert to it.
......@@ -4369,9 +4380,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
43694380 self.next_stack_offset = parent_next_stack_offset;
43704381 self.register_manager.free_registers = parent_free_registers;
43714382
4372 for (relocs) |reloc| {
4373 try self.performReloc(reloc);
4374 }
4383 try self.performReloc(branch_away_from_prong_reloc);
43754384 }
43764385
43774386 if (switch_br.data.else_body_len > 0) {
......@@ -4414,9 +4423,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
44144423 // in airCondBr.
44154424 }
44164425
4417 // We already took care of pl_op.operand earlier, so we're going
4418 // to pass .none here
4419 return self.finishAir(inst, .unreach, .{ .none, .none, .none });
4426 return self.finishAir(inst, .unreach, .{ pl_op.operand, .none, .none });
44204427}
44214428
44224429fn performReloc(self: *Self, inst: Mir.Inst.Index) !void {
test/behavior/switch.zig-9
......@@ -53,7 +53,6 @@ test "implicit comptime switch" {
5353}
5454
5555test "switch on enum" {
56 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
5756 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
5857
5958 const fruit = Fruit.Orange;
......@@ -73,7 +72,6 @@ fn nonConstSwitchOnEnum(fruit: Fruit) void {
7372}
7473
7574test "switch statement" {
76 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
7775 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
7876
7977 try nonConstSwitch(SwitchStatementFoo.C);
......@@ -91,7 +89,6 @@ const SwitchStatementFoo = enum { A, B, C, D };
9189
9290test "switch with multiple expressions" {
9391 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
94 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
9592 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
9693
9794 const x = switch (returnsFive()) {
......@@ -120,7 +117,6 @@ fn trueIfBoolFalseOtherwise(comptime T: type) bool {
120117}
121118
122119test "switching on booleans" {
123 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
124120 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
125121
126122 try testSwitchOnBools();
......@@ -218,7 +214,6 @@ fn poll() void {
218214}
219215
220216test "switch on global mutable var isn't constant-folded" {
221 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
222217 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
223218
224219 while (state < 2) {
......@@ -278,7 +273,6 @@ fn testSwitchEnumPtrCapture() !void {
278273
279274test "switch handles all cases of number" {
280275 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
281 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
282276 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
283277
284278 try testSwitchHandleAllCases();
......@@ -370,7 +364,6 @@ test "anon enum literal used in switch on union enum" {
370364}
371365
372366test "switch all prongs unreachable" {
373 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
374367 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
375368
376369 try testAllProngsUnreachable();
......@@ -582,7 +575,6 @@ test "switch on pointer type" {
582575 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
583576 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
584577 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
585 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
586578
587579 const S = struct {
588580 const X = struct {
......@@ -674,7 +666,6 @@ test "capture of integer forwards the switch condition directly" {
674666}
675667
676668test "enum value without tag name used as switch item" {
677 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
678669 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
679670
680671 const E = enum(u32) {