diff --git a/Source/Core/Core/PowerPC/JitArm64/Jit.cpp b/Source/Core/Core/PowerPC/JitArm64/Jit.cpp index 8bf5178616..7f93d359af 100644 --- a/Source/Core/Core/PowerPC/JitArm64/Jit.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/Jit.cpp @@ -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); } + 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::LinkData linkData; linkData.exitAddress = destination; linkData.exitPtrs = GetWritableCodePtr(); linkData.linkStatus = false; linkData.call = LK; + linkData.exitFarcode = primary_farcode_addr; b->linkData.push_back(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.linkStatus = false; linkData.call = false; + linkData.exitFarcode = return_farcode_addr; b->linkData.push_back(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) @@ -431,9 +470,27 @@ void JitArm64::WriteExit(Arm64Gen::ARM64Reg dest, bool LK, u32 exit_address_afte linkData.exitPtrs = GetWritableCodePtr(); linkData.linkStatus = 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); 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.linkStatus = 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); 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); } diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64Cache.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64Cache.cpp index 2fcefa019c..e991fe04c9 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64Cache.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64Cache.cpp @@ -29,8 +29,9 @@ void JitArm64BlockCache::WriteLinkBlock(Arm64Gen::ARM64XEmitter& emit, emit.MOVI2R(DISPATCHER_PC, source.exitAddress); 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(); + DEBUG_ASSERT(emit.GetCodePtr() == start + BLOCK_LINK_FAST_BL_OFFSET || emit.HasWriteFailed()); emit.BL(m_jit.GetAsmRoutines()->dispatcher); } 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 // address that was pushed onto the stack by the function that called WriteLinkBlock FixupBranch fast = emit.B(CC_GT); - emit.MOVI2R(DISPATCHER_PC, source.exitAddress); - emit.BL(m_jit.GetAsmRoutines()->do_timing); - while (emit.GetCodePtr() < start + BLOCK_LINK_FAST_BL_OFFSET && !emit.HasWriteFailed()) - emit.BRK(101); + emit.B(source.exitFarcode); + DEBUG_ASSERT(emit.GetCodePtr() == start + BLOCK_LINK_FAST_BL_OFFSET || emit.HasWriteFailed()); emit.SetJumpTarget(fast); emit.BL(dest->normalEntry); } @@ -59,16 +58,14 @@ void JitArm64BlockCache::WriteLinkBlock(Arm64Gen::ARM64XEmitter& emit, if (block_distance >= -0x40000 && block_distance <= 0x3FFFF) { emit.B(CC_GT, dest->normalEntry); - emit.MOVI2R(DISPATCHER_PC, source.exitAddress); - emit.B(m_jit.GetAsmRoutines()->do_timing); + emit.B(source.exitFarcode); } else { FixupBranch slow = emit.B(CC_LE); emit.B(dest->normalEntry); emit.SetJumpTarget(slow); - emit.MOVI2R(DISPATCHER_PC, source.exitAddress); - emit.B(m_jit.GetAsmRoutines()->do_timing); + emit.B(source.exitFarcode); } } } diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64Cache.h b/Source/Core/Core/PowerPC/JitArm64/JitArm64Cache.h index dc068054d7..1214e8c308 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64Cache.h +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64Cache.h @@ -29,7 +29,7 @@ public: void WriteLinkBlock(Arm64Gen::ARM64XEmitter& emit, const JitBlock::LinkData& source, 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); private: diff --git a/Source/Core/Core/PowerPC/JitCommon/JitCache.h b/Source/Core/Core/PowerPC/JitCommon/JitCache.h index fb72cbe07e..d3f353e815 100644 --- a/Source/Core/Core/PowerPC/JitCommon/JitCache.h +++ b/Source/Core/Core/PowerPC/JitCommon/JitCache.h @@ -70,6 +70,9 @@ struct JitBlock : public JitBlockData struct LinkData { u8* exitPtrs; // to be able to rewrite the exit jump +#ifdef _M_ARM_64 + const u8* exitFarcode; +#endif u32 exitAddress; bool linkStatus; // is it already linked? bool call;