From dd41bab365bbfcb71f11de48a8c77e5a59606f23 Mon Sep 17 00:00:00 2001 From: MerryMage Date: Sun, 30 Sep 2018 12:49:03 +0100 Subject: [PATCH 1/8] JitRegCache: Encapsulate behavior of PPCCachedReg --- .../Core/Core/PowerPC/Jit64/FPURegCache.cpp | 4 +- .../Core/Core/PowerPC/Jit64/GPRRegCache.cpp | 7 +- .../Core/Core/PowerPC/Jit64/JitRegCache.cpp | 166 ++++++++---------- Source/Core/Core/PowerPC/Jit64/JitRegCache.h | 76 +++++++- .../Core/PowerPC/Jit64/Jit_FloatingPoint.cpp | 2 +- 5 files changed, 149 insertions(+), 106 deletions(-) diff --git a/Source/Core/Core/PowerPC/Jit64/FPURegCache.cpp b/Source/Core/Core/PowerPC/Jit64/FPURegCache.cpp index 449c3d6ebf..11decfbf98 100644 --- a/Source/Core/Core/PowerPC/Jit64/FPURegCache.cpp +++ b/Source/Core/Core/PowerPC/Jit64/FPURegCache.cpp @@ -16,12 +16,12 @@ FPURegCache::FPURegCache(Jit64& jit) : RegCache{jit} void FPURegCache::StoreRegister(size_t preg, const OpArg& new_loc) { - m_emitter->MOVAPD(new_loc, m_regs[preg].location.GetSimpleReg()); + m_emitter->MOVAPD(new_loc, m_regs[preg].Location().GetSimpleReg()); } void FPURegCache::LoadRegister(size_t preg, X64Reg new_loc) { - m_emitter->MOVAPD(new_loc, m_regs[preg].location); + m_emitter->MOVAPD(new_loc, m_regs[preg].Location()); } const X64Reg* FPURegCache::GetAllocationOrder(size_t* count) const diff --git a/Source/Core/Core/PowerPC/Jit64/GPRRegCache.cpp b/Source/Core/Core/PowerPC/Jit64/GPRRegCache.cpp index 22ccacca54..ed8079e0e3 100644 --- a/Source/Core/Core/PowerPC/Jit64/GPRRegCache.cpp +++ b/Source/Core/Core/PowerPC/Jit64/GPRRegCache.cpp @@ -16,12 +16,12 @@ GPRRegCache::GPRRegCache(Jit64& jit) : RegCache{jit} void GPRRegCache::StoreRegister(size_t preg, const OpArg& new_loc) { - m_emitter->MOV(32, new_loc, m_regs[preg].location); + m_emitter->MOV(32, new_loc, m_regs[preg].Location()); } void GPRRegCache::LoadRegister(size_t preg, X64Reg new_loc) { - m_emitter->MOV(32, ::Gen::R(new_loc), m_regs[preg].location); + m_emitter->MOV(32, ::Gen::R(new_loc), m_regs[preg].Location()); } OpArg GPRRegCache::GetDefaultLocation(size_t reg) const @@ -51,8 +51,7 @@ void GPRRegCache::SetImmediate32(size_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].away |= dirty; - m_regs[preg].location = Imm32(imm_value); + m_regs[preg].SetToImm32(imm_value, dirty); } BitSet32 GPRRegCache::GetRegUtilization() const diff --git a/Source/Core/Core/PowerPC/Jit64/JitRegCache.cpp b/Source/Core/Core/PowerPC/Jit64/JitRegCache.cpp index 5cdc71dd6b..67f04e9f5b 100644 --- a/Source/Core/Core/PowerPC/Jit64/JitRegCache.cpp +++ b/Source/Core/Core/PowerPC/Jit64/JitRegCache.cpp @@ -35,38 +35,19 @@ void RegCache::Start() } for (size_t i = 0; i < m_regs.size(); i++) { - m_regs[i].location = GetDefaultLocation(i); - m_regs[i].away = false; - m_regs[i].locked = false; + m_regs[i] = PPCCachedReg{GetDefaultLocation(i)}; } - - // todo: sort to find the most popular regs - /* - int maxPreload = 2; - for (int i = 0; i < 32; i++) - { - if (stats.numReads[i] > 2 || stats.numWrites[i] >= 2) - { - LoadToX64(i, true, false); //stats.firstRead[i] <= stats.firstWrite[i], false); - maxPreload--; - if (!maxPreload) - break; - } - }*/ - // Find top regs - preload them (load bursts ain't bad) - // But only preload IF written OR reads >= 3 } void RegCache::DiscardRegContentsIfCached(size_t preg) { - if (IsBound(preg)) + if (m_regs[preg].IsBound()) { - X64Reg xr = m_regs[preg].location.GetSimpleReg(); + X64Reg xr = m_regs[preg].Location().GetSimpleReg(); m_xregs[xr].free = true; m_xregs[xr].dirty = false; m_xregs[xr].ppcReg = static_cast(INVALID_REG); - m_regs[preg].away = false; - m_regs[preg].location = GetDefaultLocation(preg); + m_regs[preg].Flushed(); } } @@ -85,28 +66,25 @@ void RegCache::Flush(FlushMode mode, BitSet32 regsToFlush) for (unsigned int i : regsToFlush) { - if (m_regs[i].locked) + if (m_regs[i].IsLocked()) { PanicAlert("Someone forgot to unlock PPC reg %u (X64 reg %i).", i, RX(i)); } - if (m_regs[i].away) - { - if (m_regs[i].location.IsSimpleReg() || m_regs[i].location.IsImm()) - { - StoreFromRegister(i, mode); - } - else - { - ASSERT_MSG(DYNA_REC, 0, "Jit64 - Flush unhandled case, reg %u PC: %08x", i, PC); - } - } - else if (m_regs[i].location.IsImm()) + 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].location = GetDefaultLocation(i); + m_regs[i].Flushed(); + break; + case PPCCachedReg::LocationType::Bound: + case PPCCachedReg::LocationType::Immediate: + StoreFromRegister(i, mode); + break; } } } @@ -145,20 +123,22 @@ int RegCache::SanityCheck() const { for (size_t i = 0; i < m_regs.size(); i++) { - if (m_regs[i].away) + switch (m_regs[i].GetLocationType()) { - if (m_regs[i].location.IsSimpleReg()) - { - Gen::X64Reg simple = m_regs[i].location.GetSimpleReg(); - if (m_xregs[simple].locked) - return 1; - if (m_xregs[simple].ppcReg != i) - return 2; - } - else if (m_regs[i].location.IsImm()) - { - return 3; - } + case PPCCachedReg::LocationType::Default: + case PPCCachedReg::LocationType::SpeculativeImmediate: + break; + case PPCCachedReg::LocationType::Bound: + { + Gen::X64Reg simple = m_regs[i].Location().GetSimpleReg(); + if (m_xregs[simple].locked) + return 1; + if (m_xregs[simple].ppcReg != i) + return 2; + break; + } + case PPCCachedReg::LocationType::Immediate: + return 3; } } return 0; @@ -166,18 +146,23 @@ int RegCache::SanityCheck() const void RegCache::KillImmediate(size_t preg, bool doLoad, bool makeDirty) { - if (m_regs[preg].away) + switch (m_regs[preg].GetLocationType()) { - if (m_regs[preg].location.IsImm()) - BindToRegister(preg, doLoad, makeDirty); - else if (m_regs[preg].location.IsSimpleReg()) - m_xregs[RX(preg)].dirty |= makeDirty; + case PPCCachedReg::LocationType::Default: + case PPCCachedReg::LocationType::SpeculativeImmediate: + break; + case PPCCachedReg::LocationType::Bound: + m_xregs[RX(preg)].dirty |= makeDirty; + break; + case PPCCachedReg::LocationType::Immediate: + BindToRegister(preg, doLoad, makeDirty); + break; } } void RegCache::BindToRegister(size_t i, bool doLoad, bool makeDirty) { - if (!m_regs[i].away || m_regs[i].location.IsImm()) + if (!m_regs[i].IsBound()) { X64Reg xr = GetFreeXReg(); if (m_xregs[xr].dirty) @@ -186,18 +171,18 @@ void RegCache::BindToRegister(size_t i, bool doLoad, bool makeDirty) PanicAlert("GetFreeXReg returned locked register"); m_xregs[xr].free = false; m_xregs[xr].ppcReg = i; - m_xregs[xr].dirty = makeDirty || m_regs[i].away; + m_xregs[xr].dirty = makeDirty || m_regs[i].IsAway(); + if (doLoad) LoadRegister(i, xr); for (size_t j = 0; j < m_regs.size(); j++) { - if (i != j && m_regs[j].location.IsSimpleReg(xr)) + if (i != j && m_regs[j].Location().IsSimpleReg(xr)) { Crash(); } } - m_regs[i].away = true; - m_regs[i].location = ::Gen::R(xr); + m_regs[i].BoundTo(xr); } else { @@ -214,45 +199,45 @@ void RegCache::BindToRegister(size_t i, bool doLoad, bool makeDirty) void RegCache::StoreFromRegister(size_t i, FlushMode mode) { - if (m_regs[i].away) + bool doStore = false; + + switch (m_regs[i].GetLocationType()) { - bool doStore; - if (m_regs[i].location.IsSimpleReg()) - { - X64Reg xr = RX(i); - doStore = m_xregs[xr].dirty; - if (mode == FlushMode::All) - { - m_xregs[xr].free = true; - m_xregs[xr].ppcReg = static_cast(INVALID_REG); - m_xregs[xr].dirty = false; - } - } - else - { - // must be immediate - do nothing - doStore = true; - } - OpArg newLoc = GetDefaultLocation(i); - if (doStore) - StoreRegister(i, newLoc); + case PPCCachedReg::LocationType::Default: + case PPCCachedReg::LocationType::SpeculativeImmediate: + return; + case PPCCachedReg::LocationType::Bound: + { + X64Reg xr = RX(i); + doStore = m_xregs[xr].dirty; if (mode == FlushMode::All) { - m_regs[i].location = newLoc; - m_regs[i].away = false; + m_xregs[xr].free = true; + m_xregs[xr].ppcReg = static_cast(INVALID_REG); + m_xregs[xr].dirty = false; } + break; } + case PPCCachedReg::LocationType::Immediate: + doStore = true; + break; + } + + if (doStore) + StoreRegister(i, GetDefaultLocation(i)); + if (mode == FlushMode::All) + m_regs[i].Flushed(); } const OpArg& RegCache::R(size_t preg) const { - return m_regs[preg].location; + return m_regs[preg].Location(); } X64Reg RegCache::RX(size_t preg) const { - if (IsBound(preg)) - return m_regs[preg].location.GetSimpleReg(); + if (m_regs[preg].IsBound()) + return m_regs[preg].Location().GetSimpleReg(); PanicAlert("Unbound register - %zu", preg); return Gen::INVALID_REG; @@ -261,7 +246,7 @@ X64Reg RegCache::RX(size_t preg) const void RegCache::UnlockAll() { for (auto& reg : m_regs) - reg.locked = false; + reg.Unlock(); } void RegCache::UnlockAllX() @@ -275,11 +260,6 @@ bool RegCache::IsFreeX(size_t xreg) const return m_xregs[xreg].free && !m_xregs[xreg].locked; } -bool RegCache::IsBound(size_t preg) const -{ - return m_regs[preg].away && m_regs[preg].location.IsSimpleReg(); -} - X64Reg RegCache::GetFreeXReg() { size_t aCount; @@ -302,7 +282,7 @@ X64Reg RegCache::GetFreeXReg() { X64Reg xreg = (X64Reg)aOrder[i]; size_t preg = m_xregs[xreg].ppcReg; - if (m_xregs[xreg].locked || m_regs[preg].locked) + if (m_xregs[xreg].locked || m_regs[preg].IsLocked()) continue; float score = ScoreRegister(xreg); if (score < min_score) diff --git a/Source/Core/Core/PowerPC/Jit64/JitRegCache.h b/Source/Core/Core/PowerPC/Jit64/JitRegCache.h index ccd9ac4d95..eee6782513 100644 --- a/Source/Core/Core/PowerPC/Jit64/JitRegCache.h +++ b/Source/Core/Core/PowerPC/Jit64/JitRegCache.h @@ -7,16 +7,81 @@ #include #include +#include "Common/Assert.h" #include "Common/x64Emitter.h" #include "Core/PowerPC/PPCAnalyst.h" class Jit64; -struct PPCCachedReg +class PPCCachedReg { - Gen::OpArg location; - bool away; // value not in source register - bool locked; +public: + enum class LocationType + { + /// Value is currently at its default location + Default, + /// 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_) + { + } + + const Gen::OpArg& Location() const { return location; } + + LocationType GetLocationType() const + { + if (!away) + { + 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; + } + + bool IsAway() const { return away; } + bool IsBound() const { return GetLocationType() == LocationType::Bound; } + + void BoundTo(Gen::X64Reg xreg) + { + away = true; + location = Gen::R(xreg); + } + + void Flushed() + { + away = false; + location = default_location; + } + + void SetToImm32(u32 imm32, bool dirty = true) + { + away |= dirty; + location = Gen::Imm32(imm32); + } + + bool IsLocked() const { return locked; } + void Lock() { locked = true; } + void Unlock() { locked = false; } + +private: + Gen::OpArg default_location{}; + Gen::OpArg location{}; + bool away = false; // value not in source register + bool locked = false; }; struct X64CachedReg @@ -75,7 +140,7 @@ public: template void Lock(T p) { - m_regs[p].locked = true; + m_regs[p].Lock(); } template void Lock(T first, Args... args) @@ -117,7 +182,6 @@ public: void UnlockAllX(); bool IsFreeX(size_t xreg) const; - bool IsBound(size_t preg) const; Gen::X64Reg GetFreeXReg(); int NumFreeRegisters() const; diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_FloatingPoint.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_FloatingPoint.cpp index 175cfec058..77ed9196ce 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_FloatingPoint.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_FloatingPoint.cpp @@ -460,7 +460,7 @@ void Jit64::fmrx(UGeckoInstruction inst) fpr.Lock(b, d); - if (fpr.IsBound(d)) + if (fpr.R(d).IsSimpleReg()) { // We don't need to load d, but if it is loaded, we need to mark it as dirty. fpr.BindToRegister(d); From ff0a6b833120670dff0185bfc832e7c17150141a Mon Sep 17 00:00:00 2001 From: MerryMage Date: Sun, 30 Sep 2018 13:14:00 +0100 Subject: [PATCH 2/8] JitRegCache: Encapsulate behavior of X64CachedReg --- .../Core/Core/PowerPC/Jit64/JitRegCache.cpp | 64 ++++++++----------- Source/Core/Core/PowerPC/Jit64/JitRegCache.h | 45 ++++++++++--- 2 files changed, 62 insertions(+), 47 deletions(-) diff --git a/Source/Core/Core/PowerPC/Jit64/JitRegCache.cpp b/Source/Core/Core/PowerPC/Jit64/JitRegCache.cpp index 67f04e9f5b..20a1c2b9c9 100644 --- a/Source/Core/Core/PowerPC/Jit64/JitRegCache.cpp +++ b/Source/Core/Core/PowerPC/Jit64/JitRegCache.cpp @@ -26,13 +26,7 @@ RegCache::RegCache(Jit64& jit) : m_jit{jit} void RegCache::Start() { - for (auto& xreg : m_xregs) - { - xreg.free = true; - xreg.dirty = false; - xreg.locked = false; - xreg.ppcReg = static_cast(INVALID_REG); - } + m_xregs.fill({}); for (size_t i = 0; i < m_regs.size(); i++) { m_regs[i] = PPCCachedReg{GetDefaultLocation(i)}; @@ -44,9 +38,7 @@ void RegCache::DiscardRegContentsIfCached(size_t preg) if (m_regs[preg].IsBound()) { X64Reg xr = m_regs[preg].Location().GetSimpleReg(); - m_xregs[xr].free = true; - m_xregs[xr].dirty = false; - m_xregs[xr].ppcReg = static_cast(INVALID_REG); + m_xregs[xr].Flushed(); m_regs[preg].Flushed(); } } @@ -60,8 +52,10 @@ void RegCache::Flush(FlushMode mode, BitSet32 regsToFlush) { for (size_t i = 0; i < m_xregs.size(); i++) { - if (m_xregs[i].locked) + if (m_xregs[i].IsLocked()) + { PanicAlert("Someone forgot to unlock X64 reg %zu", i); + } } for (unsigned int i : regsToFlush) @@ -93,9 +87,10 @@ void RegCache::FlushR(X64Reg reg) { if (reg >= m_xregs.size()) PanicAlert("Flushing non existent reg"); - if (!m_xregs[reg].free) + ASSERT(!m_xregs[reg].IsLocked()); + if (!m_xregs[reg].IsFree()) { - StoreFromRegister(m_xregs[reg].ppcReg); + StoreFromRegister(m_xregs[reg].Contents()); } } @@ -131,9 +126,9 @@ int RegCache::SanityCheck() const case PPCCachedReg::LocationType::Bound: { Gen::X64Reg simple = m_regs[i].Location().GetSimpleReg(); - if (m_xregs[simple].locked) + if (m_xregs[simple].IsLocked()) return 1; - if (m_xregs[simple].ppcReg != i) + if (m_xregs[simple].Contents() != i) return 2; break; } @@ -152,7 +147,7 @@ void RegCache::KillImmediate(size_t preg, bool doLoad, bool makeDirty) case PPCCachedReg::LocationType::SpeculativeImmediate: break; case PPCCachedReg::LocationType::Bound: - m_xregs[RX(preg)].dirty |= makeDirty; + m_xregs[RX(preg)].MakeDirty(makeDirty); break; case PPCCachedReg::LocationType::Immediate: BindToRegister(preg, doLoad, makeDirty); @@ -165,14 +160,11 @@ void RegCache::BindToRegister(size_t i, bool doLoad, bool makeDirty) if (!m_regs[i].IsBound()) { X64Reg xr = GetFreeXReg(); - if (m_xregs[xr].dirty) + if (m_xregs[xr].IsDirty()) PanicAlert("Xreg already dirty"); - if (m_xregs[xr].locked) + if (m_xregs[xr].IsLocked()) PanicAlert("GetFreeXReg returned locked register"); - m_xregs[xr].free = false; - m_xregs[xr].ppcReg = i; - m_xregs[xr].dirty = makeDirty || m_regs[i].IsAway(); - + m_xregs[xr].BoundTo(i, makeDirty || m_regs[i].IsAway()); if (doLoad) LoadRegister(i, xr); for (size_t j = 0; j < m_regs.size(); j++) @@ -188,10 +180,10 @@ void RegCache::BindToRegister(size_t i, bool doLoad, bool makeDirty) { // reg location must be simplereg; memory locations // and immediates are taken care of above. - m_xregs[RX(i)].dirty |= makeDirty; + m_xregs[RX(i)].MakeDirty(makeDirty); } - if (m_xregs[RX(i)].locked) + if (m_xregs[RX(i)].IsLocked()) { PanicAlert("Seriously WTF, this reg should have been flushed"); } @@ -209,13 +201,9 @@ void RegCache::StoreFromRegister(size_t i, FlushMode mode) case PPCCachedReg::LocationType::Bound: { X64Reg xr = RX(i); - doStore = m_xregs[xr].dirty; + doStore = m_xregs[xr].IsDirty(); if (mode == FlushMode::All) - { - m_xregs[xr].free = true; - m_xregs[xr].ppcReg = static_cast(INVALID_REG); - m_xregs[xr].dirty = false; - } + m_xregs[xr].Flushed(); break; } case PPCCachedReg::LocationType::Immediate: @@ -252,12 +240,12 @@ void RegCache::UnlockAll() void RegCache::UnlockAllX() { for (auto& xreg : m_xregs) - xreg.locked = false; + xreg.Unlock(); } bool RegCache::IsFreeX(size_t xreg) const { - return m_xregs[xreg].free && !m_xregs[xreg].locked; + return m_xregs[xreg].IsFree(); } X64Reg RegCache::GetFreeXReg() @@ -267,7 +255,7 @@ X64Reg RegCache::GetFreeXReg() for (size_t i = 0; i < aCount; i++) { X64Reg xr = aOrder[i]; - if (!m_xregs[xr].locked && m_xregs[xr].free) + if (m_xregs[xr].IsFree()) { return xr; } @@ -281,8 +269,8 @@ X64Reg RegCache::GetFreeXReg() for (size_t i = 0; i < aCount; i++) { X64Reg xreg = (X64Reg)aOrder[i]; - size_t preg = m_xregs[xreg].ppcReg; - if (m_xregs[xreg].locked || m_regs[preg].IsLocked()) + size_t preg = m_xregs[xreg].Contents(); + if (m_xregs[xreg].IsLocked() || m_regs[preg].IsLocked()) continue; float score = ScoreRegister(xreg); if (score < min_score) @@ -310,7 +298,7 @@ int RegCache::NumFreeRegisters() const size_t aCount; const X64Reg* aOrder = GetAllocationOrder(&aCount); for (size_t i = 0; i < aCount; i++) - if (!m_xregs[aOrder[i]].locked && m_xregs[aOrder[i]].free) + if (m_xregs[aOrder[i]].IsFree()) count++; return count; } @@ -319,14 +307,14 @@ int RegCache::NumFreeRegisters() const // means more bad. float RegCache::ScoreRegister(X64Reg xreg) const { - size_t preg = m_xregs[xreg].ppcReg; + size_t preg = m_xregs[xreg].Contents(); float score = 0; // If it's not dirty, we don't need a store to write it back to the register file, so // 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].dirty) + if (m_xregs[xreg].IsDirty()) score += 2; // If the register isn't actually needed in a physical register for a later instruction, diff --git a/Source/Core/Core/PowerPC/Jit64/JitRegCache.h b/Source/Core/Core/PowerPC/Jit64/JitRegCache.h index eee6782513..007ff66cd8 100644 --- a/Source/Core/Core/PowerPC/Jit64/JitRegCache.h +++ b/Source/Core/Core/PowerPC/Jit64/JitRegCache.h @@ -84,12 +84,39 @@ private: bool locked = false; }; -struct X64CachedReg +class X64CachedReg { - size_t ppcReg; - bool dirty; - bool free; - bool locked; +public: + size_t Contents() const { return ppcReg; } + + void BoundTo(size_t ppcReg_, bool dirty_) + { + free = false; + ppcReg = ppcReg_; + dirty = dirty_; + } + + void Flushed() + { + ppcReg = static_cast(Gen::INVALID_REG); + free = true; + dirty = false; + } + + bool IsFree() const { return free && !locked; } + + bool IsDirty() const { return dirty; } + void MakeDirty(bool makeDirty = true) { dirty |= makeDirty; } + + bool IsLocked() const { return locked; } + void Lock() { locked = true; } + void Unlock() { locked = false; } + +private: + size_t ppcReg = static_cast(Gen::INVALID_REG); + bool free = true; + bool dirty = false; + bool locked = false; }; class RegCache @@ -153,9 +180,9 @@ public: template void LockX(T x) { - if (m_xregs[x].locked) + if (m_xregs[x].IsLocked()) PanicAlert("RegCache: x %i already locked!", x); - m_xregs[x].locked = true; + m_xregs[x].Lock(); } template void LockX(T first, Args... args) @@ -167,9 +194,9 @@ public: template void UnlockX(T x) { - if (!m_xregs[x].locked) + if (!m_xregs[x].IsLocked()) PanicAlert("RegCache: x %i already unlocked!", x); - m_xregs[x].locked = false; + m_xregs[x].Unlock(); } template void UnlockX(T first, Args... args) From ba33e1e69b64b6856d44a40ff0ac78dc803a23b3 Mon Sep 17 00:00:00 2001 From: MerryMage Date: Sun, 30 Sep 2018 13:26:46 +0100 Subject: [PATCH 3/8] JitRegCache: Simplify ASSERTs --- .../Core/Core/PowerPC/Jit64/JitRegCache.cpp | 56 ++++++++----------- 1 file changed, 23 insertions(+), 33 deletions(-) diff --git a/Source/Core/Core/PowerPC/Jit64/JitRegCache.cpp b/Source/Core/Core/PowerPC/Jit64/JitRegCache.cpp index 20a1c2b9c9..6bd8784615 100644 --- a/Source/Core/Core/PowerPC/Jit64/JitRegCache.cpp +++ b/Source/Core/Core/PowerPC/Jit64/JitRegCache.cpp @@ -50,20 +50,15 @@ void RegCache::SetEmitter(XEmitter* emitter) void RegCache::Flush(FlushMode mode, BitSet32 regsToFlush) { - for (size_t i = 0; i < m_xregs.size(); i++) - { - if (m_xregs[i].IsLocked()) - { - PanicAlert("Someone forgot to unlock X64 reg %zu", i); - } - } + 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) { - if (m_regs[i].IsLocked()) - { - PanicAlert("Someone forgot to unlock PPC reg %u (X64 reg %i).", i, RX(i)); - } + ASSERT_MSG(DYNA_REC, !m_regs[i].IsLocked(), "Someone forgot to unlock PPC reg %u (X64 reg %i).", + i, RX(i)); switch (m_regs[i].GetLocationType()) { @@ -85,8 +80,7 @@ void RegCache::Flush(FlushMode mode, BitSet32 regsToFlush) void RegCache::FlushR(X64Reg reg) { - if (reg >= m_xregs.size()) - PanicAlert("Flushing non existent 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()) { @@ -160,20 +154,22 @@ void RegCache::BindToRegister(size_t i, bool doLoad, bool makeDirty) if (!m_regs[i].IsBound()) { X64Reg xr = GetFreeXReg(); - if (m_xregs[xr].IsDirty()) - PanicAlert("Xreg already dirty"); - if (m_xregs[xr].IsLocked()) - PanicAlert("GetFreeXReg returned locked register"); + + ASSERT_MSG(DYNA_REC, !m_xregs[xr].IsDirty(), "Xreg %i already dirty", xr); + ASSERT_MSG(DYNA_REC, !m_xregs[xr].IsLocked(), "GetFreeXReg returned locked register"); + m_xregs[xr].BoundTo(i, makeDirty || m_regs[i].IsAway()); + if (doLoad) - LoadRegister(i, xr); - for (size_t j = 0; j < m_regs.size(); j++) { - if (i != j && m_regs[j].Location().IsSimpleReg(xr)) - { - Crash(); - } + LoadRegister(i, xr); } + + ASSERT_MSG(DYNA_REC, + std::none_of(m_regs.begin(), m_regs.end(), + [xr](const auto& r) { return r.Location().IsSimpleReg(xr); }), + "Xreg %i already bound", xr); + m_regs[i].BoundTo(xr); } else @@ -183,10 +179,7 @@ void RegCache::BindToRegister(size_t i, bool doLoad, bool makeDirty) m_xregs[RX(i)].MakeDirty(makeDirty); } - if (m_xregs[RX(i)].IsLocked()) - { - PanicAlert("Seriously WTF, this reg should have been flushed"); - } + ASSERT_MSG(DYNA_REC, !m_xregs[RX(i)].IsLocked(), "WTF, this reg should have been flushed"); } void RegCache::StoreFromRegister(size_t i, FlushMode mode) @@ -224,11 +217,8 @@ const OpArg& RegCache::R(size_t preg) const X64Reg RegCache::RX(size_t preg) const { - if (m_regs[preg].IsBound()) - return m_regs[preg].Location().GetSimpleReg(); - - PanicAlert("Unbound register - %zu", preg); - return Gen::INVALID_REG; + ASSERT_MSG(DYNA_REC, m_regs[preg].IsBound(), "Unbound register - %zu", preg); + return m_regs[preg].Location().GetSimpleReg(); } void RegCache::UnlockAll() @@ -288,7 +278,7 @@ X64Reg RegCache::GetFreeXReg() } // Still no dice? Die! - ASSERT_MSG(DYNA_REC, 0, "Regcache ran out of regs"); + ASSERT_MSG(DYNA_REC, false, "Regcache ran out of regs"); return INVALID_REG; } From 66c3d1e183c677845cd44db6fe9a2147f58acfd1 Mon Sep 17 00:00:00 2001 From: MerryMage Date: Sun, 30 Sep 2018 14:11:44 +0100 Subject: [PATCH 4/8] JitRegCache: Remove FlushR No external users. --- .../Core/Core/PowerPC/Jit64/JitRegCache.cpp | 32 ++++++++----------- Source/Core/Core/PowerPC/Jit64/JitRegCache.h | 5 ++- 2 files changed, 15 insertions(+), 22 deletions(-) diff --git a/Source/Core/Core/PowerPC/Jit64/JitRegCache.cpp b/Source/Core/Core/PowerPC/Jit64/JitRegCache.cpp index 6bd8784615..a7d034ce8a 100644 --- a/Source/Core/Core/PowerPC/Jit64/JitRegCache.cpp +++ b/Source/Core/Core/PowerPC/Jit64/JitRegCache.cpp @@ -78,32 +78,16 @@ void RegCache::Flush(FlushMode mode, BitSet32 regsToFlush) } } -void RegCache::FlushR(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::FlushR(X64Reg reg, X64Reg reg2) -{ - FlushR(reg); - FlushR(reg2); -} - void RegCache::FlushLockX(X64Reg reg) { - FlushR(reg); + FlushX(reg); LockX(reg); } void RegCache::FlushLockX(X64Reg reg1, X64Reg reg2) { - FlushR(reg1); - FlushR(reg2); + FlushX(reg1); + FlushX(reg2); LockX(reg1); LockX(reg2); } @@ -293,6 +277,16 @@ 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 diff --git a/Source/Core/Core/PowerPC/Jit64/JitRegCache.h b/Source/Core/Core/PowerPC/Jit64/JitRegCache.h index 007ff66cd8..e32e42ae47 100644 --- a/Source/Core/Core/PowerPC/Jit64/JitRegCache.h +++ b/Source/Core/Core/PowerPC/Jit64/JitRegCache.h @@ -144,9 +144,6 @@ public: void Flush(FlushMode mode = FlushMode::All, BitSet32 regsToFlush = BitSet32::AllTrue(32)); - void FlushR(Gen::X64Reg reg); - void FlushR(Gen::X64Reg reg, Gen::X64Reg reg2); - void FlushLockX(Gen::X64Reg reg); void FlushLockX(Gen::X64Reg reg1, Gen::X64Reg reg2); @@ -219,6 +216,8 @@ protected: virtual BitSet32 GetRegUtilization() const = 0; virtual BitSet32 CountRegsIn(size_t preg, u32 lookahead) const = 0; + void FlushX(Gen::X64Reg reg); + float ScoreRegister(Gen::X64Reg xreg) const; Jit64& m_jit; From d9e2b3ed98af601aba3fef2389a020299276ea07 Mon Sep 17 00:00:00 2001 From: MerryMage Date: Sun, 30 Sep 2018 14:27:32 +0100 Subject: [PATCH 5/8] JitRegCache: Make {Store,Load}Register protected No reason for them to be public --- Source/Core/Core/PowerPC/Jit64/FPURegCache.h | 3 ++- Source/Core/Core/PowerPC/Jit64/GPRRegCache.h | 5 +++-- Source/Core/Core/PowerPC/Jit64/JitRegCache.h | 5 +++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Source/Core/Core/PowerPC/Jit64/FPURegCache.h b/Source/Core/Core/PowerPC/Jit64/FPURegCache.h index eef93cec1b..99ffc78887 100644 --- a/Source/Core/Core/PowerPC/Jit64/FPURegCache.h +++ b/Source/Core/Core/PowerPC/Jit64/FPURegCache.h @@ -12,11 +12,12 @@ class FPURegCache final : public RegCache { public: explicit FPURegCache(Jit64& jit); + Gen::OpArg GetDefaultLocation(size_t reg) const override; +protected: void StoreRegister(size_t preg, const Gen::OpArg& newLoc) override; void LoadRegister(size_t preg, Gen::X64Reg newLoc) override; const Gen::X64Reg* GetAllocationOrder(size_t* count) const override; - Gen::OpArg GetDefaultLocation(size_t reg) const override; BitSet32 GetRegUtilization() const override; BitSet32 CountRegsIn(size_t preg, u32 lookahead) const override; }; diff --git a/Source/Core/Core/PowerPC/Jit64/GPRRegCache.h b/Source/Core/Core/PowerPC/Jit64/GPRRegCache.h index e16bb28972..911fa96651 100644 --- a/Source/Core/Core/PowerPC/Jit64/GPRRegCache.h +++ b/Source/Core/Core/PowerPC/Jit64/GPRRegCache.h @@ -12,12 +12,13 @@ class GPRRegCache final : public RegCache { public: explicit GPRRegCache(Jit64& jit); + Gen::OpArg GetDefaultLocation(size_t reg) const override; + void SetImmediate32(size_t preg, u32 imm_value, bool dirty = true); +protected: void StoreRegister(size_t preg, const Gen::OpArg& new_loc) override; void LoadRegister(size_t preg, Gen::X64Reg new_loc) override; - Gen::OpArg GetDefaultLocation(size_t reg) const override; const Gen::X64Reg* GetAllocationOrder(size_t* count) const override; - void SetImmediate32(size_t preg, u32 imm_value, bool dirty = true); BitSet32 GetRegUtilization() const override; BitSet32 CountRegsIn(size_t preg, u32 lookahead) const override; }; diff --git a/Source/Core/Core/PowerPC/Jit64/JitRegCache.h b/Source/Core/Core/PowerPC/Jit64/JitRegCache.h index e32e42ae47..c53c080873 100644 --- a/Source/Core/Core/PowerPC/Jit64/JitRegCache.h +++ b/Source/Core/Core/PowerPC/Jit64/JitRegCache.h @@ -133,8 +133,6 @@ public: explicit RegCache(Jit64& jit); virtual ~RegCache() = default; - virtual void StoreRegister(size_t preg, const Gen::OpArg& new_loc) = 0; - virtual void LoadRegister(size_t preg, Gen::X64Reg new_loc) = 0; virtual Gen::OpArg GetDefaultLocation(size_t reg) const = 0; void Start(); @@ -211,6 +209,9 @@ public: int NumFreeRegisters() const; protected: + virtual void StoreRegister(size_t preg, const Gen::OpArg& new_loc) = 0; + virtual void LoadRegister(size_t preg, Gen::X64Reg new_loc) = 0; + virtual const Gen::X64Reg* GetAllocationOrder(size_t* count) const = 0; virtual BitSet32 GetRegUtilization() const = 0; From 29d301e303955c3675bc513cfa3a8121f7a84768 Mon Sep 17 00:00:00 2001 From: MerryMage Date: Fri, 5 Oct 2018 21:17:36 +0100 Subject: [PATCH 6/8] JitRegCache: Use preg_t for PPC register indexes --- .../Core/Core/PowerPC/Jit64/FPURegCache.cpp | 10 +++---- Source/Core/Core/PowerPC/Jit64/FPURegCache.h | 8 ++--- .../Core/Core/PowerPC/Jit64/GPRRegCache.cpp | 12 ++++---- Source/Core/Core/PowerPC/Jit64/GPRRegCache.h | 10 +++---- .../Core/Core/PowerPC/Jit64/JitRegCache.cpp | 16 +++++----- Source/Core/Core/PowerPC/Jit64/JitRegCache.h | 30 ++++++++++--------- 6 files changed, 44 insertions(+), 42 deletions(-) diff --git a/Source/Core/Core/PowerPC/Jit64/FPURegCache.cpp b/Source/Core/Core/PowerPC/Jit64/FPURegCache.cpp index 11decfbf98..9077f388c8 100644 --- a/Source/Core/Core/PowerPC/Jit64/FPURegCache.cpp +++ b/Source/Core/Core/PowerPC/Jit64/FPURegCache.cpp @@ -14,12 +14,12 @@ FPURegCache::FPURegCache(Jit64& jit) : RegCache{jit} { } -void FPURegCache::StoreRegister(size_t preg, const OpArg& new_loc) +void FPURegCache::StoreRegister(preg_t preg, const OpArg& new_loc) { m_emitter->MOVAPD(new_loc, m_regs[preg].Location().GetSimpleReg()); } -void FPURegCache::LoadRegister(size_t preg, X64Reg new_loc) +void FPURegCache::LoadRegister(preg_t preg, X64Reg new_loc) { m_emitter->MOVAPD(new_loc, m_regs[preg].Location()); } @@ -32,9 +32,9 @@ const X64Reg* FPURegCache::GetAllocationOrder(size_t* count) const return allocation_order; } -OpArg FPURegCache::GetDefaultLocation(size_t reg) const +OpArg FPURegCache::GetDefaultLocation(preg_t preg) const { - return PPCSTATE(ps[reg][0]); + return PPCSTATE(ps[preg][0]); } BitSet32 FPURegCache::GetRegUtilization() const @@ -42,7 +42,7 @@ BitSet32 FPURegCache::GetRegUtilization() const return m_jit.js.op->gprInReg; } -BitSet32 FPURegCache::CountRegsIn(size_t preg, u32 lookahead) const +BitSet32 FPURegCache::CountRegsIn(preg_t preg, u32 lookahead) const { BitSet32 regs_used; diff --git a/Source/Core/Core/PowerPC/Jit64/FPURegCache.h b/Source/Core/Core/PowerPC/Jit64/FPURegCache.h index 99ffc78887..1ecbde2bea 100644 --- a/Source/Core/Core/PowerPC/Jit64/FPURegCache.h +++ b/Source/Core/Core/PowerPC/Jit64/FPURegCache.h @@ -12,12 +12,12 @@ class FPURegCache final : public RegCache { public: explicit FPURegCache(Jit64& jit); - Gen::OpArg GetDefaultLocation(size_t reg) const override; + Gen::OpArg GetDefaultLocation(preg_t preg) const override; protected: - void StoreRegister(size_t preg, const Gen::OpArg& newLoc) override; - void LoadRegister(size_t preg, Gen::X64Reg newLoc) 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; BitSet32 GetRegUtilization() const override; - BitSet32 CountRegsIn(size_t preg, u32 lookahead) const override; + BitSet32 CountRegsIn(preg_t preg, u32 lookahead) const override; }; diff --git a/Source/Core/Core/PowerPC/Jit64/GPRRegCache.cpp b/Source/Core/Core/PowerPC/Jit64/GPRRegCache.cpp index ed8079e0e3..18b0e70602 100644 --- a/Source/Core/Core/PowerPC/Jit64/GPRRegCache.cpp +++ b/Source/Core/Core/PowerPC/Jit64/GPRRegCache.cpp @@ -14,19 +14,19 @@ GPRRegCache::GPRRegCache(Jit64& jit) : RegCache{jit} { } -void GPRRegCache::StoreRegister(size_t preg, const OpArg& new_loc) +void GPRRegCache::StoreRegister(preg_t preg, const OpArg& new_loc) { m_emitter->MOV(32, new_loc, m_regs[preg].Location()); } -void GPRRegCache::LoadRegister(size_t preg, X64Reg new_loc) +void GPRRegCache::LoadRegister(preg_t preg, X64Reg new_loc) { m_emitter->MOV(32, ::Gen::R(new_loc), m_regs[preg].Location()); } -OpArg GPRRegCache::GetDefaultLocation(size_t reg) const +OpArg GPRRegCache::GetDefaultLocation(preg_t preg) const { - return PPCSTATE(gpr[reg]); + return PPCSTATE(gpr[preg]); } const X64Reg* GPRRegCache::GetAllocationOrder(size_t* count) const @@ -46,7 +46,7 @@ const X64Reg* GPRRegCache::GetAllocationOrder(size_t* count) const return allocation_order; } -void GPRRegCache::SetImmediate32(size_t preg, u32 imm_value, bool dirty) +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. @@ -59,7 +59,7 @@ BitSet32 GPRRegCache::GetRegUtilization() const return m_jit.js.op->gprInReg; } -BitSet32 GPRRegCache::CountRegsIn(size_t preg, u32 lookahead) const +BitSet32 GPRRegCache::CountRegsIn(preg_t preg, u32 lookahead) const { BitSet32 regs_used; diff --git a/Source/Core/Core/PowerPC/Jit64/GPRRegCache.h b/Source/Core/Core/PowerPC/Jit64/GPRRegCache.h index 911fa96651..0b383cf94f 100644 --- a/Source/Core/Core/PowerPC/Jit64/GPRRegCache.h +++ b/Source/Core/Core/PowerPC/Jit64/GPRRegCache.h @@ -12,13 +12,13 @@ class GPRRegCache final : public RegCache { public: explicit GPRRegCache(Jit64& jit); - Gen::OpArg GetDefaultLocation(size_t reg) const override; - void SetImmediate32(size_t preg, u32 imm_value, bool dirty = true); + Gen::OpArg GetDefaultLocation(preg_t preg) const override; + void SetImmediate32(preg_t preg, u32 imm_value, bool dirty = true); protected: - void StoreRegister(size_t preg, const Gen::OpArg& new_loc) override; - void LoadRegister(size_t preg, Gen::X64Reg new_loc) 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; BitSet32 GetRegUtilization() const override; - BitSet32 CountRegsIn(size_t preg, u32 lookahead) const override; + BitSet32 CountRegsIn(preg_t preg, u32 lookahead) const override; }; diff --git a/Source/Core/Core/PowerPC/Jit64/JitRegCache.cpp b/Source/Core/Core/PowerPC/Jit64/JitRegCache.cpp index a7d034ce8a..f129021647 100644 --- a/Source/Core/Core/PowerPC/Jit64/JitRegCache.cpp +++ b/Source/Core/Core/PowerPC/Jit64/JitRegCache.cpp @@ -33,7 +33,7 @@ void RegCache::Start() } } -void RegCache::DiscardRegContentsIfCached(size_t preg) +void RegCache::DiscardRegContentsIfCached(preg_t preg) { if (m_regs[preg].IsBound()) { @@ -117,7 +117,7 @@ int RegCache::SanityCheck() const return 0; } -void RegCache::KillImmediate(size_t preg, bool doLoad, bool makeDirty) +void RegCache::KillImmediate(preg_t preg, bool doLoad, bool makeDirty) { switch (m_regs[preg].GetLocationType()) { @@ -133,7 +133,7 @@ void RegCache::KillImmediate(size_t preg, bool doLoad, bool makeDirty) } } -void RegCache::BindToRegister(size_t i, bool doLoad, bool makeDirty) +void RegCache::BindToRegister(preg_t i, bool doLoad, bool makeDirty) { if (!m_regs[i].IsBound()) { @@ -166,7 +166,7 @@ void RegCache::BindToRegister(size_t i, bool doLoad, bool makeDirty) ASSERT_MSG(DYNA_REC, !m_xregs[RX(i)].IsLocked(), "WTF, this reg should have been flushed"); } -void RegCache::StoreFromRegister(size_t i, FlushMode mode) +void RegCache::StoreFromRegister(preg_t i, FlushMode mode) { bool doStore = false; @@ -194,12 +194,12 @@ void RegCache::StoreFromRegister(size_t i, FlushMode mode) m_regs[i].Flushed(); } -const OpArg& RegCache::R(size_t preg) const +const OpArg& RegCache::R(preg_t preg) const { return m_regs[preg].Location(); } -X64Reg RegCache::RX(size_t preg) const +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(); @@ -243,7 +243,7 @@ X64Reg RegCache::GetFreeXReg() for (size_t i = 0; i < aCount; i++) { X64Reg xreg = (X64Reg)aOrder[i]; - size_t preg = m_xregs[xreg].Contents(); + preg_t preg = m_xregs[xreg].Contents(); if (m_xregs[xreg].IsLocked() || m_regs[preg].IsLocked()) continue; float score = ScoreRegister(xreg); @@ -291,7 +291,7 @@ void RegCache::FlushX(X64Reg reg) // means more bad. float RegCache::ScoreRegister(X64Reg xreg) const { - size_t preg = m_xregs[xreg].Contents(); + preg_t preg = m_xregs[xreg].Contents(); float score = 0; // If it's not dirty, we don't need a store to write it back to the register file, so diff --git a/Source/Core/Core/PowerPC/Jit64/JitRegCache.h b/Source/Core/Core/PowerPC/Jit64/JitRegCache.h index c53c080873..d5a2cc5621 100644 --- a/Source/Core/Core/PowerPC/Jit64/JitRegCache.h +++ b/Source/Core/Core/PowerPC/Jit64/JitRegCache.h @@ -13,6 +13,8 @@ class Jit64; +using preg_t = size_t; + class PPCCachedReg { public: @@ -87,9 +89,9 @@ private: class X64CachedReg { public: - size_t Contents() const { return ppcReg; } + preg_t Contents() const { return ppcReg; } - void BoundTo(size_t ppcReg_, bool dirty_) + void BoundTo(preg_t ppcReg_, bool dirty_) { free = false; ppcReg = ppcReg_; @@ -98,7 +100,7 @@ public: void Flushed() { - ppcReg = static_cast(Gen::INVALID_REG); + ppcReg = static_cast(Gen::INVALID_REG); free = true; dirty = false; } @@ -113,7 +115,7 @@ public: void Unlock() { locked = false; } private: - size_t ppcReg = static_cast(Gen::INVALID_REG); + preg_t ppcReg = static_cast(Gen::INVALID_REG); bool free = true; bool dirty = false; bool locked = false; @@ -133,11 +135,11 @@ public: explicit RegCache(Jit64& jit); virtual ~RegCache() = default; - virtual Gen::OpArg GetDefaultLocation(size_t reg) const = 0; + virtual Gen::OpArg GetDefaultLocation(preg_t preg) const = 0; void Start(); - void DiscardRegContentsIfCached(size_t preg); + void DiscardRegContentsIfCached(preg_t preg); void SetEmitter(Gen::XEmitter* emitter); void Flush(FlushMode mode = FlushMode::All, BitSet32 regsToFlush = BitSet32::AllTrue(32)); @@ -146,15 +148,15 @@ public: void FlushLockX(Gen::X64Reg reg1, Gen::X64Reg reg2); int SanityCheck() const; - void KillImmediate(size_t preg, bool doLoad, bool makeDirty); + 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(size_t preg, bool doLoad = true, bool makeDirty = true); - void StoreFromRegister(size_t preg, FlushMode mode = FlushMode::All); + void BindToRegister(preg_t preg, bool doLoad = true, bool makeDirty = true); + void StoreFromRegister(preg_t preg, FlushMode mode = FlushMode::All); - const Gen::OpArg& R(size_t preg) const; - Gen::X64Reg RX(size_t preg) const; + const Gen::OpArg& R(preg_t preg) const; + Gen::X64Reg RX(preg_t preg) const; // Register locking. @@ -209,13 +211,13 @@ public: int NumFreeRegisters() const; protected: - virtual void StoreRegister(size_t preg, const Gen::OpArg& new_loc) = 0; - virtual void LoadRegister(size_t preg, Gen::X64Reg new_loc) = 0; + virtual void StoreRegister(preg_t preg, const Gen::OpArg& new_loc) = 0; + virtual void LoadRegister(preg_t preg, Gen::X64Reg new_loc) = 0; virtual const Gen::X64Reg* GetAllocationOrder(size_t* count) const = 0; virtual BitSet32 GetRegUtilization() const = 0; - virtual BitSet32 CountRegsIn(size_t preg, u32 lookahead) const = 0; + virtual BitSet32 CountRegsIn(preg_t preg, u32 lookahead) const = 0; void FlushX(Gen::X64Reg reg); From d5999bc0df292ab583d28de4d47206c019b09d6a Mon Sep 17 00:00:00 2001 From: MerryMage Date: Sun, 7 Oct 2018 09:02:39 +0100 Subject: [PATCH 7/8] JitRegCache: Rename CachedReg function names * BoundTo -> SetBoundTo * Flushed -> SetFlushed * Remove argument from MakeDirty --- .../Core/Core/PowerPC/Jit64/JitRegCache.cpp | 20 ++++++++++--------- Source/Core/Core/PowerPC/Jit64/JitRegCache.h | 10 +++++----- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/Source/Core/Core/PowerPC/Jit64/JitRegCache.cpp b/Source/Core/Core/PowerPC/Jit64/JitRegCache.cpp index f129021647..a7f5e81f0c 100644 --- a/Source/Core/Core/PowerPC/Jit64/JitRegCache.cpp +++ b/Source/Core/Core/PowerPC/Jit64/JitRegCache.cpp @@ -38,8 +38,8 @@ void RegCache::DiscardRegContentsIfCached(preg_t preg) if (m_regs[preg].IsBound()) { X64Reg xr = m_regs[preg].Location().GetSimpleReg(); - m_xregs[xr].Flushed(); - m_regs[preg].Flushed(); + m_xregs[xr].SetFlushed(); + m_regs[preg].SetFlushed(); } } @@ -68,7 +68,7 @@ void RegCache::Flush(FlushMode mode, BitSet32 regsToFlush) // 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].Flushed(); + m_regs[i].SetFlushed(); break; case PPCCachedReg::LocationType::Bound: case PPCCachedReg::LocationType::Immediate: @@ -125,7 +125,8 @@ void RegCache::KillImmediate(preg_t preg, bool doLoad, bool makeDirty) case PPCCachedReg::LocationType::SpeculativeImmediate: break; case PPCCachedReg::LocationType::Bound: - m_xregs[RX(preg)].MakeDirty(makeDirty); + if (makeDirty) + m_xregs[RX(preg)].MakeDirty(); break; case PPCCachedReg::LocationType::Immediate: BindToRegister(preg, doLoad, makeDirty); @@ -142,7 +143,7 @@ void RegCache::BindToRegister(preg_t i, bool doLoad, bool makeDirty) ASSERT_MSG(DYNA_REC, !m_xregs[xr].IsDirty(), "Xreg %i already dirty", xr); ASSERT_MSG(DYNA_REC, !m_xregs[xr].IsLocked(), "GetFreeXReg returned locked register"); - m_xregs[xr].BoundTo(i, makeDirty || m_regs[i].IsAway()); + m_xregs[xr].SetBoundTo(i, makeDirty || m_regs[i].IsAway()); if (doLoad) { @@ -154,13 +155,14 @@ void RegCache::BindToRegister(preg_t i, bool doLoad, bool makeDirty) [xr](const auto& r) { return r.Location().IsSimpleReg(xr); }), "Xreg %i already bound", xr); - m_regs[i].BoundTo(xr); + m_regs[i].SetBoundTo(xr); } else { // reg location must be simplereg; memory locations // and immediates are taken care of above. - m_xregs[RX(i)].MakeDirty(makeDirty); + if (makeDirty) + m_xregs[RX(i)].MakeDirty(); } ASSERT_MSG(DYNA_REC, !m_xregs[RX(i)].IsLocked(), "WTF, this reg should have been flushed"); @@ -180,7 +182,7 @@ void RegCache::StoreFromRegister(preg_t i, FlushMode mode) X64Reg xr = RX(i); doStore = m_xregs[xr].IsDirty(); if (mode == FlushMode::All) - m_xregs[xr].Flushed(); + m_xregs[xr].SetFlushed(); break; } case PPCCachedReg::LocationType::Immediate: @@ -191,7 +193,7 @@ void RegCache::StoreFromRegister(preg_t i, FlushMode mode) if (doStore) StoreRegister(i, GetDefaultLocation(i)); if (mode == FlushMode::All) - m_regs[i].Flushed(); + m_regs[i].SetFlushed(); } const OpArg& RegCache::R(preg_t preg) const diff --git a/Source/Core/Core/PowerPC/Jit64/JitRegCache.h b/Source/Core/Core/PowerPC/Jit64/JitRegCache.h index d5a2cc5621..215b7f1898 100644 --- a/Source/Core/Core/PowerPC/Jit64/JitRegCache.h +++ b/Source/Core/Core/PowerPC/Jit64/JitRegCache.h @@ -57,13 +57,13 @@ public: bool IsAway() const { return away; } bool IsBound() const { return GetLocationType() == LocationType::Bound; } - void BoundTo(Gen::X64Reg xreg) + void SetBoundTo(Gen::X64Reg xreg) { away = true; location = Gen::R(xreg); } - void Flushed() + void SetFlushed() { away = false; location = default_location; @@ -91,14 +91,14 @@ class X64CachedReg public: preg_t Contents() const { return ppcReg; } - void BoundTo(preg_t ppcReg_, bool dirty_) + void SetBoundTo(preg_t ppcReg_, bool dirty_) { free = false; ppcReg = ppcReg_; dirty = dirty_; } - void Flushed() + void SetFlushed() { ppcReg = static_cast(Gen::INVALID_REG); free = true; @@ -108,7 +108,7 @@ public: bool IsFree() const { return free && !locked; } bool IsDirty() const { return dirty; } - void MakeDirty(bool makeDirty = true) { dirty |= makeDirty; } + void MakeDirty() { dirty = true; } bool IsLocked() const { return locked; } void Lock() { locked = true; } From d448ed3308dfa02dda19eea0d8ec2db21a1f50b1 Mon Sep 17 00:00:00 2001 From: MerryMage Date: Sun, 7 Oct 2018 09:05:37 +0100 Subject: [PATCH 8/8] JitRegCache: Fix SanityCheck --- Source/Core/Core/PowerPC/Jit64/Jit.cpp | 4 ++-- .../Core/Core/PowerPC/Jit64/JitRegCache.cpp | 20 ++++++++++--------- Source/Core/Core/PowerPC/Jit64/JitRegCache.h | 2 +- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/Source/Core/Core/PowerPC/Jit64/Jit.cpp b/Source/Core/Core/PowerPC/Jit64/Jit.cpp index 44f1b8566f..c4cfefd77a 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit.cpp @@ -935,10 +935,10 @@ u8* Jit64::DoJit(u32 em_address, JitBlock* b, u32 nextPC) } #if defined(_DEBUG) || defined(DEBUGFAST) - if (gpr.SanityCheck() || fpr.SanityCheck()) + if (!gpr.SanityCheck() || !fpr.SanityCheck()) { std::string ppc_inst = Common::GekkoDisassembler::Disassemble(op.inst.hex, em_address); - // NOTICE_LOG(DYNA_REC, "Unflushed register: %s", ppc_inst.c_str()); + NOTICE_LOG(DYNA_REC, "Unflushed register: %s", ppc_inst.c_str()); } #endif i += js.skipInstructions; diff --git a/Source/Core/Core/PowerPC/Jit64/JitRegCache.cpp b/Source/Core/Core/PowerPC/Jit64/JitRegCache.cpp index a7f5e81f0c..3b65768db3 100644 --- a/Source/Core/Core/PowerPC/Jit64/JitRegCache.cpp +++ b/Source/Core/Core/PowerPC/Jit64/JitRegCache.cpp @@ -92,7 +92,7 @@ void RegCache::FlushLockX(X64Reg reg1, X64Reg reg2) LockX(reg2); } -int RegCache::SanityCheck() const +bool RegCache::SanityCheck() const { for (size_t i = 0; i < m_regs.size(); i++) { @@ -100,21 +100,23 @@ int RegCache::SanityCheck() const { case PPCCachedReg::LocationType::Default: case PPCCachedReg::LocationType::SpeculativeImmediate: + case PPCCachedReg::LocationType::Immediate: break; case PPCCachedReg::LocationType::Bound: { - Gen::X64Reg simple = m_regs[i].Location().GetSimpleReg(); - if (m_xregs[simple].IsLocked()) - return 1; - if (m_xregs[simple].Contents() != i) - return 2; + if (m_regs[i].IsLocked()) + return false; + + Gen::X64Reg xr = m_regs[i].Location().GetSimpleReg(); + if (m_xregs[xr].IsLocked()) + return false; + if (m_xregs[xr].Contents() != i) + return false; break; } - case PPCCachedReg::LocationType::Immediate: - return 3; } } - return 0; + return true; } void RegCache::KillImmediate(preg_t preg, bool doLoad, bool makeDirty) diff --git a/Source/Core/Core/PowerPC/Jit64/JitRegCache.h b/Source/Core/Core/PowerPC/Jit64/JitRegCache.h index 215b7f1898..9c59cab388 100644 --- a/Source/Core/Core/PowerPC/Jit64/JitRegCache.h +++ b/Source/Core/Core/PowerPC/Jit64/JitRegCache.h @@ -147,7 +147,7 @@ public: void FlushLockX(Gen::X64Reg reg); void FlushLockX(Gen::X64Reg reg1, Gen::X64Reg reg2); - int SanityCheck() const; + bool SanityCheck() const; void KillImmediate(preg_t preg, bool doLoad, bool makeDirty); // TODO - instead of doload, use "read", "write"