diff --git a/Source/Core/Core/PowerPC/Jit64/Jit.cpp b/Source/Core/Core/PowerPC/Jit64/Jit.cpp index bdbb023c258..6cee5b971e3 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit.cpp @@ -1142,6 +1142,7 @@ bool Jit64::DoJit(u32 em_address, JitBlock* b, u32 nextPC) if (constant_propagation_result.gpr >= 0) { + // Mark the GPR as dirty in the register cache gpr.SetImmediate32(constant_propagation_result.gpr, constant_propagation_result.gpr_value); } diff --git a/Source/Core/Core/PowerPC/Jit64/RegCache/CachedReg.h b/Source/Core/Core/PowerPC/Jit64/RegCache/CachedReg.h index acf5480abb7..99a6e472254 100644 --- a/Source/Core/Core/PowerPC/Jit64/RegCache/CachedReg.h +++ b/Source/Core/Core/PowerPC/Jit64/RegCache/CachedReg.h @@ -16,111 +16,79 @@ using preg_t = size_t; class PPCCachedReg { public: - enum class LocationType - { - /// Value is currently at its default location - Default, - /// Value is not stored anywhere because we know it won't be read before the next write - Discarded, - /// Value is currently bound to a x64 register - Bound, - /// Value is known as an immediate and has not been written back to its default location - Immediate, - /// Value is known as an immediate and is already present at its default location - SpeculativeImmediate, - }; - PPCCachedReg() = default; - explicit PPCCachedReg(Gen::OpArg default_location_) - : default_location(default_location_), location(default_location_) + explicit PPCCachedReg(Gen::OpArg default_location) : m_default_location(default_location) {} + + Gen::OpArg GetDefaultLocation() const { return m_default_location; } + + Gen::X64Reg GetHostRegister() const { + ASSERT(m_in_host_register); + return m_host_register; } - const std::optional& Location() const { return location; } + bool IsInDefaultLocation() const { return m_in_default_location; } + bool IsInHostRegister() const { return m_in_host_register; } - LocationType GetLocationType() const + void SetFlushed(bool maintain_host_register) { - if (!location.has_value()) - return LocationType::Discarded; - - if (!away) - { - ASSERT(!revertable); - - if (location->IsImm()) - return LocationType::SpeculativeImmediate; - - ASSERT(*location == default_location); - return LocationType::Default; - } - - ASSERT(location->IsImm() || location->IsSimpleReg()); - return location->IsImm() ? LocationType::Immediate : LocationType::Bound; + ASSERT(!m_revertable); + if (!maintain_host_register) + m_in_host_register = false; + m_in_default_location = true; } - bool IsAway() const { return away; } - bool IsDiscarded() const { return !location.has_value(); } - bool IsBound() const { return GetLocationType() == LocationType::Bound; } - - void SetBoundTo(Gen::X64Reg xreg) + void SetInHostRegister(Gen::X64Reg xreg, bool dirty) { - away = true; - location = Gen::R(xreg); + if (dirty) + m_in_default_location = false; + m_in_host_register = true; + m_host_register = xreg; } + void SetDirty() { m_in_default_location = false; } + void SetDiscarded() { - ASSERT(!revertable); - away = false; - location = std::nullopt; + ASSERT(!m_revertable); + m_in_default_location = false; + m_in_host_register = false; } - void SetFlushed() - { - ASSERT(!revertable); - away = false; - location = default_location; - } - - void SetToImm32(u32 imm32, bool dirty = true) - { - away |= dirty; - location = Gen::Imm32(imm32); - } - - bool IsRevertable() const { return revertable; } + bool IsRevertable() const { return m_revertable; } void SetRevertable() { - ASSERT(IsBound()); - revertable = true; + ASSERT(m_in_host_register); + m_revertable = true; } void SetRevert() { - ASSERT(revertable); - revertable = false; - SetFlushed(); + ASSERT(m_revertable); + m_revertable = false; + SetFlushed(false); } void SetCommit() { - ASSERT(revertable); - revertable = false; + ASSERT(m_revertable); + m_revertable = false; } - bool IsLocked() const { return locked > 0; } - void Lock() { locked++; } + bool IsLocked() const { return m_locked > 0; } + void Lock() { m_locked++; } void Unlock() { ASSERT(IsLocked()); - locked--; + m_locked--; } private: - Gen::OpArg default_location{}; - std::optional location{}; - bool away = false; // value not in source register - bool revertable = false; - size_t locked = 0; + Gen::OpArg m_default_location{}; + Gen::X64Reg m_host_register{}; + bool m_in_default_location = true; + bool m_in_host_register = false; + bool m_revertable = false; + size_t m_locked = 0; }; class X64CachedReg @@ -128,25 +96,20 @@ class X64CachedReg public: preg_t Contents() const { return ppcReg; } - void SetBoundTo(preg_t ppcReg_, bool dirty_) + void SetBoundTo(preg_t ppcReg_) { free = false; ppcReg = ppcReg_; - dirty = dirty_; } void Unbind() { ppcReg = static_cast(Gen::INVALID_REG); free = true; - dirty = false; } bool IsFree() const { return free && !locked; } - bool IsDirty() const { return dirty; } - void MakeDirty() { dirty = true; } - bool IsLocked() const { return locked > 0; } void Lock() { locked++; } void Unlock() @@ -158,7 +121,6 @@ public: private: preg_t ppcReg = static_cast(Gen::INVALID_REG); bool free = true; - bool dirty = false; size_t locked = 0; }; diff --git a/Source/Core/Core/PowerPC/Jit64/RegCache/FPURegCache.cpp b/Source/Core/Core/PowerPC/Jit64/RegCache/FPURegCache.cpp index 64870ec026a..3e089ffe7dd 100644 --- a/Source/Core/Core/PowerPC/Jit64/RegCache/FPURegCache.cpp +++ b/Source/Core/Core/PowerPC/Jit64/RegCache/FPURegCache.cpp @@ -13,16 +13,54 @@ FPURegCache::FPURegCache(Jit64& jit) : RegCache{jit} { } -void FPURegCache::StoreRegister(preg_t preg, const OpArg& new_loc) +bool FPURegCache::IsImm(preg_t preg) const { - ASSERT_MSG(DYNA_REC, m_regs[preg].IsBound(), "Unbound register - {}", preg); - m_emitter->MOVAPD(new_loc, m_regs[preg].Location()->GetSimpleReg()); + return false; +} + +u32 FPURegCache::Imm32(preg_t preg) const +{ + ASSERT_MSG(DYNA_REC, false, "FPURegCache doesn't support immediates"); + return 0; +} + +s32 FPURegCache::SImm32(preg_t preg) const +{ + ASSERT_MSG(DYNA_REC, false, "FPURegCache doesn't support immediates"); + return 0; +} + +OpArg FPURegCache::R(preg_t preg) const +{ + if (m_regs[preg].IsInHostRegister()) + { + return ::Gen::R(m_regs[preg].GetHostRegister()); + } + else + { + ASSERT_MSG(DYNA_REC, m_regs[preg].IsInDefaultLocation(), "FPR {} missing!", preg); + return m_regs[preg].GetDefaultLocation(); + } +} + +void FPURegCache::StoreRegister(preg_t preg, const OpArg& new_loc, + IgnoreDiscardedRegisters ignore_discarded_registers) +{ + if (m_regs[preg].IsInHostRegister()) + { + m_emitter->MOVAPD(new_loc, m_regs[preg].GetHostRegister()); + } + else + { + ASSERT_MSG(DYNA_REC, ignore_discarded_registers != IgnoreDiscardedRegisters::No, + "FPR {} not in host register", preg); + } } void FPURegCache::LoadRegister(preg_t preg, X64Reg new_loc) { - ASSERT_MSG(DYNA_REC, !m_regs[preg].IsDiscarded(), "Discarded register - {}", preg); - m_emitter->MOVAPD(new_loc, m_regs[preg].Location().value()); + ASSERT_MSG(DYNA_REC, m_regs[preg].IsInDefaultLocation(), "FPR {} not in default location", preg); + m_emitter->MOVAPD(new_loc, m_regs[preg].GetDefaultLocation()); } void FPURegCache::DiscardImm(preg_t preg) diff --git a/Source/Core/Core/PowerPC/Jit64/RegCache/FPURegCache.h b/Source/Core/Core/PowerPC/Jit64/RegCache/FPURegCache.h index f34db9d0886..76cad940aec 100644 --- a/Source/Core/Core/PowerPC/Jit64/RegCache/FPURegCache.h +++ b/Source/Core/Core/PowerPC/Jit64/RegCache/FPURegCache.h @@ -12,9 +12,15 @@ class FPURegCache final : public RegCache public: explicit FPURegCache(Jit64& jit); + bool IsImm(preg_t preg) const override; + u32 Imm32(preg_t preg) const override; + s32 SImm32(preg_t preg) const override; + protected: + Gen::OpArg R(preg_t preg) const override; Gen::OpArg GetDefaultLocation(preg_t preg) const override; - void StoreRegister(preg_t preg, const Gen::OpArg& newLoc) override; + void StoreRegister(preg_t preg, const Gen::OpArg& newLoc, + IgnoreDiscardedRegisters ignore_discarded_registers) override; void LoadRegister(preg_t preg, Gen::X64Reg newLoc) override; void DiscardImm(preg_t preg) override; std::span GetAllocationOrder() const override; diff --git a/Source/Core/Core/PowerPC/Jit64/RegCache/GPRRegCache.cpp b/Source/Core/Core/PowerPC/Jit64/RegCache/GPRRegCache.cpp index b44382ba447..a740d76e3dc 100644 --- a/Source/Core/Core/PowerPC/Jit64/RegCache/GPRRegCache.cpp +++ b/Source/Core/Core/PowerPC/Jit64/RegCache/GPRRegCache.cpp @@ -13,16 +13,71 @@ GPRRegCache::GPRRegCache(Jit64& jit) : RegCache{jit} { } -void GPRRegCache::StoreRegister(preg_t preg, const OpArg& new_loc) +bool GPRRegCache::IsImm(preg_t preg) const { - ASSERT_MSG(DYNA_REC, !m_regs[preg].IsDiscarded(), "Discarded register - {}", preg); - m_emitter->MOV(32, new_loc, m_regs[preg].Location().value()); + return m_jit.GetConstantPropagation().HasGPR(preg); +} + +u32 GPRRegCache::Imm32(preg_t preg) const +{ + ASSERT(m_jit.GetConstantPropagation().HasGPR(preg)); + return m_jit.GetConstantPropagation().GetGPR(preg); +} + +s32 GPRRegCache::SImm32(preg_t preg) const +{ + ASSERT(m_jit.GetConstantPropagation().HasGPR(preg)); + return m_jit.GetConstantPropagation().GetGPR(preg); +} + +OpArg GPRRegCache::R(preg_t preg) const +{ + if (m_regs[preg].IsInHostRegister()) + { + return ::Gen::R(m_regs[preg].GetHostRegister()); + } + else if (m_jit.GetConstantPropagation().HasGPR(preg)) + { + return ::Gen::Imm32(m_jit.GetConstantPropagation().GetGPR(preg)); + } + else + { + ASSERT_MSG(DYNA_REC, m_regs[preg].IsInDefaultLocation(), "GPR {} missing!", preg); + return m_regs[preg].GetDefaultLocation(); + } +} + +void GPRRegCache::StoreRegister(preg_t preg, const OpArg& new_loc, + IgnoreDiscardedRegisters ignore_discarded_registers) +{ + if (m_regs[preg].IsInHostRegister()) + { + m_emitter->MOV(32, new_loc, ::Gen::R(m_regs[preg].GetHostRegister())); + } + else if (m_jit.GetConstantPropagation().HasGPR(preg)) + { + m_emitter->MOV(32, new_loc, ::Gen::Imm32(m_jit.GetConstantPropagation().GetGPR(preg))); + } + else + { + ASSERT_MSG(DYNA_REC, ignore_discarded_registers != IgnoreDiscardedRegisters::No, + "GPR {} not in host register or constant propagation", preg); + } } void GPRRegCache::LoadRegister(preg_t preg, X64Reg new_loc) { - ASSERT_MSG(DYNA_REC, !m_regs[preg].IsDiscarded(), "Discarded register - {}", preg); - m_emitter->MOV(32, ::Gen::R(new_loc), m_regs[preg].Location().value()); + const JitCommon::ConstantPropagation& constant_propagation = m_jit.GetConstantPropagation(); + if (constant_propagation.HasGPR(preg)) + { + m_emitter->MOV(32, ::Gen::R(new_loc), ::Gen::Imm32(constant_propagation.GetGPR(preg))); + } + else + { + ASSERT_MSG(DYNA_REC, m_regs[preg].IsInDefaultLocation(), "GPR {} not in default location", + preg); + m_emitter->MOV(32, ::Gen::R(new_loc), m_regs[preg].GetDefaultLocation()); + } } void GPRRegCache::DiscardImm(preg_t preg) @@ -53,8 +108,8 @@ void GPRRegCache::SetImmediate32(preg_t preg, u32 imm_value, bool dirty) { // "dirty" can be false to avoid redundantly flushing an immediate when // processing speculative constants. - DiscardRegContentsIfCached(preg); - m_regs[preg].SetToImm32(imm_value, dirty); + if (dirty) + DiscardRegister(preg); m_jit.GetConstantPropagation().SetGPR(preg, imm_value); } diff --git a/Source/Core/Core/PowerPC/Jit64/RegCache/GPRRegCache.h b/Source/Core/Core/PowerPC/Jit64/RegCache/GPRRegCache.h index a5bf5242694..9c0b394bad9 100644 --- a/Source/Core/Core/PowerPC/Jit64/RegCache/GPRRegCache.h +++ b/Source/Core/Core/PowerPC/Jit64/RegCache/GPRRegCache.h @@ -11,11 +11,18 @@ class GPRRegCache final : public RegCache { public: explicit GPRRegCache(Jit64& jit); + + bool IsImm(preg_t preg) const override; + u32 Imm32(preg_t preg) const override; + s32 SImm32(preg_t preg) const override; + void SetImmediate32(preg_t preg, u32 imm_value, bool dirty = true); protected: + Gen::OpArg R(preg_t preg) const override; Gen::OpArg GetDefaultLocation(preg_t preg) const override; - void StoreRegister(preg_t preg, const Gen::OpArg& new_loc) override; + void StoreRegister(preg_t preg, const Gen::OpArg& new_loc, + IgnoreDiscardedRegisters ignore_discarded_registers) override; void LoadRegister(preg_t preg, Gen::X64Reg new_loc) override; void DiscardImm(preg_t preg) override; std::span GetAllocationOrder() const override; diff --git a/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.cpp b/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.cpp index d1e06661709..2a787f31207 100644 --- a/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.cpp +++ b/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.cpp @@ -136,7 +136,7 @@ bool RCOpArg::IsImm() const { if (const preg_t* preg = std::get_if(&contents)) { - return rc->R(*preg).IsImm(); + return rc->IsImm(*preg); } else if (std::holds_alternative(contents)) { @@ -149,7 +149,7 @@ s32 RCOpArg::SImm32() const { if (const preg_t* preg = std::get_if(&contents)) { - return rc->R(*preg).SImm32(); + return rc->SImm32(*preg); } else if (const u32* imm = std::get_if(&contents)) { @@ -163,7 +163,7 @@ u32 RCOpArg::Imm32() const { if (const preg_t* preg = std::get_if(&contents)) { - return rc->R(*preg).Imm32(); + return rc->Imm32(*preg); } else if (const u32* imm = std::get_if(&contents)) { @@ -297,25 +297,16 @@ bool RegCache::SanityCheck() const { for (size_t i = 0; i < m_regs.size(); i++) { - switch (m_regs[i].GetLocationType()) - { - case PPCCachedReg::LocationType::Default: - case PPCCachedReg::LocationType::Discarded: - case PPCCachedReg::LocationType::SpeculativeImmediate: - case PPCCachedReg::LocationType::Immediate: - break; - case PPCCachedReg::LocationType::Bound: + if (m_regs[i].IsInHostRegister()) { if (m_regs[i].IsLocked() || m_regs[i].IsRevertable()) return false; - Gen::X64Reg xr = m_regs[i].Location()->GetSimpleReg(); + Gen::X64Reg xr = m_regs[i].GetHostRegister(); if (m_xregs[xr].IsLocked()) return false; if (m_xregs[xr].Contents() != i) return false; - break; - } } } return true; @@ -379,13 +370,7 @@ void RegCache::Discard(BitSet32 pregs) ASSERT_MSG(DYNA_REC, !m_regs[i].IsRevertable(), "Register transaction is in progress for {}!", i); - if (m_regs[i].IsBound()) - { - X64Reg xr = RX(i); - m_xregs[xr].Unbind(); - } - - m_regs[i].SetDiscarded(); + DiscardRegister(i); } } @@ -401,25 +386,7 @@ void RegCache::Flush(BitSet32 pregs, IgnoreDiscardedRegisters ignore_discarded_r ASSERT_MSG(DYNA_REC, !m_regs[i].IsRevertable(), "Register transaction is in progress for {}!", i); - switch (m_regs[i].GetLocationType()) - { - case PPCCachedReg::LocationType::Default: - break; - case PPCCachedReg::LocationType::Discarded: - ASSERT_MSG(DYNA_REC, ignore_discarded_registers != IgnoreDiscardedRegisters::No, - "Attempted to flush discarded PPC reg {}", i); - 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; - } + StoreFromRegister(i, FlushMode::Full, ignore_discarded_registers); } } @@ -427,9 +394,9 @@ void RegCache::Reset(BitSet32 pregs) { for (preg_t i : pregs) { - ASSERT_MSG(DYNA_REC, !m_regs[i].IsAway(), + ASSERT_MSG(DYNA_REC, !m_regs[i].IsInHostRegister(), "Attempted to reset a loaded register (did you mean to flush it?)"); - m_regs[i].SetFlushed(); + m_regs[i].SetFlushed(false); } } @@ -465,7 +432,7 @@ void RegCache::PreloadRegisters(BitSet32 to_preload) { if (NumFreeRegisters() < 2) return; - if (!R(preg).IsImm()) + if (!IsImm(preg)) BindToRegister(preg, true, false); } } @@ -492,48 +459,46 @@ void RegCache::FlushX(X64Reg reg) } } -void RegCache::DiscardRegContentsIfCached(preg_t preg) +void RegCache::DiscardRegister(preg_t preg) { - if (m_regs[preg].IsBound()) + if (m_regs[preg].IsInHostRegister()) { - X64Reg xr = m_regs[preg].Location()->GetSimpleReg(); + X64Reg xr = m_regs[preg].GetHostRegister(); m_xregs[xr].Unbind(); - m_regs[preg].SetFlushed(); } + + m_regs[preg].SetDiscarded(); } void RegCache::BindToRegister(preg_t i, bool doLoad, bool makeDirty) { - if (!m_regs[i].IsBound()) + if (!m_regs[i].IsInHostRegister()) { X64Reg xr = GetFreeXReg(); - ASSERT_MSG(DYNA_REC, !m_xregs[xr].IsDirty(), "Xreg {} already dirty", Common::ToUnderlying(xr)); ASSERT_MSG(DYNA_REC, !m_xregs[xr].IsLocked(), "GetFreeXReg returned locked register"); ASSERT_MSG(DYNA_REC, !m_regs[i].IsRevertable(), "Invalid transaction state"); - m_xregs[xr].SetBoundTo(i, makeDirty || m_regs[i].IsAway()); + m_xregs[xr].SetBoundTo(i); if (doLoad) - { - ASSERT_MSG(DYNA_REC, !m_regs[i].IsDiscarded(), "Attempted to load a discarded value"); LoadRegister(i, xr); - } ASSERT_MSG(DYNA_REC, - std::ranges::none_of( - m_regs, [xr](const auto& l) { return l.has_value() && l->IsSimpleReg(xr); }, - &PPCCachedReg::Location), + std::ranges::none_of(m_regs, + [xr](const auto& r) { + return r.IsInHostRegister() && r.GetHostRegister() == xr; + }), "Xreg {} already bound", Common::ToUnderlying(xr)); - m_regs[i].SetBoundTo(xr); + m_regs[i].SetInHostRegister(xr, makeDirty); } else { // reg location must be simplereg; memory locations // and immediates are taken care of above. if (makeDirty) - m_xregs[RX(i)].MakeDirty(); + m_regs[i].SetDirty(); } if (makeDirty) @@ -543,36 +508,19 @@ void RegCache::BindToRegister(preg_t i, bool doLoad, bool makeDirty) "WTF, this reg ({} -> {}) should have been flushed", i, Common::ToUnderlying(RX(i))); } -void RegCache::StoreFromRegister(preg_t i, FlushMode mode) +void RegCache::StoreFromRegister(preg_t i, FlushMode mode, + IgnoreDiscardedRegisters ignore_discarded_registers) { // When a transaction is in progress, allowing the store would overwrite the old value. ASSERT_MSG(DYNA_REC, !m_regs[i].IsRevertable(), "Register transaction on {} is in progress!", i); - bool doStore = false; + if (!m_regs[i].IsInDefaultLocation()) + StoreRegister(i, GetDefaultLocation(i), ignore_discarded_registers); - switch (m_regs[i].GetLocationType()) - { - case PPCCachedReg::LocationType::Default: - case PPCCachedReg::LocationType::Discarded: - case PPCCachedReg::LocationType::SpeculativeImmediate: - return; - case PPCCachedReg::LocationType::Bound: - { - X64Reg xr = RX(i); - doStore = m_xregs[xr].IsDirty(); - if (mode == FlushMode::Full) - m_xregs[xr].Unbind(); - break; - } - case PPCCachedReg::LocationType::Immediate: - doStore = true; - break; - } + if (mode == FlushMode::Full && m_regs[i].IsInHostRegister()) + m_xregs[m_regs[i].GetHostRegister()].Unbind(); - if (doStore) - StoreRegister(i, GetDefaultLocation(i)); - if (mode == FlushMode::Full) - m_regs[i].SetFlushed(); + m_regs[i].SetFlushed(mode != FlushMode::Full); } X64Reg RegCache::GetFreeXReg() @@ -637,7 +585,7 @@ float RegCache::ScoreRegister(X64Reg xreg) const // bias a bit against dirty registers. Testing shows that a bias of 2 seems roughly // right: 3 causes too many extra clobbers, while 1 saves very few clobbers relative // to the number of extra stores it causes. - if (m_xregs[xreg].IsDirty()) + if (!m_regs[preg].IsInDefaultLocation()) score += 2; // If the register isn't actually needed in a physical register for a later instruction, @@ -658,16 +606,10 @@ float RegCache::ScoreRegister(X64Reg xreg) const return score; } -const OpArg& RegCache::R(preg_t preg) const -{ - ASSERT_MSG(DYNA_REC, !m_regs[preg].IsDiscarded(), "Discarded register - {}", preg); - return m_regs[preg].Location().value(); -} - X64Reg RegCache::RX(preg_t preg) const { - ASSERT_MSG(DYNA_REC, m_regs[preg].IsBound(), "Unbound register - {}", preg); - return m_regs[preg].Location()->GetSimpleReg(); + ASSERT_MSG(DYNA_REC, m_regs[preg].IsInHostRegister(), "Not in host register - {}", preg); + return m_regs[preg].GetHostRegister(); } void RegCache::Lock(preg_t preg) @@ -723,29 +665,23 @@ void RegCache::Realize(preg_t preg) return; } - switch (m_regs[preg].GetLocationType()) + if (IsImm(preg)) { - case PPCCachedReg::LocationType::Default: - if (kill_mem) - { - do_bind(); - return; - } - m_constraints[preg].Realized(RCConstraint::RealizedLoc::Mem); - return; - case PPCCachedReg::LocationType::Discarded: - case PPCCachedReg::LocationType::Bound: - do_bind(); - return; - case PPCCachedReg::LocationType::Immediate: - case PPCCachedReg::LocationType::SpeculativeImmediate: if (dirty || kill_imm) - { do_bind(); - return; - } - m_constraints[preg].Realized(RCConstraint::RealizedLoc::Imm); - break; + else + m_constraints[preg].Realized(RCConstraint::RealizedLoc::Imm); + } + else if (!m_regs[preg].IsInHostRegister()) + { + if (kill_mem) + do_bind(); + else + m_constraints[preg].Realized(RCConstraint::RealizedLoc::Mem); + } + else + { + do_bind(); } } diff --git a/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.h b/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.h index 1ff4e27ea78..0a7ab3836d2 100644 --- a/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.h +++ b/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.h @@ -157,12 +157,14 @@ public: bool IsImm(Args... pregs) const { static_assert(sizeof...(pregs) > 0); - return (R(pregs).IsImm() && ...); + return (IsImm(preg_t(pregs)) && ...); } - u32 Imm32(preg_t preg) const { return R(preg).Imm32(); } - s32 SImm32(preg_t preg) const { return R(preg).SImm32(); } - bool IsBound(preg_t preg) const { return m_regs[preg].IsBound(); } + virtual bool IsImm(preg_t preg) const = 0; + virtual u32 Imm32(preg_t preg) const = 0; + virtual s32 SImm32(preg_t preg) const = 0; + + bool IsBound(preg_t preg) const { return m_regs[preg].IsInHostRegister(); } RCOpArg Use(preg_t preg, RCMode mode); RCOpArg UseNoImm(preg_t preg, RCMode mode); @@ -191,7 +193,8 @@ protected: 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 StoreRegister(preg_t preg, const Gen::OpArg& new_loc, + IgnoreDiscardedRegisters ignore_discarded_registers) = 0; virtual void LoadRegister(preg_t preg, Gen::X64Reg new_loc) = 0; virtual void DiscardImm(preg_t preg) = 0; @@ -201,16 +204,18 @@ protected: virtual BitSet32 CountRegsIn(preg_t preg, u32 lookahead) const = 0; void FlushX(Gen::X64Reg reg); - void DiscardRegContentsIfCached(preg_t preg); + void DiscardRegister(preg_t preg); void BindToRegister(preg_t preg, bool doLoad = true, bool makeDirty = true); - void StoreFromRegister(preg_t preg, FlushMode mode = FlushMode::Full); + void StoreFromRegister( + preg_t preg, FlushMode mode = FlushMode::Full, + IgnoreDiscardedRegisters ignore_discarded_registers = IgnoreDiscardedRegisters::No); Gen::X64Reg GetFreeXReg(); int NumFreeRegisters() const; float ScoreRegister(Gen::X64Reg xreg) const; - const Gen::OpArg& R(preg_t preg) const; + virtual Gen::OpArg R(preg_t preg) const = 0; Gen::X64Reg RX(preg_t preg) const; void Lock(preg_t preg);