diff --git a/deps/zig/register_manager.zig b/deps/zig/register_manager.zig index 24250f97..27dee698 100644 --- a/deps/zig/register_manager.zig +++ b/deps/zig/register_manager.zig @@ -10,7 +10,7 @@ const expectEqualSlices = std.testing.expectEqualSlices; const log = std.log.scoped(.register_manager); -pub const AllocateRegistersError = error{ +pub const AllocateRegistersError = error { OutOfRegisters, // No registers are available anymore OutOfMemory, // Spilling in codegen runs out of memory Overflow, // Spilling triggers integer overflow @@ -52,29 +52,32 @@ pub fn RegisterManager( } fn excludeRegister(reg: Register, register_class: RegisterBitSet) bool { - const index = indexOfRegIntoTracked(reg) orelse return true; + const index = self.indexOfRegIntoTracked(reg) orelse return true; return !register_class.isSet(index); } fn markRegIndexAllocated(self: *Self, tracked_index: TrackedIndex) void { self.allocated_registers.set(tracked_index); } + fn markRegAllocated(self: *Self, reg: Register) void { - self.markRegIndexAllocated(indexOfRegIntoTracked(reg) orelse return); + self.markRegIndexAllocated(self.indexOfRegIntoTracked(reg) orelse return); } fn markRegIndexUsed(self: *Self, tracked_index: TrackedIndex) void { self.free_registers.unset(tracked_index); } + fn markRegUsed(self: *Self, reg: Register) void { - self.markRegIndexUsed(indexOfRegIntoTracked(reg) orelse return); + self.markRegIndexUsed(self.indexOfRegIntoTracked(reg) orelse return); } fn markRegIndexFree(self: *Self, tracked_index: TrackedIndex) void { self.free_registers.set(tracked_index); } + fn markRegFree(self: *Self, reg: Register) void { - self.markRegIndexFree(indexOfRegIntoTracked(reg) orelse return); + self.markRegIndexFree(self.indexOfRegIntoTracked(reg) orelse return); } pub fn indexOfReg( @@ -102,8 +105,8 @@ pub fn RegisterManager( return if (set_index < set.len) @intCast(set_index) else null; } - pub fn indexOfRegIntoTracked(reg: Register) ?TrackedIndex { - return indexOfReg(tracked_registers, reg); + pub fn indexOfRegIntoTracked(self: *Self, reg: Register) ?TrackedIndex { + return self.indexOfReg(tracked_registers, reg); } pub fn regAtTrackedIndex(tracked_index: TrackedIndex) Register { @@ -111,97 +114,57 @@ pub fn RegisterManager( } /// Returns true when this register is not tracked - pub fn isRegIndexFree(self: Self, tracked_index: TrackedIndex) bool { + pub fn isRegIndexFree(self: *Self, tracked_index: TrackedIndex) bool { return self.free_registers.isSet(tracked_index); } - pub fn isRegFree(self: Self, reg: Register) bool { - return self.isRegIndexFree(indexOfRegIntoTracked(reg) orelse return true); + + pub fn isRegFree(self: *Self, reg: Register) bool { + return self.isRegIndexFree(self.indexOfRegIntoTracked(reg) orelse return true); } - /// Returns whether this register was allocated in the course - /// of this function. - /// + /// Returns whether this register was allocated in the course of this function. /// Returns false when this register is not tracked - pub fn isRegAllocated(self: Self, reg: Register) bool { - const index = indexOfRegIntoTracked(reg) orelse return false; + pub fn isRegAllocated(self: *Self, reg: Register) bool { + const index = self.indexOfRegIntoTracked(reg) orelse return false; return self.allocated_registers.isSet(index); } /// Returns whether this register is locked /// /// Returns false when this register is not tracked - fn isRegIndexLocked(self: Self, tracked_index: TrackedIndex) bool { + fn isRegIndexLocked(self: *Self, tracked_index: TrackedIndex) bool { return self.locked_registers.isSet(tracked_index); } - pub fn isRegLocked(self: Self, reg: Register) bool { - return self.isRegIndexLocked(indexOfRegIntoTracked(reg) orelse return false); + + pub fn isRegLocked(self: *Self, reg: Register) bool { + return self.isRegIndexLocked(self.indexOfRegIntoTracked(reg) orelse return false); } - pub const RegisterLock = struct { tracked_index: TrackedIndex }; + pub const RegisterLock = struct { + tracked_index: TrackedIndex, + }; - /// Prevents the register from being allocated until they are - /// unlocked again. - /// Returns `RegisterLock` if the register was not already - /// locked, or `null` otherwise. - /// Only the owner of the `RegisterLock` can unlock the - /// register later. + /// Locks the register from allocation pub fn lockRegIndex(self: *Self, tracked_index: TrackedIndex) ?RegisterLock { - log.debug("locking {}", .{regAtTrackedIndex(tracked_index)}); - if (self.isRegIndexLocked(tracked_index)) { - log.debug(" register already locked", .{}); - return null; - } + if (self.isRegIndexLocked(tracked_index)) return null; self.locked_registers.set(tracked_index); return RegisterLock{ .tracked_index = tracked_index }; } - pub fn lockReg(self: *Self, reg: Register) ?RegisterLock { - return self.lockRegIndex(indexOfRegIntoTracked(reg) orelse return null); - } - - /// Like `lockReg` but asserts the register was unused always - /// returning a valid lock. - pub fn lockRegIndexAssumeUnused(self: *Self, tracked_index: TrackedIndex) RegisterLock { - log.debug("locking asserting free {}", .{regAtTrackedIndex(tracked_index)}); - assert(!self.isRegIndexLocked(tracked_index)); - self.locked_registers.set(tracked_index); - return RegisterLock{ .tracked_index = tracked_index }; - } - pub fn lockRegAssumeUnused(self: *Self, reg: Register) RegisterLock { - return self.lockRegIndexAssumeUnused(indexOfRegIntoTracked(reg) orelse unreachable); - } - /// Like `lockReg` but locks multiple registers. - pub fn lockRegs( - self: *Self, - comptime count: comptime_int, - regs: [count]Register, - ) [count]?RegisterLock { - var results: [count]?RegisterLock = undefined; - for (&results, regs) |*result, reg| result.* = self.lockReg(reg); - return results; - } - - /// Like `lockRegAssumeUnused` but locks multiple registers. - pub fn lockRegsAssumeUnused( - self: *Self, - comptime count: comptime_int, - regs: [count]Register, - ) [count]RegisterLock { - var results: [count]RegisterLock = undefined; - for (&results, regs) |*result, reg| result.* = self.lockRegAssumeUnused(reg); - return results; + pub fn lockReg(self: *Self, reg: Register) ?RegisterLock { + return self.lockRegIndex(self.indexOfRegIntoTracked(reg) orelse return null); } - /// Unlocks the register allowing its re-allocation and re-use. - /// Requires `RegisterLock` to unlock a register. + /// Unlocks the register for re-use + /// Tracks registers which are locked from being allocated /// Call `lockReg` to obtain the lock first. pub fn unlockReg(self: *Self, lock: RegisterLock) void { - log.debug("unlocking {}", .{regAtTrackedIndex(lock.tracked_index)}); self.locked_registers.unset(lock.tracked_index); } - pub fn lockedRegsExist(self: Self) bool { - return self.locked_registers.count() > 0; + pub fn tryAllocReg(self: *Self, inst: ?Inst, register_class: RegisterBitSet) ?Register { + return if (try |regs| self.tryAllocRegs(1, [1]?Inst{inst}, register_class)) regs[0] + else null; } /// Allocates a specified number of registers, optionally @@ -213,8 +176,6 @@ pub fn RegisterManager( insts: [count]?Inst, register_class: RegisterBitSet, ) ?[count]Register { - comptime assert(count > 0 and count <= tracked_registers.len); - var free_and_not_locked_registers = self.free_registers; free_and_not_locked_registers.setIntersection(register_class); @@ -222,14 +183,12 @@ pub fn RegisterManager( unlocked_registers.toggleAll(); free_and_not_locked_registers.setIntersection(unlocked_registers); - // Track the register if (free_and_not_locked_registers.count() < count) return null; var regs: [count]Register = undefined; var i: usize = 0; for (tracked_registers) |reg| { if (i >= count) break; - if (excludeRegister(reg, register_class)) continue; if (self.isRegLocked(reg)) continue; if (!self.isRegFree(reg)) continue; @@ -239,11 +198,10 @@ pub fn RegisterManager( assert(i == count); for (regs, insts) |reg, inst| { - log.debug("tryAllocReg {} for inst {?}", .{ reg, inst }); self.markRegAllocated(reg); if (inst) |tracked_inst| { - const index = indexOfRegIntoTracked(reg).?; // indexOfReg() on a callee-preserved reg should never return null + const index = self.indexOfRegIntoTracked(reg).?; self.registers[index] = tracked_inst; self.markRegUsed(reg); } @@ -251,84 +209,5 @@ pub fn RegisterManager( return regs; } - - /// Allocates a register and optionally tracks it with a - /// corresponding instruction. Returns `null` if all registers - /// are allocated. - pub fn tryAllocReg(self: *Self, inst: ?Inst, register_class: RegisterBitSet) ?Register { - return if (try |regs| self.tryAllocRegs(1, [1]?Inst{inst}, register_class)) regs[0] - else null; - } - - /// Allocates a specified number of registers, optionally - /// tracking them. Asserts that count is not - /// larger than the total number of registers available. - pub fn allocRegs( - self: *Self, - comptime count: comptime_int, - insts: [count]?Inst, - register_class: RegisterBitSet, - ) ![count]Register { - return try self.tryAllocRegs(count, insts, register_class) - orelse return AllocateRegistersError.OutOfRegisters; - } - - /// Allocates a register and optionally tracks it with a - - /// corresponding instruction. - pub fn allocReg(self: *Self, inst: ?Inst, register_class: RegisterBitSet) !Register { - return try self.allocRegs(1, [1]?Inst{inst}, register_class)[0]; - } - - /// Spills the register if it is currently allocated. If a - /// corresponding instruction is passed, will also track this - /// register. - - pub fn freeRegs(self: *Self, regs: []Register) void { - for (regs) |reg| { - log.debug("freeing {}", .{ reg }); - if (!self.isRegAllocated(reg)) continue; - - const index = indexOfRegIntoTracked(reg) orelse continue; - const inst = self.registers[index]; - - self.registers[index] = Inst.init; - self.markRegFree(reg); - - log.debug(" freed {}", .{ inst }); - } - } - - /// Allocates the specified register with the specified - /// instruction. Asserts that the register is free and no - /// spilling is necessary. - fn getRegIndexAssumeFree( - self: *Self, - tracked_index: TrackedIndex, - inst: ?Inst, - ) void { - log.debug("getRegAssumeFree {} for inst {?}", .{ regAtTrackedIndex(tracked_index), inst }); - self.markRegIndexAllocated(tracked_index); - - assert(self.isRegIndexFree(tracked_index)); - if (inst) |tracked_inst| { - self.registers[tracked_index] = tracked_inst; - self.markRegIndexUsed(tracked_index); - } - } - pub fn getRegAssumeFree(self: *Self, reg: Register, inst: ?Inst) void { - self.getRegIndexAssumeFree(indexOfRegIntoTracked(reg) orelse return, inst); - } - - - /// Marks the specified register as free - fn freeRegIndex(self: *Self, tracked_index: TrackedIndex) void { - log.debug("freeing register {}", .{regAtTrackedIndex(tracked_index)}); - self.registers[tracked_index] = undefined; - self.markRegIndexFree(tracked_index); - } - pub fn freeReg(self: *Self, reg: Register) void { - self.freeRegIndex(indexOfRegIntoTracked(reg) orelse return); - } }; }