mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-23 06:09:50 -06:00
Merge pull request #12306 from JosJuice/hle-discard
PPCAnalyst: Don't discard registers across HLE'd functions
This commit is contained in:
@ -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) ||
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
return false;
|
m_code.emplace_back(Interpreter::HLEFunction, result.hook_index);
|
||||||
|
|
||||||
m_code.emplace_back(EndBlock, js.downcountAmount);
|
if (result.type != HLE::HookType::Replace)
|
||||||
m_code.emplace_back();
|
return false;
|
||||||
return true;
|
|
||||||
});
|
m_code.emplace_back(EndBlock, js.downcountAmount);
|
||||||
|
m_code.emplace_back();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CachedInterpreter::Jit(u32 address)
|
void CachedInterpreter::Jit(u32 address)
|
||||||
|
@ -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()
|
||||||
|
@ -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);
|
||||||
return false;
|
|
||||||
|
|
||||||
MOV(32, R(RSCRATCH), PPCSTATE(npc));
|
if (result.type != HLE::HookType::Replace)
|
||||||
js.downcountAmount += js.st.numCycles;
|
return false;
|
||||||
WriteExitDestInRSCRATCH();
|
|
||||||
return true;
|
MOV(32, R(RSCRATCH), PPCSTATE(npc));
|
||||||
});
|
js.downcountAmount += js.st.numCycles;
|
||||||
|
WriteExitDestInRSCRATCH();
|
||||||
|
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,
|
||||||
|
@ -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);
|
||||||
return false;
|
|
||||||
|
|
||||||
LDR(IndexType::Unsigned, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(npc));
|
if (result.type != HLE::HookType::Replace)
|
||||||
js.downcountAmount += js.st.numCycles;
|
return false;
|
||||||
WriteExit(DISPATCHER_PC);
|
|
||||||
return true;
|
LDR(IndexType::Unsigned, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(npc));
|
||||||
});
|
js.downcountAmount += js.st.numCycles;
|
||||||
|
WriteExit(DISPATCHER_PC);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void JitArm64::DumpCode(const u8* start, const u8* end)
|
void JitArm64::DumpCode(const u8* start, const u8* end)
|
||||||
|
@ -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.
|
||||||
|
Reference in New Issue
Block a user