mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-17 08:20:30 +02:00
ARM64 IR JIT: Look up the block for a jump to a register at the jump
Each jr and jalr now does the dispatcher's lookup itself, so each has its own indirect branch, which the CPU predicts much better than the one in the dispatcher that every one of them shared. Out of downcount or with no block yet, it goes to the dispatcher as before. Cycles over 10 emulated seconds: -2.3% in ATV, -1.4% Tekken 6 and Ridge Racer, -1.2% Daxter, -1.1% Killzone, and -0.3% to -0.8% in the rest. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
f247df5e4d
commit
e33f38afa6
2 files changed
+30
-3
No files matched your search
@@ -51,7 +51,23 @@ void Arm64JitBackend::CompIR_Exit(IRInst inst) {
|
||||
exitReg = regs_.MapGPR(inst.src1);
|
||||
FlushAll();
|
||||
MOV(SCRATCH1, exitReg);
|
||||
B(dispatcherPCInSCRATCH1_);
|
||||
// The dispatcher's lookup, here: each of these then has its own indirect branch, which the
|
||||
// CPU predicts far better than one shared by every jr. Anything unusual goes the long way.
|
||||
MovToPC(SCRATCH1);
|
||||
{
|
||||
// Out of the downcount, or no block yet: the dispatcher, with the PC stored.
|
||||
FixupBranch inTime = TBZ(DOWNCOUNTREG, 31);
|
||||
B(hooks_.dispatcher);
|
||||
SetJumpTarget(inTime);
|
||||
ANDI2R(SCRATCH1, SCRATCH1, Memory::BLOCK_SHADOW_ENTRY_MASK);
|
||||
MOVP2R(SCRATCH2_64, Memory::blockShadow);
|
||||
LDR(SCRATCH1, SCRATCH2_64, SCRATCH1_64);
|
||||
FixupBranch found = CBNZ(SCRATCH1);
|
||||
B(dispatcherNoCheck_);
|
||||
SetJumpTarget(found);
|
||||
ADD(SCRATCH1_64, JITBASEREG, SCRATCH1_64);
|
||||
BR(SCRATCH1_64);
|
||||
}
|
||||
break;
|
||||
|
||||
case IROp::ExitToPC:
|
||||
|
||||
@@ -75,8 +75,19 @@ bool Arm64JitBackend::CompileBlock(IRBlockCache *irBlockCache, int block_num) {
|
||||
// An accurate dot product can flush several registers around its call.
|
||||
size_t sizeEstimate = 0;
|
||||
const IRInst *estimateInsts = irBlockCache->GetBlockInstructionPtr(*block);
|
||||
for (int i = 0; i < block->GetNumIRInstructions(); ++i)
|
||||
sizeEstimate += estimateInsts[i].op == IROp::Vec4VfpuDot || estimateInsts[i].op == IROp::Vec4VfpuMultiDot ? 96 : 32;
|
||||
for (int i = 0; i < block->GetNumIRInstructions(); ++i) {
|
||||
switch (estimateInsts[i].op) {
|
||||
case IROp::Vec4VfpuDot:
|
||||
case IROp::Vec4VfpuMultiDot:
|
||||
// The jump to a register looks up the block itself.
|
||||
case IROp::ExitToReg:
|
||||
sizeEstimate += 96;
|
||||
break;
|
||||
default:
|
||||
sizeEstimate += 32;
|
||||
break;
|
||||
}
|
||||
}
|
||||
BeginWrite(std::min(GetSpaceLeft(), sizeEstimate));
|
||||
|
||||
u32 startPC = block->GetOriginalStart();
|
||||
|
||||
Reference in new issue
Block a user