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
This commit is contained in:
skidau 2010-12-15 22:13:31 +00:00
parent aee96e12c6
commit a90d0e8985
4 changed files with 57 additions and 1 deletions

View File

@ -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.

View File

@ -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;
// 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.

View File

@ -43,6 +43,7 @@ public:
void CompileDispatcher();
const u8 *CompileStub();
void Compile(int start_addr);
void ClearCallFlag();
void MainOpFallback(UDSPInstruction inst);

View File

@ -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
}