Merge pull request #1809 from magumagu/simplify-isi

JIT: simplify ISI handling.
This commit is contained in:
skidau 2015-01-04 20:31:16 +11:00
commit b06a3fb144
9 changed files with 51 additions and 80 deletions

View File

@ -500,14 +500,7 @@ void Jit64::Jit(u32 em_address)
ClearCache(); ClearCache();
} }
int block_num = blocks.AllocateBlock(em_address); int blockSize = code_buffer.GetSize();
JitBlock *b = blocks.GetBlock(block_num);
blocks.FinalizeBlock(block_num, jo.enableBlocklink, DoJit(em_address, &code_buffer, b));
}
const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlock *b)
{
int blockSize = code_buf->GetSize();
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bEnableDebugging) if (SConfig::GetInstance().m_LocalCoreStartupParameter.bEnableDebugging)
{ {
@ -532,6 +525,26 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
} }
} }
// Analyze the block, collect all instructions it is made of (including inlining,
// if that is enabled), reorder instructions for optimal performance, and join joinable instructions.
u32 nextPC = analyzer.Analyze(em_address, &code_block, &code_buffer, blockSize);
if (code_block.m_memory_exception)
{
// Address of instruction could not be translated
NPC = nextPC;
PowerPC::ppcState.Exceptions |= EXCEPTION_ISI;
PowerPC::CheckExceptions();
return;
}
int block_num = blocks.AllocateBlock(em_address);
JitBlock *b = blocks.GetBlock(block_num);
blocks.FinalizeBlock(block_num, jo.enableBlocklink, DoJit(em_address, &code_buffer, b, nextPC));
}
const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlock *b, u32 nextPC)
{
js.firstFPInstructionFound = false; js.firstFPInstructionFound = false;
js.isLastInstruction = false; js.isLastInstruction = false;
js.blockStart = em_address; js.blockStart = em_address;
@ -540,10 +553,6 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
jit->js.numLoadStoreInst = 0; jit->js.numLoadStoreInst = 0;
jit->js.numFloatingPointInst = 0; jit->js.numFloatingPointInst = 0;
// Analyze the block, collect all instructions it is made of (including inlining,
// if that is enabled), reorder instructions for optimal performance, and join joinable instructions.
u32 nextPC = analyzer.Analyze(em_address, &code_block, code_buf, blockSize);
PPCAnalyst::CodeOp *ops = code_buf->codebuffer; PPCAnalyst::CodeOp *ops = code_buf->codebuffer;
const u8 *start = AlignCode4(); // TODO: Test if this or AlignCode16 make a difference from GetCodePtr const u8 *start = AlignCode4(); // TODO: Test if this or AlignCode16 make a difference from GetCodePtr
@ -594,7 +603,6 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
js.skipnext = false; js.skipnext = false;
js.carryFlagSet = false; js.carryFlagSet = false;
js.carryFlagInverted = false; js.carryFlagInverted = false;
js.compilerPC = nextPC;
// Translate instructions // Translate instructions
for (u32 i = 0; i < code_block.m_num_instructions; i++) for (u32 i = 0; i < code_block.m_num_instructions; i++)
{ {
@ -812,20 +820,6 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
} }
} }
if (code_block.m_memory_exception)
{
b->memoryException = true;
// Address of instruction could not be translated
MOV(32, PPCSTATE(npc), Imm32(js.compilerPC));
OR(32, PPCSTATE(Exceptions), Imm32(EXCEPTION_ISI));
// Remove the invalid instruction from the icache, forcing a recompile
MOV(64, R(RSCRATCH), ImmPtr(jit->GetBlockCache()->GetICachePtr(js.compilerPC)));
MOV(32,MatR(RSCRATCH),Imm32(JIT_ICACHE_INVALID_WORD));
WriteExceptionExit();
}
if (code_block.m_broken) if (code_block.m_broken)
{ {

View File

@ -71,7 +71,7 @@ public:
// Jit! // Jit!
void Jit(u32 em_address) override; void Jit(u32 em_address) override;
const u8* DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buffer, JitBlock *b); const u8* DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buffer, JitBlock *b, u32 nextPC);
BitSet32 CallerSavedRegistersInUse(); BitSet32 CallerSavedRegistersInUse();

View File

