diff --git a/src/dynarmic/backend/arm64/emit_arm64.cpp b/src/dynarmic/backend/arm64/emit_arm64.cpp index c40eca80..771e0f28 100644 --- a/src/dynarmic/backend/arm64/emit_arm64.cpp +++ b/src/dynarmic/backend/arm64/emit_arm64.cpp @@ -133,6 +133,17 @@ void EmitIR(oaknut::CodeGenerator&, EmitContext ctx.reg_alloc.DefineAsExisting(inst, args[0]); } +static void EmitAddCycles(oaknut::CodeGenerator& code, EmitContext&, size_t cycles_to_add) { + code.LDR(Xscratch0, SP, offsetof(StackLayout, cycles_remaining)); + if (oaknut::AddSubImm::is_valid(cycles_to_add)) { + code.SUBS(Xscratch0, Xscratch0, cycles_to_add); + } else { + code.MOV(Xscratch1, cycles_to_add); + code.SUBS(Xscratch0, Xscratch0, Xscratch1); + } + code.STR(Xscratch0, SP, offsetof(StackLayout, cycles_remaining)); +} + EmittedBlockInfo EmitArm64(oaknut::CodeGenerator& code, IR::Block block, const EmitConfig& conf) { EmittedBlockInfo ebi; @@ -141,6 +152,19 @@ EmittedBlockInfo EmitArm64(oaknut::CodeGenerator& code, IR::Block block, const E ebi.entry_point = code.ptr(); + if (ctx.block.GetCondition() == IR::Cond::AL) { + ASSERT(!ctx.block.HasConditionFailedLocation()); + } else { + ASSERT(ctx.block.HasConditionFailedLocation()); + + oaknut::Label pass = EmitA32Cond(code, ctx, ctx.block.GetCondition()); + if (conf.enable_cycle_counting) { + EmitAddCycles(code, ctx, ctx.block.ConditionFailedCycleCount()); + } + EmitA32ConditionFailedTerminal(code, ctx); + code.l(pass); + } + for (auto iter = block.begin(); iter != block.end(); ++iter) { IR::Inst* inst = &*iter; @@ -172,15 +196,7 @@ EmittedBlockInfo EmitArm64(oaknut::CodeGenerator& code, IR::Block block, const E reg_alloc.AssertNoMoreUses(); if (ctx.conf.enable_cycle_counting) { - const size_t cycles_to_add = block.CycleCount(); - code.LDR(Xscratch0, SP, offsetof(StackLayout, cycles_remaining)); - if (oaknut::AddSubImm::is_valid(cycles_to_add)) { - code.SUBS(Xscratch0, Xscratch0, cycles_to_add); - } else { - code.MOV(Xscratch1, cycles_to_add); - code.SUBS(Xscratch0, Xscratch0, Xscratch1); - } - code.STR(Xscratch0, SP, offsetof(StackLayout, cycles_remaining)); + EmitAddCycles(code, ctx, block.CycleCount()); } EmitA32Terminal(code, ctx); diff --git a/src/dynarmic/backend/arm64/emit_arm64.h b/src/dynarmic/backend/arm64/emit_arm64.h index 652f19cd..b2176778 100644 --- a/src/dynarmic/backend/arm64/emit_arm64.h +++ b/src/dynarmic/backend/arm64/emit_arm64.h @@ -68,5 +68,6 @@ void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst); void EmitRelocation(oaknut::CodeGenerator& code, EmitContext& ctx, LinkTarget link_target); oaknut::Label EmitA32Cond(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Cond cond); void EmitA32Terminal(oaknut::CodeGenerator& code, EmitContext& ctx); +void EmitA32ConditionFailedTerminal(oaknut::CodeGenerator& code, EmitContext& ctx); } // namespace Dynarmic::Backend::Arm64 diff --git a/src/dynarmic/backend/arm64/emit_arm64_a32.cpp b/src/dynarmic/backend/arm64/emit_arm64_a32.cpp index 3a5b8d92..392ad4d2 100644 --- a/src/dynarmic/backend/arm64/emit_arm64_a32.cpp +++ b/src/dynarmic/backend/arm64/emit_arm64_a32.cpp @@ -123,6 +123,11 @@ void EmitA32Terminal(oaknut::CodeGenerator& code, EmitContext& ctx) { EmitA32Terminal(code, ctx, ctx.block.GetTerminal(), location.SetSingleStepping(false), location.SingleStepping()); } +void EmitA32ConditionFailedTerminal(oaknut::CodeGenerator& code, EmitContext& ctx) { + const A32::LocationDescriptor location{ctx.block.Location()}; + EmitA32Terminal(code, ctx, IR::Term::LinkBlock{ctx.block.ConditionFailedLocation()}, location.SetSingleStepping(false), location.SingleStepping()); +} + template<> void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst);