Merge pull request #4650 from degasus/jitcache

JitCache: Use pointers in the ICache and dispatchers.
This commit is contained in:
Markus Wick 2017-01-15 15:59:10 +01:00 committed by GitHub
commit 5297309dfa
4 changed files with 30 additions and 48 deletions

View File

@ -106,31 +106,24 @@ void Jit64AsmRoutineManager::Generate()
// The following is a translation of JitBaseBlockCache::Dispatch into assembly. // The following is a translation of JitBaseBlockCache::Dispatch into assembly.
// Fast block number lookup. // Fast block number lookup.
// ((PC >> 2) & mask) * sizeof(JitBlock*) = (PC & (mask << 2)) * 2
MOV(32, R(RSCRATCH), PPCSTATE(pc)); MOV(32, R(RSCRATCH), PPCSTATE(pc));
u64 icache = reinterpret_cast<u64>(g_jit->GetBlockCache()->GetICache()); u64 icache = reinterpret_cast<u64>(g_jit->GetBlockCache()->GetICache());
AND(32, R(RSCRATCH), Imm32(JitBaseBlockCache::iCache_Mask << 2)); AND(32, R(RSCRATCH), Imm32(JitBaseBlockCache::iCache_Mask << 2));
if (icache <= INT_MAX) if (icache <= INT_MAX)
{ {
MOV(32, R(RSCRATCH), MDisp(RSCRATCH, static_cast<s32>(icache))); MOV(64, R(RSCRATCH), MScaled(RSCRATCH, SCALE_2, static_cast<s32>(icache)));
} }
else else
{ {
MOV(64, R(RSCRATCH2), Imm64(icache)); MOV(64, R(RSCRATCH2), Imm64(icache));
MOV(32, R(RSCRATCH), MRegSum(RSCRATCH2, RSCRATCH)); MOV(64, R(RSCRATCH), MComplex(RSCRATCH2, RSCRATCH, SCALE_2, 0));
} }
// Check whether the block we found matches the current state. // Check if we found a block.
u64 blocks = reinterpret_cast<u64>(g_jit->GetBlockCache()->GetBlocks()); TEST(64, R(RSCRATCH), R(RSCRATCH));
IMUL(32, RSCRATCH, R(RSCRATCH), Imm32(sizeof(JitBlock))); FixupBranch not_found = J_CC(CC_Z);
if (blocks <= INT_MAX)
{
ADD(64, R(RSCRATCH), Imm32(static_cast<s32>(blocks)));
}
else
{
MOV(64, R(RSCRATCH2), Imm64(blocks));
ADD(64, R(RSCRATCH), R(RSCRATCH2));
}
// Check both block.effectiveAddress and block.msrBits. // Check both block.effectiveAddress and block.msrBits.
MOV(32, R(RSCRATCH2), PPCSTATE(msr)); MOV(32, R(RSCRATCH2), PPCSTATE(msr));
AND(32, R(RSCRATCH2), Imm32(JitBlock::JIT_CACHE_MSR_MASK)); AND(32, R(RSCRATCH2), Imm32(JitBlock::JIT_CACHE_MSR_MASK));
@ -138,10 +131,11 @@ void Jit64AsmRoutineManager::Generate()
MOV(32, R(RSCRATCH_EXTRA), PPCSTATE(pc)); MOV(32, R(RSCRATCH_EXTRA), PPCSTATE(pc));
OR(64, R(RSCRATCH2), R(RSCRATCH_EXTRA)); OR(64, R(RSCRATCH2), R(RSCRATCH_EXTRA));
CMP(64, R(RSCRATCH2), MDisp(RSCRATCH, static_cast<s32>(offsetof(JitBlock, effectiveAddress)))); CMP(64, R(RSCRATCH2), MDisp(RSCRATCH, static_cast<s32>(offsetof(JitBlock, effectiveAddress))));
FixupBranch notfound = J_CC(CC_NE); FixupBranch state_mismatch = J_CC(CC_NE);
// Success; branch to the block we found. // Success; branch to the block we found.
JMPptr(MDisp(RSCRATCH, static_cast<s32>(offsetof(JitBlock, normalEntry)))); JMPptr(MDisp(RSCRATCH, static_cast<s32>(offsetof(JitBlock, normalEntry))));
SetJumpTarget(notfound); SetJumpTarget(not_found);
SetJumpTarget(state_mismatch);
// Failure; call into the block cache to update the state, then try again. // Failure; call into the block cache to update the state, then try again.
// (We need to loop because Jit() might not actually generate a block // (We need to loop because Jit() might not actually generate a block