@ -791,7 +791,6 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, u32 exitAddress)
case ShortIdleLoop: case ShortIdleLoop:
case FPExceptionCheck: case FPExceptionCheck:
case DSIExceptionCheck: case DSIExceptionCheck:
case ISIException:
case ExtExceptionCheck: case ExtExceptionCheck:
case BreakPointCheck: case BreakPointCheck:
case Int3: case Int3:
@ -2242,20 +2241,6 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, u32 exitAddress)
Jit->SetJumpTarget(noMemException); Jit->SetJumpTarget(noMemException);
break; break;
} }
case ISIException:
{
unsigned InstLoc = ibuild->GetImmValue(getOp1(I));
// Address of instruction could not be translated
Jit->MOV(32, PPCSTATE(npc), Imm32(InstLoc));
Jit->OR(32, PPCSTATE(Exceptions), Imm32(EXCEPTION_ISI));
// Remove the invalid instruction from the icache, forcing a recompile
Jit->MOV(64, R(RSCRATCH), ImmPtr(jit->GetBlockCache()->GetICachePtr(InstLoc)));
Jit->MOV(32, MatR(RSCRATCH), Imm32(JIT_ICACHE_INVALID_WORD));
Jit->WriteExceptionExit();
break;
}
case ExtExceptionCheck: case ExtExceptionCheck:
{ {
unsigned InstLoc = ibuild->GetImmValue(getOp1(I)); unsigned InstLoc = ibuild->GetImmValue(getOp1(I));

View File

@ -489,14 +489,8 @@ void JitIL::Jit(u32 em_address)
{ {
ClearCache(); ClearCache();
} }
int block_num = blocks.AllocateBlock(em_address);
JitBlock *b = blocks.GetBlock(block_num);
blocks.FinalizeBlock(block_num, jo.enableBlocklink, DoJit(em_address, &code_buffer, b));
}
const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlock *b) int blockSize = code_buffer.GetSize();
{
int blockSize = code_buf->GetSize();
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bEnableDebugging) if (SConfig::GetInstance().m_LocalCoreStartupParameter.bEnableDebugging)
{ {
@ -517,6 +511,26 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
} }
} }
// Analyze the block, collect all instructions it is made of (including inlining,
// if that is enabled), reorder instructions for optimal performance, and join joinable instructions.
u32 nextPC = analyzer.Analyze(em_address, &code_block, &code_buffer, blockSize);
if (code_block.m_memory_exception)
{
// Address of instruction could not be translated
NPC = nextPC;
PowerPC::ppcState.Exceptions |= EXCEPTION_ISI;
PowerPC::CheckExceptions();
return;
}
int block_num = blocks.AllocateBlock(em_address);
JitBlock *b = blocks.GetBlock(block_num);
blocks.FinalizeBlock(block_num, jo.enableBlocklink, DoJit(em_address, &code_buffer, b, nextPC));
}
const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlock *b, u32 nextPC)
{
js.isLastInstruction = false; js.isLastInstruction = false;
js.blockStart = em_address; js.blockStart = em_address;
js.fifoBytesThisBlock = 0; js.fifoBytesThisBlock = 0;
@ -524,10 +538,6 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
jit->js.numLoadStoreInst = 0; jit->js.numLoadStoreInst = 0;
jit->js.numFloatingPointInst = 0; jit->js.numFloatingPointInst = 0;
// Analyze the block, collect all instructions it is made of (including inlining,
// if that is enabled), reorder instructions for optimal performance, and join joinable instructions.
u32 nextPC = analyzer.Analyze(em_address, &code_block, code_buf, blockSize);
PPCAnalyst::CodeOp *ops = code_buf->codebuffer; PPCAnalyst::CodeOp *ops = code_buf->codebuffer;
const u8 *start = AlignCode4(); // TODO: Test if this or AlignCode16 make a difference from GetCodePtr const u8 *start = AlignCode4(); // TODO: Test if this or AlignCode16 make a difference from GetCodePtr
@ -681,12 +691,6 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
} }
} }
if (code_block.m_memory_exception)
{
b->memoryException = true;
ibuild.EmitISIException(ibuild.EmitIntConst(em_address));
}
// Perform actual code generation // Perform actual code generation
WriteCode(nextPC); WriteCode(nextPC);

View File

@ -54,7 +54,7 @@ public:
// Jit! // Jit!
void Jit(u32 em_address) override; void Jit(u32 em_address) override;
const u8* DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buffer, JitBlock *b); const u8* DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buffer, JitBlock *b, u32 nextPC);
void Trace(); void Trace();

View File

