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 {...@@ -4300,17 +4300,6 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
4300 );4300 );
4301 defer self.gpa.free(liveness.deaths);4301 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
4314 var extra_index: usize = switch_br.end;4303 var extra_index: usize = switch_br.end;
4315 var case_i: u32 = 0;4304 var case_i: u32 = 0;
4316 while (case_i < switch_br.data.cases_len) : (case_i += 1) {4305 while (case_i < switch_br.data.cases_len) : (case_i += 1) {
...@@ -4320,21 +4309,43 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {...@@ -4320,21 +4309,43 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
4320 const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len];4309 const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len];
4321 extra_index = case.end + items.len + case_body.len;4310 extra_index = case.end + items.len + case_body.len;
43224311
4323 var relocs = try self.gpa.alloc(u32, items.len);4312 // For every item, we compare it to condition and branch into
4324 defer self.gpa.free(relocs);4313 // the prong if they are equal. After we compared to all
43254314 // items, we branch into the next prong (or if no other prongs
4326 if (items.len == 1) {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| {
4327 const condition = try self.resolveInst(pl_op.operand);4331 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
4330 const operands: BinOpOperands = .{ .mcv = .{4334 const operands: BinOpOperands = .{ .mcv = .{
4331 .lhs = condition,4335 .lhs = condition,
4332 .rhs = item,4336 .rhs = item_mcv,
4333 } };4337 } };
4334 const cmp_result = try self.cmp(operands, condition_ty, .eq);4338 const cmp_result = try self.cmp(operands, condition_ty, .neq);
4335 relocs[0] = try self.condBr(cmp_result);4339 branch_into_prong_relocs[idx] = try self.condBr(cmp_result);
4336 } else {4340 }
4337 return self.fail("TODO switch with multiple items", .{});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);
4338 }4349 }
43394350
4340 // Capture the state of register and stack allocation state so that we can revert to it.4351 // 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 {...@@ -4369,9 +4380,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
4369 self.next_stack_offset = parent_next_stack_offset;4380 self.next_stack_offset = parent_next_stack_offset;
4370 self.register_manager.free_registers = parent_free_registers;4381 self.register_manager.free_registers = parent_free_registers;
43714382
4372 for (relocs) |reloc| {4383 try self.performReloc(branch_away_from_prong_reloc);
4373 try self.performReloc(reloc);
4374 }
4375 }4384 }
43764385
4377 if (switch_br.data.else_body_len > 0) {4386 if (switch_br.data.else_body_len > 0) {
...@@ -4414,9 +4423,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {...@@ -4414,9 +4423,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
4414 // in airCondBr.4423 // in airCondBr.
4415 }4424 }
44164425
4417 // We already took care of pl_op.operand earlier, so we're going4426 return self.finishAir(inst, .unreach, .{ pl_op.operand, .none, .none });
4418 // to pass .none here
4419 return self.finishAir(inst, .unreach, .{ .none, .none, .none });
4420}4427}
44214428
4422fn performReloc(self: *Self, inst: Mir.Inst.Index) !void {4429fn performReloc(self: *Self, inst: Mir.Inst.Index) !void {
test/behavior/switch.zig-9
...@@ -53,7 +53,6 @@ test "implicit comptime switch" {...@@ -53,7 +53,6 @@ test "implicit comptime switch" {
53}53}
5454
55test "switch on enum" {55test "switch on enum" {
56 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
57 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO56 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
5857
59 const fruit = Fruit.Orange;58 const fruit = Fruit.Orange;
...@@ -73,7 +72,6 @@ fn nonConstSwitchOnEnum(fruit: Fruit) void {...@@ -73,7 +72,6 @@ fn nonConstSwitchOnEnum(fruit: Fruit) void {
73}72}
7473
75test "switch statement" {74test "switch statement" {
76 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
77 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO75 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
7876
79 try nonConstSwitch(SwitchStatementFoo.C);77 try nonConstSwitch(SwitchStatementFoo.C);
...@@ -91,7 +89,6 @@ const SwitchStatementFoo = enum { A, B, C, D };...@@ -91,7 +89,6 @@ const SwitchStatementFoo = enum { A, B, C, D };
9189
92test "switch with multiple expressions" {90test "switch with multiple expressions" {
93 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO91 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
94 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
95 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO92 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
9693
97 const x = switch (returnsFive()) {94 const x = switch (returnsFive()) {
...@@ -120,7 +117,6 @@ fn trueIfBoolFalseOtherwise(comptime T: type) bool {...@@ -120,7 +117,6 @@ fn trueIfBoolFalseOtherwise(comptime T: type) bool {
120}117}
121118
122test "switching on booleans" {119test "switching on booleans" {
123 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
124 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO120 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
125121
126 try testSwitchOnBools();122 try testSwitchOnBools();
...@@ -218,7 +214,6 @@ fn poll() void {...@@ -218,7 +214,6 @@ fn poll() void {
218}214}
219215
220test "switch on global mutable var isn't constant-folded" {216test "switch on global mutable var isn't constant-folded" {
221 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
222 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO217 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
223218
224 while (state < 2) {219 while (state < 2) {
...@@ -278,7 +273,6 @@ fn testSwitchEnumPtrCapture() !void {...@@ -278,7 +273,6 @@ fn testSwitchEnumPtrCapture() !void {
278273
279test "switch handles all cases of number" {274test "switch handles all cases of number" {
280 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO275 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
281 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
282 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO276 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
283277
284 try testSwitchHandleAllCases();278 try testSwitchHandleAllCases();
...@@ -370,7 +364,6 @@ test "anon enum literal used in switch on union enum" {...@@ -370,7 +364,6 @@ test "anon enum literal used in switch on union enum" {
370}364}
371365
372test "switch all prongs unreachable" {366test "switch all prongs unreachable" {
373 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
374 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO367 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
375368
376 try testAllProngsUnreachable();369 try testAllProngsUnreachable();
...@@ -582,7 +575,6 @@ test "switch on pointer type" {...@@ -582,7 +575,6 @@ test "switch on pointer type" {
582 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO575 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
583 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO576 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
584 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO577 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
585 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
586578
587 const S = struct {579 const S = struct {
588 const X = struct {580 const X = struct {
...@@ -674,7 +666,6 @@ test "capture of integer forwards the switch condition directly" {...@@ -674,7 +666,6 @@ test "capture of integer forwards the switch condition directly" {
674}666}
675667
676test "enum value without tag name used as switch item" {668test "enum value without tag name used as switch item" {
677 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
678 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO669 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
679670
680 const E = enum(u32) {671 const E = enum(u32) {