View File

@ -73,18 +73,12 @@ void JitArm64::GenerateAsm()
// iCache[(address >> 2) & iCache_Mask]; // iCache[(address >> 2) & iCache_Mask];
ARM64Reg pc_masked = W25; ARM64Reg pc_masked = W25;
ARM64Reg cache_base = X27; ARM64Reg cache_base = X27;
ARM64Reg block_num = W27;
ANDI2R(pc_masked, DISPATCHER_PC, JitBaseBlockCache::iCache_Mask << 2);
MOVP2R(cache_base, g_jit->GetBlockCache()->GetICache());
LDR(block_num, cache_base, EncodeRegTo64(pc_masked));
// blocks[block_num]
ARM64Reg block = X30; ARM64Reg block = X30;
ARM64Reg jit_block_size = W24; ORRI2R(pc_masked, WZR, JitBaseBlockCache::iCache_Mask << 3);
MOVI2R(jit_block_size, sizeof(JitBlock)); AND(pc_masked, pc_masked, DISPATCHER_PC, ArithOption(DISPATCHER_PC, ST_LSL, 1));
MUL(block_num, block_num, jit_block_size); MOVP2R(cache_base, g_jit->GetBlockCache()->GetICache());
MOVP2R(block, g_jit->GetBlockCache()->GetBlocks()); LDR(block, cache_base, EncodeRegTo64(pc_masked));
ADD(block, block, EncodeRegTo64(block_num)); FixupBranch not_found = CBZ(block);
// b.effectiveAddress != addr || b.msrBits != msr // b.effectiveAddress != addr || b.msrBits != msr
ARM64Reg pc_and_msr = W25; ARM64Reg pc_and_msr = W25;
@ -102,6 +96,7 @@ void JitArm64::GenerateAsm()
// return blocks[block_num].normalEntry; // return blocks[block_num].normalEntry;
LDR(INDEX_UNSIGNED, block, block, offsetof(JitBlock, normalEntry)); LDR(INDEX_UNSIGNED, block, block, offsetof(JitBlock, normalEntry));
BR(block); BR(block);
SetJumpTarget(not_found);
SetJumpTarget(pc_missmatch); SetJumpTarget(pc_missmatch);
SetJumpTarget(msr_missmatch); SetJumpTarget(msr_missmatch);
} }

View File

