diff --git a/src/core/cpu_recompiler_code_generator.h b/src/core/cpu_recompiler_code_generator.h index 3364407b6..85cd223c6 100644 --- a/src/core/cpu_recompiler_code_generator.h +++ b/src/core/cpu_recompiler_code_generator.h @@ -78,6 +78,9 @@ public: Value EmitLoadGuestMemory(const Value& address, RegSize size); void EmitStoreGuestMemory(const Value& address, const Value& value); + // Unconditional branch to pointer. May allocate a scratch register. + void EmitBranch(const void* address, bool allow_scratch = true); + // Branching, generates two paths. void EmitBranch(Condition condition, Reg lr_reg, Value&& branch_target); void EmitBranchIfBitClear(HostReg reg, RegSize size, u8 bit, LabelType* label); diff --git a/src/core/cpu_recompiler_code_generator_aarch64.cpp b/src/core/cpu_recompiler_code_generator_aarch64.cpp index 0e85b0ae7..d3b7c8e5e 100644 --- a/src/core/cpu_recompiler_code_generator_aarch64.cpp +++ b/src/core/cpu_recompiler_code_generator_aarch64.cpp @@ -1390,6 +1390,24 @@ void CodeGenerator::EmitCancelInterpreterLoadDelayForReg(Reg reg) m_emit->Bind(&skip_cancel); } +void CodeGenerator::EmitBranch(const void* address, bool allow_scratch) +{ + const s64 jump_distance = + static_cast(reinterpret_cast(address) - reinterpret_cast(GetCurrentCodePointer())); + Assert(Common::IsAligned(jump_distance, 4)); + if (a64::Instruction::IsValidImmPCOffset(a64::UncondBranchType, jump_distance >> 2)) + { + m_emit->b(jump_distance >> 2); + return; + } + + Assert(allow_scratch); + + Value temp = m_register_cache.AllocateScratch(RegSize_64); + m_emit->Mov(GetHostReg64(temp), reinterpret_cast(address)); + m_emit->br(GetHostReg64(temp)); +} + template static void EmitConditionalJump(Condition condition, bool invert, a64::MacroAssembler* emit, const T& label) { diff --git a/src/core/cpu_recompiler_code_generator_x64.cpp b/src/core/cpu_recompiler_code_generator_x64.cpp index fb377775f..2203116d8 100644 --- a/src/core/cpu_recompiler_code_generator_x64.cpp +++ b/src/core/cpu_recompiler_code_generator_x64.cpp @@ -1792,6 +1792,21 @@ void CodeGenerator::EmitCancelInterpreterLoadDelayForReg(Reg reg) m_emit->L(skip_cancel); } +void CodeGenerator::EmitBranch(const void* address, bool allow_scratch) +{ + if (Xbyak::inner::IsInInt32(reinterpret_cast(address))) + { + m_emit->jmp(address); + return; + } + + Assert(allow_scratch); + + Value temp = m_register_cache.AllocateScratch(RegSize_64); + m_emit->mov(GetHostReg64(temp), reinterpret_cast(address)); + m_emit->jmp(GetHostReg64(temp)); +} + template static void EmitConditionalJump(Condition condition, bool invert, Xbyak::CodeGenerator* emit, const T& label) {