diff --git a/src/dynarmic/backend/arm64/address_space.cpp b/src/dynarmic/backend/arm64/address_space.cpp index 402932bc..70acb229 100644 --- a/src/dynarmic/backend/arm64/address_space.cpp +++ b/src/dynarmic/backend/arm64/address_space.cpp @@ -124,13 +124,27 @@ static void LinkBlockLinks(const CodePtr entry_point, const CodePtr target_ptr, using namespace oaknut; using namespace oaknut::util; - for (auto [ptr_offset] : block_relocations_list) { + for (auto [ptr_offset, type] : block_relocations_list) { CodeGenerator c{reinterpret_cast(entry_point + ptr_offset)}; - if (target_ptr) { - c.B((void*)target_ptr); - } else { - c.NOP(); + switch (type) { + case BlockRelocationType::Branch: + if (target_ptr) { + c.B((void*)target_ptr); + } else { + c.NOP(); + } + break; + case BlockRelocationType::MoveToScratch0: + if (target_ptr) { + c.ADRL(Xscratch0, (void*)target_ptr); + } else { + c.NOP(); + c.NOP(); + } + break; + default: + ASSERT_FALSE("Invalid BlockRelocationType"); } } } diff --git a/src/dynarmic/backend/arm64/emit_arm64.cpp b/src/dynarmic/backend/arm64/emit_arm64.cpp index df38bda2..117c957a 100644 --- a/src/dynarmic/backend/arm64/emit_arm64.cpp +++ b/src/dynarmic/backend/arm64/emit_arm64.cpp @@ -256,9 +256,19 @@ void EmitRelocation(oaknut::CodeGenerator& code, EmitContext& ctx, LinkTarget li code.NOP(); } -void EmitBlockLinkRelocation(oaknut::CodeGenerator& code, EmitContext& ctx, const IR::LocationDescriptor& descriptor) { - ctx.ebi.block_relocations[descriptor].emplace_back(BlockRelocation{code.ptr() - ctx.ebi.entry_point}); - code.NOP(); +void EmitBlockLinkRelocation(oaknut::CodeGenerator& code, EmitContext& ctx, const IR::LocationDescriptor& descriptor, BlockRelocationType type) { + ctx.ebi.block_relocations[descriptor].emplace_back(BlockRelocation{code.ptr() - ctx.ebi.entry_point, type}); + switch (type) { + case BlockRelocationType::Branch: + code.NOP(); + break; + case BlockRelocationType::MoveToScratch0: + code.NOP(); + code.NOP(); + break; + default: + UNREACHABLE(); + } } } // namespace Dynarmic::Backend::Arm64 diff --git a/src/dynarmic/backend/arm64/emit_arm64.h b/src/dynarmic/backend/arm64/emit_arm64.h index 6d13e7e3..eac19d24 100644 --- a/src/dynarmic/backend/arm64/emit_arm64.h +++ b/src/dynarmic/backend/arm64/emit_arm64.h @@ -91,8 +91,14 @@ struct Relocation { LinkTarget target; }; +enum class BlockRelocationType { + Branch, + MoveToScratch0, +}; + struct BlockRelocation { std::ptrdiff_t code_offset; + BlockRelocationType type; }; struct EmittedBlockInfo { @@ -165,7 +171,7 @@ EmittedBlockInfo EmitArm64(oaknut::CodeGenerator& code, IR::Block block, const E template void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst); void EmitRelocation(oaknut::CodeGenerator& code, EmitContext& ctx, LinkTarget link_target); -void EmitBlockLinkRelocation(oaknut::CodeGenerator& code, EmitContext& ctx, const IR::LocationDescriptor& descriptor); +void EmitBlockLinkRelocation(oaknut::CodeGenerator& code, EmitContext& ctx, const IR::LocationDescriptor& descriptor, BlockRelocationType type); oaknut::Label EmitA32Cond(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Cond cond); oaknut::Label EmitA64Cond(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Cond cond); void EmitA32Terminal(oaknut::CodeGenerator& code, EmitContext& ctx); diff --git a/src/dynarmic/backend/arm64/emit_arm64_a32.cpp b/src/dynarmic/backend/arm64/emit_arm64_a32.cpp index 62eb9c1a..cee91dc9 100644 --- a/src/dynarmic/backend/arm64/emit_arm64_a32.cpp +++ b/src/dynarmic/backend/arm64/emit_arm64_a32.cpp @@ -67,11 +67,11 @@ void EmitA32Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::Li if (ctx.conf.enable_cycle_counting) { code.CMP(Xticks, 0); code.B(LE, fail); - EmitBlockLinkRelocation(code, ctx, terminal.next); + EmitBlockLinkRelocation(code, ctx, terminal.next, BlockRelocationType::Branch); } else { code.LDAR(Wscratch0, Xhalt); code.CBNZ(Wscratch0, fail); - EmitBlockLinkRelocation(code, ctx, terminal.next); + EmitBlockLinkRelocation(code, ctx, terminal.next, BlockRelocationType::Branch); } } @@ -85,7 +85,7 @@ void EmitA32Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::Li EmitSetUpperLocationDescriptor(code, ctx, terminal.next, initial_location); if (ctx.conf.HasOptimization(OptimizationFlag::BlockLinking) && !is_single_step) { - EmitBlockLinkRelocation(code, ctx, terminal.next); + EmitBlockLinkRelocation(code, ctx, terminal.next, BlockRelocationType::Branch); } code.MOV(Wscratch0, A32::LocationDescriptor{terminal.next}.PC()); diff --git a/src/dynarmic/backend/arm64/emit_arm64_a64.cpp b/src/dynarmic/backend/arm64/emit_arm64_a64.cpp index ddad8254..85973b79 100644 --- a/src/dynarmic/backend/arm64/emit_arm64_a64.cpp +++ b/src/dynarmic/backend/arm64/emit_arm64_a64.cpp @@ -46,11 +46,11 @@ void EmitA64Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::Li if (ctx.conf.enable_cycle_counting) { code.CMP(Xticks, 0); code.B(LE, fail); - EmitBlockLinkRelocation(code, ctx, terminal.next); + EmitBlockLinkRelocation(code, ctx, terminal.next, BlockRelocationType::Branch); } else { code.LDAR(Wscratch0, Xhalt); code.CBNZ(Wscratch0, fail); - EmitBlockLinkRelocation(code, ctx, terminal.next); + EmitBlockLinkRelocation(code, ctx, terminal.next, BlockRelocationType::Branch); } } @@ -62,7 +62,7 @@ void EmitA64Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::Li void EmitA64Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::LinkBlockFast terminal, IR::LocationDescriptor, bool is_single_step) { if (ctx.conf.HasOptimization(OptimizationFlag::BlockLinking) && !is_single_step) { - EmitBlockLinkRelocation(code, ctx, terminal.next); + EmitBlockLinkRelocation(code, ctx, terminal.next, BlockRelocationType::Branch); } code.MOV(Xscratch0, A64::LocationDescriptor{terminal.next}.PC());