diff options
Diffstat (limited to 'src/shader_recompiler/frontend')
| -rw-r--r-- | src/shader_recompiler/frontend/maxwell/translate/impl/integer_compare_and_set.cpp | 66 |
1 files changed, 58 insertions, 8 deletions
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/integer_compare_and_set.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/integer_compare_and_set.cpp index a2cd8d7c6..34fa7345c 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/integer_compare_and_set.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/integer_compare_and_set.cpp | |||
| @@ -9,7 +9,56 @@ | |||
| 9 | 9 | ||
| 10 | namespace Shader::Maxwell { | 10 | namespace Shader::Maxwell { |
| 11 | namespace { | 11 | namespace { |
| 12 | void ISET(TranslatorVisitor& v, u64 insn, const IR::U32& src_a) { | 12 | IR::U1 ExtendedIntegerCompare(IR::IREmitter& ir, const IR::U32& operand_1, const IR::U32& operand_2, |
| 13 | CompareOp compare_op, bool is_signed) { | ||
| 14 | const IR::U32 zero{ir.Imm32(0)}; | ||
| 15 | const IR::U32 carry{ir.Select(ir.GetCFlag(), ir.Imm32(1), zero)}; | ||
| 16 | const IR::U1 z_flag{ir.GetZFlag()}; | ||
| 17 | const IR::U32 intermediate{ir.IAdd(ir.IAdd(operand_1, ir.BitwiseNot(operand_2)), carry)}; | ||
| 18 | const IR::U1 flip_logic{is_signed ? ir.Imm1(false) | ||
| 19 | : ir.LogicalXor(ir.ILessThan(operand_1, zero, true), | ||
| 20 | ir.ILessThan(operand_2, zero, true))}; | ||
| 21 | switch (compare_op) { | ||
| 22 | case CompareOp::False: | ||
| 23 | return ir.Imm1(false); | ||
| 24 | case CompareOp::LessThan: | ||
| 25 | return IR::U1{ir.Select(flip_logic, ir.IGreaterThanEqual(intermediate, zero, true), | ||
| 26 | ir.ILessThan(intermediate, zero, true))}; | ||
| 27 | case CompareOp::Equal: | ||
| 28 | return ir.LogicalAnd(ir.IEqual(intermediate, zero), z_flag); | ||
| 29 | case CompareOp::LessThanEqual: { | ||
| 30 | const IR::U1 base_cmp{ir.Select(flip_logic, ir.IGreaterThanEqual(intermediate, zero, true), | ||
| 31 | ir.ILessThan(intermediate, zero, true))}; | ||
| 32 | return ir.LogicalOr(base_cmp, ir.LogicalAnd(ir.IEqual(intermediate, zero), z_flag)); | ||
| 33 | } | ||
| 34 | case CompareOp::GreaterThan: { | ||
| 35 | const IR::U1 base_cmp{ir.Select(flip_logic, ir.ILessThanEqual(intermediate, zero, true), | ||
| 36 | ir.IGreaterThan(intermediate, zero, true))}; | ||
| 37 | const IR::U1 not_z{ir.LogicalNot(z_flag)}; | ||
| 38 | return ir.LogicalOr(base_cmp, ir.LogicalAnd(ir.IEqual(intermediate, zero), not_z)); | ||
| 39 | } | ||
| 40 | case CompareOp::NotEqual: | ||
| 41 | return ir.LogicalOr(ir.INotEqual(intermediate, zero), | ||
| 42 | ir.LogicalAnd(ir.IEqual(intermediate, zero), ir.LogicalNot(z_flag))); | ||
| 43 | case CompareOp::GreaterThanEqual: { | ||
| 44 | const IR::U1 base_cmp{ir.Select(flip_logic, ir.ILessThan(intermediate, zero, true), | ||
| 45 | ir.IGreaterThanEqual(intermediate, zero, true))}; | ||
| 46 | return ir.LogicalOr(base_cmp, ir.LogicalAnd(ir.IEqual(intermediate, zero), z_flag)); | ||
| 47 | } | ||
| 48 | case CompareOp::True: | ||
| 49 | return ir.Imm1(true); | ||
| 50 | default: | ||
| 51 | throw NotImplementedException("Invalid compare op {}", compare_op); | ||
| 52 | } | ||
| 53 | } | ||
| 54 | |||
| 55 | IR::U1 IsetCompare(IR::IREmitter& ir, const IR::U32& operand_1, const IR::U32& operand_2, | ||
| 56 | CompareOp compare_op, bool is_signed, bool x) { | ||
| 57 | return x ? ExtendedIntegerCompare(ir, operand_1, operand_2, compare_op, is_signed) | ||
| 58 | : IntegerCompare(ir, operand_1, operand_2, compare_op, is_signed); | ||
| 59 | } | ||
| 60 | |||
| 61 | void ISET(TranslatorVisitor& v, u64 insn, const IR::U32& src_b) { | ||
| 13 | union { | 62 | union { |
| 14 | u64 insn; | 63 | u64 insn; |
| 15 | BitField<0, 8, IR::Reg> dest_reg; | 64 | BitField<0, 8, IR::Reg> dest_reg; |
| @@ -24,27 +73,28 @@ void ISET(TranslatorVisitor& v, u64 insn, const IR::U32& src_a) { | |||
| 24 | BitField<49, 3, CompareOp> compare_op; | 73 | BitField<49, 3, CompareOp> compare_op; |
| 25 | } const iset{insn}; | 74 | } const iset{insn}; |
| 26 | 75 | ||
| 27 | if (iset.x != 0) { | 76 | const IR::U32 src_a{v.X(iset.src_reg)}; |
| 28 | throw NotImplementedException("ISET.X"); | ||
| 29 | } | ||
| 30 | |||
| 31 | const IR::U32 src_reg{v.X(iset.src_reg)}; | ||
| 32 | const bool is_signed{iset.is_signed != 0}; | 77 | const bool is_signed{iset.is_signed != 0}; |
| 78 | const IR::U32 zero{v.ir.Imm32(0)}; | ||
| 79 | const bool x{iset.x != 0}; | ||
| 80 | const IR::U1 cmp_result{IsetCompare(v.ir, src_a, src_b, iset.compare_op, is_signed, x)}; | ||
| 81 | |||
| 33 | IR::U1 pred{v.ir.GetPred(iset.pred)}; | 82 | IR::U1 pred{v.ir.GetPred(iset.pred)}; |
| 34 | if (iset.neg_pred != 0) { | 83 | if (iset.neg_pred != 0) { |
| 35 | pred = v.ir.LogicalNot(pred); | 84 | pred = v.ir.LogicalNot(pred); |
| 36 | } | 85 | } |
| 37 | const IR::U1 cmp_result{IntegerCompare(v.ir, src_reg, src_a, iset.compare_op, is_signed)}; | ||
| 38 | const IR::U1 bop_result{PredicateCombine(v.ir, cmp_result, pred, iset.bop)}; | 86 | const IR::U1 bop_result{PredicateCombine(v.ir, cmp_result, pred, iset.bop)}; |
| 39 | 87 | ||
| 40 | const IR::U32 one_mask{v.ir.Imm32(-1)}; | 88 | const IR::U32 one_mask{v.ir.Imm32(-1)}; |
| 41 | const IR::U32 fp_one{v.ir.Imm32(0x3f800000)}; | 89 | const IR::U32 fp_one{v.ir.Imm32(0x3f800000)}; |
| 42 | const IR::U32 zero{v.ir.Imm32(0)}; | ||
| 43 | const IR::U32 pass_result{iset.bf == 0 ? one_mask : fp_one}; | 90 | const IR::U32 pass_result{iset.bf == 0 ? one_mask : fp_one}; |
| 44 | const IR::U32 result{v.ir.Select(bop_result, pass_result, zero)}; | 91 | const IR::U32 result{v.ir.Select(bop_result, pass_result, zero)}; |
| 45 | 92 | ||
| 46 | v.X(iset.dest_reg, result); | 93 | v.X(iset.dest_reg, result); |
| 47 | if (iset.cc != 0) { | 94 | if (iset.cc != 0) { |
| 95 | if (x) { | ||
| 96 | throw NotImplementedException("ISET.CC + X"); | ||
| 97 | } | ||
| 48 | const IR::U1 is_zero{v.ir.IEqual(result, zero)}; | 98 | const IR::U1 is_zero{v.ir.IEqual(result, zero)}; |
| 49 | v.SetZFlag(is_zero); | 99 | v.SetZFlag(is_zero); |
| 50 | if (iset.bf != 0) { | 100 | if (iset.bf != 0) { |