From 9edb90171aa304746b4f811551da549d3d008520 Mon Sep 17 00:00:00 2001 From: fleroviux Date: Sun, 9 Feb 2025 19:24:29 +0100 Subject: [PATCH] Add CVT_NZCV_HFLAG instruction to IR --- .../dynarec/backend/arm64/arm64_backend.cpp | 6 +++ src/dual/src/arm/dynarec/dynarec_cpu.cpp | 46 +++++++++---------- src/dual/src/arm/dynarec/ir/disassemble.cpp | 1 + src/dual/src/arm/dynarec/ir/emitter.hpp | 4 ++ src/dual/src/arm/dynarec/ir/instruction.hpp | 2 +- 5 files changed, 35 insertions(+), 24 deletions(-) diff --git a/src/dual/src/arm/dynarec/backend/arm64/arm64_backend.cpp b/src/dual/src/arm/dynarec/backend/arm64/arm64_backend.cpp index 7a427f3..2242ad7 100644 --- a/src/dual/src/arm/dynarec/backend/arm64/arm64_backend.cpp +++ b/src/dual/src/arm/dynarec/backend/arm64/arm64_backend.cpp @@ -124,6 +124,12 @@ void ARM64Backend::Execute(const ir::Function& function, bool debug) { code.MOV(nzcv_reg, hflags_reg); // TODO(fleroviux): implement move elimination break; } + case ir::Instruction::Type::CVT_NZCV_HFLAG: { + const oaknut::WReg nzcv_reg = GetLocation(instruction->GetArg(0u).AsValue()).AsWReg(); + const oaknut::WReg hflags_reg = GetLocation(instruction->GetOut(0u)).AsWReg(); + code.MOV(hflags_reg, nzcv_reg); // TODO(fleroviux): implement move elimination + break; + } // Control Flow case ir::Instruction::Type::BR: { diff --git a/src/dual/src/arm/dynarec/dynarec_cpu.cpp b/src/dual/src/arm/dynarec/dynarec_cpu.cpp index eb61f52..f33cbbd 100644 --- a/src/dual/src/arm/dynarec/dynarec_cpu.cpp +++ b/src/dual/src/arm/dynarec/dynarec_cpu.cpp @@ -221,33 +221,33 @@ void DynarecCPU::TestBackend() { { ir::Emitter emitter{*bb_loop, m_tmp_memory_arena}; - const ir::U32Value& value_r0 = emitter.LDGPR(GPR::R0, Mode::User); - - const ir::HostFlagsValue* hflags; - const ir::U32Value& result = emitter.ADD(value_r0, emitter.LDCONST(0xFFFFFFFFu), &hflags); - emitter.STGPR(GPR::R0, Mode::User, result); - emitter.STGPR(GPR::R8, Mode::User, emitter.LDGPR(GPR::R0, Mode::User)); - emitter.STGPR(GPR::R0, Mode::User, emitter.LDGPR(GPR::R0, Mode::User)); - - emitter.STCPSR(emitter.LDCPSR()); - emitter.STCPSR(emitter.LDCPSR()); - emitter.STSPSR(Mode::IRQ, emitter.LDSPSR(Mode::IRQ)); - emitter.STSPSR(Mode::FIQ, emitter.LDSPSR(Mode::FIQ)); - emitter.STSPSR(Mode::IRQ, emitter.LDSPSR(Mode::IRQ)); - emitter.STSPSR(Mode::FIQ, emitter.LDSPSR(Mode::FIQ)); - - emitter.BR_IF(ir::Condition::EQ, *hflags, *bb_exit, *bb_loop); +// const ir::U32Value& value_r0 = emitter.LDGPR(GPR::R0, Mode::User); +// const ir::HostFlagsValue* hflags; +// const ir::U32Value& result = emitter.ADD(value_r0, emitter.LDCONST(0xFFFFFFFFu), &hflags); +// emitter.STGPR(GPR::R0, Mode::User, result); +// emitter.STGPR(GPR::R8, Mode::User, emitter.LDGPR(GPR::R0, Mode::User)); +// emitter.STGPR(GPR::R0, Mode::User, emitter.LDGPR(GPR::R0, Mode::User)); +// emitter.STCPSR(emitter.LDCPSR()); +// emitter.STCPSR(emitter.LDCPSR()); +// emitter.STSPSR(Mode::IRQ, emitter.LDSPSR(Mode::IRQ)); +// emitter.STSPSR(Mode::FIQ, emitter.LDSPSR(Mode::FIQ)); +// emitter.STSPSR(Mode::IRQ, emitter.LDSPSR(Mode::IRQ)); +// emitter.STSPSR(Mode::FIQ, emitter.LDSPSR(Mode::FIQ)); +// emitter.BR_IF(ir::Condition::EQ, *hflags, *bb_exit, *bb_loop); + + const ir::HostFlagsValue* add_hflags; + const ir::U32Value& add_result = emitter.ADD(emitter.LDGPR(GPR::R0, Mode::User), emitter.LDCONST(0xFFFFFFFFu), &add_hflags); + emitter.STGPR(GPR::R0, Mode::User, add_result); + + const ir::U32Value& cpsr_old = emitter.LDCPSR(); + const ir::U32Value& cpsr_new = emitter.ORR(emitter.BIC(cpsr_old, emitter.LDCONST(0xF0000000u)), emitter.CVT_HFLAG_NZCV(*add_hflags)); + emitter.STCPSR(cpsr_new); + + emitter.BR_IF(ir::Condition::EQ, emitter.CVT_NZCV_HFLAG(emitter.LDCPSR()), *bb_exit, *bb_loop); } { ir::Emitter emitter{*bb_exit, m_tmp_memory_arena}; - -// const ir::HostFlagsValue* hflags; -// const ir::U32Value& r1_value = emitter.LDGPR(GPR::R1, Mode::User); -// const ir::U32Value& result_value = emitter.LSL(r1_value, emitter.LDCONST(1), &hflags); -// emitter.STGPR(GPR::R1, Mode::User, result_value); -// emitter.STCPSR(emitter.CVT_HFLAG_NZCV(*hflags)); - emitter.EXIT(); } diff --git a/src/dual/src/arm/dynarec/ir/disassemble.cpp b/src/dual/src/arm/dynarec/ir/disassemble.cpp index 193060f..28d26bf 100644 --- a/src/dual/src/arm/dynarec/ir/disassemble.cpp +++ b/src/dual/src/arm/dynarec/ir/disassemble.cpp @@ -134,6 +134,7 @@ static const char* get_instruction_mnemonic(Instruction::Type type) { case Instruction::Type::LDSPSR: return "ldspsr"; case Instruction::Type::STSPSR: return "stspsr"; case Instruction::Type::CVT_HFLAG_NZCV: return "cvt.hflag.nzcv"; + case Instruction::Type::CVT_NZCV_HFLAG: return "cvt.nzcv.hflag"; case Instruction::Type::BR: return "br"; case Instruction::Type::BR_IF: return "br_if"; case Instruction::Type::EXIT: return "exit"; diff --git a/src/dual/src/arm/dynarec/ir/emitter.hpp b/src/dual/src/arm/dynarec/ir/emitter.hpp index 4bab97b..8814bbc 100644 --- a/src/dual/src/arm/dynarec/ir/emitter.hpp +++ b/src/dual/src/arm/dynarec/ir/emitter.hpp @@ -52,6 +52,10 @@ class Emitter { return std::get<0>(Emit(Type::CVT_HFLAG_NZCV, 0u, hflag_value)); } + const HostFlagsValue& CVT_NZCV_HFLAG(const U32Value& nzcv_value) { + return std::get<0>(Emit(Type::CVT_NZCV_HFLAG, 0u, nzcv_value)); + } + void BR(const BasicBlock& basic_block) { Emit(Type::BR, 0u, basic_block); } diff --git a/src/dual/src/arm/dynarec/ir/instruction.hpp b/src/dual/src/arm/dynarec/ir/instruction.hpp index 0c94738..b6acc58 100644 --- a/src/dual/src/arm/dynarec/ir/instruction.hpp +++ b/src/dual/src/arm/dynarec/ir/instruction.hpp @@ -25,7 +25,7 @@ struct Instruction { // Flag Management CVT_HFLAG_NZCV, - // ... + CVT_NZCV_HFLAG, // Control Flow BR,