CachedInterpreter: Combine Interpret, CheckDSI, CheckProgram, and WritePC

I tried making the new templated Interpret callback test only the relevant exceptions (EXCEPTION_DSI, EXCEPTION_PROGRAM, or both), but didn't find a significant performance boost in it. As I am learning, the biggest bottleneck is the number of callbacks emitted, not usually the actual contents of them.
This commit is contained in:
mitaclaw 2024-05-05 21:34:52 -07:00
parent ae43b10eff
commit 6c3024c3b1
2 changed files with 63 additions and 53 deletions

View File

@ -98,11 +98,37 @@ s32 CachedInterpreter::EndBlock(PowerPC::PowerPCState& ppc_state, const EndBlock
return 0; return 0;
} }
template <bool write_pc>
s32 CachedInterpreter::Interpret(PowerPC::PowerPCState& ppc_state, s32 CachedInterpreter::Interpret(PowerPC::PowerPCState& ppc_state,
const InterpretOperands& operands) const InterpretOperands& operands)
{ {
const auto& [interpreter, func, current_pc, inst] = operands; if constexpr (write_pc)
func(interpreter, inst); {
ppc_state.pc = operands.current_pc;
ppc_state.npc = operands.current_pc + 4;
}
operands.func(operands.interpreter, operands.inst);
return sizeof(AnyCallback) + sizeof(operands);
}
template <bool write_pc>
s32 CachedInterpreter::InterpretAndCheckExceptions(
PowerPC::PowerPCState& ppc_state, const InterpretAndCheckExceptionsOperands& operands)
{
if constexpr (write_pc)
{
ppc_state.pc = operands.current_pc;
ppc_state.npc = operands.current_pc + 4;
}
operands.func(operands.interpreter, operands.inst);
if ((ppc_state.Exceptions & (EXCEPTION_DSI | EXCEPTION_PROGRAM)) != 0)
{
ppc_state.pc = operands.current_pc;
ppc_state.downcount -= operands.downcount;
operands.power_pc.CheckExceptions();
return 0;
}
return sizeof(AnyCallback) + sizeof(operands); return sizeof(AnyCallback) + sizeof(operands);
} }
@ -115,16 +141,8 @@ s32 CachedInterpreter::HLEFunction(PowerPC::PowerPCState& ppc_state,
return sizeof(AnyCallback) + sizeof(operands); return sizeof(AnyCallback) + sizeof(operands);
} }
s32 CachedInterpreter::WritePC(PowerPC::PowerPCState& ppc_state, const WritePCOperands& operands)
{
const auto& [current_pc] = operands;
ppc_state.pc = current_pc;
ppc_state.npc = current_pc + 4;
return sizeof(AnyCallback) + sizeof(operands);
}
s32 CachedInterpreter::WriteBrokenBlockNPC(PowerPC::PowerPCState& ppc_state, s32 CachedInterpreter::WriteBrokenBlockNPC(PowerPC::PowerPCState& ppc_state,
const WritePCOperands& operands) const WriteBrokenBlockNPCOperands& operands)
{ {
const auto& [current_pc] = operands; const auto& [current_pc] = operands;
ppc_state.npc = current_pc; ppc_state.npc = current_pc;
@ -145,33 +163,6 @@ s32 CachedInterpreter::CheckFPU(PowerPC::PowerPCState& ppc_state, const CheckHal
return sizeof(AnyCallback) + sizeof(operands); return sizeof(AnyCallback) + sizeof(operands);
} }
s32 CachedInterpreter::CheckDSI(PowerPC::PowerPCState& ppc_state, const CheckHaltOperands& operands)
{
const auto& [power_pc, current_pc, downcount] = operands;
if ((ppc_state.Exceptions & EXCEPTION_DSI) != 0)
{
ppc_state.pc = current_pc;
ppc_state.downcount -= downcount;
power_pc.CheckExceptions();
return 0;
}
return sizeof(AnyCallback) + sizeof(operands);
}
s32 CachedInterpreter::CheckProgramException(PowerPC::PowerPCState& ppc_state,
const CheckHaltOperands& operands)
{
const auto& [power_pc, current_pc, downcount] = operands;
if ((ppc_state.Exceptions & EXCEPTION_PROGRAM) != 0)
{
ppc_state.pc = current_pc;
ppc_state.downcount -= downcount;
power_pc.CheckExceptions();
return 0;
}
return sizeof(AnyCallback) + sizeof(operands);
}
s32 CachedInterpreter::CheckBreakpoint(PowerPC::PowerPCState& ppc_state, s32 CachedInterpreter::CheckBreakpoint(PowerPC::PowerPCState& ppc_state,
const CheckHaltOperands& operands) const CheckHaltOperands& operands)
{ {
@ -344,14 +335,25 @@ bool CachedInterpreter::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
js.firstFPInstructionFound = true; js.firstFPInstructionFound = true;
} }
if (op.canEndBlock) // Instruction may cause a DSI Exception or Program Exception.
Write(WritePC, {js.compilerPC}); if ((jo.memcheck && (op.opinfo->flags & FL_LOADSTORE) != 0) ||
Write(Interpret, (!op.canEndBlock && ShouldHandleFPExceptionForInstruction(&op)))
{interpreter, Interpreter::GetInterpreterOp(op.inst), js.compilerPC, op.inst}); {
if (jo.memcheck && (op.opinfo->flags & FL_LOADSTORE) != 0) const InterpretAndCheckExceptionsOperands operands = {
Write(CheckDSI, {power_pc, js.compilerPC, js.downcountAmount}); {interpreter, Interpreter::GetInterpreterOp(op.inst), js.compilerPC, op.inst},
if (!op.canEndBlock && ShouldHandleFPExceptionForInstruction(&op)) power_pc,
Write(CheckProgramException, {power_pc, js.compilerPC, js.downcountAmount}); js.downcountAmount};
Write(op.canEndBlock ? InterpretAndCheckExceptions<true> :
InterpretAndCheckExceptions<false>,
operands);
}
else
{
const InterpretOperands operands = {interpreter, Interpreter::GetInterpreterOp(op.inst),
js.compilerPC, op.inst};
Write(op.canEndBlock ? Interpret<true> : Interpret<false>, operands);
}
if (op.branchIsIdleLoop) if (op.branchIsIdleLoop)
Write(CheckIdle, {m_system.GetCoreTiming(), js.blockStart}); Write(CheckIdle, {m_system.GetCoreTiming(), js.blockStart});
if (op.canEndBlock) if (op.canEndBlock)

View File

@ -64,20 +64,22 @@ private:
struct EndBlockOperands; struct EndBlockOperands;
struct InterpretOperands; struct InterpretOperands;
struct InterpretAndCheckExceptionsOperands;
struct HLEFunctionOperands; struct HLEFunctionOperands;
struct WritePCOperands; struct WriteBrokenBlockNPCOperands;
struct CheckHaltOperands; struct CheckHaltOperands;
struct CheckIdleOperands; struct CheckIdleOperands;
static s32 EndBlock(PowerPC::PowerPCState& ppc_state, const EndBlockOperands& operands); static s32 EndBlock(PowerPC::PowerPCState& ppc_state, const EndBlockOperands& operands);
template <bool write_pc>
static s32 Interpret(PowerPC::PowerPCState& ppc_state, const InterpretOperands& operands); static s32 Interpret(PowerPC::PowerPCState& ppc_state, const InterpretOperands& operands);
template <bool write_pc>
static s32 InterpretAndCheckExceptions(PowerPC::PowerPCState& ppc_state,
const InterpretAndCheckExceptionsOperands& operands);
static s32 HLEFunction(PowerPC::PowerPCState& ppc_state, const HLEFunctionOperands& operands); static s32 HLEFunction(PowerPC::PowerPCState& ppc_state, const HLEFunctionOperands& operands);
static s32 WritePC(PowerPC::PowerPCState& ppc_state, const WritePCOperands& operands); static s32 WriteBrokenBlockNPC(PowerPC::PowerPCState& ppc_state,
static s32 WriteBrokenBlockNPC(PowerPC::PowerPCState& ppc_state, const WritePCOperands& operands); const WriteBrokenBlockNPCOperands& operands);
static s32 CheckFPU(PowerPC::PowerPCState& ppc_state, const CheckHaltOperands& operands); static s32 CheckFPU(PowerPC::PowerPCState& ppc_state, const CheckHaltOperands& operands);
static s32 CheckDSI(PowerPC::PowerPCState& ppc_state, const CheckHaltOperands& operands);
static s32 CheckProgramException(PowerPC::PowerPCState& ppc_state,
const CheckHaltOperands& operands);
static s32 CheckBreakpoint(PowerPC::PowerPCState& ppc_state, const CheckHaltOperands& operands); static s32 CheckBreakpoint(PowerPC::PowerPCState& ppc_state, const CheckHaltOperands& operands);
static s32 CheckIdle(PowerPC::PowerPCState& ppc_state, const CheckIdleOperands& operands); static s32 CheckIdle(PowerPC::PowerPCState& ppc_state, const CheckIdleOperands& operands);
@ -101,6 +103,12 @@ struct CachedInterpreter::InterpretOperands
UGeckoInstruction inst; UGeckoInstruction inst;
}; };
struct CachedInterpreter::InterpretAndCheckExceptionsOperands : InterpretOperands
{
PowerPC::PowerPCManager& power_pc;
u32 downcount;
};
struct CachedInterpreter::HLEFunctionOperands struct CachedInterpreter::HLEFunctionOperands
{ {
Core::System& system; Core::System& system;
@ -108,7 +116,7 @@ struct CachedInterpreter::HLEFunctionOperands
u32 hook_index; u32 hook_index;
}; };
struct CachedInterpreter::WritePCOperands struct CachedInterpreter::WriteBrokenBlockNPCOperands
{ {
u32 current_pc; u32 current_pc;
u32 : 32; u32 : 32;