Merge pull request #12306 from JosJuice/hle-discard

PPCAnalyst: Don't discard registers across HLE'd functions
This commit is contained in:
Mai
2023-11-28 04:05:31 +01:00
committed by GitHub
7 changed files with 92 additions and 68 deletions

View File

@ -200,6 +200,23 @@ HookFlag GetHookFlagsByIndex(u32 index)
return os_patches[index].flags; return os_patches[index].flags;
} }
TryReplaceFunctionResult TryReplaceFunction(u32 address)
{
const u32 hook_index = GetHookByFunctionAddress(address);
if (hook_index == 0)
return {};
const HookType type = GetHookTypeByIndex(hook_index);
if (type != HookType::Start && type != HookType::Replace)
return {};
const HookFlag flags = GetHookFlagsByIndex(hook_index);
if (!IsEnabled(flags))
return {};
return {type, hook_index};
}
bool IsEnabled(HookFlag flag) bool IsEnabled(HookFlag flag)
{ {
return flag != HLE::HookFlag::Debug || Config::Get(Config::MAIN_ENABLE_DEBUGGING) || return flag != HLE::HookFlag::Debug || Config::Get(Config::MAIN_ENABLE_DEBUGGING) ||

View File

@ -19,9 +19,9 @@ using HookFunction = void (*)(const Core::CPUThreadGuard&);
enum class HookType enum class HookType
{ {
None, // Do not hook the function
Start, // Hook the beginning of the function and execute the function afterwards Start, // Hook the beginning of the function and execute the function afterwards
Replace, // Replace the function with the HLE version Replace, // Replace the function with the HLE version
None, // Do not hook the function
}; };
enum class HookFlag enum class HookFlag
@ -39,6 +39,14 @@ struct Hook
HookFlag flags; HookFlag flags;
}; };
struct TryReplaceFunctionResult
{
HookType type = HookType::None;
u32 hook_index = 0;
explicit operator bool() const { return type != HookType::None; }
};
void PatchFixedFunctions(Core::System& system); void PatchFixedFunctions(Core::System& system);
void PatchFunctions(Core::System& system); void PatchFunctions(Core::System& system);
void Clear(); void Clear();
@ -59,32 +67,8 @@ HookFlag GetHookFlagsByIndex(u32 index);
bool IsEnabled(HookFlag flag); bool IsEnabled(HookFlag flag);
// Performs the backend-independent preliminary checking before calling a // Performs the backend-independent preliminary checking for whether a function
// FunctionObject to do the actual replacing. Typically, this callback will // can be HLEd. If it can be, the information needed for HLEing it is returned.
// be in the backend itself, containing the backend-specific portions TryReplaceFunctionResult TryReplaceFunction(u32 address);
// required in replacing a function.
//
// fn may be any object that satisfies the FunctionObject concept in the C++
// standard library. That is, any lambda, object with an overloaded function
// call operator, or regular function pointer.
//
// fn must return a bool indicating whether or not function replacing occurred.
// fn must also accept a parameter list of the form: fn(u32 function, HLE::HookType type).
template <typename FunctionObject>
bool ReplaceFunctionIfPossible(u32 address, FunctionObject fn)
{
const u32 hook_index = GetHookByFunctionAddress(address);
if (hook_index == 0)
return false;
const HookType type = GetHookTypeByIndex(hook_index);
if (type != HookType::Start && type != HookType::Replace)
return false;
const HookFlag flags = GetHookFlagsByIndex(hook_index);
if (!IsEnabled(flags))
return false;
return fn(hook_index, type);
}
} // namespace HLE } // namespace HLE

View File

