From a2b3199adf301e4bb9c699894078c354ff256864 Mon Sep 17 00:00:00 2001 From: Merry Date: Sat, 23 Jul 2022 11:22:48 +0100 Subject: [PATCH] Convert NZCV to C flag where able --- src/dynarmic/backend/x64/emit_x64.cpp | 16 ++++++++++++++++ src/dynarmic/ir/ir_emitter.cpp | 4 ++++ src/dynarmic/ir/ir_emitter.h | 1 + src/dynarmic/ir/opcodes.inc | 1 + .../ir/opt/a32_get_set_elimination_pass.cpp | 8 ++++++++ 5 files changed, 30 insertions(+) diff --git a/src/dynarmic/backend/x64/emit_x64.cpp b/src/dynarmic/backend/x64/emit_x64.cpp index 68e65c87..dd8f2681 100644 --- a/src/dynarmic/backend/x64/emit_x64.cpp +++ b/src/dynarmic/backend/x64/emit_x64.cpp @@ -188,6 +188,22 @@ void EmitX64::EmitGetNZCVFromOp(EmitContext& ctx, IR::Inst* inst) { ctx.reg_alloc.DefineValue(inst, nzcv); } +void EmitX64::EmitGetCFlagFromNZCV(EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + + if (args[0].IsImmediate()) { + const Xbyak::Reg32 result = ctx.reg_alloc.ScratchGpr().cvt32(); + const u32 value = (args[0].GetImmediateU32() >> 8) & 1; + code.mov(result, value); + ctx.reg_alloc.DefineValue(inst, result); + } else { + const Xbyak::Reg32 result = ctx.reg_alloc.UseScratchGpr(args[0]).cvt32(); + code.shr(result, 8); + code.and_(result, 1); + ctx.reg_alloc.DefineValue(inst, result); + } +} + void EmitX64::EmitNZCVFromPackedFlags(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); diff --git a/src/dynarmic/ir/ir_emitter.cpp b/src/dynarmic/ir/ir_emitter.cpp index f588d3db..004b1303 100644 --- a/src/dynarmic/ir/ir_emitter.cpp +++ b/src/dynarmic/ir/ir_emitter.cpp @@ -135,6 +135,10 @@ U32U64 IREmitter::ConditionalSelect(Cond cond, const U32U64& a, const U32U64& b) } } +U1 IREmitter::GetCFlagFromNZCV(const NZCV& nzcv) { + return Inst(Opcode::GetCFlagFromNZCV, nzcv); +} + NZCV IREmitter::NZCVFromPackedFlags(const U32& a) { return Inst(Opcode::NZCVFromPackedFlags, a); } diff --git a/src/dynarmic/ir/ir_emitter.h b/src/dynarmic/ir/ir_emitter.h index 7c5bb0c7..62ea7e64 100644 --- a/src/dynarmic/ir/ir_emitter.h +++ b/src/dynarmic/ir/ir_emitter.h @@ -101,6 +101,7 @@ public: NZCV ConditionalSelect(Cond cond, const NZCV& a, const NZCV& b); U32U64 ConditionalSelect(Cond cond, const U32U64& a, const U32U64& b); + U1 GetCFlagFromNZCV(const NZCV& nzcv); NZCV NZCVFromPackedFlags(const U32& a); // This pseudo-instruction may only be added to instructions that support it. NZCV NZCVFrom(const Value& value); diff --git a/src/dynarmic/ir/opcodes.inc b/src/dynarmic/ir/opcodes.inc index 335d4477..c2954c31 100644 --- a/src/dynarmic/ir/opcodes.inc +++ b/src/dynarmic/ir/opcodes.inc @@ -92,6 +92,7 @@ OPCODE(GetNZFromOp, NZCV, Opaq OPCODE(GetUpperFromOp, U128, Opaque ) OPCODE(GetLowerFromOp, U128, Opaque ) +OPCODE(GetCFlagFromNZCV, U1, NZCV ) OPCODE(NZCVFromPackedFlags, NZCV, U32 ) // Calculations diff --git a/src/dynarmic/ir/opt/a32_get_set_elimination_pass.cpp b/src/dynarmic/ir/opt/a32_get_set_elimination_pass.cpp index 2abd52b1..95aef345 100644 --- a/src/dynarmic/ir/opt/a32_get_set_elimination_pass.cpp +++ b/src/dynarmic/ir/opt/a32_get_set_elimination_pass.cpp @@ -182,6 +182,14 @@ void A32GetSetElimination(IR::Block& block, A32GetSetEliminationOptions opt) { break; } case IR::Opcode::A32GetCFlag: { + if (cpsr_info.c.register_value.IsEmpty() && cpsr_info.nzcv.register_value.GetType() == IR::Type::NZCVFlags) { + ir.SetInsertionPointBefore(inst); + IR::U1 c = ir.GetCFlagFromNZCV(IR::NZCV{cpsr_info.nzcv.register_value}); + inst->ReplaceUsesWith(c); + cpsr_info.c.register_value = c; + break; + } + do_get(cpsr_info.c, inst); // ensure source is not deleted cpsr_info.nzc = {};