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) = .{},...@@ -105,6 +105,13 @@ frame_allocs: std.MultiArrayList(FrameAlloc) = .{},
105free_frame_indices: std.AutoArrayHashMapUnmanaged(FrameIndex, void) = .{},105free_frame_indices: std.AutoArrayHashMapUnmanaged(FrameIndex, void) = .{},
106frame_locs: std.MultiArrayList(Mir.FrameLoc) = .{},106frame_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
108/// Debug field, used to find bugs in the compiler.115/// Debug field, used to find bugs in the compiler.
109air_bookkeeping: @TypeOf(air_bookkeeping_init) = air_bookkeeping_init,116air_bookkeeping: @TypeOf(air_bookkeeping_init) = air_bookkeeping_init,
110117
...@@ -815,6 +822,7 @@ pub fn generate(...@@ -815,6 +822,7 @@ pub fn generate(
815 function.frame_allocs.deinit(gpa);822 function.frame_allocs.deinit(gpa);
816 function.free_frame_indices.deinit(gpa);823 function.free_frame_indices.deinit(gpa);
817 function.frame_locs.deinit(gpa);824 function.frame_locs.deinit(gpa);
825 function.loop_repeat_info.deinit(gpa);
818 var block_it = function.blocks.valueIterator();826 var block_it = function.blocks.valueIterator();
819 while (block_it.next()) |block| block.deinit(gpa);827 while (block_it.next()) |block| block.deinit(gpa);
820 function.blocks.deinit(gpa);828 function.blocks.deinit(gpa);
...@@ -2247,7 +2255,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -2247,7 +2255,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
2247 .bitcast => try self.airBitCast(inst),2255 .bitcast => try self.airBitCast(inst),
2248 .block => try self.airBlock(inst),2256 .block => try self.airBlock(inst),
2249 .br => try self.airBr(inst),2257 .br => try self.airBr(inst),
2250 .repeat => return self.fail("TODO implement `repeat`", .{}),2258 .repeat => try self.airRepeat(inst),
2251 .switch_dispatch => return self.fail("TODO implement `switch_dispatch`", .{}),2259 .switch_dispatch => return self.fail("TODO implement `switch_dispatch`", .{}),
2252 .trap => try self.airTrap(),2260 .trap => try self.airTrap(),
2253 .breakpoint => try self.airBreakpoint(),2261 .breakpoint => try self.airBreakpoint(),
...@@ -13629,15 +13637,13 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void {...@@ -13629,15 +13637,13 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void {
13629 self.scope_generation += 1;13637 self.scope_generation += 1;
13630 const state = try self.saveState();13638 const state = try self.saveState();
1363113639
13632 const jmp_target: Mir.Inst.Index = @intCast(self.mir_instructions.len);13640 try self.loop_repeat_info.putNoClobber(self.gpa, inst, .{
13633 try self.genBody(body);13641 .state = state,
13634 try self.restoreState(state, &.{}, .{13642 .jmp_target = @intCast(self.mir_instructions.len),
13635 .emit_instructions = true,
13636 .update_tracking = false,
13637 .resurrect = false,
13638 .close_scope = true,
13639 });13643 });
13640 _ = try self.asmJmpReloc(jmp_target);13644 defer assert(self.loop_repeat_info.remove(inst));
13645
13646 try self.genBody(body);
1364113647
13642 self.finishAirBookkeeping();13648 self.finishAirBookkeeping();
13643}13649}
...@@ -13680,12 +13686,19 @@ fn lowerBlock(self: *Self, inst: Air.Inst.Index, body: []const Air.Inst.Index) !...@@ -13680,12 +13686,19 @@ fn lowerBlock(self: *Self, inst: Air.Inst.Index, body: []const Air.Inst.Index) !
13680}13686}
1368113687
13682fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {13688fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {
13689 const zcu = self.pt.zcu;
13683 const switch_br = self.air.unwrapSwitch(inst);13690 const switch_br = self.air.unwrapSwitch(inst);
13684 const condition = try self.resolveInst(switch_br.operand);13691 const condition = try self.resolveInst(switch_br.operand);
13685 const condition_ty = self.typeOf(switch_br.operand);13692 const condition_ty = self.typeOf(switch_br.operand);
13686 const liveness = try self.liveness.getSwitchBr(self.gpa, inst, switch_br.cases_len + 1);13693 const liveness = try self.liveness.getSwitchBr(self.gpa, inst, switch_br.cases_len + 1);
13687 defer self.gpa.free(liveness.deaths);13694 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
13689 // If the condition dies here in this switch instruction, process13702 // If the condition dies here in this switch instruction, process
13690 // that death now instead of later as this has an effect on13703 // that death now instead of later as this has an effect on
13691 // whether it needs to be spilled in the branches13704 // whether it needs to be spilled in the branches
...@@ -13698,13 +13711,11 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -13698,13 +13711,11 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {
1369813711
13699 var it = switch_br.iterateCases();13712 var it = switch_br.iterateCases();
13700 while (it.next()) |case| {13713 while (it.next()) |case| {
13701 if (case.ranges.len > 0) return self.fail("TODO: switch with ranges", .{});13714 var relocs = try self.gpa.alloc(Mir.Inst.Index, case.items.len + case.ranges.len);
13702
13703 var relocs = try self.gpa.alloc(Mir.Inst.Index, case.items.len);
13704 defer self.gpa.free(relocs);13715 defer self.gpa.free(relocs);
1370513716
13706 try self.spillEflagsIfOccupied();13717 try self.spillEflagsIfOccupied();
13707 for (case.items, relocs, 0..) |item, *reloc, i| {13718 for (case.items, relocs[0..case.items.len]) |item, *reloc| {
13708 const item_mcv = try self.resolveInst(item);13719 const item_mcv = try self.resolveInst(item);
13709 const cc: Condition = switch (condition) {13720 const cc: Condition = switch (condition) {
13710 .eflags => |cc| switch (item_mcv.immediate) {13721 .eflags => |cc| switch (item_mcv.immediate) {
...@@ -13717,12 +13728,62 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -13717,12 +13728,62 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {
13717 break :cc .e;13728 break :cc .e;
13718 },13729 },
13719 };13730 };
13720 reloc.* = try self.asmJccReloc(if (i < relocs.len - 1) cc else cc.negate(), undefined);13731 reloc.* = try self.asmJccReloc(cc, undefined);
13721 }13732 }
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
13723 for (liveness.deaths[case.idx]) |operand| try self.processDeath(operand);13783 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);
13726 try self.genBody(case.body);13787 try self.genBody(case.body);
13727 try self.restoreState(state, &.{}, .{13788 try self.restoreState(state, &.{}, .{
13728 .emit_instructions = false,13789 .emit_instructions = false,
...@@ -13731,7 +13792,8 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -13731,7 +13792,8 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {
13731 .close_scope = true,13792 .close_scope = true,
13732 });13793 });
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);
13735 }13797 }
1373613798
13737 if (switch_br.else_body_len > 0) {13799 if (switch_br.else_body_len > 0) {
...@@ -13827,6 +13889,19 @@ fn airBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -13827,6 +13889,19 @@ fn airBr(self: *Self, inst: Air.Inst.Index) !void {
13827 self.finishAirBookkeeping();13889 self.finishAirBookkeeping();
13828}13890}
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
13830fn airAsm(self: *Self, inst: Air.Inst.Index) !void {13905fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
13831 const pt = self.pt;13906 const pt = self.pt;
13832 const zcu = pt.zcu;13907 const zcu = pt.zcu;