Commit 3c74a478a4

Jacob Young <jacobly0@users.noreply.github.com>
2025-01-03 05:20:53
x86_64: fix unnecessary register saving
1 parent 7f22c41
Changed files (3)
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);
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);
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);