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;
}
template <bool write_pc>
s32 CachedInterpreter::Interpret(PowerPC::PowerPCState& ppc_state,
const InterpretOperands& operands)
{
const auto& [interpreter, func, current_pc, inst] = operands;
func(interpreter, inst);
if constexpr (write_pc)
{
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);
}
@ -115,16 +141,8 @@ s32 CachedInterpreter::HLEFunction(PowerPC::PowerPCState& ppc_state,
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,
const WritePCOperands& operands)
const WriteBrokenBlockNPCOperands& operands)
{
const auto& [current_pc] = operands;
ppc_state.npc = current_pc;
@ -145,33 +163,6 @@ s32 CachedInterpreter::CheckFPU(PowerPC::PowerPCState& ppc_state, const CheckHal
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,
const CheckHaltOperands& operands)
{
@ -344,14 +335,25 @@ bool CachedInterpreter::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
js.firstFPInstructionFound = true;
}
if (op.canEndBlock)
Write(WritePC, {js.compilerPC});
Write(Interpret,
{interpreter, Interpreter::GetInterpreterOp(op.inst), js.compilerPC, op.inst});
if (jo.memcheck && (op.opinfo->flags & FL_LOADSTORE) != 0)
Write(CheckDSI, {power_pc, js.compilerPC, js.downcountAmount});
if (!op.canEndBlock && ShouldHandleFPExceptionForInstruction(&op))
Write(CheckProgramException, {power_pc, js.compilerPC, js.downcountAmount});
// Instruction may cause a DSI Exception or Program Exception.
if ((jo.memcheck && (op.opinfo->flags & FL_LOADSTORE) != 0) ||
(!op.canEndBlock && ShouldHandleFPExceptionForInstruction(&op)))
{
const InterpretAndCheckExceptionsOperands operands = {
{interpreter, Interpreter::GetInterpreterOp(op.inst), js.compilerPC, op.inst},
power_pc,
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)
Write(CheckIdle, {m_system.GetCoreTiming(), js.blockStart});
if (op.canEndBlock)

View File

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