JitArm64: Extract block exit link area generation.

Always use 3 instructions on linking.
This commit is contained in:
degasus 2017-02-15 09:29:37 +01:00
parent d8479869dc
commit 674e7430d0
3 changed files with 56 additions and 47 deletions

View File

@ -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);
} }

View File

@ -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();
} }

View File

@ -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;