@ -110,7 +110,6 @@ using namespace Gen;
{ {
JitBlock &b = blocks[num_blocks]; JitBlock &b = blocks[num_blocks];
b.invalid = false; b.invalid = false;
b.memoryException = false;
b.originalAddress = em_address; b.originalAddress = em_address;
b.linkData.clear(); b.linkData.clear();
num_blocks++; //commit the current block num_blocks++; //commit the current block
@ -132,11 +131,7 @@ using namespace Gen;
block_map[std::make_pair(pAddr + 4 * b.originalSize - 1, pAddr)] = block_num; block_map[std::make_pair(pAddr + 4 * b.originalSize - 1, pAddr)] = block_num;
// Blocks where a memory exception (ISI) occurred in the instruction fetch have to if (block_link)
// execute the ISI handler as the next instruction. These blocks cannot be
// linked to other blocks. The block will be recompiled after the ISI is handled
// and so we do not link other blocks to it either.
if (block_link && !b.memoryException)
{ {
for (const auto& e : b.linkData) for (const auto& e : b.linkData)
{ {

View File

@ -42,7 +42,6 @@ struct JitBlock
int runCount; // for profiling. int runCount; // for profiling.
bool invalid; bool invalid;
bool memoryException;
struct LinkData struct LinkData
{ {
@ -121,6 +120,9 @@ class JitBaseBlockCache
void LinkBlock(int i); void LinkBlock(int i);
void UnlinkBlock(int i); void UnlinkBlock(int i);
u32* GetICachePtr(u32 addr);
void DestroyBlock(int block_num, bool invalidate);
// Virtual for overloaded // Virtual for overloaded
virtual void WriteLinkBlock(u8* location, const u8* address) = 0; virtual void WriteLinkBlock(u8* location, const u8* address) = 0;
virtual void WriteDestroyBlock(const u8* location, u32 address) = 0; virtual void WriteDestroyBlock(const u8* location, u32 address) = 0;
@ -148,17 +150,13 @@ public:
std::array<u8, JIT_ICACHEEX_SIZE> iCacheEx; std::array<u8, JIT_ICACHEEX_SIZE> iCacheEx;
std::array<u8, JIT_ICACHE_SIZE> iCacheVMEM; std::array<u8, JIT_ICACHE_SIZE> iCacheVMEM;
u32* GetICachePtr(u32 addr);
// Fast way to get a block. Only works on the first ppc instruction of a block. // Fast way to get a block. Only works on the first ppc instruction of a block.
int GetBlockNumberFromStartAddress(u32 em_address); int GetBlockNumberFromStartAddress(u32 em_address);
u32 GetOriginalFirstOp(int block_num);
CompiledCode GetCompiledCodeFromBlock(int block_num); CompiledCode GetCompiledCodeFromBlock(int block_num);
// DOES NOT WORK CORRECTLY WITH INLINING // DOES NOT WORK CORRECTLY WITH INLINING
void InvalidateICache(u32 address, const u32 length, bool forced); void InvalidateICache(u32 address, const u32 length, bool forced);
void DestroyBlock(int block_num, bool invalidate);
}; };
// x86 BlockCache // x86 BlockCache

View File

@ -1476,7 +1476,7 @@ static const std::string opcodeNames[] = {
"FResult_End", "StorePaired", "StoreSingle", "StoreDouble", "StoreFReg", "FResult_End", "StorePaired", "StoreSingle", "StoreDouble", "StoreFReg",
"FDCmpCR", "CInt16", "CInt32", "SystemCall", "RFIExit", "FDCmpCR", "CInt16", "CInt32", "SystemCall", "RFIExit",
"InterpreterBranch", "IdleBranch", "ShortIdleLoop", "InterpreterBranch", "IdleBranch", "ShortIdleLoop",
"FPExceptionCheckStart", "FPExceptionCheckEnd", "ISIException", "ExtExceptionCheck", "FPExceptionCheckStart", "FPExceptionCheckEnd", "ExtExceptionCheck",
"Tramp", "BlockStart", "BlockEnd", "Int3", "Tramp", "BlockStart", "BlockEnd", "Int3",
}; };
static const unsigned alwaysUsedList[] = { static const unsigned alwaysUsedList[] = {
@ -1485,7 +1485,7 @@ static const unsigned alwaysUsedList[] = {
Store16, Store32, StoreSingle, StoreDouble, StorePaired, StoreFReg, FDCmpCR, Store16, Store32, StoreSingle, StoreDouble, StorePaired, StoreFReg, FDCmpCR,
BlockStart, BlockEnd, IdleBranch, BranchCond, BranchUncond, ShortIdleLoop, BlockStart, BlockEnd, IdleBranch, BranchCond, BranchUncond, ShortIdleLoop,
SystemCall, InterpreterBranch, RFIExit, FPExceptionCheck, SystemCall, InterpreterBranch, RFIExit, FPExceptionCheck,
DSIExceptionCheck, ISIException, ExtExceptionCheck, BreakPointCheck, DSIExceptionCheck, ExtExceptionCheck, BreakPointCheck,
Int3, Tramp, Nop Int3, Tramp, Nop
}; };
static const unsigned extra8RegList[] = { static const unsigned extra8RegList[] = {

View File

@ -166,7 +166,7 @@ enum Opcode
// used for exception checking, at least until someone // used for exception checking, at least until someone
// has a better idea of integrating it // has a better idea of integrating it
FPExceptionCheck, DSIExceptionCheck, FPExceptionCheck, DSIExceptionCheck,
ISIException, ExtExceptionCheck, BreakPointCheck, ExtExceptionCheck, BreakPointCheck,
// "Opcode" representing a register too far away to // "Opcode" representing a register too far away to
// reference directly; this is a size optimization // reference directly; this is a size optimization
Tramp, Tramp,
@ -551,11 +551,6 @@ public:
return EmitUOp(DSIExceptionCheck, pc); return EmitUOp(DSIExceptionCheck, pc);
} }
InstLoc EmitISIException(InstLoc dest)
{
return EmitUOp(ISIException, dest);
}
InstLoc EmitExtExceptionCheck(InstLoc pc) InstLoc EmitExtExceptionCheck(InstLoc pc)
{ {
return EmitUOp(ExtExceptionCheck, pc); return EmitUOp(ExtExceptionCheck, pc);