diff --git a/Source/Core/Core/PowerPC/BreakPoints.cpp b/Source/Core/Core/PowerPC/BreakPoints.cpp index 1fef4e4e25..c933348eaf 100644 --- a/Source/Core/Core/PowerPC/BreakPoints.cpp +++ b/Source/Core/Core/PowerPC/BreakPoints.cpp @@ -306,9 +306,13 @@ void MemChecks::Add(TMemCheck memory_check) { m_mem_checks.emplace_back(std::move(memory_check)); } - // If this is the first one, clear the JIT cache so it can switch to - // watchpoint-compatible code. - if (!had_any) + + const bool registers_changed = UpdateRegistersUsedInConditions(); + + // If this is the first memcheck, clear the JIT cache so it can switch to watchpoint-compatible + // code. Or, if the memcheck's condition wants to read from a new register, + // clear the JIT cache to make the slow memory access code flush that register. + if (!had_any || registers_changed) m_system.GetJitInterface().ClearCache(guard); m_system.GetMMU().DBATUpdated(); } @@ -336,7 +340,10 @@ bool MemChecks::Remove(u32 address) const Core::CPUThreadGuard guard(m_system); m_mem_checks.erase(iter); - if (!HasAny()) + + const bool registers_changed = UpdateRegistersUsedInConditions(); + + if (registers_changed || !HasAny()) m_system.GetJitInterface().ClearCache(guard); m_system.GetMMU().DBATUpdated(); return true; @@ -379,6 +386,27 @@ bool MemChecks::OverlapsMemcheck(u32 address, u32 length) const }); } +bool MemChecks::UpdateRegistersUsedInConditions() +{ + BitSet32 gprs_used, fprs_used; + for (TMemCheck& mem_check : m_mem_checks) + { + if (mem_check.condition) + { + gprs_used |= mem_check.condition->GetGPRsUsed(); + fprs_used |= mem_check.condition->GetFPRsUsed(); + } + } + + const bool registers_changed = + gprs_used != m_gprs_used_in_conditions || fprs_used != m_fprs_used_in_conditions; + + m_gprs_used_in_conditions = gprs_used; + m_fprs_used_in_conditions = fprs_used; + + return registers_changed; +} + bool TMemCheck::Action(Core::System& system, u64 value, u32 addr, bool write, size_t size, u32 pc) { if (!is_enabled) diff --git a/Source/Core/Core/PowerPC/BreakPoints.h b/Source/Core/Core/PowerPC/BreakPoints.h index 9b07fb53c0..e48def944b 100644 --- a/Source/Core/Core/PowerPC/BreakPoints.h +++ b/Source/Core/Core/PowerPC/BreakPoints.h @@ -8,6 +8,7 @@ #include #include +#include "Common/BitSet.h" #include "Common/CommonTypes.h" #include "Core/PowerPC/Expression.h" @@ -127,7 +128,15 @@ public: void Clear(); bool HasAny() const { return !m_mem_checks.empty(); } + BitSet32 GetGPRsUsedInConditions() { return m_gprs_used_in_conditions; } + BitSet32 GetFPRsUsedInConditions() { return m_fprs_used_in_conditions; } + private: + // Returns whether any change was made + bool UpdateRegistersUsedInConditions(); + TMemChecks m_mem_checks; Core::System& m_system; + BitSet32 m_gprs_used_in_conditions; + BitSet32 m_fprs_used_in_conditions; }; diff --git a/Source/Core/Core/PowerPC/Expression.cpp b/Source/Core/Core/PowerPC/Expression.cpp index a05fa2c8b2..38b003a806 100644 --- a/Source/Core/Core/PowerPC/Expression.cpp +++ b/Source/Core/Core/PowerPC/Expression.cpp @@ -495,3 +495,22 @@ std::string Expression::GetText() const { return m_text; } + +void Expression::ComputeRegistersUsed() +{ + if (m_has_computed_registers_used) + return; + + for (const VarBinding& bind : m_binds) + { + switch (bind.type) + { + case VarBindingType::GPR: + m_gprs_used[bind.index] = true; + break; + case VarBindingType::FPR: + m_fprs_used[bind.index] = true; + break; + } + } +} diff --git a/Source/Core/Core/PowerPC/Expression.h b/Source/Core/Core/PowerPC/Expression.h index 3c439f9e9e..deee9e69ad 100644 --- a/Source/Core/Core/PowerPC/Expression.h +++ b/Source/Core/Core/PowerPC/Expression.h @@ -9,6 +9,8 @@ #include #include +#include "Common/BitSet.h" + struct expr; struct expr_var_list; @@ -41,6 +43,18 @@ public: std::string GetText() const; + BitSet32 GetGPRsUsed() + { + ComputeRegistersUsed(); + return m_gprs_used; + } + + BitSet32 GetFPRsUsed() + { + ComputeRegistersUsed(); + return m_fprs_used; + } + private: enum class SynchronizeDirection { @@ -69,10 +83,16 @@ private: void SynchronizeBindings(Core::System& system, SynchronizeDirection dir) const; void Reporting(const double result) const; + void ComputeRegistersUsed(); + std::string m_text; ExprPointer m_expr; ExprVarListPointer m_vars; std::vector m_binds; + + BitSet32 m_gprs_used; + BitSet32 m_fprs_used; + bool m_has_computed_registers_used = false; }; inline bool EvaluateCondition(Core::System& system, const std::optional& condition)