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:
parent
aee96e12c6
commit
a90d0e8985
|
@ -32,6 +32,7 @@ enum
|
||||||
CODE_IDLE_SKIP = 2,
|
CODE_IDLE_SKIP = 2,
|
||||||
CODE_LOOP_START = 4,
|
CODE_LOOP_START = 4,
|
||||||
CODE_LOOP_END = 8,
|
CODE_LOOP_END = 8,
|
||||||
|
CODE_CALL = 16,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Easy to query array covering the whole of instruction memory.
|
// Easy to query array covering the whole of instruction memory.
|
||||||
|
|
|
@ -31,6 +31,9 @@
|
||||||
using namespace Gen;
|
using namespace Gen;
|
||||||
|
|
||||||
const u8 *stubEntryPoint;
|
const u8 *stubEntryPoint;
|
||||||
|
u16 blocksCompiled;
|
||||||
|
u16 unresolvedCalls;
|
||||||
|
int startAddr;
|
||||||
|
|
||||||
DSPEmitter::DSPEmitter() : storeIndex(-1), storeIndex2(-1)
|
DSPEmitter::DSPEmitter() : storeIndex(-1), storeIndex2(-1)
|
||||||
{
|
{
|
||||||
|
@ -56,6 +59,8 @@ DSPEmitter::DSPEmitter() : storeIndex(-1), storeIndex2(-1)
|
||||||
blockLinks[i] = 0;
|
blockLinks[i] = 0;
|
||||||
blockSize[i] = 0;
|
blockSize[i] = 0;
|
||||||
}
|
}
|
||||||
|
blocksCompiled = 0;
|
||||||
|
unresolvedCalls = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
DSPEmitter::~DSPEmitter()
|
DSPEmitter::~DSPEmitter()
|
||||||
|
@ -74,6 +79,8 @@ void DSPEmitter::ClearIRAM() {
|
||||||
blockLinks[i] = 0;
|
blockLinks[i] = 0;
|
||||||
blockSize[i] = 0;
|
blockSize[i] = 0;
|
||||||
}
|
}
|
||||||
|
blocksCompiled = 0;
|
||||||
|
unresolvedCalls = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Must go out of block if exception is detected
|
// Must go out of block if exception is detected
|
||||||
|
@ -183,8 +190,41 @@ void DSPEmitter::Default(UDSPInstruction _inst)
|
||||||
EmitInstruction(_inst);
|
EmitInstruction(_inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DSPEmitter::ClearCallFlag()
|
||||||
|
{
|
||||||
|
DSPAnalyzer::code_flags[startAddr] &= ~DSPAnalyzer::CODE_CALL;
|
||||||
|
--unresolvedCalls;
|
||||||
|
}
|
||||||
|
|
||||||
void DSPEmitter::Compile(int start_addr)
|
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();
|
const u8 *entryPoint = AlignCode16();
|
||||||
ABI_PushAllCalleeSavedRegsAndAdjustStack();
|
ABI_PushAllCalleeSavedRegsAndAdjustStack();
|
||||||
// ABI_AlignStack(0);
|
// ABI_AlignStack(0);
|
||||||
|
@ -222,6 +262,13 @@ void DSPEmitter::Compile(int start_addr)
|
||||||
UDSPInstruction inst = dsp_imem_read(compilePC);
|
UDSPInstruction inst = dsp_imem_read(compilePC);
|
||||||
const DSPOPCTemplate *opcode = GetOpTemplate(inst);
|
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);
|
EmitInstruction(inst);
|
||||||
|
|
||||||
blockSize[start_addr]++;
|
blockSize[start_addr]++;
|
||||||
|
@ -334,7 +381,12 @@ void DSPEmitter::Compile(int start_addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
blocks[start_addr] = (CompiledCode)entryPoint;
|
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;
|
blockLinks[start_addr] = (CompiledCode)blockLinkEntry;
|
||||||
|
|
||||||
if (blockSize[start_addr] == 0)
|
if (blockSize[start_addr] == 0)
|
||||||
{
|
{
|
||||||
// just a safeguard, should never happen anymore.
|
// just a safeguard, should never happen anymore.
|
||||||
|
|
|
@ -43,6 +43,7 @@ public:
|
||||||
void CompileDispatcher();
|
void CompileDispatcher();
|
||||||
const u8 *CompileStub();
|
const u8 *CompileStub();
|
||||||
void Compile(int start_addr);
|
void Compile(int start_addr);
|
||||||
|
void ClearCallFlag();
|
||||||
|
|
||||||
void MainOpFallback(UDSPInstruction inst);
|
void MainOpFallback(UDSPInstruction inst);
|
||||||
|
|
||||||
|
|
|
@ -156,6 +156,7 @@ void r_jcc(const UDSPInstruction opc, DSPEmitter& emitter)
|
||||||
{
|
{
|
||||||
emitter.MOV(64, R(RAX), ImmPtr((void *)(emitter.blockLinks[dest])));
|
emitter.MOV(64, R(RAX), ImmPtr((void *)(emitter.blockLinks[dest])));
|
||||||
emitter.JMPptr(R(RAX));
|
emitter.JMPptr(R(RAX));
|
||||||
|
emitter.ClearCallFlag();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -222,6 +223,7 @@ void r_call(const UDSPInstruction opc, DSPEmitter& emitter)
|
||||||
{
|
{
|
||||||
emitter.MOV(64, R(RAX), ImmPtr((void *)(emitter.blockLinks[dest])));
|
emitter.MOV(64, R(RAX), ImmPtr((void *)(emitter.blockLinks[dest])));
|
||||||
emitter.JMPptr(R(RAX));
|
emitter.JMPptr(R(RAX));
|
||||||
|
emitter.ClearCallFlag();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue