forked from suyu/suyu
99 lines
3 KiB
C++
99 lines
3 KiB
C++
// 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
|