diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.h b/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.h index 019edaa726..159cfb6836 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.h +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.h @@ -177,6 +177,59 @@ public: // Requires unlocking after done Arm64Gen::ARM64Reg GetReg(); + class ScopedARM64Reg + { + public: + inline ScopedARM64Reg() = default; + ScopedARM64Reg(const ScopedARM64Reg&) = delete; + explicit inline ScopedARM64Reg(Arm64RegCache& cache) : m_reg(cache.GetReg()), m_gpr(&cache) {} + inline ScopedARM64Reg(Arm64Gen::ARM64Reg reg) : m_reg(reg) {} + inline ScopedARM64Reg(ScopedARM64Reg&& scoped_reg) { *this = std::move(scoped_reg); } + inline ~ScopedARM64Reg() { Unlock(); } + + inline ScopedARM64Reg& operator=(const ScopedARM64Reg&) = delete; + inline ScopedARM64Reg& operator=(Arm64Gen::ARM64Reg reg) + { + Unlock(); + m_reg = reg; + return *this; + } + inline ScopedARM64Reg& operator=(ScopedARM64Reg&& scoped_reg) + { + // Taking ownership of an existing scoped register, no need to release. + m_reg = scoped_reg.m_reg; + m_gpr = scoped_reg.m_gpr; + scoped_reg.Invalidate(); + return *this; + } + + inline Arm64Gen::ARM64Reg GetReg() const { return m_reg; } + inline operator Arm64Gen::ARM64Reg() const { return GetReg(); } + inline void Unlock() + { + // Only unlock the register if GPR is set. + if (m_gpr != nullptr) + { + m_gpr->Unlock(m_reg); + } + Invalidate(); + } + + private: + inline void Invalidate() + { + m_reg = Arm64Gen::ARM64Reg::INVALID_REG; + m_gpr = nullptr; + } + + Arm64Gen::ARM64Reg m_reg = Arm64Gen::ARM64Reg::INVALID_REG; + Arm64RegCache* m_gpr = nullptr; + }; + + // Returns a temporary register + // Unlocking is implicitly handled through RAII + inline ScopedARM64Reg GetScopedReg() { return ScopedARM64Reg(*this); } + void UpdateLastUsed(BitSet32 regs_used); // Get available host registers