JitArm64: Extract block exit link area generation.
Always use 3 instructions on linking.
This commit is contained in:
parent
d8479869dc
commit
674e7430d0
|
@ -325,20 +325,10 @@ void JitArm64::WriteExit(u32 destination, bool LK, u32 exit_address_after_return
|
||||||
linkData.call = LK;
|
linkData.call = LK;
|
||||||
b->linkData.push_back(linkData);
|
b->linkData.push_back(linkData);
|
||||||
|
|
||||||
MOVI2R(DISPATCHER_PC, destination);
|
blocks.WriteLinkBlock(*this, linkData);
|
||||||
|
|
||||||
if (!LK)
|
if (LK)
|
||||||
{
|
{
|
||||||
B(dispatcher);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
BL(dispatcher);
|
|
||||||
|
|
||||||
// MOVI2R might only require one instruction. So the const offset of 20 bytes
|
|
||||||
// might be wrong. Be sure and just add a NOP here.
|
|
||||||
HINT(HINT_NOP);
|
|
||||||
|
|
||||||
// Write the regular exit node after the return.
|
// Write the regular exit node after the return.
|
||||||
linkData.exitAddress = exit_address_after_return;
|
linkData.exitAddress = exit_address_after_return;
|
||||||
linkData.exitPtrs = GetWritableCodePtr();
|
linkData.exitPtrs = GetWritableCodePtr();
|
||||||
|
@ -346,8 +336,7 @@ void JitArm64::WriteExit(u32 destination, bool LK, u32 exit_address_after_return
|
||||||
linkData.call = false;
|
linkData.call = false;
|
||||||
b->linkData.push_back(linkData);
|
b->linkData.push_back(linkData);
|
||||||
|
|
||||||
MOVI2R(DISPATCHER_PC, exit_address_after_return);
|
blocks.WriteLinkBlock(*this, linkData);
|
||||||
B(dispatcher);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -387,8 +376,7 @@ void JitArm64::WriteExit(Arm64Gen::ARM64Reg dest, bool LK, u32 exit_address_afte
|
||||||
linkData.call = false;
|
linkData.call = false;
|
||||||
b->linkData.push_back(linkData);
|
b->linkData.push_back(linkData);
|
||||||
|
|
||||||
MOVI2R(DISPATCHER_PC, exit_address_after_return);
|
blocks.WriteLinkBlock(*this, linkData);
|
||||||
B(dispatcher);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -417,8 +405,7 @@ void JitArm64::FakeLKExit(u32 exit_address_after_return)
|
||||||
linkData.call = false;
|
linkData.call = false;
|
||||||
b->linkData.push_back(linkData);
|
b->linkData.push_back(linkData);
|
||||||
|
|
||||||
MOVI2R(DISPATCHER_PC, exit_address_after_return);
|
blocks.WriteLinkBlock(*this, linkData);
|
||||||
B(dispatcher);
|
|
||||||
|
|
||||||
SetJumpTarget(skip_exit);
|
SetJumpTarget(skip_exit);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
// Licensed under GPLv2+
|
// Licensed under GPLv2+
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include "Core/PowerPC/JitArm64/Jit.h"
|
|
||||||
#include "Common/CommonTypes.h"
|
|
||||||
#include "Core/PowerPC/JitArm64/JitArm64Cache.h"
|
#include "Core/PowerPC/JitArm64/JitArm64Cache.h"
|
||||||
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "Core/PowerPC/JitArm64/Jit.h"
|
||||||
#include "Core/PowerPC/JitCommon/JitBase.h"
|
#include "Core/PowerPC/JitCommon/JitBase.h"
|
||||||
#include "Core/PowerPC/JitInterface.h"
|
#include "Core/PowerPC/JitInterface.h"
|
||||||
|
|
||||||
|
@ -12,39 +12,57 @@ JitArm64BlockCache::JitArm64BlockCache(JitBase& jit) : JitBaseBlockCache{jit}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void JitArm64BlockCache::WriteLinkBlock(Arm64Gen::ARM64XEmitter& emit,
|
||||||
|
const JitBlock::LinkData& source, const JitBlock* dest)
|
||||||
|
{
|
||||||
|
if (!dest)
|
||||||
|
{
|
||||||
|
// Use a fixed amount of instructions, so we can assume to use 3 instructions on patching.
|
||||||
|
emit.MOVZ(DISPATCHER_PC, source.exitAddress & 0xFFFF, SHIFT_0);
|
||||||
|
emit.MOVK(DISPATCHER_PC, source.exitAddress >> 16, SHIFT_16);
|
||||||
|
|
||||||
|
if (source.call)
|
||||||
|
emit.BL(m_jit.GetAsmRoutines()->dispatcher);
|
||||||
|
else
|
||||||
|
emit.B(m_jit.GetAsmRoutines()->dispatcher);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (source.call)
|
||||||
|
{
|
||||||
|
// The "fast" BL must be the third instruction. So just use the former two to inline the
|
||||||
|
// downcount check here. It's better to do this near jump before the long jump to the other
|
||||||
|
// block.
|
||||||
|
FixupBranch fast_link = emit.B(CC_PL);
|
||||||
|
emit.BL(dest->checkedEntry);
|
||||||
|
emit.SetJumpTarget(fast_link);
|
||||||
|
emit.BL(dest->normalEntry);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Are we able to jump directly to the normal entry?
|
||||||
|
s64 distance = ((s64)dest->normalEntry - (s64)emit.GetCodePtr()) >> 2;
|
||||||
|
if (distance >= -0x40000 && distance <= 0x3FFFF)
|
||||||
|
{
|
||||||
|
emit.B(CC_PL, dest->normalEntry);
|
||||||
|
emit.B(dest->checkedEntry);
|
||||||
|
emit.BRK(101);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
FixupBranch fast_link = emit.B(CC_PL);
|
||||||
|
emit.B(dest->checkedEntry);
|
||||||
|
emit.SetJumpTarget(fast_link);
|
||||||
|
emit.B(dest->normalEntry);
|
||||||
|
}
|
||||||
|
|
||||||
void JitArm64BlockCache::WriteLinkBlock(const JitBlock::LinkData& source, const JitBlock* dest)
|
void JitArm64BlockCache::WriteLinkBlock(const JitBlock::LinkData& source, const JitBlock* dest)
|
||||||
{
|
{
|
||||||
u8* location = source.exitPtrs;
|
u8* location = source.exitPtrs;
|
||||||
ARM64XEmitter emit(location);
|
ARM64XEmitter emit(location);
|
||||||
|
|
||||||
if (dest)
|
WriteLinkBlock(emit, source, dest);
|
||||||
{
|
|
||||||
if (source.call)
|
|
||||||
{
|
|
||||||
emit.BL(dest->checkedEntry);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Are we able to jump directly to the normal entry?
|
|
||||||
s64 distance = ((s64)dest->normalEntry - (s64)location) >> 2;
|
|
||||||
if (distance >= -0x40000 && distance <= 0x3FFFF)
|
|
||||||
{
|
|
||||||
emit.B(CC_PL, dest->normalEntry);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use the checked entry if either downcount is smaller zero,
|
|
||||||
// or if we're not able to inline the downcount check here.
|
|
||||||
emit.B(dest->checkedEntry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
emit.MOVI2R(DISPATCHER_PC, source.exitAddress);
|
|
||||||
if (source.call)
|
|
||||||
emit.BL(m_jit.GetAsmRoutines()->dispatcher);
|
|
||||||
else
|
|
||||||
emit.B(m_jit.GetAsmRoutines()->dispatcher);
|
|
||||||
}
|
|
||||||
emit.FlushIcache();
|
emit.FlushIcache();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "Common/Arm64Emitter.h"
|
||||||
#include "Core/PowerPC/JitCommon/JitCache.h"
|
#include "Core/PowerPC/JitCommon/JitCache.h"
|
||||||
|
|
||||||
class JitBase;
|
class JitBase;
|
||||||
|
@ -15,6 +16,9 @@ class JitArm64BlockCache : public JitBaseBlockCache
|
||||||
public:
|
public:
|
||||||
explicit JitArm64BlockCache(JitBase& jit);
|
explicit JitArm64BlockCache(JitBase& jit);
|
||||||
|
|
||||||
|
void WriteLinkBlock(Arm64Gen::ARM64XEmitter& emit, const JitBlock::LinkData& source,
|
||||||
|
const JitBlock* dest = nullptr);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void WriteLinkBlock(const JitBlock::LinkData& source, const JitBlock* dest) override;
|
void WriteLinkBlock(const JitBlock::LinkData& source, const JitBlock* dest) override;
|
||||||
void WriteDestroyBlock(const JitBlock& block) override;
|
void WriteDestroyBlock(const JitBlock& block) override;
|
||||||
|
|
Loading…
Reference in New Issue