diff --git a/src/dynarmic/backend/arm64/emit_arm64.cpp b/src/dynarmic/backend/arm64/emit_arm64.cpp index 8ce101ea..e687ee09 100644 --- a/src/dynarmic/backend/arm64/emit_arm64.cpp +++ b/src/dynarmic/backend/arm64/emit_arm64.cpp @@ -83,7 +83,7 @@ void EmitIR(oaknut::CodeGenerator& code, EmitContext& c auto flags = ctx.reg_alloc.WriteFlags(inst); RegAlloc::Realize(Wvalue, flags); - code.CMP(*Wvalue, WZR); + code.TST(*Wvalue, *Wvalue); } template<> @@ -98,6 +98,17 @@ void EmitIR(oaknut::CodeGenerator&, EmitContext& ctx ASSERT(ctx.reg_alloc.IsValueLive(inst)); } +template<> +void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + + auto Wc = ctx.reg_alloc.WriteW(inst); + auto Wnzcv = ctx.reg_alloc.ReadW(args[0]); + RegAlloc::Realize(Wc, Wnzcv); + + code.AND(Wc, Wnzcv, 1 << 29); +} + template<> void EmitIR(oaknut::CodeGenerator&, EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); diff --git a/src/dynarmic/backend/arm64/emit_arm64_a32.cpp b/src/dynarmic/backend/arm64/emit_arm64_a32.cpp index 41142fdc..dee1f1e5 100644 --- a/src/dynarmic/backend/arm64/emit_arm64_a32.cpp +++ b/src/dynarmic/backend/arm64/emit_arm64_a32.cpp @@ -275,11 +275,12 @@ void EmitIR(oaknut::CodeGenerator& code, EmitContext& auto Wc = ctx.reg_alloc.ReadW(args[1]); RegAlloc::Realize(Wnz, Wc); - // TODO: Store in Flags + // TODO: Track latent value + code.LDR(Wscratch0, Xstate, offsetof(A32JitState, cpsr_nzcv)); code.AND(Wscratch0, Wscratch0, 0x10000000); code.ORR(Wscratch0, Wscratch0, Wnz); - code.SBFX(Wscratch0, Wc, 29, 1); + code.ORR(Wscratch0, Wscratch0, Wc); code.STR(Wscratch0, Xstate, offsetof(A32JitState, cpsr_nzcv)); } @@ -288,11 +289,8 @@ void EmitIR(oaknut::CodeGenerator& code, EmitContext& c auto Wflag = ctx.reg_alloc.WriteW(inst); RegAlloc::Realize(Wflag); - // TODO: Store in Flags - - code.LDR(Wscratch0, Xstate, offsetof(A32JitState, cpsr_nzcv)); - code.LSR(Wflag, Wscratch0, 29); - code.AND(Wflag, Wflag, 1); + code.LDR(Wflag, Xstate, offsetof(A32JitState, cpsr_nzcv)); + code.AND(Wflag, Wflag, 1 << 29); } template<> diff --git a/src/dynarmic/backend/arm64/emit_arm64_data_processing.cpp b/src/dynarmic/backend/arm64/emit_arm64_data_processing.cpp index 8c40c046..865fff6a 100644 --- a/src/dynarmic/backend/arm64/emit_arm64_data_processing.cpp +++ b/src/dynarmic/backend/arm64/emit_arm64_data_processing.cpp @@ -117,7 +117,6 @@ void EmitIR(oaknut::CodeGenerator& code, EmitCo template<> void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { - // TODO: Use host flags auto args = ctx.reg_alloc.GetArgumentInfo(inst); auto Wresult = ctx.reg_alloc.WriteW(inst); @@ -129,12 +128,12 @@ void EmitIR(oaknut::CodeGenerator& code, EmitCon template<> void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { - // TODO: Use host flags auto args = ctx.reg_alloc.GetArgumentInfo(inst); auto Wresult = ctx.reg_alloc.WriteW(inst); auto Woperand = ctx.reg_alloc.ReadW(args[0]); RegAlloc::Realize(Wresult, Woperand); + ctx.reg_alloc.SpillFlags(); code.CMP(Woperand, 0); code.CSET(Wresult, EQ); @@ -142,12 +141,12 @@ void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, template<> void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { - // TODO: Use host flags auto args = ctx.reg_alloc.GetArgumentInfo(inst); auto Wresult = ctx.reg_alloc.WriteW(inst); auto Xoperand = ctx.reg_alloc.ReadX(args[0]); RegAlloc::Realize(Wresult, Xoperand); + ctx.reg_alloc.SpillFlags(); code.CMP(Xoperand, 0); code.CSET(Wresult, EQ); @@ -221,26 +220,37 @@ void EmitIR(oaknut::CodeGenerator& code, EmitCon code.CSEL(Wresult, Wresult, WZR, LT); } } else { - if (shift_arg.IsImmediate()) { - auto Wresult = ctx.reg_alloc.WriteW(inst); - auto Wcarry_out = ctx.reg_alloc.WriteW(carry_inst); - auto Woperand = ctx.reg_alloc.ReadW(operand_arg); - auto Wcarry_in = ctx.reg_alloc.ReadW(carry_arg); - RegAlloc::Realize(Wresult, Wcarry_out, Woperand, Wcarry_in); + if (shift_arg.IsImmediate() && shift_arg.GetImmediateU8() == 0) { + ctx.reg_alloc.DefineAsExisting(inst, operand_arg); + ctx.reg_alloc.DefineAsExisting(carry_inst, carry_arg); + } else if (shift_arg.IsImmediate()) { + // TODO: Use RMIF const u8 shift = shift_arg.GetImmediateU8(); - if (shift == 0) { - code.MOV(*Wresult, Woperand); - code.MOV(*Wcarry_out, Wcarry_in); - } else if (shift < 32) { + if (shift < 32) { + auto Wresult = ctx.reg_alloc.WriteW(inst); + auto Wcarry_out = ctx.reg_alloc.WriteW(carry_inst); + auto Woperand = ctx.reg_alloc.ReadW(operand_arg); + RegAlloc::Realize(Wresult, Wcarry_out, Woperand); + code.UBFX(Wcarry_out, Woperand, 32 - shift, 1); + code.LSL(Wcarry_out, Wcarry_out, 29); code.LSL(Wresult, Woperand, shift); } else if (shift > 32) { + auto Wresult = ctx.reg_alloc.WriteW(inst); + auto Wcarry_out = ctx.reg_alloc.WriteW(carry_inst); + RegAlloc::Realize(Wresult, Wcarry_out); + code.MOV(Wresult, WZR); code.MOV(Wcarry_out, WZR); } else { - code.AND(Wcarry_out, Wresult, 1); + auto Wresult = ctx.reg_alloc.WriteW(inst); + auto Wcarry_out = ctx.reg_alloc.WriteW(carry_inst); + auto Woperand = ctx.reg_alloc.ReadW(operand_arg); + RegAlloc::Realize(Wresult, Wcarry_out, Woperand); + + code.UBFIZ(Wcarry_out, Woperand, 29, 1); code.MOV(Wresult, WZR); } } else { @@ -262,7 +272,7 @@ void EmitIR(oaknut::CodeGenerator& code, EmitCon code.NEG(Wscratch0, Wshift); code.LSR(Wcarry_out, Woperand, Wscratch0); code.LSL(Wresult, Woperand, Wshift); - code.AND(Wcarry_out, Wcarry_out, 1); + code.UBFIZ(Wcarry_out, Wcarry_out, 29, 1); code.CMP(Wscratch1, 32); code.CSEL(Wresult, Wresult, WZR, LT); code.CSEL(Wcarry_out, Wcarry_out, WZR, LE); diff --git a/src/dynarmic/backend/arm64/reg_alloc.cpp b/src/dynarmic/backend/arm64/reg_alloc.cpp index be52a9f8..41446bb2 100644 --- a/src/dynarmic/backend/arm64/reg_alloc.cpp +++ b/src/dynarmic/backend/arm64/reg_alloc.cpp @@ -27,6 +27,14 @@ static bool IsValuelessType(IR::Type type) { } } +Argument::~Argument() { + if (!IsImmediate()) { + if (auto host_loc = reg_alloc.ValueLocation(value.GetInst())) { + reg_alloc.ValueInfo(*host_loc).UpdateUses(); + } + } +} + IR::Type Argument::GetType() const { return value.GetType(); } @@ -101,6 +109,18 @@ bool HostLocInfo::IsOneRemainingUse() const { return accumulated_uses + 1 == expected_uses && uses_this_inst == 1; } +void HostLocInfo::UpdateUses() { + accumulated_uses += uses_this_inst; + uses_this_inst = 0; + + if (accumulated_uses == expected_uses) { + *this = {}; + } else { + realized = false; + locked = false; + } +} + RegAlloc::ArgumentInfo RegAlloc::GetArgumentInfo(IR::Inst* inst) { ArgumentInfo ret = {Argument{*this}, Argument{*this}, Argument{*this}, Argument{*this}}; for (size_t i = 0; i < inst->NumArgs(); i++) { @@ -229,19 +249,8 @@ template int RegAlloc::RealizeWriteImpl(const IR::Inst* va void RegAlloc::Unlock(HostLoc host_loc) { HostLocInfo& info = ValueInfo(host_loc); - if (!info.realized) { - return; - } - - info.accumulated_uses += info.uses_this_inst; - info.uses_this_inst = 0; - - if (info.accumulated_uses == info.expected_uses) { - info = {}; - } else { - info.realized = false; - info.locked = false; - } + ASSERT(info.locked && info.realized); + info.UpdateUses(); } int RegAlloc::AllocateRegister(const std::array& regs, const std::vector& order) const { diff --git a/src/dynarmic/backend/arm64/reg_alloc.h b/src/dynarmic/backend/arm64/reg_alloc.h index 712d1c85..12360022 100644 --- a/src/dynarmic/backend/arm64/reg_alloc.h +++ b/src/dynarmic/backend/arm64/reg_alloc.h @@ -39,6 +39,8 @@ struct Argument { public: using copyable_reference = std::reference_wrapper; + ~Argument(); + IR::Type GetType() const; bool IsImmediate() const; @@ -124,6 +126,7 @@ struct HostLocInfo { bool IsCompletelyEmpty() const; bool IsImmediatelyAllocatable() const; bool IsOneRemainingUse() const; + void UpdateUses(); }; class RegAlloc {