BranchWatch: Extract shared function logic

IsolateWasOverwritten and IsolateNotOverwritten share the same basic
logic and have almost exactly the same code, with the only difference
being the comparison function used to keep or discard branches. To avoid
unnecessary code duplication and ensure that the functions stay in sync
after any future changes, create a helper function that takes the
comparison function as a parameter and have IsolateWasOverwritten and
IsolateNotOverwritten call that helper.
This commit is contained in:
Dentomologist
2025-08-06 14:35:24 -07:00
parent 72ef27c157
commit bd79bc47cc
2 changed files with 15 additions and 44 deletions

View File

@@ -6,6 +6,7 @@
#include <algorithm>
#include <cstddef>
#include <cstdio>
#include <functional>
#include <fmt/format.h>
@@ -200,7 +201,8 @@ void BranchWatch::IsolateNotExecuted(const CPUThreadGuard&)
}
}
void BranchWatch::IsolateWasOverwritten(const CPUThreadGuard& guard)
void BranchWatch::IsolateOverwrittenShared(const CPUThreadGuard& guard,
const std::function<bool(u32, u32)>& compare_func)
{
if (Core::GetState(guard.GetSystem()) == Core::State::Uninitialized)
{
@@ -223,7 +225,7 @@ void BranchWatch::IsolateWasOverwritten(const CPUThreadGuard& guard)
PowerPC::MMU::HostTryReadInstruction(guard, kv.first.origin_addr, address_space);
if (!read_result.has_value())
continue;
if (kv.first.original_inst.hex == read_result->value)
if (compare_func(kv.first.original_inst.hex, read_result->value))
kv.second.hits_snapshot = ++m_blacklist_size; // Any non-zero number will work.
}
}
@@ -235,61 +237,27 @@ void BranchWatch::IsolateWasOverwritten(const CPUThreadGuard& guard)
return;
}
case Phase::Reduction:
std::erase_if(m_selection, [&guard](const Selection::value_type& value) -> bool {
std::erase_if(m_selection, [&](const Selection::value_type& value) -> bool {
const std::optional read_result = PowerPC::MMU::HostTryReadInstruction(
guard, value.collection_ptr->first.origin_addr,
value.is_virtual ? PowerPC::RequestedAddressSpace::Virtual :
PowerPC::RequestedAddressSpace::Physical);
if (!read_result.has_value())
return false;
return value.collection_ptr->first.original_inst.hex == read_result->value;
return compare_func(value.collection_ptr->first.original_inst.hex, read_result->value);
});
return;
}
}
void BranchWatch::IsolateWasOverwritten(const CPUThreadGuard& guard)
{
IsolateOverwrittenShared(guard, std::equal_to<u32>());
}
void BranchWatch::IsolateNotOverwritten(const CPUThreadGuard& guard)
{
if (Core::GetState(guard.GetSystem()) == Core::State::Uninitialized)
{
ASSERT_MSG(CORE, false, "Core is uninitialized.");
return;
}
switch (m_recording_phase)
{
case Phase::Blacklist:
{
// Same dirty hack with != rather than ==, see above for details
const auto routine = [&](Collection& collection, PowerPC::RequestedAddressSpace address_space) {
for (Collection::value_type& kv : collection)
if (kv.second.hits_snapshot == 0)
{
const std::optional read_result =
PowerPC::MMU::HostTryReadInstruction(guard, kv.first.origin_addr, address_space);
if (!read_result.has_value())
continue;
if (kv.first.original_inst.hex != read_result->value)
kv.second.hits_snapshot = ++m_blacklist_size; // Any non-zero number will work.
}
};
routine(m_collection_vt, PowerPC::RequestedAddressSpace::Virtual);
routine(m_collection_vf, PowerPC::RequestedAddressSpace::Virtual);
routine(m_collection_pt, PowerPC::RequestedAddressSpace::Physical);
routine(m_collection_pf, PowerPC::RequestedAddressSpace::Physical);
return;
}
case Phase::Reduction:
std::erase_if(m_selection, [&guard](const Selection::value_type& value) -> bool {
const std::optional read_result = PowerPC::MMU::HostTryReadInstruction(
guard, value.collection_ptr->first.origin_addr,
value.is_virtual ? PowerPC::RequestedAddressSpace::Virtual :
PowerPC::RequestedAddressSpace::Physical);
if (!read_result.has_value())
return false;
return value.collection_ptr->first.original_inst.hex != read_result->value;
});
return;
}
IsolateOverwrittenShared(guard, std::not_equal_to<u32>());
}
void BranchWatch::UpdateHitsSnapshot()

View File

@@ -261,6 +261,9 @@ private:
return GetCollectionP(condition);
}
void IsolateOverwrittenShared(const CPUThreadGuard& guard,
const std::function<bool(u32, u32)>& compare_func);
std::size_t m_blacklist_size = 0;
Phase m_recording_phase = Phase::Blacklist;
bool m_recording_active = false;