From a90d0e898560082f2bd3f9f3249afc116e51ed5c Mon Sep 17 00:00:00 2001 From: skidau Date: Wed, 15 Dec 2010 22:13:31 +0000 Subject: [PATCH] LLE JIT: Used a reiterative approach to linking blocks. The JIT flags blocks that have calls to blocks which have not yet been compiled. After more blocks have been compiled, the JIT reattempts to link the flagged blocks. This is repeated until the minimum number of unlinked blocks are left. This increases the success rate of the block linker and resultant speed up. Based on an idea by nakee. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6589 8ced0084-cf51-0410-be5f-012b33b47a6e --- Source/Core/DSPCore/Src/DSPAnalyzer.h | 1 + Source/Core/DSPCore/Src/DSPEmitter.cpp | 54 +++++++++++++++++++- Source/Core/DSPCore/Src/DSPEmitter.h | 1 + Source/Core/DSPCore/Src/Jit/DSPJitBranch.cpp | 2 + 4 files changed, 57 insertions(+), 1 deletion(-) diff --git a/Source/Core/DSPCore/Src/DSPAnalyzer.h b/Source/Core/DSPCore/Src/DSPAnalyzer.h index 135e3e70a7..541b76147c 100644 --- a/Source/Core/DSPCore/Src/DSPAnalyzer.h +++ b/Source/Core/DSPCore/Src/DSPAnalyzer.h @@ -32,6 +32,7 @@ enum CODE_IDLE_SKIP = 2, CODE_LOOP_START = 4, CODE_LOOP_END = 8, + CODE_CALL = 16, }; // Easy to query array covering the whole of instruction memory. diff --git a/Source/Core/DSPCore/Src/DSPEmitter.cpp b/Source/Core/DSPCore/Src/DSPEmitter.cpp index 27c636d6dc..d251a8ce75 100644 --- a/Source/Core/DSPCore/Src/DSPEmitter.cpp +++ b/Source/Core/DSPCore/Src/DSPEmitter.cpp @@ -31,6 +31,9 @@ using namespace Gen; const u8 *stubEntryPoint; +u16 blocksCompiled; +u16 unresolvedCalls; +int startAddr; DSPEmitter::DSPEmitter() : storeIndex(-1), storeIndex2(-1) { @@ -56,6 +59,8 @@ DSPEmitter::DSPEmitter() : storeIndex(-1), storeIndex2(-1) blockLinks[i] = 0; blockSize[i] = 0; } + blocksCompiled = 0; + unresolvedCalls = 0; } DSPEmitter::~DSPEmitter() @@ -74,6 +79,8 @@ void DSPEmitter::ClearIRAM() { blockLinks[i] = 0; blockSize[i] = 0; } + blocksCompiled = 0; + unresolvedCalls = 0; } // Must go out of block if exception is detected @@ -183,8 +190,41 @@ void DSPEmitter::Default(UDSPInstruction _inst) EmitInstruction(_inst); } +void DSPEmitter::ClearCallFlag() +{ + DSPAnalyzer::code_flags[startAddr] &= ~DSPAnalyzer::CODE_CALL; + --unresolvedCalls; +} + void DSPEmitter::Compile(int start_addr) { + // Remember the current block address for later + startAddr = start_addr; + blocksCompiled++; + + // If the number of unresolved calls exceeds 50, there is a critical + // block that probably cannot be resolved. If this occurs, quit linking + // blocks. Currently occurs in the zelda ucode. + if (unresolvedCalls <= 50) + { + // After every 10 blocks, clear out the blocks that have unresolved + // calls, and reattempt relinking. + if (blocksCompiled >= 10 && unresolvedCalls > 0) + { + for(int i = 0x0000; i < MAX_BLOCKS; ++i) + { + if (DSPAnalyzer::code_flags[i] & DSPAnalyzer::CODE_CALL) + { + blocks[i] = (CompiledCode)stubEntryPoint; + blockLinks[i] = 0; + blockSize[i] = 0; + } + } + // Reset and reattempt relinking + blocksCompiled = 0; + } + } + const u8 *entryPoint = AlignCode16(); ABI_PushAllCalleeSavedRegsAndAdjustStack(); // ABI_AlignStack(0); @@ -222,6 +262,13 @@ void DSPEmitter::Compile(int start_addr) UDSPInstruction inst = dsp_imem_read(compilePC); const DSPOPCTemplate *opcode = GetOpTemplate(inst); + // Scan for CALL's to delay block link. TODO: Scan for J_CC after it is jitted. + if (opcode->jitFunc && (opcode->opcode >= 0x02b0 && opcode->opcode <= 0x02bf)) + { + DSPAnalyzer::code_flags[start_addr] |= DSPAnalyzer::CODE_CALL; + ++unresolvedCalls; + } + EmitInstruction(inst); blockSize[start_addr]++; @@ -334,7 +381,12 @@ void DSPEmitter::Compile(int start_addr) } blocks[start_addr] = (CompiledCode)entryPoint; - blockLinks[start_addr] = (CompiledCode)blockLinkEntry; + + // Mark this block as a linkable destination if it does not contain + // any unresolved CALL's + if (!(DSPAnalyzer::code_flags[start_addr] & DSPAnalyzer::CODE_CALL)) + blockLinks[start_addr] = (CompiledCode)blockLinkEntry; + if (blockSize[start_addr] == 0) { // just a safeguard, should never happen anymore. diff --git a/Source/Core/DSPCore/Src/DSPEmitter.h b/Source/Core/DSPCore/Src/DSPEmitter.h index a5fb0f2f0c..0571f87f6d 100644 --- a/Source/Core/DSPCore/Src/DSPEmitter.h +++ b/Source/Core/DSPCore/Src/DSPEmitter.h @@ -43,6 +43,7 @@ public: void CompileDispatcher(); const u8 *CompileStub(); void Compile(int start_addr); + void ClearCallFlag(); void MainOpFallback(UDSPInstruction inst); diff --git a/Source/Core/DSPCore/Src/Jit/DSPJitBranch.cpp b/Source/Core/DSPCore/Src/Jit/DSPJitBranch.cpp index a7accf046b..551b6d26f6 100644 --- a/Source/Core/DSPCore/Src/Jit/DSPJitBranch.cpp +++ b/Source/Core/DSPCore/Src/Jit/DSPJitBranch.cpp @@ -156,6 +156,7 @@ void r_jcc(const UDSPInstruction opc, DSPEmitter& emitter) { emitter.MOV(64, R(RAX), ImmPtr((void *)(emitter.blockLinks[dest]))); emitter.JMPptr(R(RAX)); + emitter.ClearCallFlag(); } #endif } @@ -222,6 +223,7 @@ void r_call(const UDSPInstruction opc, DSPEmitter& emitter) { emitter.MOV(64, R(RAX), ImmPtr((void *)(emitter.blockLinks[dest]))); emitter.JMPptr(R(RAX)); + emitter.ClearCallFlag(); } #endif }