diff --git a/Source/Core/Core/PowerPC/Jit64/Jit.cpp b/Source/Core/Core/PowerPC/Jit64/Jit.cpp index 0705366aec..2cdad6e54d 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit.cpp @@ -920,10 +920,8 @@ u8* Jit64::DoJit(u32 em_address, JitBlock* b, u32 nextPC) fpr.Commit(); // If we have a register that will never be used again, flush it. - for (int j : ~op.gprInUse) - gpr.StoreFromRegister(j); - for (int j : ~op.fprInUse) - fpr.StoreFromRegister(j); + gpr.Flush(~op.gprInUse); + fpr.Flush(~op.fprInUse); if (opinfo->flags & FL_LOADSTORE) ++js.numLoadStoreInst; diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_FloatingPoint.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_FloatingPoint.cpp index a891ad5438..fcf65ee9b8 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_FloatingPoint.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_FloatingPoint.cpp @@ -116,7 +116,7 @@ void Jit64::HandleNaNs(UGeckoInstruction inst, X64Reg xmm_out, X64Reg xmm, X64Re else { // SSE2 fallback - RCX64Reg tmp = fpr.Scratch(fpr.GetFreeXReg()); + RCX64Reg tmp = fpr.Scratch(); RegCache::Realize(tmp); MOVAPD(clobber, R(xmm)); CMPPD(clobber, R(clobber), CMP_UNORD); diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp index cdf9dc4218..f132959dcb 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp @@ -173,6 +173,7 @@ void Jit64::ComputeRC(preg_t preg, bool needs_test, bool needs_sext) if (needs_test) { TEST(32, arg, arg); + arg.Unlock(); } else { @@ -180,11 +181,9 @@ void Jit64::ComputeRC(preg_t preg, bool needs_test, bool needs_sext) // better to flush it here so that we don't have to flush it on both sides of the branch. // We don't want to do this if a test is needed though, because it would interrupt macro-op // fusion. - for (int j : ~js.op->gprInUse) - gpr.StoreFromRegister(j); + arg.Unlock(); + gpr.Flush(~js.op->gprInUse); } - - arg.Unlock(); DoMergedBranchCondition(); } } diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp index c106b98bb9..0c6bb929a2 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp @@ -271,7 +271,7 @@ void Jit64::dcbx(UGeckoInstruction inst) X64Reg value = RSCRATCH2; RCOpArg Ra = inst.RA ? gpr.Use(inst.RA, RCMode::Read) : RCOpArg::Imm32(0); RCOpArg Rb = gpr.Use(inst.RB, RCMode::Read); - RCX64Reg tmp = gpr.Scratch(gpr.GetFreeXReg()); + RCX64Reg tmp = gpr.Scratch(); RegCache::Realize(Ra, Rb, tmp); MOV_sum(32, addr, Ra, Rb); diff --git a/Source/Core/Core/PowerPC/Jit64/RegCache/CachedReg.h b/Source/Core/Core/PowerPC/Jit64/RegCache/CachedReg.h index 127073b5cf..3c7d5b4912 100644 --- a/Source/Core/Core/PowerPC/Jit64/RegCache/CachedReg.h +++ b/Source/Core/Core/PowerPC/Jit64/RegCache/CachedReg.h @@ -101,7 +101,6 @@ public: ASSERT(IsLocked()); locked--; } - void UnlockAll() { locked = 0; } // TODO: Remove from final version private: Gen::OpArg default_location{}; @@ -142,7 +141,6 @@ public: ASSERT(IsLocked()); locked--; } - void UnlockAll() { locked = 0; } // TODO: Remove from final version private: preg_t ppcReg = static_cast(Gen::INVALID_REG); diff --git a/Source/Core/Core/PowerPC/Jit64/RegCache/FPURegCache.h b/Source/Core/Core/PowerPC/Jit64/RegCache/FPURegCache.h index cb482911b2..fd7d2bb53c 100644 --- a/Source/Core/Core/PowerPC/Jit64/RegCache/FPURegCache.h +++ b/Source/Core/Core/PowerPC/Jit64/RegCache/FPURegCache.h @@ -12,9 +12,9 @@ class FPURegCache final : public RegCache { public: explicit FPURegCache(Jit64& jit); - Gen::OpArg GetDefaultLocation(preg_t preg) const override; protected: + Gen::OpArg GetDefaultLocation(preg_t preg) const override; void StoreRegister(preg_t preg, const Gen::OpArg& newLoc) override; void LoadRegister(preg_t preg, Gen::X64Reg newLoc) override; const Gen::X64Reg* GetAllocationOrder(size_t* count) const override; diff --git a/Source/Core/Core/PowerPC/Jit64/RegCache/GPRRegCache.h b/Source/Core/Core/PowerPC/Jit64/RegCache/GPRRegCache.h index d340d6c6d2..a80182ad92 100644 --- a/Source/Core/Core/PowerPC/Jit64/RegCache/GPRRegCache.h +++ b/Source/Core/Core/PowerPC/Jit64/RegCache/GPRRegCache.h @@ -12,10 +12,10 @@ class GPRRegCache final : public RegCache { public: explicit GPRRegCache(Jit64& jit); - Gen::OpArg GetDefaultLocation(preg_t preg) const override; void SetImmediate32(preg_t preg, u32 imm_value, bool dirty = true); protected: + Gen::OpArg GetDefaultLocation(preg_t preg) const override; void StoreRegister(preg_t preg, const Gen::OpArg& new_loc) override; void LoadRegister(preg_t preg, Gen::X64Reg new_loc) override; const Gen::X64Reg* GetAllocationOrder(size_t* count) const override; diff --git a/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.cpp b/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.cpp index 0edf0ac875..9b7fc14cd9 100644 --- a/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.cpp +++ b/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.cpp @@ -47,7 +47,7 @@ RCOpArg::RCOpArg(X64Reg xr) : rc(nullptr), contents(xr) RCOpArg::RCOpArg(RegCache* rc_, preg_t preg) : rc(rc_), contents(preg) { - rc->NewLock(preg); + rc->Lock(preg); } RCOpArg::~RCOpArg() @@ -128,14 +128,14 @@ void RCOpArg::Unlock() if (const preg_t* preg = std::get_if(&contents)) { ASSERT(rc); - rc->NewUnlock(*preg); + rc->Unlock(*preg); } else if (const X64Reg* xr = std::get_if(&contents)) { // If rc, we got this from an RCX64Reg. // If !rc, we got this from RCOpArg::R. if (rc) - rc->NewUnlockX(*xr); + rc->UnlockX(*xr); } else { @@ -191,12 +191,12 @@ RCX64Reg::RCX64Reg() = default; RCX64Reg::RCX64Reg(RegCache* rc_, preg_t preg) : rc(rc_), contents(preg) { - rc->NewLock(preg); + rc->Lock(preg); } RCX64Reg::RCX64Reg(RegCache* rc_, X64Reg xr) : rc(rc_), contents(xr) { - rc->NewLockX(xr); + rc->LockX(xr); } RCX64Reg::~RCX64Reg() @@ -251,12 +251,12 @@ void RCX64Reg::Unlock() if (const preg_t* preg = std::get_if(&contents)) { ASSERT(rc); - rc->NewUnlock(*preg); + rc->Unlock(*preg); } else if (const X64Reg* xr = std::get_if(&contents)) { ASSERT(rc); - rc->NewUnlockX(*xr); + rc->UnlockX(*xr); } else { @@ -302,66 +302,11 @@ void RegCache::Start() } } -void RegCache::DiscardRegContentsIfCached(preg_t preg) -{ - if (m_regs[preg].IsBound()) - { - X64Reg xr = m_regs[preg].Location().GetSimpleReg(); - m_xregs[xr].SetFlushed(); - m_regs[preg].SetFlushed(); - } -} - void RegCache::SetEmitter(XEmitter* emitter) { m_emitter = emitter; } -void RegCache::Flush(FlushMode mode, BitSet32 regsToFlush) -{ - ASSERT_MSG( - DYNA_REC, - std::none_of(m_xregs.begin(), m_xregs.end(), [](const auto& x) { return x.IsLocked(); }), - "Someone forgot to unlock a X64 reg"); - - for (unsigned int i : regsToFlush) - { - ASSERT_MSG(DYNA_REC, !m_regs[i].IsLocked(), "Someone forgot to unlock PPC reg %u (X64 reg %i).", - i, RX(i)); - ASSERT_MSG(DYNA_REC, !m_regs[i].IsRevertable(), "Register transaction is in progress!"); - - switch (m_regs[i].GetLocationType()) - { - case PPCCachedReg::LocationType::Default: - break; - case PPCCachedReg::LocationType::SpeculativeImmediate: - // We can have a cached value without a host register through speculative constants. - // It must be cleared when flushing, otherwise it may be out of sync with PPCSTATE, - // if PPCSTATE is modified externally (e.g. fallback to interpreter). - m_regs[i].SetFlushed(); - break; - case PPCCachedReg::LocationType::Bound: - case PPCCachedReg::LocationType::Immediate: - StoreFromRegister(i, mode); - break; - } - } -} - -void RegCache::FlushLockX(X64Reg reg) -{ - FlushX(reg); - LockX(reg); -} - -void RegCache::FlushLockX(X64Reg reg1, X64Reg reg2) -{ - FlushX(reg1); - FlushX(reg2); - LockX(reg1); - LockX(reg2); -} - bool RegCache::SanityCheck() const { for (size_t i = 0; i < m_regs.size(); i++) @@ -389,20 +334,149 @@ bool RegCache::SanityCheck() const return true; } -void RegCache::KillImmediate(preg_t preg, bool doLoad, bool makeDirty) +RCOpArg RegCache::Use(preg_t preg, RCMode mode) { - switch (m_regs[preg].GetLocationType()) + m_constraints[preg].AddUse(mode); + return RCOpArg{this, preg}; +} + +RCOpArg RegCache::UseNoImm(preg_t preg, RCMode mode) +{ + m_constraints[preg].AddUseNoImm(mode); + return RCOpArg{this, preg}; +} + +RCOpArg RegCache::BindOrImm(preg_t preg, RCMode mode) +{ + m_constraints[preg].AddBindOrImm(mode); + return RCOpArg{this, preg}; +} + +RCX64Reg RegCache::Bind(preg_t preg, RCMode mode) +{ + m_constraints[preg].AddBind(mode); + return RCX64Reg{this, preg}; +} + +RCX64Reg RegCache::RevertableBind(preg_t preg, RCMode mode) +{ + m_constraints[preg].AddRevertableBind(mode); + return RCX64Reg{this, preg}; +} + +RCX64Reg RegCache::Scratch() +{ + return Scratch(GetFreeXReg()); +} + +RCX64Reg RegCache::Scratch(X64Reg xr) +{ + FlushX(xr); + return RCX64Reg{this, xr}; +} + +RCForkGuard RegCache::Fork() +{ + return RCForkGuard{*this}; +} + +void RegCache::Flush(BitSet32 pregs) +{ + ASSERT_MSG( + DYNA_REC, + std::none_of(m_xregs.begin(), m_xregs.end(), [](const auto& x) { return x.IsLocked(); }), + "Someone forgot to unlock a X64 reg"); + + for (preg_t i : pregs) { - case PPCCachedReg::LocationType::Default: - case PPCCachedReg::LocationType::SpeculativeImmediate: - break; - case PPCCachedReg::LocationType::Bound: - if (makeDirty) - m_xregs[RX(preg)].MakeDirty(); - break; - case PPCCachedReg::LocationType::Immediate: - BindToRegister(preg, doLoad, makeDirty); - break; + ASSERT_MSG(DYNA_REC, !m_regs[i].IsLocked(), + "Someone forgot to unlock PPC reg %zu (X64 reg %i).", i, RX(i)); + ASSERT_MSG(DYNA_REC, !m_regs[i].IsRevertable(), "Register transaction is in progress!"); + + switch (m_regs[i].GetLocationType()) + { + case PPCCachedReg::LocationType::Default: + break; + case PPCCachedReg::LocationType::SpeculativeImmediate: + // We can have a cached value without a host register through speculative constants. + // It must be cleared when flushing, otherwise it may be out of sync with PPCSTATE, + // if PPCSTATE is modified externally (e.g. fallback to interpreter). + m_regs[i].SetFlushed(); + break; + case PPCCachedReg::LocationType::Bound: + case PPCCachedReg::LocationType::Immediate: + StoreFromRegister(i); + break; + } + } +} + +void RegCache::Revert() +{ + ASSERT(IsAllUnlocked()); + for (auto& reg : m_regs) + { + if (reg.IsRevertable()) + reg.SetRevert(); + } +} + +void RegCache::Commit() +{ + ASSERT(IsAllUnlocked()); + for (auto& reg : m_regs) + { + if (reg.IsRevertable()) + reg.SetCommit(); + } +} + +bool RegCache::IsAllUnlocked() const +{ + return std::none_of(m_regs.begin(), m_regs.end(), [](const auto& r) { return r.IsLocked(); }) && + std::none_of(m_xregs.begin(), m_xregs.end(), [](const auto& x) { return x.IsLocked(); }) && + !IsAnyConstraintActive(); +} + +void RegCache::PreloadRegisters(BitSet32 to_preload) +{ + for (preg_t preg : to_preload) + { + if (NumFreeRegisters() < 2) + return; + if (!R(preg).IsImm()) + BindToRegister(preg, true, false); + } +} + +BitSet32 RegCache::RegistersInUse() const +{ + BitSet32 result; + for (size_t i = 0; i < m_xregs.size(); i++) + { + if (!m_xregs[i].IsFree()) + result[i] = true; + } + return result; +} + +void RegCache::FlushX(X64Reg reg) +{ + ASSERT_MSG(DYNA_REC, reg < m_xregs.size(), "Flushing non-existent reg %i", reg); + ASSERT(!m_xregs[reg].IsLocked()); + if (!m_xregs[reg].IsFree()) + { + StoreFromRegister(m_xregs[reg].Contents()); + } +} + +void RegCache::DiscardRegContentsIfCached(preg_t preg) +{ + if (m_regs[preg].IsBound()) + { + X64Reg xr = m_regs[preg].Location().GetSimpleReg(); + m_xregs[xr].SetFlushed(); + m_regs[preg].SetFlushed(); } } @@ -457,7 +531,7 @@ void RegCache::StoreFromRegister(preg_t i, FlushMode mode) { X64Reg xr = RX(i); doStore = m_xregs[xr].IsDirty(); - if (mode == FlushMode::All) + if (mode == FlushMode::Full) m_xregs[xr].SetFlushed(); break; } @@ -468,39 +542,10 @@ void RegCache::StoreFromRegister(preg_t i, FlushMode mode) if (doStore) StoreRegister(i, GetDefaultLocation(i)); - if (mode == FlushMode::All) + if (mode == FlushMode::Full) m_regs[i].SetFlushed(); } -const OpArg& RegCache::R(preg_t preg) const -{ - return m_regs[preg].Location(); -} - -X64Reg RegCache::RX(preg_t preg) const -{ - ASSERT_MSG(DYNA_REC, m_regs[preg].IsBound(), "Unbound register - %zu", preg); - return m_regs[preg].Location().GetSimpleReg(); -} - -void RegCache::UnlockAll() -{ - for (auto& reg : m_regs) - reg.UnlockAll(); - m_constraints.fill({}); -} - -void RegCache::UnlockAllX() -{ - for (auto& xreg : m_xregs) - xreg.UnlockAll(); -} - -bool RegCache::IsFreeX(size_t xreg) const -{ - return m_xregs[xreg].IsFree(); -} - X64Reg RegCache::GetFreeXReg() { size_t aCount; @@ -556,16 +601,6 @@ int RegCache::NumFreeRegisters() const return count; } -void RegCache::FlushX(X64Reg reg) -{ - ASSERT_MSG(DYNA_REC, reg < m_xregs.size(), "Flushing non-existent reg %i", reg); - ASSERT(!m_xregs[reg].IsLocked()); - if (!m_xregs[reg].IsFree()) - { - StoreFromRegister(m_xregs[reg].Contents()); - } -} - // Estimate roughly how bad it would be to de-allocate this register. Higher score // means more bad. float RegCache::ScoreRegister(X64Reg xreg) const @@ -598,102 +633,23 @@ float RegCache::ScoreRegister(X64Reg xreg) const return score; } -RCOpArg RegCache::Use(preg_t preg, RCMode mode) +const OpArg& RegCache::R(preg_t preg) const { - m_constraints[preg].AddUse(mode); - return RCOpArg{this, preg}; + return m_regs[preg].Location(); } -RCOpArg RegCache::UseNoImm(preg_t preg, RCMode mode) +X64Reg RegCache::RX(preg_t preg) const { - m_constraints[preg].AddUseNoImm(mode); - return RCOpArg{this, preg}; + ASSERT_MSG(DYNA_REC, m_regs[preg].IsBound(), "Unbound register - %zu", preg); + return m_regs[preg].Location().GetSimpleReg(); } -RCOpArg RegCache::BindOrImm(preg_t preg, RCMode mode) -{ - m_constraints[preg].AddBindOrImm(mode); - return RCOpArg{this, preg}; -} - -RCX64Reg RegCache::Bind(preg_t preg, RCMode mode) -{ - m_constraints[preg].AddBind(mode); - return RCX64Reg{this, preg}; -} - -RCX64Reg RegCache::RevertableBind(preg_t preg, RCMode mode) -{ - m_constraints[preg].AddRevertableBind(mode); - return RCX64Reg{this, preg}; -} - -RCX64Reg RegCache::Scratch(X64Reg xr) -{ - FlushX(xr); - return RCX64Reg{this, xr}; -} - -RCForkGuard RegCache::Fork() -{ - return RCForkGuard{*this}; -} - -void RegCache::Revert() -{ - ASSERT(IsAllUnlocked()); - for (auto& reg : m_regs) - { - if (reg.IsRevertable()) - reg.SetRevert(); - } -} - -void RegCache::Commit() -{ - ASSERT(IsAllUnlocked()); - for (auto& reg : m_regs) - { - if (reg.IsRevertable()) - reg.SetCommit(); - } -} - -bool RegCache::IsAllUnlocked() const -{ - return std::none_of(m_regs.begin(), m_regs.end(), [](const auto& r){ return r.IsLocked(); }) && - std::none_of(m_xregs.begin(), m_xregs.end(), [](const auto& x){ return x.IsLocked(); }) && - !IsAnyConstraintActive(); -} - -void RegCache::PreloadRegisters(BitSet32 to_preload) -{ - for (preg_t preg : to_preload) - { - if (NumFreeRegisters() < 2) - return; - if (!R(preg).IsImm()) - BindToRegister(preg, true, false); - } -} - -BitSet32 RegCache::RegistersInUse() const -{ - BitSet32 result; - for (size_t i = 0; i < m_xregs.size(); i++) - { - if (!m_xregs[i].IsFree()) - result[i] = true; - } - return result; -} - -void RegCache::NewLock(preg_t preg) +void RegCache::Lock(preg_t preg) { m_regs[preg].Lock(); } -void RegCache::NewUnlock(preg_t preg) +void RegCache::Unlock(preg_t preg) { m_regs[preg].Unlock(); if (!m_regs[preg].IsLocked()) @@ -703,12 +659,12 @@ void RegCache::NewUnlock(preg_t preg) } } -void RegCache::NewLockX(X64Reg xr) +void RegCache::LockX(X64Reg xr) { m_xregs[xr].Lock(); } -void RegCache::NewUnlockX(X64Reg xr) +void RegCache::UnlockX(X64Reg xr) { m_xregs[xr].Unlock(); } diff --git a/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.h b/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.h index 67f010d0d6..522eb513bb 100644 --- a/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.h +++ b/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.h @@ -126,89 +126,16 @@ class RegCache public: enum class FlushMode { - All, + Full, MaintainState, }; explicit RegCache(Jit64& jit); virtual ~RegCache() = default; - virtual Gen::OpArg GetDefaultLocation(preg_t preg) const = 0; - void Start(); - - void DiscardRegContentsIfCached(preg_t preg); void SetEmitter(Gen::XEmitter* emitter); - - void Flush(FlushMode mode = FlushMode::All, BitSet32 regsToFlush = BitSet32::AllTrue(32)); - - void FlushLockX(Gen::X64Reg reg); - void FlushLockX(Gen::X64Reg reg1, Gen::X64Reg reg2); - bool SanityCheck() const; - void KillImmediate(preg_t preg, bool doLoad, bool makeDirty); - - // TODO - instead of doload, use "read", "write" - // read only will not set dirty flag - void BindToRegister(preg_t preg, bool doLoad = true, bool makeDirty = true); - void StoreFromRegister(preg_t preg, FlushMode mode = FlushMode::All); - - const Gen::OpArg& R(preg_t preg) const; - Gen::X64Reg RX(preg_t preg) const; - - // Register locking. - - // these are powerpc reg indices - template - void Lock(T p) // TODO: Make private - { - m_regs[p].Lock(); - } - template - void Lock(T first, Args... args) - { - Lock(first); - Lock(args...); - } - - // these are x64 reg indices - template - void LockX(T x) - { - if (m_xregs[x].IsLocked()) - PanicAlert("RegCache: x %i already locked!", x); - m_xregs[x].Lock(); - } - template - void LockX(T first, Args... args) - { - LockX(first); - LockX(args...); - } - - template - void UnlockX(T x) - { - if (!m_xregs[x].IsLocked()) - PanicAlert("RegCache: x %i already unlocked!", x); - m_xregs[x].Unlock(); - } - template - void UnlockX(T first, Args... args) - { - UnlockX(first); - UnlockX(args...); - } - - void UnlockAll(); - void UnlockAllX(); - - bool IsFreeX(size_t xreg) const; - - Gen::X64Reg GetFreeXReg(); - int NumFreeRegisters() const; - - // New interface template static void Realize(Ts&... rc) @@ -238,15 +165,17 @@ public: RCOpArg BindOrImm(preg_t preg, RCMode mode); RCX64Reg Bind(preg_t preg, RCMode mode); RCX64Reg RevertableBind(preg_t preg, RCMode mode); + RCX64Reg Scratch(); RCX64Reg Scratch(Gen::X64Reg xr); RCForkGuard Fork(); + void Flush(BitSet32 pregs = BitSet32::AllTrue(32)); void Revert(); void Commit(); bool IsAllUnlocked() const; - void PreloadRegisters(BitSet32 regs); + void PreloadRegisters(BitSet32 pregs); BitSet32 RegistersInUse() const; protected: @@ -254,6 +183,7 @@ protected: friend class RCX64Reg; friend class RCForkGuard; + virtual Gen::OpArg GetDefaultLocation(preg_t preg) const = 0; virtual void StoreRegister(preg_t preg, const Gen::OpArg& new_loc) = 0; virtual void LoadRegister(preg_t preg, Gen::X64Reg new_loc) = 0; @@ -263,14 +193,22 @@ protected: virtual BitSet32 CountRegsIn(preg_t preg, u32 lookahead) const = 0; void FlushX(Gen::X64Reg reg); + void DiscardRegContentsIfCached(preg_t preg); + void BindToRegister(preg_t preg, bool doLoad = true, bool makeDirty = true); + void StoreFromRegister(preg_t preg, FlushMode mode = FlushMode::Full); + Gen::X64Reg GetFreeXReg(); + + int NumFreeRegisters() const; float ScoreRegister(Gen::X64Reg xreg) const; - // New interface - void NewLock(preg_t preg); - void NewUnlock(preg_t preg); - void NewLockX(Gen::X64Reg xr); - void NewUnlockX(Gen::X64Reg xr); + const Gen::OpArg& R(preg_t preg) const; + Gen::X64Reg RX(preg_t preg) const; + + void Lock(preg_t preg); + void Unlock(preg_t preg); + void LockX(Gen::X64Reg xr); + void UnlockX(Gen::X64Reg xr); bool IsRealized(preg_t preg) const; void Realize(preg_t preg);