authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-08-30 23:33:57+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-09-01 18:30:32+01:00
logfd70d9db9960a98fb97def91aa34f56c15499ebf
tree7fa700d15a8d1c8d1242eb23ebbcf2c6ec7db09b
parentcb68c0917ab6ef858a7a9a3ed9e85672304f7ab2
signaturelock-open Commit is signed but in an unrecognized format.

x86_64: un-regress `loop` and `switch_br`

This does *not* yet implement the new `loop_switch_br` instruction.

1 files changed, 91 insertions(+), 16 deletions(-)

src/arch/x86_64/CodeGen.zig+91-16
......@@ -105,6 +105,13 @@ frame_allocs: std.MultiArrayList(FrameAlloc) = .{},
105105free_frame_indices: std.AutoArrayHashMapUnmanaged(FrameIndex, void) = .{},
106106frame_locs: std.MultiArrayList(Mir.FrameLoc) = .{},
107107
108loop_repeat_info: std.AutoHashMapUnmanaged(Air.Inst.Index, struct {
109 /// The state to restore before branching.
110 state: State,
111 /// The branch target.
112 jmp_target: Mir.Inst.Index,
113}) = .{},
114
108115/// Debug field, used to find bugs in the compiler.
109116air_bookkeeping: @TypeOf(air_bookkeeping_init) = air_bookkeeping_init,
110117
......@@ -815,6 +822,7 @@ pub fn generate(
815822 function.frame_allocs.deinit(gpa);
816823 function.free_frame_indices.deinit(gpa);
817824 function.frame_locs.deinit(gpa);
825 function.loop_repeat_info.deinit(gpa);
818826 var block_it = function.blocks.valueIterator();
819827 while (block_it.next()) |block| block.deinit(gpa);
820828 function.blocks.deinit(gpa);
......@@ -2247,7 +2255,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
22472255 .bitcast => try self.airBitCast(inst),
22482256 .block => try self.airBlock(inst),
22492257 .br => try self.airBr(inst),
2250 .repeat => return self.fail("TODO implement `repeat`", .{}),
2258 .repeat => try self.airRepeat(inst),
22512259 .switch_dispatch => return self.fail("TODO implement `switch_dispatch`", .{}),
22522260 .trap => try self.airTrap(),
22532261 .breakpoint => try self.airBreakpoint(),
......@@ -13629,15 +13637,13 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void {
1362913637 self.scope_generation += 1;
1363013638 const state = try self.saveState();
1363113639
13632 const jmp_target: Mir.Inst.Index = @intCast(self.mir_instructions.len);
13633 try self.genBody(body);
13634 try self.restoreState(state, &.{}, .{
13635 .emit_instructions = true,
13636 .update_tracking = false,
13637 .resurrect = false,
13638 .close_scope = true,
13640 try self.loop_repeat_info.putNoClobber(self.gpa, inst, .{
13641 .state = state,
13642 .jmp_target = @intCast(self.mir_instructions.len),
1363913643 });
13640 _ = try self.asmJmpReloc(jmp_target);
13644 defer assert(self.loop_repeat_info.remove(inst));
13645
13646 try self.genBody(body);
1364113647
1364213648 self.finishAirBookkeeping();
1364313649}
......@@ -13680,12 +13686,19 @@ fn lowerBlock(self: *Self, inst: Air.Inst.Index, body: []const Air.Inst.Index) !
1368013686}
1368113687
1368213688fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {
13689 const zcu = self.pt.zcu;
1368313690 const switch_br = self.air.unwrapSwitch(inst);
1368413691 const condition = try self.resolveInst(switch_br.operand);
1368513692 const condition_ty = self.typeOf(switch_br.operand);
1368613693 const liveness = try self.liveness.getSwitchBr(self.gpa, inst, switch_br.cases_len + 1);
1368713694 defer self.gpa.free(liveness.deaths);
1368813695
13696 const signedness = switch (condition_ty.zigTypeTag(zcu)) {
13697 .bool, .pointer => .unsigned,
13698 .int, .@"enum", .error_set => condition_ty.intInfo(zcu).signedness,
13699 else => unreachable,
13700 };
13701
1368913702 // If the condition dies here in this switch instruction, process
1369013703 // that death now instead of later as this has an effect on
1369113704 // whether it needs to be spilled in the branches
......@@ -13698,13 +13711,11 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {
1369813711
1369913712 var it = switch_br.iterateCases();
1370013713 while (it.next()) |case| {
13701 if (case.ranges.len > 0) return self.fail("TODO: switch with ranges", .{});
13702
13703 var relocs = try self.gpa.alloc(Mir.Inst.Index, case.items.len);
13714 var relocs = try self.gpa.alloc(Mir.Inst.Index, case.items.len + case.ranges.len);
1370413715 defer self.gpa.free(relocs);
1370513716
1370613717 try self.spillEflagsIfOccupied();
13707 for (case.items, relocs, 0..) |item, *reloc, i| {
13718 for (case.items, relocs[0..case.items.len]) |item, *reloc| {
1370813719 const item_mcv = try self.resolveInst(item);
1370913720 const cc: Condition = switch (condition) {
1371013721 .eflags => |cc| switch (item_mcv.immediate) {
......@@ -13717,12 +13728,62 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {
1371713728 break :cc .e;
1371813729 },
1371913730 };
13720 reloc.* = try self.asmJccReloc(if (i < relocs.len - 1) cc else cc.negate(), undefined);
13731 reloc.* = try self.asmJccReloc(cc, undefined);
1372113732 }
1372213733
13734 for (case.ranges, relocs[case.items.len..]) |range, *reloc| {
13735 const min_mcv = try self.resolveInst(range[0]);
13736 const max_mcv = try self.resolveInst(range[1]);
13737 // `null` means always false.
13738 const lt_min: ?Condition = switch (condition) {
13739 .eflags => |cc| switch (min_mcv.immediate) {
13740 0 => null, // condition never <0
13741 1 => cc.negate(),
13742 else => unreachable,
13743 },
13744 else => cc: {
13745 try self.genBinOpMir(.{ ._, .cmp }, condition_ty, condition, min_mcv);
13746 break :cc switch (signedness) {
13747 .unsigned => .b,
13748 .signed => .l,
13749 };
13750 },
13751 };
13752 const lt_min_reloc = if (lt_min) |cc| r: {
13753 break :r try self.asmJccReloc(cc, undefined);
13754 } else null;
13755 // `null` means always true.
13756 const lte_max: ?Condition = switch (condition) {
13757 .eflags => |cc| switch (max_mcv.immediate) {
13758 0 => cc.negate(),
13759 1 => null, // condition always >=1
13760 else => unreachable,
13761 },
13762 else => cc: {
13763 try self.genBinOpMir(.{ ._, .cmp }, condition_ty, condition, max_mcv);
13764 break :cc switch (signedness) {
13765 .unsigned => .be,
13766 .signed => .le,
13767 };
13768 },
13769 };
13770 // "Success" case is in `reloc`....
13771 if (lte_max) |cc| {
13772 reloc.* = try self.asmJccReloc(cc, undefined);
13773 } else {
13774 reloc.* = try self.asmJmpReloc(undefined);
13775 }
13776 // ...and "fail" case falls through to next checks.
13777 if (lt_min_reloc) |r| self.performReloc(r);
13778 }
13779
13780 // The jump to skip this case if the conditions all failed.
13781 const skip_case_reloc = try self.asmJmpReloc(undefined);
13782
1372313783 for (liveness.deaths[case.idx]) |operand| try self.processDeath(operand);
1372413784
13725 for (relocs[0 .. relocs.len - 1]) |reloc| self.performReloc(reloc);
13785 // Relocate all success cases to the body we're about to generate.
13786 for (relocs) |reloc| self.performReloc(reloc);
1372613787 try self.genBody(case.body);
1372713788 try self.restoreState(state, &.{}, .{
1372813789 .emit_instructions = false,
......@@ -13731,7 +13792,8 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {
1373113792 .close_scope = true,
1373213793 });
1373313794
13734 self.performReloc(relocs[relocs.len - 1]);
13795 // Relocate the "skip" branch to fall through to the next case.
13796 self.performReloc(skip_case_reloc);
1373513797 }
1373613798
1373713799 if (switch_br.else_body_len > 0) {
......@@ -13827,6 +13889,19 @@ fn airBr(self: *Self, inst: Air.Inst.Index) !void {
1382713889 self.finishAirBookkeeping();
1382813890}
1382913891
13892fn airRepeat(self: *Self, inst: Air.Inst.Index) !void {
13893 const loop_inst = self.air.instructions.items(.data)[@intFromEnum(inst)].repeat.loop_inst;
13894 const repeat_info = self.loop_repeat_info.get(loop_inst).?;
13895 try self.restoreState(repeat_info.state, &.{}, .{
13896 .emit_instructions = true,
13897 .update_tracking = false,
13898 .resurrect = false,
13899 .close_scope = true,
13900 });
13901 _ = try self.asmJmpReloc(repeat_info.jmp_target);
13902 self.finishAirBookkeeping();
13903}
13904
1383013905fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
1383113906 const pt = self.pt;
1383213907 const zcu = pt.zcu;