// 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/impl.h" namespace Shader::Maxwell { namespace { enum class CompareOp : u64 { F, // Always false LT, // Less than EQ, // Equal LE, // Less than or equal GT, // Greater than NE, // Not equal GE, // Greater than or equal T, // Always true }; enum class Bop : u64 { AND, OR, XOR, }; IR::U1 Compare(IR::IREmitter& ir, CompareOp op, const IR::U32& lhs, const IR::U32& rhs, bool is_signed) { switch (op) { case CompareOp::F: return ir.Imm1(false); case CompareOp::LT: return ir.ILessThan(lhs, rhs, is_signed); case CompareOp::EQ: return ir.IEqual(lhs, rhs); case CompareOp::LE: return ir.ILessThanEqual(lhs, rhs, is_signed); case CompareOp::GT: return ir.IGreaterThan(lhs, rhs, is_signed); case CompareOp::NE: return ir.INotEqual(lhs, rhs); case CompareOp::GE: return ir.IGreaterThanEqual(lhs, rhs, is_signed); case CompareOp::T: return ir.Imm1(true); } throw NotImplementedException("Invalid ISETP compare op {}", op); } IR::U1 Combine(IR::IREmitter& ir, Bop bop, const IR::U1& comparison, const IR::U1& bop_pred) { switch (bop) { case Bop::AND: return ir.LogicalAnd(comparison, bop_pred); case Bop::OR: return ir.LogicalOr(comparison, bop_pred); case Bop::XOR: return ir.LogicalXor(comparison, bop_pred); } throw NotImplementedException("Invalid ISETP bop {}", bop); } void ISETP(TranslatorVisitor& v, u64 insn, const IR::U32& op_b) { union { u64 raw; BitField<0, 3, IR::Pred> dest_pred_b; BitField<3, 3, IR::Pred> dest_pred_a; BitField<8, 8, IR::Reg> src_reg_a; BitField<39, 3, IR::Pred> bop_pred; BitField<42, 1, u64> neg_bop_pred; BitField<45, 2, Bop> bop; BitField<48, 1, u64> is_signed; BitField<49, 3, CompareOp> compare_op; } const isetp{insn}; const Bop bop{isetp.bop}; const IR::U32 op_a{v.X(isetp.src_reg_a)}; const IR::U1 comparison{Compare(v.ir, isetp.compare_op, op_a, op_b, isetp.is_signed != 0)}; const IR::U1 bop_pred{v.ir.GetPred(isetp.bop_pred, isetp.neg_bop_pred != 0)}; const IR::U1 result_a{Combine(v.ir, bop, comparison, bop_pred)}; const IR::U1 result_b{Combine(v.ir, bop, v.ir.LogicalNot(comparison), bop_pred)}; v.ir.SetPred(isetp.dest_pred_a, result_a); v.ir.SetPred(isetp.dest_pred_b, result_b); } } // Anonymous namespace void TranslatorVisitor::ISETP_reg(u64 insn) { ISETP(*this, insn, GetReg20(insn)); } void TranslatorVisitor::ISETP_cbuf(u64 insn) { ISETP(*this, insn, GetCbuf(insn)); } void TranslatorVisitor::ISETP_imm(u64 insn) { ISETP(*this, insn, GetImm20(insn)); } } // namespace Shader::Maxwell