authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-01-02 23:20:53-05:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-01-16 20:42:08-05:00
log3c74a478a41d2f806f3b9b2bb86fffbc40e100c3
tree8ff4dc5ff57130b2a33c5189363187a38cc0236f
parent7f22c41e09741de8cd7d87b938c0b15a9b4bd32e

x86_64: fix unnecessary register saving


3 files changed, 23 insertions(+), 31 deletions(-)

src/arch/x86_64/CodeGen.zig+17-26
...@@ -9731,7 +9731,7 @@ fn computeFrameLayout(self: *CodeGen, cc: std.builtin.CallingConvention) !FrameL...@@ -9731,7 +9731,7 @@ fn computeFrameLayout(self: *CodeGen, cc: std.builtin.CallingConvention) !FrameL
97319731
9732 // Create list of registers to save in the prologue.9732 // Create list of registers to save in the prologue.
9733 // TODO handle register classes9733 // TODO handle register classes
9734 var save_reg_list = Mir.RegisterList{};9734 var save_reg_list: Mir.RegisterList = .empty;
9735 const callee_preserved_regs =9735 const callee_preserved_regs =
9736 abi.getCalleePreservedRegs(abi.resolveCallingConvention(cc, self.target.*));9736 abi.getCalleePreservedRegs(abi.resolveCallingConvention(cc, self.target.*));
9737 for (callee_preserved_regs) |reg| {9737 for (callee_preserved_regs) |reg| {
...@@ -9972,43 +9972,34 @@ fn restoreState(self: *CodeGen, state: State, deaths: []const Air.Inst.Index, co...@@ -9972,43 +9972,34 @@ fn restoreState(self: *CodeGen, state: State, deaths: []const Air.Inst.Index, co
9972 reg_locks.deinit();9972 reg_locks.deinit();
9973 };9973 };
99749974
9975 for (0..state.registers.len) |index| {9975 for (
9976 const current_maybe_inst = if (self.register_manager.free_registers.isSet(index))9976 0..,
9977 null9977 self.register_manager.registers,
9978 else9978 state.registers,
9979 self.register_manager.registers[index];9979 state.reg_tracking,
9980 const target_maybe_inst = if (state.free_registers.isSet(index))9980 ) |reg_i, current_slot, target_slot, reg_tracking| {
9981 null9981 const reg_index: RegisterManager.TrackedIndex = @intCast(reg_i);
9982 else9982 const current_maybe_inst = if (self.register_manager.isRegIndexFree(reg_index)) null else current_slot;
9983 state.registers[index];9983 const target_maybe_inst = if (state.free_registers.isSet(reg_index)) null else target_slot;
9984 if (std.debug.runtime_safety) if (target_maybe_inst) |target_inst|9984 if (std.debug.runtime_safety) if (target_maybe_inst) |target_inst|
9985 assert(self.inst_tracking.getIndex(target_inst).? < state.inst_tracking_len);9985 assert(self.inst_tracking.getIndex(target_inst).? < state.inst_tracking_len);
9986 if (opts.emit_instructions) {9986 if (opts.emit_instructions) {
9987 if (current_maybe_inst) |current_inst| {9987 if (current_maybe_inst) |current_inst|
9988 try self.inst_tracking.getPtr(current_inst).?.spill(self, current_inst);9988 try self.inst_tracking.getPtr(current_inst).?.spill(self, current_inst);
9989 }9989 if (target_maybe_inst) |target_inst|
9990 if (target_maybe_inst) |target_inst| {9990 try self.inst_tracking.getPtr(target_inst).?.materialize(self, target_inst, reg_tracking);
9991 const target_tracking = self.inst_tracking.getPtr(target_inst).?;
9992 try target_tracking.materialize(self, target_inst, state.reg_tracking[index]);
9993 }
9994 }9991 }
9995 if (opts.update_tracking) {9992 if (opts.update_tracking) {
9996 if (current_maybe_inst) |current_inst| {9993 if (current_maybe_inst) |current_inst| {
9997 try self.inst_tracking.getPtr(current_inst).?.trackSpill(self, current_inst);9994 try self.inst_tracking.getPtr(current_inst).?.trackSpill(self, current_inst);
9998 }9995 self.register_manager.freeRegIndex(reg_index);
9999 {
10000 const reg = RegisterManager.regAtTrackedIndex(@intCast(index));
10001 self.register_manager.freeReg(reg);
10002 self.register_manager.getRegAssumeFree(reg, target_maybe_inst);
10003 }9996 }
10004 if (target_maybe_inst) |target_inst| {9997 if (target_maybe_inst) |target_inst| {
10005 self.inst_tracking.getPtr(target_inst).?.trackMaterialize(9998 self.register_manager.getRegIndexAssumeFree(reg_index, target_maybe_inst);
10006 target_inst,9999 self.inst_tracking.getPtr(target_inst).?.trackMaterialize(target_inst, reg_tracking);
10007 state.reg_tracking[index],
10008 );
10009 }10000 }
10010 } else if (target_maybe_inst) |_|10001 } else if (target_maybe_inst) |_|
10011 try reg_locks.append(self.register_manager.lockRegIndexAssumeUnused(@intCast(index)));10002 try reg_locks.append(self.register_manager.lockRegIndexAssumeUnused(reg_index));
10012 }10003 }
10013 if (opts.emit_instructions) if (self.eflags_inst) |inst|10004 if (opts.emit_instructions) if (self.eflags_inst) |inst|
10014 try self.inst_tracking.getPtr(inst).?.spill(self, inst);10005 try self.inst_tracking.getPtr(inst).?.spill(self, inst);
src/arch/x86_64/Mir.zig+3-1
...@@ -1168,11 +1168,13 @@ pub const AirOffset = struct { air_inst: Air.Inst.Index, off: i32 };...@@ -1168,11 +1168,13 @@ pub const AirOffset = struct { air_inst: Air.Inst.Index, off: i32 };
11681168
1169/// Used in conjunction with payload to transfer a list of used registers in a compact manner.1169/// Used in conjunction with payload to transfer a list of used registers in a compact manner.
1170pub const RegisterList = struct {1170pub const RegisterList = struct {
1171 bitset: BitSet = BitSet.initEmpty(),1171 bitset: BitSet,
11721172
1173 const BitSet = IntegerBitSet(32);1173 const BitSet = IntegerBitSet(32);
1174 const Self = @This();1174 const Self = @This();
11751175
1176 pub const empty: RegisterList = .{ .bitset = .initEmpty() };
1177
1176 fn getIndexForReg(registers: []const Register, reg: Register) BitSet.MaskInt {1178 fn getIndexForReg(registers: []const Register, reg: Register) BitSet.MaskInt {
1177 for (registers, 0..) |cpreg, i| {1179 for (registers, 0..) |cpreg, i| {
1178 if (reg.id() == cpreg.id()) return @intCast(i);1180 if (reg.id() == cpreg.id()) return @intCast(i);
src/register_manager.zig+3-4
...@@ -99,8 +99,7 @@ pub fn RegisterManager(...@@ -99,8 +99,7 @@ pub fn RegisterManager(
99 max_id = @max(elem_id, max_id);99 max_id = @max(elem_id, max_id);
100 }100 }
101101
102 const OptionalIndex = std.math.IntFittingRange(0, set.len);102 comptime var map: [max_id - min_id + 1]std.math.IntFittingRange(0, set.len) = @splat(set.len);
103 comptime var map = [1]OptionalIndex{set.len} ** (max_id - min_id + 1);
104 inline for (set, 0..) |elem, elem_index| map[comptime elem.id() - min_id] = elem_index;103 inline for (set, 0..) |elem, elem_index| map[comptime elem.id() - min_id] = elem_index;
105104
106 const id_index = reg.id() -% min_id;105 const id_index = reg.id() -% min_id;
...@@ -384,7 +383,7 @@ pub fn RegisterManager(...@@ -384,7 +383,7 @@ pub fn RegisterManager(
384 /// Allocates the specified register with the specified383 /// Allocates the specified register with the specified
385 /// instruction. Asserts that the register is free and no384 /// instruction. Asserts that the register is free and no
386 /// spilling is necessary.385 /// spilling is necessary.
387 fn getRegIndexAssumeFree(386 pub fn getRegIndexAssumeFree(
388 self: *Self,387 self: *Self,
389 tracked_index: TrackedIndex,388 tracked_index: TrackedIndex,
390 inst: ?Air.Inst.Index,389 inst: ?Air.Inst.Index,
...@@ -403,7 +402,7 @@ pub fn RegisterManager(...@@ -403,7 +402,7 @@ pub fn RegisterManager(
403 }402 }
404403
405 /// Marks the specified register as free404 /// Marks the specified register as free
406 fn freeRegIndex(self: *Self, tracked_index: TrackedIndex) void {405 pub fn freeRegIndex(self: *Self, tracked_index: TrackedIndex) void {
407 log.debug("freeing register {}", .{regAtTrackedIndex(tracked_index)});406 log.debug("freeing register {}", .{regAtTrackedIndex(tracked_index)});
408 self.registers[tracked_index] = undefined;407 self.registers[tracked_index] = undefined;
409 self.markRegIndexFree(tracked_index);408 self.markRegIndexFree(tracked_index);