From a6637c257f3bdaa740b19ba4590ae42a3d45f62b Mon Sep 17 00:00:00 2001 From: skidau Date: Mon, 3 Jan 2011 10:39:48 +0000 Subject: [PATCH] LLE JIT: Reworked the block linking code. It now keeps track of what each block is waiting on, minimising the amount of recompiling. Both jumps and calls can now become linked. The code also checks the cycle count before jumping to the linked block. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6728 8ced0084-cf51-0410-be5f-012b33b47a6e --- Source/Core/DSPCore/Src/DSPAnalyzer.h | 3 +- Source/Core/DSPCore/Src/DSPEmitter.cpp | 78 ++++-------- Source/Core/DSPCore/Src/DSPEmitter.h | 5 +- Source/Core/DSPCore/Src/Jit/DSPJitBranch.cpp | 120 ++++++++----------- 4 files changed, 78 insertions(+), 128 deletions(-) diff --git a/Source/Core/DSPCore/Src/DSPAnalyzer.h b/Source/Core/DSPCore/Src/DSPAnalyzer.h index 6ccd8f771f..aeb3b9e480 100644 --- a/Source/Core/DSPCore/Src/DSPAnalyzer.h +++ b/Source/Core/DSPCore/Src/DSPAnalyzer.h @@ -32,8 +32,7 @@ enum CODE_IDLE_SKIP = 2, CODE_LOOP_START = 4, CODE_LOOP_END = 8, - CODE_CALL = 16, - CODE_UPDATE_SR = 32, + CODE_UPDATE_SR = 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 b887f2d0d7..5835196a60 100644 --- a/Source/Core/DSPCore/Src/DSPEmitter.cpp +++ b/Source/Core/DSPCore/Src/DSPEmitter.cpp @@ -31,9 +31,6 @@ using namespace Gen; const u8 *stubEntryPoint; -u16 blocksCompiled; -u16 unresolvedCalls; -u16 unresolvedCallsThisBlock; DSPEmitter::DSPEmitter() : storeIndex(-1), storeIndex2(-1) { @@ -59,8 +56,6 @@ DSPEmitter::DSPEmitter() : storeIndex(-1), storeIndex2(-1) blockLinks[i] = 0; blockSize[i] = 0; } - blocksCompiled = 0; - unresolvedCalls = 0; } DSPEmitter::~DSPEmitter() @@ -79,8 +74,6 @@ void DSPEmitter::ClearIRAM() { blockLinks[i] = 0; blockSize[i] = 0; } - blocksCompiled = 0; - unresolvedCalls = 0; } // Must go out of block if exception is detected @@ -196,41 +189,11 @@ void DSPEmitter::unknown_instruction(UDSPInstruction inst) PanicAlert("unknown_instruction %04x - Fix me ;)", inst); } -void DSPEmitter::ClearCallFlag() -{ - --unresolvedCallsThisBlock; -} - -void DSPEmitter::Compile(int start_addr) +void DSPEmitter::Compile(u16 start_addr) { // Remember the current block address for later startAddr = start_addr; - blocksCompiled++; - unresolvedCallsThisBlock = 0; - - // If the number of unresolved calls exceeds 8, there is a critical - // block that probably cannot be resolved. If this occurs, quit linking - // blocks. Currently occurs in the zelda ucode. - if (unresolvedCalls <= 8) - { - // 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; - unresolvedCalls = 0; - } - } + unresolvedJumps[start_addr].clear(); const u8 *entryPoint = AlignCode16(); ABI_PushAllCalleeSavedRegsAndAdjustStack(); @@ -288,19 +251,14 @@ 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 >= 0x0290 && opcode->opcode <= 0x029f) || - (opcode->opcode >= 0x02b0 && opcode->opcode <= 0x02bf))) - { - ++unresolvedCallsThisBlock; - } - EmitInstruction(inst); blockSize[start_addr]++; compilePC += opcode->size; + // If the block was trying to link into itself, remove the link + unresolvedJumps[start_addr].remove(compilePC); + fixup_pc = true; // Handle loop condition, only if current instruction was flagged as a loop destination @@ -411,16 +369,26 @@ void DSPEmitter::Compile(int start_addr) // Mark this block as a linkable destination if it does not contain // any unresolved CALL's - if (unresolvedCallsThisBlock == 0) + if (unresolvedJumps[start_addr].empty()) { - DSPAnalyzer::code_flags[start_addr] &= ~DSPAnalyzer::CODE_CALL; blockLinks[start_addr] = (CompiledCode)blockLinkEntry; - } - else - { - DSPAnalyzer::code_flags[start_addr] |= DSPAnalyzer::CODE_CALL; - blockLinks[start_addr] = 0; - ++unresolvedCalls; + + for(u16 i = 0x0000; i < 0xffff; ++i) + { + if (!unresolvedJumps[i].empty()) + { + // Check if there were any blocks waiting for this block to be linkable + int size = unresolvedJumps[i].size(); + unresolvedJumps[i].remove(start_addr); + if (unresolvedJumps[i].size() < size) + { + // Mark the block to be recompiled again + blocks[i] = (CompiledCode)stubEntryPoint; + blockLinks[i] = 0; + blockSize[i] = 0; + } + } + } } if (blockSize[start_addr] == 0) diff --git a/Source/Core/DSPCore/Src/DSPEmitter.h b/Source/Core/DSPCore/Src/DSPEmitter.h index 7e6030dab3..56749b228b 100644 --- a/Source/Core/DSPCore/Src/DSPEmitter.h +++ b/Source/Core/DSPCore/Src/DSPEmitter.h @@ -18,6 +18,8 @@ #ifndef _DSPEMITTER_H #define _DSPEMITTER_H +#include + #include "DSPCommon.h" #include "x64Emitter.h" @@ -41,7 +43,7 @@ public: void CompileDispatcher(); const u8 *CompileStub(); - void Compile(int start_addr); + void Compile(u16 start_addr); void ClearCallFlag(); void Default(UDSPInstruction inst); @@ -252,6 +254,7 @@ public: u16 startAddr; CompiledCode *blockLinks; u16 *blockSize; + std::list unresolvedJumps[0x10000]; private: CompiledCode *blocks; diff --git a/Source/Core/DSPCore/Src/Jit/DSPJitBranch.cpp b/Source/Core/DSPCore/Src/Jit/DSPJitBranch.cpp index 512b36e969..2cf41b61c5 100644 --- a/Source/Core/DSPCore/Src/Jit/DSPJitBranch.cpp +++ b/Source/Core/DSPCore/Src/Jit/DSPJitBranch.cpp @@ -162,49 +162,58 @@ void WriteBranchExit(DSPEmitter& emitter) emitter.RET(); } +void WriteBlockLink(DSPEmitter& emitter, u16 dest) +{ + // Jump directly to the called block if it has already been compiled. + if (!(dest >= emitter.startAddr && dest <= emitter.compilePC)) + { + if (emitter.blockLinks[dest] != 0 ) + { +#ifdef _M_IX86 // All32 + // Check if we have enough cycles to execute the next block + emitter.MOV(16, R(ESI), M(&cyclesLeft)); + emitter.CMP(16, R(ESI), Imm16(emitter.blockSize[emitter.startAddr] + emitter.blockSize[dest])); + FixupBranch notEnoughCycles = emitter.J_CC(CC_BE); + + emitter.SUB(16, R(ESI), Imm16(emitter.blockSize[emitter.startAddr])); + emitter.MOV(16, M(&cyclesLeft), R(ESI)); + emitter.JMPptr(M(&emitter.blockLinks[dest])); + + emitter.SetJumpTarget(notEnoughCycles); +#else + // Check if we have enough cycles to execute the next block + emitter.CMP(16, R(R12), Imm16(emitter.blockSize[emitter.startAddr] + emitter.blockSize[dest])); + FixupBranch notEnoughCycles = emitter.J_CC(CC_BE); + + emitter.SUB(16, R(R12), Imm16(emitter.blockSize[emitter.startAddr])); + emitter.MOV(64, R(RAX), ImmPtr((void *)emitter.blockLinks[dest])); + emitter.JMPptr(R(RAX)); + + emitter.SetJumpTarget(notEnoughCycles); +#endif + } + else + { + // The destination has not been compiled yet. Add it to the list + // of blocks that this block is waiting on. + emitter.unresolvedJumps[emitter.startAddr].push_back(dest); + } + } +} + void r_jcc(const UDSPInstruction opc, DSPEmitter& emitter) { u16 dest = dsp_imem_read(emitter.compilePC + 1); + const DSPOPCTemplate *opcode = GetOpTemplate(opc); + + // If the block is unconditional, attempt to link block + if (opcode->uncond_branch) + WriteBlockLink(emitter, dest); #ifdef _M_IX86 // All32 emitter.MOV(16, M(&(g_dsp.pc)), Imm16(dest)); - - // Jump directly to the called block if it has already been compiled. - if (emitter.blockLinks[dest]) - { - // Check if we have enough cycles to execute the next block - emitter.MOV(16, R(ESI), M(&cyclesLeft)); - emitter.CMP(16, R(ESI), Imm16(emitter.blockSize[emitter.startAddr] + emitter.blockSize[dest])); - FixupBranch notEnoughCycles = emitter.J_CC(CC_BE); - - emitter.SUB(16, R(ESI), Imm16(emitter.blockSize[emitter.startAddr])); - emitter.MOV(16, M(&cyclesLeft), R(ESI)); - emitter.JMPptr(M(&emitter.blockLinks[dest])); - emitter.ClearCallFlag(); - - emitter.SetJumpTarget(notEnoughCycles); - } #else emitter.MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); emitter.MOV(16, MatR(RAX), Imm16(dest)); - - // Jump directly to the next block if it has already been compiled. - if (emitter.blockLinks[dest]) - { - // Check if we have enough cycles to execute the next block - //emitter.MOV(64, R(R12), ImmPtr(&cyclesLeft)); - //emitter.MOV(16, R(RAX), MatR(R12)); - //emitter.CMP(16, R(RAX), Imm16(emitter.blockSize[emitter.startAddr] + emitter.blockSize[dest])); - //FixupBranch notEnoughCycles = emitter.J_CC(CC_BE); - - //emitter.SUB(16, R(RAX), Imm16(emitter.blockSize[emitter.startAddr])); - //emitter.MOV(16, MatR(R12), R(RAX)); - - //emitter.MOV(64, R(RAX), ImmPtr((void *)(emitter.blockLinks[dest]))); - //emitter.JMPptr(R(RAX)); - //emitter.ClearCallFlag(); - - //emitter.SetJumpTarget(notEnoughCycles); - } #endif WriteBranchExit(emitter); } @@ -261,48 +270,19 @@ void DSPEmitter::jmprcc(const UDSPInstruction opc) void r_call(const UDSPInstruction opc, DSPEmitter& emitter) { - u16 dest = dsp_imem_read(emitter.compilePC + 1); emitter.MOV(16, R(DX), Imm16(emitter.compilePC + 2)); emitter.dsp_reg_store_stack(DSP_STACK_C); + u16 dest = dsp_imem_read(emitter.compilePC + 1); + const DSPOPCTemplate *opcode = GetOpTemplate(opc); + + // If the block is unconditional, attempt to link block + if (opcode->uncond_branch) + WriteBlockLink(emitter, dest); #ifdef _M_IX86 // All32 emitter.MOV(16, M(&(g_dsp.pc)), Imm16(dest)); - - // Jump directly to the called block if it has already been compiled. - if (emitter.blockLinks[dest]) - { - // Check if we have enough cycles to execute the next block - //emitter.MOV(16, R(ESI), M(&cyclesLeft)); - //emitter.CMP(16, R(ESI), Imm16(emitter.blockSize[emitter.startAddr] + emitter.blockSize[dest])); - //FixupBranch notEnoughCycles = emitter.J_CC(CC_BE); - - //emitter.SUB(16, R(ESI), Imm16(emitter.blockSize[emitter.startAddr])); - //emitter.MOV(16, M(&cyclesLeft), R(ESI)); - //emitter.JMPptr(M(&emitter.blockLinks[dest])); - //emitter.ClearCallFlag(); - - //emitter.SetJumpTarget(notEnoughCycles); - } #else emitter.MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); emitter.MOV(16, MatR(RAX), Imm16(dest)); - - // Jump directly to the called block if it has already been compiled. - if (emitter.blockLinks[dest]) - { - // Check if we have enough cycles to execute the next block - emitter.MOV(64, R(R12), ImmPtr(&cyclesLeft)); - emitter.MOV(16, R(RAX), MatR(R12)); - emitter.CMP(16, R(RAX), Imm16(emitter.blockSize[emitter.startAddr] + emitter.blockSize[dest])); - FixupBranch notEnoughCycles = emitter.J_CC(CC_BE); - - emitter.SUB(16, R(RAX), Imm16(emitter.blockSize[emitter.startAddr])); - emitter.MOV(16, MatR(R12), R(RAX)); - emitter.MOV(64, R(RAX), ImmPtr((void *)(emitter.blockLinks[dest]))); - emitter.JMPptr(R(RAX)); - emitter.ClearCallFlag(); - - emitter.SetJumpTarget(notEnoughCycles); - } #endif WriteBranchExit(emitter); }