JitArm64: Use farcode in WriteLinkBlock
Now block link nearcode is back to a length of three instructions. Unfortunately, the code I'm adding to Jit.cpp ends up being a bit messy because we need to handle the case of already being in farcode...
This commit is contained in:
parent
1813f0fdb5
commit
d2c5d79614
|
@ -372,12 +372,29 @@ void JitArm64::WriteExit(u32 destination, bool LK, u32 exit_address_after_return
|
||||||
STP(IndexType::Pre, ARM64Reg::X0, ARM64Reg::X1, ARM64Reg::SP, -16);
|
STP(IndexType::Pre, ARM64Reg::X0, ARM64Reg::X1, ARM64Reg::SP, -16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr size_t primary_farcode_size = 3 * sizeof(u32);
|
||||||
|
const bool switch_to_far_code = !IsInFarCode();
|
||||||
|
const u8* primary_farcode_addr;
|
||||||
|
if (switch_to_far_code)
|
||||||
|
{
|
||||||
|
SwitchToFarCode();
|
||||||
|
primary_farcode_addr = GetCodePtr();
|
||||||
|
SwitchToNearCode();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
primary_farcode_addr = GetCodePtr() + JitArm64BlockCache::BLOCK_LINK_SIZE +
|
||||||
|
(LK ? JitArm64BlockCache::BLOCK_LINK_SIZE : 0);
|
||||||
|
}
|
||||||
|
const u8* return_farcode_addr = primary_farcode_addr + primary_farcode_size;
|
||||||
|
|
||||||
JitBlock* b = js.curBlock;
|
JitBlock* b = js.curBlock;
|
||||||
JitBlock::LinkData linkData;
|
JitBlock::LinkData linkData;
|
||||||
linkData.exitAddress = destination;
|
linkData.exitAddress = destination;
|
||||||
linkData.exitPtrs = GetWritableCodePtr();
|
linkData.exitPtrs = GetWritableCodePtr();
|
||||||
linkData.linkStatus = false;
|
linkData.linkStatus = false;
|
||||||
linkData.call = LK;
|
linkData.call = LK;
|
||||||
|
linkData.exitFarcode = primary_farcode_addr;
|
||||||
b->linkData.push_back(linkData);
|
b->linkData.push_back(linkData);
|
||||||
|
|
||||||
blocks.WriteLinkBlock(*this, linkData);
|
blocks.WriteLinkBlock(*this, linkData);
|
||||||
|
@ -391,10 +408,32 @@ void JitArm64::WriteExit(u32 destination, bool LK, u32 exit_address_after_return
|
||||||
linkData.exitPtrs = GetWritableCodePtr();
|
linkData.exitPtrs = GetWritableCodePtr();
|
||||||
linkData.linkStatus = false;
|
linkData.linkStatus = false;
|
||||||
linkData.call = false;
|
linkData.call = false;
|
||||||
|
linkData.exitFarcode = return_farcode_addr;
|
||||||
b->linkData.push_back(linkData);
|
b->linkData.push_back(linkData);
|
||||||
|
|
||||||
blocks.WriteLinkBlock(*this, linkData);
|
blocks.WriteLinkBlock(*this, linkData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (switch_to_far_code)
|
||||||
|
SwitchToFarCode();
|
||||||
|
DEBUG_ASSERT(GetCodePtr() == primary_farcode_addr || HasWriteFailed());
|
||||||
|
MOVI2R(DISPATCHER_PC, destination);
|
||||||
|
if (LK)
|
||||||
|
BL(GetAsmRoutines()->do_timing);
|
||||||
|
else
|
||||||
|
B(GetAsmRoutines()->do_timing);
|
||||||
|
|
||||||
|
if (LK)
|
||||||
|
{
|
||||||
|
if (GetCodePtr() == return_farcode_addr - sizeof(u32))
|
||||||
|
BRK(101);
|
||||||
|
DEBUG_ASSERT(GetCodePtr() == return_farcode_addr || HasWriteFailed());
|
||||||
|
MOVI2R(DISPATCHER_PC, exit_address_after_return);
|
||||||
|
B(GetAsmRoutines()->do_timing);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (switch_to_far_code)
|
||||||
|
SwitchToNearCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
void JitArm64::WriteExit(Arm64Gen::ARM64Reg dest, bool LK, u32 exit_address_after_return)
|
void JitArm64::WriteExit(Arm64Gen::ARM64Reg dest, bool LK, u32 exit_address_after_return)
|
||||||
|
@ -431,9 +470,27 @@ void JitArm64::WriteExit(Arm64Gen::ARM64Reg dest, bool LK, u32 exit_address_afte
|
||||||
linkData.exitPtrs = GetWritableCodePtr();
|
linkData.exitPtrs = GetWritableCodePtr();
|
||||||
linkData.linkStatus = false;
|
linkData.linkStatus = false;
|
||||||
linkData.call = false;
|
linkData.call = false;
|
||||||
|
const bool switch_to_far_code = !IsInFarCode();
|
||||||
|
if (switch_to_far_code)
|
||||||
|
{
|
||||||
|
SwitchToFarCode();
|
||||||
|
linkData.exitFarcode = GetCodePtr();
|
||||||
|
SwitchToNearCode();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
linkData.exitFarcode = GetCodePtr() + JitArm64BlockCache::BLOCK_LINK_SIZE;
|
||||||
|
}
|
||||||
b->linkData.push_back(linkData);
|
b->linkData.push_back(linkData);
|
||||||
|
|
||||||
blocks.WriteLinkBlock(*this, linkData);
|
blocks.WriteLinkBlock(*this, linkData);
|
||||||
|
|
||||||
|
if (switch_to_far_code)
|
||||||
|
SwitchToFarCode();
|
||||||
|
MOVI2R(DISPATCHER_PC, exit_address_after_return);
|
||||||
|
B(GetAsmRoutines()->do_timing);
|
||||||
|
if (switch_to_far_code)
|
||||||
|
SwitchToNearCode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -465,10 +522,28 @@ void JitArm64::FakeLKExit(u32 exit_address_after_return)
|
||||||
linkData.exitPtrs = GetWritableCodePtr();
|
linkData.exitPtrs = GetWritableCodePtr();
|
||||||
linkData.linkStatus = false;
|
linkData.linkStatus = false;
|
||||||
linkData.call = false;
|
linkData.call = false;
|
||||||
|
const bool switch_to_far_code = !IsInFarCode();
|
||||||
|
if (switch_to_far_code)
|
||||||
|
{
|
||||||
|
SwitchToFarCode();
|
||||||
|
linkData.exitFarcode = GetCodePtr();
|
||||||
|
SwitchToNearCode();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
linkData.exitFarcode = GetCodePtr() + JitArm64BlockCache::BLOCK_LINK_SIZE;
|
||||||
|
}
|
||||||
b->linkData.push_back(linkData);
|
b->linkData.push_back(linkData);
|
||||||
|
|
||||||
blocks.WriteLinkBlock(*this, linkData);
|
blocks.WriteLinkBlock(*this, linkData);
|
||||||
|
|
||||||
|
if (switch_to_far_code)
|
||||||
|
SwitchToFarCode();
|
||||||
|
MOVI2R(DISPATCHER_PC, exit_address_after_return);
|
||||||
|
B(GetAsmRoutines()->do_timing);
|
||||||
|
if (switch_to_far_code)
|
||||||
|
SwitchToNearCode();
|
||||||
|
|
||||||
SetJumpTarget(skip_exit);
|
SetJumpTarget(skip_exit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,8 +29,9 @@ void JitArm64BlockCache::WriteLinkBlock(Arm64Gen::ARM64XEmitter& emit,
|
||||||
emit.MOVI2R(DISPATCHER_PC, source.exitAddress);
|
emit.MOVI2R(DISPATCHER_PC, source.exitAddress);
|
||||||
if (source.call)
|
if (source.call)
|
||||||
{
|
{
|
||||||
while (emit.GetCodePtr() < start + BLOCK_LINK_FAST_BL_OFFSET && !emit.HasWriteFailed())
|
if (emit.GetCodePtr() == start + BLOCK_LINK_FAST_BL_OFFSET - sizeof(u32))
|
||||||
emit.NOP();
|
emit.NOP();
|
||||||
|
DEBUG_ASSERT(emit.GetCodePtr() == start + BLOCK_LINK_FAST_BL_OFFSET || emit.HasWriteFailed());
|
||||||
emit.BL(m_jit.GetAsmRoutines()->dispatcher);
|
emit.BL(m_jit.GetAsmRoutines()->dispatcher);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -45,10 +46,8 @@ void JitArm64BlockCache::WriteLinkBlock(Arm64Gen::ARM64XEmitter& emit,
|
||||||
// The "fast" BL should be the last instruction, so that the return address matches the
|
// The "fast" BL should be the last instruction, so that the return address matches the
|
||||||
// address that was pushed onto the stack by the function that called WriteLinkBlock
|
// address that was pushed onto the stack by the function that called WriteLinkBlock
|
||||||
FixupBranch fast = emit.B(CC_GT);
|
FixupBranch fast = emit.B(CC_GT);
|
||||||
emit.MOVI2R(DISPATCHER_PC, source.exitAddress);
|
emit.B(source.exitFarcode);
|
||||||
emit.BL(m_jit.GetAsmRoutines()->do_timing);
|
DEBUG_ASSERT(emit.GetCodePtr() == start + BLOCK_LINK_FAST_BL_OFFSET || emit.HasWriteFailed());
|
||||||
while (emit.GetCodePtr() < start + BLOCK_LINK_FAST_BL_OFFSET && !emit.HasWriteFailed())
|
|
||||||
emit.BRK(101);
|
|
||||||
emit.SetJumpTarget(fast);
|
emit.SetJumpTarget(fast);
|
||||||
emit.BL(dest->normalEntry);
|
emit.BL(dest->normalEntry);
|
||||||
}
|
}
|
||||||
|
@ -59,16 +58,14 @@ void JitArm64BlockCache::WriteLinkBlock(Arm64Gen::ARM64XEmitter& emit,
|
||||||
if (block_distance >= -0x40000 && block_distance <= 0x3FFFF)
|
if (block_distance >= -0x40000 && block_distance <= 0x3FFFF)
|
||||||
{
|
{
|
||||||
emit.B(CC_GT, dest->normalEntry);
|
emit.B(CC_GT, dest->normalEntry);
|
||||||
emit.MOVI2R(DISPATCHER_PC, source.exitAddress);
|
emit.B(source.exitFarcode);
|
||||||
emit.B(m_jit.GetAsmRoutines()->do_timing);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
FixupBranch slow = emit.B(CC_LE);
|
FixupBranch slow = emit.B(CC_LE);
|
||||||
emit.B(dest->normalEntry);
|
emit.B(dest->normalEntry);
|
||||||
emit.SetJumpTarget(slow);
|
emit.SetJumpTarget(slow);
|
||||||
emit.MOVI2R(DISPATCHER_PC, source.exitAddress);
|
emit.B(source.exitFarcode);
|
||||||
emit.B(m_jit.GetAsmRoutines()->do_timing);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ public:
|
||||||
void WriteLinkBlock(Arm64Gen::ARM64XEmitter& emit, const JitBlock::LinkData& source,
|
void WriteLinkBlock(Arm64Gen::ARM64XEmitter& emit, const JitBlock::LinkData& source,
|
||||||
const JitBlock* dest = nullptr);
|
const JitBlock* dest = nullptr);
|
||||||
|
|
||||||
static constexpr size_t BLOCK_LINK_SIZE = 5 * sizeof(u32);
|
static constexpr size_t BLOCK_LINK_SIZE = 3 * sizeof(u32);
|
||||||
static constexpr size_t BLOCK_LINK_FAST_BL_OFFSET = BLOCK_LINK_SIZE - sizeof(u32);
|
static constexpr size_t BLOCK_LINK_FAST_BL_OFFSET = BLOCK_LINK_SIZE - sizeof(u32);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -70,6 +70,9 @@ struct JitBlock : public JitBlockData
|
||||||
struct LinkData
|
struct LinkData
|
||||||
{
|
{
|
||||||
u8* exitPtrs; // to be able to rewrite the exit jump
|
u8* exitPtrs; // to be able to rewrite the exit jump
|
||||||
|
#ifdef _M_ARM_64
|
||||||
|
const u8* exitFarcode;
|
||||||
|
#endif
|
||||||
u32 exitAddress;
|
u32 exitAddress;
|
||||||
bool linkStatus; // is it already linked?
|
bool linkStatus; // is it already linked?
|
||||||
bool call;
|
bool call;
|
||||||
|
|
Loading…
Reference in New Issue