@ -46,7 +46,7 @@ void JitBaseBlockCache::Init()
s_clear_jit_cache_thread_safe = CoreTiming::RegisterEvent("clearJitCache", ClearCacheThreadSafe); s_clear_jit_cache_thread_safe = CoreTiming::RegisterEvent("clearJitCache", ClearCacheThreadSafe);
JitRegister::Init(SConfig::GetInstance().m_perfDir); JitRegister::Init(SConfig::GetInstance().m_perfDir);
iCache.fill(0); iCache.fill(nullptr);
Clear(); Clear();
} }
@ -99,12 +99,7 @@ bool JitBaseBlockCache::IsFull() const
return num_blocks >= MAX_NUM_BLOCKS - 1; return num_blocks >= MAX_NUM_BLOCKS - 1;
} }
JitBlock* JitBaseBlockCache::GetBlocks() JitBlock** JitBaseBlockCache::GetICache()
{
return blocks.data();
}
int* JitBaseBlockCache::GetICache()
{ {
return iCache.data(); return iCache.data();
} }
@ -140,9 +135,8 @@ void JitBaseBlockCache::FinalizeBlock(JitBlock& block, bool block_link, const u8
std::make_pair(old_b.physicalAddress + 4 * old_b.originalSize - 1, old_b.physicalAddress)); std::make_pair(old_b.physicalAddress + 4 * old_b.originalSize - 1, old_b.physicalAddress));
DestroyBlock(old_b, true); DestroyBlock(old_b, true);
} }
const int block_num = static_cast<int>(&block - &blocks[0]);
start_block_map[block.physicalAddress] = &block; start_block_map[block.physicalAddress] = &block;
FastLookupEntryForAddress(block.effectiveAddress) = block_num; FastLookupEntryForAddress(block.effectiveAddress) = &block;
u32 pAddr = block.physicalAddress; u32 pAddr = block.physicalAddress;
@ -190,16 +184,16 @@ JitBlock* JitBaseBlockCache::GetBlockFromStartAddress(u32 addr, u32 msr)
const u8* JitBaseBlockCache::Dispatch() const u8* JitBaseBlockCache::Dispatch()
{ {
int block_num = FastLookupEntryForAddress(PC); JitBlock* block = FastLookupEntryForAddress(PC);
while (blocks[block_num].effectiveAddress != PC || while (!block || block->effectiveAddress != PC ||
blocks[block_num].msrBits != (MSR & JitBlock::JIT_CACHE_MSR_MASK)) block->msrBits != (MSR & JitBlock::JIT_CACHE_MSR_MASK))
{ {
MoveBlockIntoFastCache(PC, MSR & JitBlock::JIT_CACHE_MSR_MASK); MoveBlockIntoFastCache(PC, MSR & JitBlock::JIT_CACHE_MSR_MASK);
block_num = FastLookupEntryForAddress(PC); block = FastLookupEntryForAddress(PC);
} }
return blocks[block_num].normalEntry; return block->normalEntry;
} }
void JitBaseBlockCache::InvalidateICache(u32 address, const u32 length, bool forced) void JitBaseBlockCache::InvalidateICache(u32 address, const u32 length, bool forced)
@ -326,7 +320,7 @@ void JitBaseBlockCache::DestroyBlock(JitBlock& block, bool invalidate)
} }
block.invalid = true; block.invalid = true;
start_block_map.erase(block.physicalAddress); start_block_map.erase(block.physicalAddress);
FastLookupEntryForAddress(block.effectiveAddress) = 0; FastLookupEntryForAddress(block.effectiveAddress) = nullptr;
UnlinkBlock(block); UnlinkBlock(block);
@ -353,12 +347,12 @@ void JitBaseBlockCache::MoveBlockIntoFastCache(u32 addr, u32 msr)
} }
else else
{ {
FastLookupEntryForAddress(addr) = static_cast<int>(block - &blocks[0]); FastLookupEntryForAddress(addr) = block;
LinkBlock(*block); LinkBlock(*block);
} }
} }
int& JitBaseBlockCache::FastLookupEntryForAddress(u32 address) JitBlock*& JitBaseBlockCache::FastLookupEntryForAddress(u32 address)
{ {
return iCache[(address >> 2) & iCache_Mask]; return iCache[(address >> 2) & iCache_Mask];
} }

View File

@ -127,8 +127,7 @@ public:
bool IsFull() const; bool IsFull() const;
// Code Cache // Code Cache
JitBlock* GetBlocks(); JitBlock** GetICache();
int* GetICache();
void RunOnBlocks(std::function<void(const JitBlock&)> f); void RunOnBlocks(std::function<void(const JitBlock&)> f);
JitBlock* AllocateBlock(u32 em_address); JitBlock* AllocateBlock(u32 em_address);
@ -164,7 +163,7 @@ private:
void MoveBlockIntoFastCache(u32 em_address, u32 msr); void MoveBlockIntoFastCache(u32 em_address, u32 msr);
// Fast but risky block lookup based on iCache. // Fast but risky block lookup based on iCache.
int& FastLookupEntryForAddress(u32 address); JitBlock*& FastLookupEntryForAddress(u32 address);
// We store the metadata of all blocks in a linear way within this array. // We store the metadata of all blocks in a linear way within this array.
// Note: blocks[0] must not be used as it is referenced as invalid block in iCache. // Note: blocks[0] must not be used as it is referenced as invalid block in iCache.
@ -190,5 +189,5 @@ private:
// This array is indexed with the masked PC and likely holds the correct block id. // This array is indexed with the masked PC and likely holds the correct block id.
// This is used as a fast cache of start_block_map used in the assembly dispatcher. // This is used as a fast cache of start_block_map used in the assembly dispatcher.
std::array<int, iCache_Num_Elements> iCache; // start_addr & mask -> number std::array<JitBlock*, iCache_Num_Elements> iCache; // start_addr & mask -> number
}; };