// Copyright 2021 yuzu Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #include "common/bit_field.h" #include "common/common_types.h" #include "shader_recompiler/frontend/maxwell/translate/impl/common_funcs.h" #include "shader_recompiler/frontend/maxwell/translate/impl/impl.h" namespace Shader::Maxwell { namespace { enum class FPCompareOp : u64 { F, LT, EQ, LE, GT, NE, GE, NUM, Nan, LTU, EQU, LEU, GTU, NEU, GEU, T, }; bool IsCompareOpOrdered(FPCompareOp op) { switch (op) { case FPCompareOp::LTU: case FPCompareOp::EQU: case FPCompareOp::LEU: case FPCompareOp::GTU: case FPCompareOp::NEU: case FPCompareOp::GEU: return false; default: return true; } } IR::U1 FloatingPointCompare(IR::IREmitter& ir, const IR::F32& operand_1, const IR::F32& operand_2, FPCompareOp compare_op, IR::FpControl control) { const bool ordered{IsCompareOpOrdered(compare_op)}; switch (compare_op) { case FPCompareOp::F: return ir.Imm1(false); case FPCompareOp::LT: case FPCompareOp::LTU: return ir.FPLessThan(operand_1, operand_2, control, ordered); case FPCompareOp::EQ: case FPCompareOp::EQU: return ir.FPEqual(operand_1, operand_2, control, ordered); case FPCompareOp::LE: case FPCompareOp::LEU: return ir.FPLessThanEqual(operand_1, operand_2, control, ordered); case FPCompareOp::GT: case FPCompareOp::GTU: return ir.FPGreaterThan(operand_1, operand_2, control, ordered); case FPCompareOp::NE: case FPCompareOp::NEU: return ir.FPNotEqual(operand_1, operand_2, control, ordered); case FPCompareOp::GE: case FPCompareOp::GEU: return ir.FPGreaterThanEqual(operand_1, operand_2, control, ordered); case FPCompareOp::NUM: return ir.FPOrdered(operand_1, operand_2); case FPCompareOp::Nan: return ir.FPUnordered(operand_1, operand_2); case FPCompareOp::T: return ir.Imm1(true); default: throw NotImplementedException("Invalid compare op {}", compare_op); } } void FCMP(TranslatorVisitor& v, u64 insn, const IR::U32& src_a, const IR::F32& operand) { union { u64 insn; BitField<0, 8, IR::Reg> dest_reg; BitField<8, 8, IR::Reg> src_reg; BitField<47, 1, u64> ftz; BitField<48, 4, FPCompareOp> compare_op; } const fcmp{insn}; const IR::F32 zero{v.ir.Imm32(0.0f)}; const IR::F32 neg_zero{v.ir.Imm32(-0.0f)}; IR::FpControl control{.fmz_mode{fcmp.ftz != 0 ? IR::FmzMode::FTZ : IR::FmzMode::None}}; const IR::U1 cmp_result{FloatingPointCompare(v.ir, operand, zero, fcmp.compare_op, control)}; const IR::U32 src_reg{v.X(fcmp.src_reg)}; const IR::U32 result{v.ir.Select(cmp_result, src_reg, src_a)}; v.X(fcmp.dest_reg, result); } } // Anonymous namespace void TranslatorVisitor::FCMP_reg(u64 insn) { FCMP(*this, insn, GetReg20(insn), GetFloatReg39(insn)); } void TranslatorVisitor::FCMP_rc(u64 insn) { FCMP(*this, insn, GetReg39(insn), GetFloatCbuf(insn)); } void TranslatorVisitor::FCMP_cr(u64 insn) { FCMP(*this, insn, GetCbuf(insn), GetFloatReg39(insn)); } void TranslatorVisitor::FCMP_imm(u64 insn) { FCMP(*this, insn, GetReg39(insn), GetFloatImm20(insn)); } } // namespace Shader::Maxwell