emit_arm64: Handle cond prologue
This commit is contained in:
parent
aa6b31f2b8
commit
2ac12562ab
3 changed files with 31 additions and 9 deletions
|
@ -133,6 +133,17 @@ void EmitIR<IR::Opcode::NZCVFromPackedFlags>(oaknut::CodeGenerator&, EmitContext
|
||||||
ctx.reg_alloc.DefineAsExisting(inst, args[0]);
|
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 EmitArm64(oaknut::CodeGenerator& code, IR::Block block, const EmitConfig& conf) {
|
||||||
EmittedBlockInfo ebi;
|
EmittedBlockInfo ebi;
|
||||||
|
|
||||||
|
@ -141,6 +152,19 @@ EmittedBlockInfo EmitArm64(oaknut::CodeGenerator& code, IR::Block block, const E
|
||||||
|
|
||||||
ebi.entry_point = code.ptr<CodePtr>();
|
ebi.entry_point = code.ptr<CodePtr>();
|
||||||
|
|
||||||
|
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) {
|
for (auto iter = block.begin(); iter != block.end(); ++iter) {
|
||||||
IR::Inst* inst = &*iter;
|
IR::Inst* inst = &*iter;
|
||||||
|
|
||||||
|
@ -172,15 +196,7 @@ EmittedBlockInfo EmitArm64(oaknut::CodeGenerator& code, IR::Block block, const E
|
||||||
reg_alloc.AssertNoMoreUses();
|
reg_alloc.AssertNoMoreUses();
|
||||||
|
|
||||||
if (ctx.conf.enable_cycle_counting) {
|
if (ctx.conf.enable_cycle_counting) {
|
||||||
const size_t cycles_to_add = block.CycleCount();
|
EmitAddCycles(code, ctx, 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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EmitA32Terminal(code, ctx);
|
EmitA32Terminal(code, ctx);
|
||||||
|
|
|
@ -68,5 +68,6 @@ void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst);
|
||||||
void EmitRelocation(oaknut::CodeGenerator& code, EmitContext& ctx, LinkTarget link_target);
|
void EmitRelocation(oaknut::CodeGenerator& code, EmitContext& ctx, LinkTarget link_target);
|
||||||
oaknut::Label EmitA32Cond(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Cond cond);
|
oaknut::Label EmitA32Cond(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Cond cond);
|
||||||
void EmitA32Terminal(oaknut::CodeGenerator& code, EmitContext& ctx);
|
void EmitA32Terminal(oaknut::CodeGenerator& code, EmitContext& ctx);
|
||||||
|
void EmitA32ConditionFailedTerminal(oaknut::CodeGenerator& code, EmitContext& ctx);
|
||||||
|
|
||||||
} // namespace Dynarmic::Backend::Arm64
|
} // namespace Dynarmic::Backend::Arm64
|
||||||
|
|
|
@ -123,6 +123,11 @@ void EmitA32Terminal(oaknut::CodeGenerator& code, EmitContext& ctx) {
|
||||||
EmitA32Terminal(code, ctx, ctx.block.GetTerminal(), location.SetSingleStepping(false), location.SingleStepping());
|
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<>
|
template<>
|
||||||
void EmitIR<IR::Opcode::A32SetCheckBit>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
|
void EmitIR<IR::Opcode::A32SetCheckBit>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
|
||||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
|
|
Loading…
Reference in a new issue