From 590ec866b07dc32fd5a190b710d1aa66937a2d85 Mon Sep 17 00:00:00 2001 From: MerryMage Date: Mon, 15 Oct 2018 21:00:52 +0100 Subject: [PATCH] JitRegCache: Add revertable binds --- .../Core/PowerPC/Jit64/RegCache/CachedReg.h | 42 ++++++++++++++--- .../PowerPC/Jit64/RegCache/JitRegCache.cpp | 47 ++++++++++++++++++- .../Core/PowerPC/Jit64/RegCache/JitRegCache.h | 3 ++ 3 files changed, 85 insertions(+), 7 deletions(-) diff --git a/Source/Core/Core/PowerPC/Jit64/RegCache/CachedReg.h b/Source/Core/Core/PowerPC/Jit64/RegCache/CachedReg.h index 813fa29478..2755604247 100644 --- a/Source/Core/Core/PowerPC/Jit64/RegCache/CachedReg.h +++ b/Source/Core/Core/PowerPC/Jit64/RegCache/CachedReg.h @@ -41,6 +41,8 @@ public: { if (!away) { + ASSERT(!revertable); + if (location.IsImm()) return LocationType::SpeculativeImmediate; @@ -63,6 +65,7 @@ public: void SetFlushed() { + ASSERT(!revertable); away = false; location = default_location; } @@ -73,6 +76,24 @@ public: location = Gen::Imm32(imm32); } + bool IsRevertable() const { return revertable; } + void SetRevertable() + { + ASSERT(IsBound()); + revertable = true; + } + void SetRevert() + { + ASSERT(revertable); + revertable = false; + SetFlushed(); + } + void SetCommit() + { + ASSERT(revertable); + revertable = false; + } + bool IsLocked() const { return locked > 0; } void Lock() { locked++; } void Unlock() @@ -86,6 +107,7 @@ private: Gen::OpArg default_location{}; Gen::OpArg location{}; bool away = false; // value not in source register + bool revertable = false; size_t locked = 0; }; @@ -139,6 +161,7 @@ public: bool ShouldLoad() const { return read; } bool ShouldDirty() const { return write; } bool ShouldKillImmediate() const { return kill_imm; } + bool ShouldBeRevertable() const { return revertable; } void Realized() { realized = true; } void RealizedBound() @@ -147,16 +170,17 @@ public: bind = true; } - void AddUse(RCMode mode) { AddConstraint(false, mode, false); } - void AddUseNoImm(RCMode mode) { AddConstraint(false, mode, true); } - void AddBind(RCMode mode) { AddConstraint(true, mode, false); } + void AddUse(RCMode mode) { AddConstraint(false, mode, false, false); } + void AddUseNoImm(RCMode mode) { AddConstraint(false, mode, true, false); } + void AddBind(RCMode mode) { AddConstraint(true, mode, false, false); } + void AddRevertableBind(RCMode mode) { AddConstraint(true, mode, false, true); } private: - void AddConstraint(bool should_bind, RCMode mode, bool should_kill_imm) + void AddConstraint(bool should_bind, RCMode mode, bool should_kill_imm, bool should_revertable) { if (realized) { - ASSERT(IsCompatible(should_bind, mode, should_kill_imm)); + ASSERT(IsCompatible(should_bind, mode, should_kill_imm, should_revertable)); return; } @@ -166,6 +190,9 @@ private: if (should_kill_imm) kill_imm = true; + if (should_revertable) + revertable = true; + switch (mode) { case RCMode::Read: @@ -181,12 +208,14 @@ private: } } - bool IsCompatible(bool should_bind, RCMode mode, bool should_kill_imm) + bool IsCompatible(bool should_bind, RCMode mode, bool should_kill_imm, bool should_revertable) { if (should_bind && !bind) return false; if (should_kill_imm && !kill_imm) return false; + if (should_revertable && !revertable) + return false; switch (mode) { @@ -204,4 +233,5 @@ private: bool write = false; bool read = false; bool kill_imm = false; + bool revertable = false; }; diff --git a/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.cpp b/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.cpp index 3526d17894..4c02b739bb 100644 --- a/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.cpp +++ b/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.cpp @@ -328,6 +328,7 @@ void RegCache::Flush(FlushMode mode, BitSet32 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()) { @@ -373,7 +374,7 @@ bool RegCache::SanityCheck() const break; case PPCCachedReg::LocationType::Bound: { - if (m_regs[i].IsLocked()) + if (m_regs[i].IsLocked() || m_regs[i].IsRevertable()) return false; Gen::X64Reg xr = m_regs[i].Location().GetSimpleReg(); @@ -413,6 +414,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"); + ASSERT_MSG(DYNA_REC, !m_regs[i].IsRevertable(), "Invalid transaction state"); m_xregs[xr].SetBoundTo(i, makeDirty || m_regs[i].IsAway()); @@ -441,6 +443,9 @@ void RegCache::BindToRegister(preg_t i, bool doLoad, bool makeDirty) void RegCache::StoreFromRegister(preg_t i, FlushMode mode) { + // When a transaction is in progress, allowing the store would overwrite the old value. + ASSERT_MSG(DYNA_REC, !m_regs[i].IsRevertable(), "Register transaction is in progress!"); + bool doStore = false; switch (m_regs[i].GetLocationType()) @@ -611,6 +616,18 @@ RCX64Reg RegCache::Bind(preg_t preg, RCMode mode) return RCX64Reg{this, preg}; } +RCX64Reg RegCache::BindOrImm(preg_t preg, RCMode mode) +{ + m_constraints[preg].AddBindOrImm(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); @@ -622,6 +639,26 @@ 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(); }) && @@ -673,6 +710,14 @@ void RegCache::Realize(preg_t preg) m_constraints[preg].RealizedBound(); }; + if (m_constraints[preg].ShouldBeRevertable()) + { + StoreFromRegister(preg, FlushMode::MaintainState); + do_bind(); + m_regs[preg].SetRevertable(); + return; + } + if (m_constraints[preg].ShouldBind()) { do_bind(); diff --git a/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.h b/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.h index 64040a5172..99cba2141e 100644 --- a/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.h +++ b/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.h @@ -235,9 +235,12 @@ public: RCOpArg Use(preg_t preg, RCMode mode); RCOpArg UseNoImm(preg_t preg, RCMode mode); RCX64Reg Bind(preg_t preg, RCMode mode); + RCX64Reg RevertableBind(preg_t preg, RCMode mode); RCX64Reg Scratch(Gen::X64Reg xr); RCForkGuard Fork(); + void Revert(); + void Commit(); bool IsAllUnlocked() const;