@ -269,17 +269,19 @@ bool CachedInterpreter::CheckIdle(CachedInterpreter& cached_interpreter, u32 idl
bool CachedInterpreter::HandleFunctionHooking(u32 address) bool CachedInterpreter::HandleFunctionHooking(u32 address)
{ {
return HLE::ReplaceFunctionIfPossible(address, [&](u32 hook_index, HLE::HookType type) { const auto result = HLE::TryReplaceFunction(address);
m_code.emplace_back(WritePC, address); if (!result)
m_code.emplace_back(Interpreter::HLEFunction, hook_index); return false;
if (type != HLE::HookType::Replace) m_code.emplace_back(WritePC, address);
m_code.emplace_back(Interpreter::HLEFunction, result.hook_index);
if (result.type != HLE::HookType::Replace)
return false; return false;
m_code.emplace_back(EndBlock, js.downcountAmount); m_code.emplace_back(EndBlock, js.downcountAmount);
m_code.emplace_back(); m_code.emplace_back();
return true; return true;
});
} }
void CachedInterpreter::Jit(u32 address) void CachedInterpreter::Jit(u32 address)

View File

@ -106,10 +106,13 @@ void Interpreter::Trace(const UGeckoInstruction& inst)
bool Interpreter::HandleFunctionHooking(u32 address) bool Interpreter::HandleFunctionHooking(u32 address)
{ {
return HLE::ReplaceFunctionIfPossible(address, [this](u32 hook_index, HLE::HookType type) { const auto result = HLE::TryReplaceFunction(address);
HLEFunction(*this, hook_index); if (!result)
return type != HLE::HookType::Start; return false;
});
HLEFunction(*this, result.hook_index);
return result.type != HLE::HookType::Start;
} }
int Interpreter::SingleStepInner() int Interpreter::SingleStepInner()

View File

@ -1238,17 +1238,19 @@ void Jit64::IntializeSpeculativeConstants()
bool Jit64::HandleFunctionHooking(u32 address) bool Jit64::HandleFunctionHooking(u32 address)
{ {
return HLE::ReplaceFunctionIfPossible(address, [&](u32 hook_index, HLE::HookType type) { const auto result = HLE::TryReplaceFunction(address);
HLEFunction(hook_index); if (!result)
return false;
if (type != HLE::HookType::Replace) HLEFunction(result.hook_index);
if (result.type != HLE::HookType::Replace)
return false; return false;
MOV(32, R(RSCRATCH), PPCSTATE(npc)); MOV(32, R(RSCRATCH), PPCSTATE(npc));
js.downcountAmount += js.st.numCycles; js.downcountAmount += js.st.numCycles;
WriteExitDestInRSCRATCH(); WriteExitDestInRSCRATCH();
return true; return true;
});
} }
void LogGeneratedX86(size_t size, const PPCAnalyst::CodeBuffer& code_buffer, const u8* normalEntry, void LogGeneratedX86(size_t size, const PPCAnalyst::CodeBuffer& code_buffer, const u8* normalEntry,

View File

@ -696,17 +696,19 @@ void JitArm64::WriteConditionalExceptionExit(int exception, ARM64Reg temp_gpr, A
bool JitArm64::HandleFunctionHooking(u32 address) bool JitArm64::HandleFunctionHooking(u32 address)
{ {
return HLE::ReplaceFunctionIfPossible(address, [&](u32 hook_index, HLE::HookType type) { const auto result = HLE::TryReplaceFunction(address);
HLEFunction(hook_index); if (!result)
return false;
if (type != HLE::HookType::Replace) HLEFunction(result.hook_index);
if (result.type != HLE::HookType::Replace)
return false; return false;
LDR(IndexType::Unsigned, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(npc)); LDR(IndexType::Unsigned, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(npc));
js.downcountAmount += js.st.numCycles; js.downcountAmount += js.st.numCycles;
WriteExit(DISPATCHER_PC); WriteExit(DISPATCHER_PC);
return true; return true;
});
} }
void JitArm64::DumpCode(const u8* start, const u8* end) void JitArm64::DumpCode(const u8* start, const u8* end)

View File

@ -18,6 +18,7 @@
#include "Core/Config/MainSettings.h" #include "Core/Config/MainSettings.h"
#include "Core/ConfigManager.h" #include "Core/ConfigManager.h"
#include "Core/Core.h" #include "Core/Core.h"
#include "Core/HLE/HLE.h"
#include "Core/PowerPC/JitCommon/JitBase.h" #include "Core/PowerPC/JitCommon/JitBase.h"
#include "Core/PowerPC/MMU.h" #include "Core/PowerPC/MMU.h"
#include "Core/PowerPC/PPCSymbolDB.h" #include "Core/PowerPC/PPCSymbolDB.h"
@ -970,15 +971,18 @@ u32 PPCAnalyzer::Analyze(u32 address, CodeBlock* block, CodeBuffer* buffer,
fprDiscardable = BitSet32{}; fprDiscardable = BitSet32{};
} }
const bool hle = !!HLE::TryReplaceFunction(op.address);
const bool may_exit_block = hle || op.canEndBlock || op.canCauseException;
const BitSet8 opWantsCR = op.wantsCR; const BitSet8 opWantsCR = op.wantsCR;
const bool opWantsFPRF = op.wantsFPRF; const bool opWantsFPRF = op.wantsFPRF;
const bool opWantsCA = op.wantsCA; const bool opWantsCA = op.wantsCA;
op.wantsCR = wantsCR | BitSet8(op.canEndBlock || op.canCauseException ? 0xFF : 0); op.wantsCR = wantsCR | BitSet8(may_exit_block ? 0xFF : 0);
op.wantsFPRF = wantsFPRF || op.canEndBlock || op.canCauseException; op.wantsFPRF = wantsFPRF || may_exit_block;
op.wantsCA = wantsCA || op.canEndBlock || op.canCauseException; op.wantsCA = wantsCA || may_exit_block;
wantsCR |= opWantsCR | BitSet8(op.canEndBlock || op.canCauseException ? 0xFF : 0); wantsCR |= opWantsCR | BitSet8(may_exit_block ? 0xFF : 0);
wantsFPRF |= opWantsFPRF || op.canEndBlock || op.canCauseException; wantsFPRF |= opWantsFPRF || may_exit_block;
wantsCA |= opWantsCA || op.canEndBlock || op.canCauseException; wantsCA |= opWantsCA || may_exit_block;
wantsCR &= ~op.outputCR | opWantsCR; wantsCR &= ~op.outputCR | opWantsCR;
wantsFPRF &= !op.outputFPRF || opWantsFPRF; wantsFPRF &= !op.outputFPRF || opWantsFPRF;
wantsCA &= !op.outputCA || opWantsCA; wantsCA &= !op.outputCA || opWantsCA;
@ -989,7 +993,19 @@ u32 PPCAnalyzer::Analyze(u32 address, CodeBlock* block, CodeBuffer* buffer,
op.fprInXmm = fprInXmm; op.fprInXmm = fprInXmm;
gprInUse |= op.regsIn | op.regsOut; gprInUse |= op.regsIn | op.regsOut;
fprInUse |= op.fregsIn | op.GetFregsOut(); fprInUse |= op.fregsIn | op.GetFregsOut();
if (op.canEndBlock || op.canCauseException)
if (strncmp(op.opinfo->opname, "stfd", 4))
fprInXmm |= op.fregsIn;
if (hle)
{
gprInUse = BitSet32{};
fprInUse = BitSet32{};
fprInXmm = BitSet32{};
gprDiscardable = BitSet32{};
fprDiscardable = BitSet32{};
}
else if (op.canEndBlock || op.canCauseException)
{ {
gprDiscardable = BitSet32{}; gprDiscardable = BitSet32{};
fprDiscardable = BitSet32{}; fprDiscardable = BitSet32{};
@ -1001,8 +1017,6 @@ u32 PPCAnalyzer::Analyze(u32 address, CodeBlock* block, CodeBuffer* buffer,
fprDiscardable |= op.GetFregsOut(); fprDiscardable |= op.GetFregsOut();
fprDiscardable &= ~op.fregsIn; fprDiscardable &= ~op.fregsIn;
} }
if (strncmp(op.opinfo->opname, "stfd", 4))
fprInXmm |= op.fregsIn;
} }
// Forward scan, for flags that need the other direction for calculation. // Forward scan, for flags that need the other direction for calculation.