CPU/Recompiler: Create block links for self-looping blocks
This way invalidation will rewrite the jump back to the compiler. Otherwise a SMC block can end up looping itself indefinitely. Might help with Spyro 2/3. I can't seem to make them crash anymore.
This commit is contained in:
parent
2e805d56dd
commit
99f133223c
|
@ -1421,6 +1421,22 @@ const void* CPU::CodeCache::CreateBlockLink(Block* block, void* code, u32 newpc)
|
|||
return dst;
|
||||
}
|
||||
|
||||
const void* CPU::CodeCache::CreateSelfBlockLink(Block* block, void* code, const void* block_start)
|
||||
{
|
||||
const void* dst = g_dispatcher;
|
||||
if (g_settings.cpu_recompiler_block_linking)
|
||||
{
|
||||
dst = block_start;
|
||||
|
||||
BlockLinkMap::iterator iter = s_block_links.emplace(block->pc, code);
|
||||
DebugAssert(block->num_exit_links < MAX_BLOCK_EXIT_LINKS);
|
||||
block->exit_links[block->num_exit_links++] = iter;
|
||||
}
|
||||
|
||||
DEBUG_LOG("Self linking {} with dst pc {:08X} to {}", code, block->pc, dst);
|
||||
return dst;
|
||||
}
|
||||
|
||||
void CPU::CodeCache::BacklinkBlocks(u32 pc, const void* dst)
|
||||
{
|
||||
if (!g_settings.cpu_recompiler_block_linking)
|
||||
|
|
|
@ -239,6 +239,7 @@ const void* GetInterpretUncachedBlockFunction();
|
|||
void CompileOrRevalidateBlock(u32 start_pc);
|
||||
void DiscardAndRecompileBlock(u32 start_pc);
|
||||
const void* CreateBlockLink(Block* from_block, void* code, u32 newpc);
|
||||
const void* CreateSelfBlockLink(Block* block, void* code, const void* block_start);
|
||||
|
||||
void AddLoadStoreInfo(void* code_address, u32 code_size, u32 guest_pc, const void* thunk_address);
|
||||
void AddLoadStoreInfo(void* code_address, u32 code_size, u32 guest_pc, u32 guest_block, TickCount cycles,
|
||||
|
|
|
@ -741,17 +741,11 @@ void CPU::ARM32Recompiler::EndAndLinkBlock(const std::optional<u32>& newpc, bool
|
|||
}
|
||||
else
|
||||
{
|
||||
if (newpc.value() == m_block->pc)
|
||||
{
|
||||
// Special case: ourselves! No need to backlink then.
|
||||
DEBUG_LOG("Linking block at {:08X} to self", m_block->pc);
|
||||
armEmitJmp(armAsm, armAsm->GetBuffer()->GetStartAddress<const void*>(), true);
|
||||
}
|
||||
else
|
||||
{
|
||||
const void* target = CodeCache::CreateBlockLink(m_block, armAsm->GetCursorAddress<void*>(), newpc.value());
|
||||
armEmitJmp(armAsm, target, true);
|
||||
}
|
||||
const void* target = (newpc.value() == m_block->pc) ?
|
||||
CodeCache::CreateSelfBlockLink(m_block, armAsm->GetCursorAddress<void*>(),
|
||||
armAsm->GetBuffer()->GetStartAddress<const void*>()) :
|
||||
CodeCache::CreateBlockLink(m_block, armAsm->GetCursorAddress<void*>(), newpc.value());
|
||||
armEmitJmp(armAsm, target, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -901,17 +901,11 @@ void CPU::ARM64Recompiler::EndAndLinkBlock(const std::optional<u32>& newpc, bool
|
|||
}
|
||||
else
|
||||
{
|
||||
if (newpc.value() == m_block->pc)
|
||||
{
|
||||
// Special case: ourselves! No need to backlink then.
|
||||
DEBUG_LOG("Linking block at {:08X} to self", m_block->pc);
|
||||
armEmitJmp(armAsm, armAsm->GetBuffer()->GetStartAddress<const void*>(), true);
|
||||
}
|
||||
else
|
||||
{
|
||||
const void* target = CodeCache::CreateBlockLink(m_block, armAsm->GetCursorAddress<void*>(), newpc.value());
|
||||
armEmitJmp(armAsm, target, true);
|
||||
}
|
||||
const void* target = (newpc.value() == m_block->pc) ?
|
||||
CodeCache::CreateSelfBlockLink(m_block, armAsm->GetCursorAddress<void*>(),
|
||||
armAsm->GetBuffer()->GetStartAddress<const void*>()) :
|
||||
CodeCache::CreateBlockLink(m_block, armAsm->GetCursorAddress<void*>(), newpc.value());
|
||||
armEmitJmp(armAsm, target, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ using namespace biscuit;
|
|||
RISCV64Recompiler s_instance;
|
||||
Recompiler* g_compiler = &s_instance;
|
||||
|
||||
} // namespace CPU::Recompiler
|
||||
} // namespace CPU
|
||||
|
||||
bool rvIsCallerSavedRegister(u32 id)
|
||||
{
|
||||
|
@ -150,7 +150,8 @@ void rvEmitFarLoad(biscuit::Assembler* rvAsm, const biscuit::GPR& reg, const voi
|
|||
rvAsm->LWU(reg, lo, reg);
|
||||
}
|
||||
|
||||
[[maybe_unused]] void rvEmitFarStore(biscuit::Assembler* rvAsm, const biscuit::GPR& reg, const void* addr, const biscuit::GPR& tempreg)
|
||||
[[maybe_unused]] void rvEmitFarStore(biscuit::Assembler* rvAsm, const biscuit::GPR& reg, const void* addr,
|
||||
const biscuit::GPR& tempreg)
|
||||
{
|
||||
const auto [hi, lo] = rvGetAddressImmediates(rvAsm->GetCursorPointer(), addr);
|
||||
rvAsm->AUIPC(tempreg, hi);
|
||||
|
@ -697,17 +698,11 @@ void CPU::RISCV64Recompiler::EndAndLinkBlock(const std::optional<u32>& newpc, bo
|
|||
}
|
||||
else
|
||||
{
|
||||
if (newpc.value() == m_block->pc)
|
||||
{
|
||||
// Special case: ourselves! No need to backlink then.
|
||||
DEBUG_LOG("Linking block at {:08X} to self", m_block->pc);
|
||||
rvEmitJmp(rvAsm, rvAsm->GetBufferPointer(0));
|
||||
}
|
||||
else
|
||||
{
|
||||
const void* target = CreateBlockLink(m_block, rvAsm->GetCursorPointer(), newpc.value());
|
||||
rvEmitJmp(rvAsm, target);
|
||||
}
|
||||
const void* target =
|
||||
(newpc.value() == m_block->pc) ?
|
||||
CodeCache::CreateSelfBlockLink(m_block, rvAsm->GetCursorPointer(), rvAsm->GetBufferPointer(0)) :
|
||||
CodeCache::CreateBlockLink(m_block, rvAsm->GetCursorPointer(), newpc.value());
|
||||
rvEmitJmp(rvAsm, target);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -629,17 +629,10 @@ void CPU::X64Recompiler::EndAndLinkBlock(const std::optional<u32>& newpc, bool d
|
|||
}
|
||||
else
|
||||
{
|
||||
if (newpc.value() == m_block->pc)
|
||||
{
|
||||
// Special case: ourselves! No need to backlink then.
|
||||
DEBUG_LOG("Linking block at {:08X} to self", m_block->pc);
|
||||
cg->jmp(cg->getCode());
|
||||
}
|
||||
else
|
||||
{
|
||||
const void* target = CodeCache::CreateBlockLink(m_block, cg->getCurr<void*>(), newpc.value());
|
||||
cg->jmp(target, CodeGenerator::T_NEAR);
|
||||
}
|
||||
const void* target = (newpc.value() == m_block->pc) ?
|
||||
CodeCache::CreateSelfBlockLink(m_block, cg->getCurr<void*>(), cg->getCode()) :
|
||||
CodeCache::CreateBlockLink(m_block, cg->getCurr<void*>(), newpc.value());
|
||||
cg->jmp(target, CodeGenerator::T_NEAR);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue