From 3c74a478a41d2f806f3b9b2bb86fffbc40e100c3 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Thu, 2 Jan 2025 23:20:53 -0500 Subject: [PATCH] x86_64: fix unnecessary register saving --- src/arch/x86_64/CodeGen.zig | 43 +++++++++++++++---------------------- src/arch/x86_64/Mir.zig | 4 +++- src/register_manager.zig | 7 +++--- 3 files changed, 23 insertions(+), 31 deletions(-) diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 93eb16f795..cb7be5cfc8 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -9731,7 +9731,7 @@ fn computeFrameLayout(self: *CodeGen, cc: std.builtin.CallingConvention) !FrameL // Create list of registers to save in the prologue. // TODO handle register classes - var save_reg_list = Mir.RegisterList{}; + var save_reg_list: Mir.RegisterList = .empty; const callee_preserved_regs = abi.getCalleePreservedRegs(abi.resolveCallingConvention(cc, self.target.*)); for (callee_preserved_regs) |reg| { @@ -9972,43 +9972,34 @@ fn restoreState(self: *CodeGen, state: State, deaths: []const Air.Inst.Index, co reg_locks.deinit(); }; - for (0..state.registers.len) |index| { - const current_maybe_inst = if (self.register_manager.free_registers.isSet(index)) - null - else - self.register_manager.registers[index]; - const target_maybe_inst = if (state.free_registers.isSet(index)) - null - else - state.registers[index]; + for ( + 0.., + self.register_manager.registers, + state.registers, + state.reg_tracking, + ) |reg_i, current_slot, target_slot, reg_tracking| { + const reg_index: RegisterManager.TrackedIndex = @intCast(reg_i); + const current_maybe_inst = if (self.register_manager.isRegIndexFree(reg_index)) null else current_slot; + const target_maybe_inst = if (state.free_registers.isSet(reg_index)) null else target_slot; if (std.debug.runtime_safety) if (target_maybe_inst) |target_inst| assert(self.inst_tracking.getIndex(target_inst).? < state.inst_tracking_len); if (opts.emit_instructions) { - if (current_maybe_inst) |current_inst| { + if (current_maybe_inst) |current_inst| try self.inst_tracking.getPtr(current_inst).?.spill(self, current_inst); - } - if (target_maybe_inst) |target_inst| { - const target_tracking = self.inst_tracking.getPtr(target_inst).?; - try target_tracking.materialize(self, target_inst, state.reg_tracking[index]); - } + if (target_maybe_inst) |target_inst| + try self.inst_tracking.getPtr(target_inst).?.materialize(self, target_inst, reg_tracking); } if (opts.update_tracking) { if (current_maybe_inst) |current_inst| { try self.inst_tracking.getPtr(current_inst).?.trackSpill(self, current_inst); - } - { - const reg = RegisterManager.regAtTrackedIndex(@intCast(index)); - self.register_manager.freeReg(reg); - self.register_manager.getRegAssumeFree(reg, target_maybe_inst); + self.register_manager.freeRegIndex(reg_index); } if (target_maybe_inst) |target_inst| { - self.inst_tracking.getPtr(target_inst).?.trackMaterialize( - target_inst, - state.reg_tracking[index], - ); + self.register_manager.getRegIndexAssumeFree(reg_index, target_maybe_inst); + self.inst_tracking.getPtr(target_inst).?.trackMaterialize(target_inst, reg_tracking); } } else if (target_maybe_inst) |_| - try reg_locks.append(self.register_manager.lockRegIndexAssumeUnused(@intCast(index))); + try reg_locks.append(self.register_manager.lockRegIndexAssumeUnused(reg_index)); } if (opts.emit_instructions) if (self.eflags_inst) |inst| try self.inst_tracking.getPtr(inst).?.spill(self, inst); diff --git a/src/arch/x86_64/Mir.zig b/src/arch/x86_64/Mir.zig index 595f79e8dd..10e6dc4618 100644 --- a/src/arch/x86_64/Mir.zig +++ b/src/arch/x86_64/Mir.zig @@ -1168,11 +1168,13 @@ pub const AirOffset = struct { air_inst: Air.Inst.Index, off: i32 }; /// Used in conjunction with payload to transfer a list of used registers in a compact manner. pub const RegisterList = struct { - bitset: BitSet = BitSet.initEmpty(), + bitset: BitSet, const BitSet = IntegerBitSet(32); const Self = @This(); + pub const empty: RegisterList = .{ .bitset = .initEmpty() }; + fn getIndexForReg(registers: []const Register, reg: Register) BitSet.MaskInt { for (registers, 0..) |cpreg, i| { if (reg.id() == cpreg.id()) return @intCast(i); diff --git a/src/register_manager.zig b/src/register_manager.zig index 4176dd7d83..b9d3b6db0b 100644 --- a/src/register_manager.zig +++ b/src/register_manager.zig @@ -99,8 +99,7 @@ pub fn RegisterManager( max_id = @max(elem_id, max_id); } - const OptionalIndex = std.math.IntFittingRange(0, set.len); - comptime var map = [1]OptionalIndex{set.len} ** (max_id - min_id + 1); + comptime var map: [max_id - min_id + 1]std.math.IntFittingRange(0, set.len) = @splat(set.len); inline for (set, 0..) |elem, elem_index| map[comptime elem.id() - min_id] = elem_index; const id_index = reg.id() -% min_id; @@ -384,7 +383,7 @@ pub fn RegisterManager( /// Allocates the specified register with the specified /// instruction. Asserts that the register is free and no /// spilling is necessary. - fn getRegIndexAssumeFree( + pub fn getRegIndexAssumeFree( self: *Self, tracked_index: TrackedIndex, inst: ?Air.Inst.Index, @@ -403,7 +402,7 @@ pub fn RegisterManager( } /// Marks the specified register as free - fn freeRegIndex(self: *Self, tracked_index: TrackedIndex) void { + pub fn freeRegIndex(self: *Self, tracked_index: TrackedIndex) void { log.debug("freeing register {}", .{regAtTrackedIndex(tracked_index)}); self.registers[tracked_index] = undefined; self.markRegIndexFree(tracked_index);