From 96e43164d0bc9d09530c240dba3d012cf2178daf Mon Sep 17 00:00:00 2001 From: JosJuice Date: Fri, 27 Dec 2024 14:47:41 +0100 Subject: [PATCH] PowerPC: Track registers used in memory break point conditions --- Source/Core/Core/PowerPC/BreakPoints.cpp | 29 ++++++++++++++++++++++-- Source/Core/Core/PowerPC/BreakPoints.h | 9 ++++++++ Source/Core/Core/PowerPC/Expression.cpp | 19 ++++++++++++++++ Source/Core/Core/PowerPC/Expression.h | 20 ++++++++++++++++ 4 files changed, 75 insertions(+), 2 deletions(-) diff --git a/Source/Core/Core/PowerPC/BreakPoints.cpp b/Source/Core/Core/PowerPC/BreakPoints.cpp index 45c66fde2b..31c2ac425b 100644 --- a/Source/Core/Core/PowerPC/BreakPoints.cpp +++ b/Source/Core/Core/PowerPC/BreakPoints.cpp @@ -346,8 +346,12 @@ void MemChecks::Update() { const Core::CPUThreadGuard guard(m_system); - // Clear the JIT cache so it can switch the watchpoint-compatible mode. - if (m_mem_breakpoints_set != HasAny()) + const bool registers_changed = UpdateRegistersUsedInConditions(); + + // If we've added a first memcheck, clear the JIT cache so it can switch to watchpoint-compatible + // code. Or, if we've added a memcheck whose condition wants to read from a new register, + // clear the JIT cache to make the slow memory access code flush that register. + if (registers_changed || m_mem_breakpoints_set != HasAny()) { m_system.GetJitInterface().ClearCache(guard); m_mem_breakpoints_set = HasAny(); @@ -356,6 +360,27 @@ void MemChecks::Update() m_system.GetMMU().DBATUpdated(); } +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; +} + TMemCheck* MemChecks::GetMemCheck(u32 address, size_t size) { const auto iter = std::ranges::find_if(m_mem_checks, [address, size](const auto& mc) { diff --git a/Source/Core/Core/PowerPC/BreakPoints.h b/Source/Core/Core/PowerPC/BreakPoints.h index 6b08c25c8d..da71e340c8 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,8 +128,16 @@ 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; bool m_mem_breakpoints_set = false; }; diff --git a/Source/Core/Core/PowerPC/Expression.cpp b/Source/Core/Core/PowerPC/Expression.cpp index 7c12b3b16a..380b26c742 100644 --- a/Source/Core/Core/PowerPC/Expression.cpp +++ b/Source/Core/Core/PowerPC/Expression.cpp @@ -494,3 +494,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)