authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-06-03 15:52:03+02:00
committergravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-06-04 19:58:34+02:00
logd5ee45117722c1685f4b739686d74ccc7cf5b8d9
tree7f6f7bb2390fc52578883515ad4277a536bece03
parent4fdacca51231668b72bf302ce97335d2a8d93128
signaturelock-open Commit is signed but in an unrecognized format.

stage2 ARM: introduce support for basic switch expressions


2 files changed, 45 insertions(+), 37 deletions(-)

src/arch/arm/CodeGen.zig+45-31
......@@ -953,15 +953,6 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
953953 return reg;
954954}
955955
956/// Allocates a new register and copies `mcv` into it.
957/// `reg_owner` is the instruction that gets associated with the register in the register table.
958/// This can have a side effect of spilling instructions to the stack to free up a register.
959fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue {
960 const reg = try self.register_manager.allocReg(reg_owner, gp);
961 try self.genSetReg(self.air.typeOfIndex(reg_owner), reg, mcv);
962 return MCValue{ .register = reg };
963}
964
965956fn airAlloc(self: *Self, inst: Air.Inst.Index) !void {
966957 const stack_offset = try self.allocMemPtr(inst);
967958 return self.finishAir(inst, .{ .ptr_stack_offset = stack_offset }, .{ .none, .none, .none });
......@@ -2185,6 +2176,9 @@ fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_ind
21852176 .stack_offset => |off| {
21862177 log.debug("%{d} => stack offset {d} (reused)", .{ inst, off });
21872178 },
2179 .cpsr_flags => {
2180 log.debug("%{d} => cpsr_flags (reused)", .{inst});
2181 },
21882182 else => return false,
21892183 }
21902184
......@@ -2487,7 +2481,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
24872481 else => unreachable,
24882482 };
24892483
2490 if (self.liveness.operandDies(inst, 0)) {
2484 if (self.reuseOperand(inst, operand, 0, field)) {
24912485 break :result field;
24922486 } else {
24932487 // Copy to new register
......@@ -2511,6 +2505,41 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void {
25112505 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
25122506}
25132507
2508/// Allocates a new register. If Inst in non-null, additionally tracks
2509/// this register and the corresponding int and removes all previous
2510/// tracking. Does not do the actual moving (that is handled by
2511/// genSetReg).
2512fn prepareNewRegForMoving(
2513 self: *Self,
2514 track_inst: ?Air.Inst.Index,
2515 register_class: RegisterManager.RegisterBitSet,
2516 mcv: MCValue,
2517) !Register {
2518 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
2519 const reg = try self.register_manager.allocReg(track_inst, register_class);
2520
2521 if (track_inst) |inst| {
2522 // Overwrite the MCValue associated with this inst
2523 branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
2524
2525 // If the previous MCValue occupied some space we track, we
2526 // need to make sure it is marked as free now.
2527 switch (mcv) {
2528 .cpsr_flags => {
2529 assert(self.cpsr_flags_inst.? == inst);
2530 self.cpsr_flags_inst = null;
2531 },
2532 .register => |prev_reg| {
2533 assert(!self.register_manager.isRegFree(prev_reg));
2534 self.register_manager.freeReg(prev_reg);
2535 },
2536 else => {},
2537 }
2538 }
2539
2540 return reg;
2541}
2542
25142543/// Don't call this function directly. Use binOp instead.
25152544///
25162545/// Calling this function signals an intention to generate a Mir
......@@ -2537,18 +2566,12 @@ fn binOpRegister(
25372566 null;
25382567 defer if (lhs_lock) |reg| self.register_manager.unlockReg(reg);
25392568
2540 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
2541
25422569 const lhs_reg = if (lhs_is_register) lhs.register else blk: {
25432570 const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: {
25442571 break :inst Air.refToIndex(md.lhs).?;
25452572 } else null;
25462573
2547 const reg = try self.register_manager.allocReg(track_inst, gp);
2548
2549 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
2550
2551 break :blk reg;
2574 break :blk try self.prepareNewRegForMoving(track_inst, gp, lhs);
25522575 };
25532576 const new_lhs_lock = self.register_manager.lockReg(lhs_reg);
25542577 defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg);
......@@ -2558,11 +2581,7 @@ fn binOpRegister(
25582581 break :inst Air.refToIndex(md.rhs).?;
25592582 } else null;
25602583
2561 const reg = try self.register_manager.allocReg(track_inst, gp);
2562
2563 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
2564
2565 break :blk reg;
2584 break :blk try self.prepareNewRegForMoving(track_inst, gp, rhs);
25662585 };
25672586 const new_rhs_lock = self.register_manager.lockReg(rhs_reg);
25682587 defer if (new_rhs_lock) |reg| self.register_manager.unlockReg(reg);
......@@ -2652,8 +2671,6 @@ fn binOpImmediate(
26522671 null;
26532672 defer if (lhs_lock) |reg| self.register_manager.unlockReg(reg);
26542673
2655 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
2656
26572674 const lhs_reg = if (lhs_is_register) lhs.register else blk: {
26582675 const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: {
26592676 break :inst Air.refToIndex(
......@@ -2661,11 +2678,7 @@ fn binOpImmediate(
26612678 ).?;
26622679 } else null;
26632680
2664 const reg = try self.register_manager.allocReg(track_inst, gp);
2665
2666 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
2667
2668 break :blk reg;
2681 break :blk try self.prepareNewRegForMoving(track_inst, gp, lhs);
26692682 };
26702683 const new_lhs_lock = self.register_manager.lockReg(lhs_reg);
26712684 defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg);
......@@ -3444,7 +3457,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
34443457 if (RegisterManager.indexOfRegIntoTracked(reg) == null) {
34453458 // Save function return value into a tracked register
34463459 log.debug("airCall: copying {} as it is not tracked", .{reg});
3447 break :result try self.copyToNewRegister(inst, info.return_value);
3460 const new_reg = try self.copyToTmpRegister(fn_ty.fnReturnType(), info.return_value);
3461 break :result MCValue{ .register = new_reg };
34483462 }
34493463 },
34503464 else => {},
......@@ -4124,7 +4138,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
41244138 var case_i: u32 = 0;
41254139 while (case_i < switch_br.data.cases_len) : (case_i += 1) {
41264140 const case = self.air.extraData(Air.SwitchBr.Case, extra_index);
4127 const items = @bitCast([]const Air.Inst.Ref, self.air.extra[case.end..][0..case.data.items_len]);
4141 const items = @ptrCast([]const Air.Inst.Ref, self.air.extra[case.end..][0..case.data.items_len]);
41284142 assert(items.len > 0);
41294143 const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len];
41304144 extra_index = case.end + items.len + case_body.len;
test/behavior/switch.zig-6
......@@ -5,7 +5,6 @@ const expectError = std.testing.expectError;
55const expectEqual = std.testing.expectEqual;
66
77test "switch with numbers" {
8 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
109
1110 try testSwitchWithNumbers(13);
......@@ -21,7 +20,6 @@ fn testSwitchWithNumbers(x: u32) !void {
2120}
2221
2322test "switch with all ranges" {
24 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2523 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2624
2725 try expect(testSwitchWithAllRanges(50, 3) == 1);
......@@ -176,7 +174,6 @@ test "undefined.u0" {
176174}
177175
178176test "switch with disjoint range" {
179 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
180177 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
181178
182179 var q: u8 = 0;
......@@ -397,7 +394,6 @@ fn switchWithUnreachable(x: i32) i32 {
397394}
398395
399396test "capture value of switch with all unreachable prongs" {
400 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
401397 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
402398
403399 const x = return_a_number() catch |err| switch (err) {
......@@ -412,7 +408,6 @@ fn return_a_number() anyerror!i32 {
412408
413409test "switch on integer with else capturing expr" {
414410 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
415 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
416411 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
417412
418413 const S = struct {
......@@ -658,7 +653,6 @@ test "switch capture copies its payload" {
658653}
659654
660655test "capture of integer forwards the switch condition directly" {
661 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
662656 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
663657
664658 const S = struct {