PowerPC: Track registers used in memory breakpoint conditions

This commit is contained in:
JosJuice
2025-07-27 08:32:44 +02:00
parent 57b145990d
commit 78afea1312
4 changed files with 82 additions and 2 deletions
+29 -2
View File
@@ -10,6 +10,7 @@
#include <string>
#include <vector>
#include "Common/BitSet.h"
#include "Common/CommonTypes.h"
#include "Common/Logging/Log.h"
#include "Core/Core.h"
@@ -341,8 +342,13 @@ 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. And conversely, if the
// aforementioned functionality is no longer needed, clear the JIT cache to switch to faster code.
if (registers_changed || m_mem_breakpoints_set != HasAny())
{
m_system.GetJitInterface().ClearCache(guard);
m_mem_breakpoints_set = HasAny();
@@ -351,6 +357,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) {
+9
View File
@@ -8,6 +8,7 @@
#include <string>
#include <vector>
#include "Common/BitSet.h"
#include "Common/CommonTypes.h"
#include "Core/PowerPC/Expression.h"
@@ -129,9 +130,17 @@ 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;
};
+24
View File
@@ -25,6 +25,7 @@ using std::isinf;
using std::isnan;
#include <expr.h>
#include "Common/BitSet.h"
#include "Common/CommonTypes.h"
#include "Common/Logging/Log.h"
#include "Core/Core.h"
@@ -503,3 +504,26 @@ 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;
default:
break;
}
}
m_has_computed_registers_used = true;
}
+20
View File
@@ -9,6 +9,8 @@
#include <string_view>
#include <vector>
#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<VarBinding> 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<Expression>& condition)