diff --git a/src/backend_x64/emit_x64.cpp b/src/backend_x64/emit_x64.cpp index ec80c6ad..08296684 100644 --- a/src/backend_x64/emit_x64.cpp +++ b/src/backend_x64/emit_x64.cpp @@ -9,6 +9,7 @@ #include "backend_x64/block_of_code.h" #include "backend_x64/emit_x64.h" #include "common/assert.h" +#include "common/bit_util.h" #include "common/common_types.h" #include "common/variant_util.h" #include "frontend/ir/basic_block.h" @@ -130,6 +131,28 @@ void EmitX64::EmitGetNZCVFromOp(EmitContext& ctx, IR::Inst* inst) { ctx.reg_alloc.DefineValue(inst, nzcv); } +void EmitX64::EmitNZCVFromPackedFlags(EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + + if (args[0].IsImmediate()) { + Xbyak::Reg32 nzcv = ctx.reg_alloc.ScratchGpr().cvt32(); + u32 value = 0; + value |= Common::Bit<31>(args[0].GetImmediateU32()) ? (1 << 15) : 0; + value |= Common::Bit<30>(args[0].GetImmediateU32()) ? (1 << 14) : 0; + value |= Common::Bit<29>(args[0].GetImmediateU32()) ? (1 << 8) : 0; + value |= Common::Bit<28>(args[0].GetImmediateU32()) ? (1 << 0) : 0; + code->mov(nzcv, value); + ctx.reg_alloc.DefineValue(inst, nzcv); + } else { + Xbyak::Reg32 nzcv = ctx.reg_alloc.UseScratchGpr(args[0]).cvt32(); + // TODO: Optimize + code->shr(nzcv, 28); + code->imul(nzcv, nzcv, 0b00010000'10000001); + code->and_(nzcv.cvt8(), 1); + ctx.reg_alloc.DefineValue(inst, nzcv); + } +} + void EmitX64::EmitAddCycles(size_t cycles) { ASSERT(cycles < std::numeric_limits::max()); code->sub(qword[r15 + code->GetJitStateInfo().offsetof_cycles_remaining], static_cast(cycles)); diff --git a/src/frontend/ir/ir_emitter.cpp b/src/frontend/ir/ir_emitter.cpp index 9198be70..02c3864b 100644 --- a/src/frontend/ir/ir_emitter.cpp +++ b/src/frontend/ir/ir_emitter.cpp @@ -107,6 +107,10 @@ U32U64 IREmitter::ConditionalSelect(Cond cond, const U32U64& a, const U32U64& b) } } +NZCV IREmitter::NZCVFromPackedFlags(const U32& a) { + return Inst(Opcode::NZCVFromPackedFlags, a); +} + NZCV IREmitter::NZCVFrom(const Value& value) { return Inst(Opcode::GetNZCVFromOp, value); } diff --git a/src/frontend/ir/ir_emitter.h b/src/frontend/ir/ir_emitter.h index 77dd5955..f7e628ee 100644 --- a/src/frontend/ir/ir_emitter.h +++ b/src/frontend/ir/ir_emitter.h @@ -81,6 +81,7 @@ public: U64 ConditionalSelect(Cond cond, const U64& a, const U64& b); U32U64 ConditionalSelect(Cond cond, const U32U64& a, const U32U64& b); + 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/frontend/ir/opcodes.inc b/src/frontend/ir/opcodes.inc index 8d1eac5e..dc1b9833 100644 --- a/src/frontend/ir/opcodes.inc +++ b/src/frontend/ir/opcodes.inc @@ -68,6 +68,8 @@ OPCODE(GetOverflowFromOp, T::U1, T::U32 OPCODE(GetGEFromOp, T::U32, T::U32 ) OPCODE(GetNZCVFromOp, T::NZCVFlags, T::Opaque ) +OPCODE(NZCVFromPackedFlags, T::NZCVFlags, T::U32 ) + // Calculations OPCODE(Pack2x32To1x64, T::U64, T::U32, T::U32 ) OPCODE(LeastSignificantWord, T::U32, T::U64 )