diff options
| author | 2021-03-03 00:41:05 -0500 | |
|---|---|---|
| committer | 2021-07-22 21:51:23 -0400 | |
| commit | 980cafdc27444484a2a2794be5de92ea18de6e27 (patch) | |
| tree | 0b95eaadb03bec8c0ccb8ed31f3d8d42e7689a9c /src/shader_recompiler/frontend/maxwell | |
| parent | shader: Implement IADD3 (diff) | |
| download | yuzu-980cafdc27444484a2a2794be5de92ea18de6e27.tar.gz yuzu-980cafdc27444484a2a2794be5de92ea18de6e27.tar.xz yuzu-980cafdc27444484a2a2794be5de92ea18de6e27.zip | |
shader: Implement LOP and LOP3
Diffstat (limited to 'src/shader_recompiler/frontend/maxwell')
7 files changed, 225 insertions, 31 deletions
diff --git a/src/shader_recompiler/frontend/maxwell/maxwell.inc b/src/shader_recompiler/frontend/maxwell/maxwell.inc index 1515285bf..5d0b91598 100644 --- a/src/shader_recompiler/frontend/maxwell/maxwell.inc +++ b/src/shader_recompiler/frontend/maxwell/maxwell.inc | |||
| @@ -178,8 +178,8 @@ INST(LOP_reg, "LOP (reg)", "0101 1100 0100 0---") | |||
| 178 | INST(LOP_cbuf, "LOP (cbuf)", "0100 1100 0100 0---") | 178 | INST(LOP_cbuf, "LOP (cbuf)", "0100 1100 0100 0---") |
| 179 | INST(LOP_imm, "LOP (imm)", "0011 100- 0100 0---") | 179 | INST(LOP_imm, "LOP (imm)", "0011 100- 0100 0---") |
| 180 | INST(LOP3_reg, "LOP3 (reg)", "0101 1011 1110 0---") | 180 | INST(LOP3_reg, "LOP3 (reg)", "0101 1011 1110 0---") |
| 181 | INST(LOP3_cbuf, "LOP3 (cbuf)", "0011 11-- ---- ----") | 181 | INST(LOP3_cbuf, "LOP3 (cbuf)", "0000 001- ---- ----") |
| 182 | INST(LOP3_imm, "LOP3 (imm)", "0000 001- ---- ----") | 182 | INST(LOP3_imm, "LOP3 (imm)", "0011 11-- ---- ----") |
| 183 | INST(LOP32I, "LOP32I", "0000 01-- ---- ----") | 183 | INST(LOP32I, "LOP32I", "0000 01-- ---- ----") |
| 184 | INST(MEMBAR, "MEMBAR", "1110 1111 1001 1---") | 184 | INST(MEMBAR, "MEMBAR", "1110 1111 1001 1---") |
| 185 | INST(MOV_reg, "MOV (reg)", "0101 1100 1001 1---") | 185 | INST(MOV_reg, "MOV (reg)", "0101 1100 1001 1---") |
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/common_funcs.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/common_funcs.cpp index 62f825a92..9d4ac2e36 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/common_funcs.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/common_funcs.cpp | |||
| @@ -5,9 +5,8 @@ | |||
| 5 | #include "shader_recompiler/frontend/maxwell/translate/impl/common_funcs.h" | 5 | #include "shader_recompiler/frontend/maxwell/translate/impl/common_funcs.h" |
| 6 | 6 | ||
| 7 | namespace Shader::Maxwell { | 7 | namespace Shader::Maxwell { |
| 8 | [[nodiscard]] IR::U1 IntegerCompare(IR::IREmitter& ir, const IR::U32& operand_1, | 8 | IR::U1 IntegerCompare(IR::IREmitter& ir, const IR::U32& operand_1, const IR::U32& operand_2, |
| 9 | const IR::U32& operand_2, CompareOp compare_op, | 9 | CompareOp compare_op, bool is_signed) { |
| 10 | bool is_signed) { | ||
| 11 | switch (compare_op) { | 10 | switch (compare_op) { |
| 12 | case CompareOp::False: | 11 | case CompareOp::False: |
| 13 | return ir.Imm1(false); | 12 | return ir.Imm1(false); |
| @@ -30,8 +29,8 @@ namespace Shader::Maxwell { | |||
| 30 | } | 29 | } |
| 31 | } | 30 | } |
| 32 | 31 | ||
| 33 | [[nodiscard]] IR::U1 PredicateCombine(IR::IREmitter& ir, const IR::U1& predicate_1, | 32 | IR::U1 PredicateCombine(IR::IREmitter& ir, const IR::U1& predicate_1, const IR::U1& predicate_2, |
| 34 | const IR::U1& predicate_2, BooleanOp bop) { | 33 | BooleanOp bop) { |
| 35 | switch (bop) { | 34 | switch (bop) { |
| 36 | case BooleanOp::AND: | 35 | case BooleanOp::AND: |
| 37 | return ir.LogicalAnd(predicate_1, predicate_2); | 36 | return ir.LogicalAnd(predicate_1, predicate_2); |
| @@ -43,4 +42,20 @@ namespace Shader::Maxwell { | |||
| 43 | throw NotImplementedException("Invalid bop {}", bop); | 42 | throw NotImplementedException("Invalid bop {}", bop); |
| 44 | } | 43 | } |
| 45 | } | 44 | } |
| 45 | |||
| 46 | IR::U1 PredicateOperation(IR::IREmitter& ir, const IR::U32& result, PredicateOp op) { | ||
| 47 | switch (op) { | ||
| 48 | case PredicateOp::False: | ||
| 49 | return ir.Imm1(false); | ||
| 50 | case PredicateOp::True: | ||
| 51 | return ir.Imm1(true); | ||
| 52 | case PredicateOp::Zero: | ||
| 53 | return ir.IEqual(result, ir.Imm32(0)); | ||
| 54 | case PredicateOp::NonZero: | ||
| 55 | return ir.INotEqual(result, ir.Imm32(0)); | ||
| 56 | default: | ||
| 57 | throw NotImplementedException("Invalid Predicate operation {}", op); | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 46 | } // namespace Shader::Maxwell | 61 | } // namespace Shader::Maxwell |
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/common_funcs.h b/src/shader_recompiler/frontend/maxwell/translate/impl/common_funcs.h index 61e13fa18..c9ae5c500 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/common_funcs.h +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/common_funcs.h | |||
| @@ -13,4 +13,6 @@ namespace Shader::Maxwell { | |||
| 13 | 13 | ||
| 14 | [[nodiscard]] IR::U1 PredicateCombine(IR::IREmitter& ir, const IR::U1& predicate_1, | 14 | [[nodiscard]] IR::U1 PredicateCombine(IR::IREmitter& ir, const IR::U1& predicate_1, |
| 15 | const IR::U1& predicate_2, BooleanOp bop); | 15 | const IR::U1& predicate_2, BooleanOp bop); |
| 16 | |||
| 17 | [[nodiscard]] IR::U1 PredicateOperation(IR::IREmitter& ir, const IR::U32& result, PredicateOp op); | ||
| 16 | } // namespace Shader::Maxwell | 18 | } // namespace Shader::Maxwell |
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h b/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h index ad09ade7c..c6253c40c 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h | |||
| @@ -28,6 +28,13 @@ enum class BooleanOp : u64 { | |||
| 28 | XOR, | 28 | XOR, |
| 29 | }; | 29 | }; |
| 30 | 30 | ||
| 31 | enum class PredicateOp : u64 { | ||
| 32 | False, | ||
| 33 | True, | ||
| 34 | Zero, | ||
| 35 | NonZero, | ||
| 36 | }; | ||
| 37 | |||
| 31 | class TranslatorVisitor { | 38 | class TranslatorVisitor { |
| 32 | public: | 39 | public: |
| 33 | explicit TranslatorVisitor(Environment& env_, IR::Block& block) : env{env_}, ir(block) {} | 40 | explicit TranslatorVisitor(Environment& env_, IR::Block& block) : env{env_}, ir(block) {} |
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/logic_operation.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/logic_operation.cpp new file mode 100644 index 000000000..e786a388e --- /dev/null +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/logic_operation.cpp | |||
| @@ -0,0 +1,77 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/bit_field.h" | ||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "shader_recompiler/frontend/maxwell/translate/impl/common_funcs.h" | ||
| 8 | #include "shader_recompiler/frontend/maxwell/translate/impl/impl.h" | ||
| 9 | |||
| 10 | namespace Shader::Maxwell { | ||
| 11 | namespace { | ||
| 12 | enum class LogicalOp : u64 { | ||
| 13 | AND, | ||
| 14 | OR, | ||
| 15 | XOR, | ||
| 16 | PASS_B, | ||
| 17 | }; | ||
| 18 | |||
| 19 | [[nodiscard]] IR::U32 LogicalOperation(IR::IREmitter& ir, const IR::U32& operand_1, | ||
| 20 | const IR::U32& operand_2, LogicalOp op) { | ||
| 21 | switch (op) { | ||
| 22 | case LogicalOp::AND: | ||
| 23 | return ir.BitwiseAnd(operand_1, operand_2); | ||
| 24 | case LogicalOp::OR: | ||
| 25 | return ir.BitwiseOr(operand_1, operand_2); | ||
| 26 | case LogicalOp::XOR: | ||
| 27 | return ir.BitwiseXor(operand_1, operand_2); | ||
| 28 | case LogicalOp::PASS_B: | ||
| 29 | return operand_2; | ||
| 30 | default: | ||
| 31 | throw NotImplementedException("Invalid Logical operation {}", op); | ||
| 32 | } | ||
| 33 | } | ||
| 34 | |||
| 35 | void LOP(TranslatorVisitor& v, u64 insn, IR::U32 op_b) { | ||
| 36 | union { | ||
| 37 | u64 insn; | ||
| 38 | BitField<0, 8, IR::Reg> dest_reg; | ||
| 39 | BitField<8, 8, IR::Reg> src_reg; | ||
| 40 | BitField<39, 1, u64> neg_a; | ||
| 41 | BitField<40, 1, u64> neg_b; | ||
| 42 | BitField<41, 2, LogicalOp> bit_op; | ||
| 43 | BitField<43, 1, u64> x; | ||
| 44 | BitField<44, 2, PredicateOp> pred_op; | ||
| 45 | BitField<48, 3, IR::Pred> pred; | ||
| 46 | } const lop{insn}; | ||
| 47 | |||
| 48 | if (lop.x != 0) { | ||
| 49 | throw NotImplementedException("LOP X"); | ||
| 50 | } | ||
| 51 | IR::U32 op_a{v.X(lop.src_reg)}; | ||
| 52 | if (lop.neg_a != 0) { | ||
| 53 | op_a = v.ir.BitwiseNot(op_a); | ||
| 54 | } | ||
| 55 | if (lop.neg_b != 0) { | ||
| 56 | op_b = v.ir.BitwiseNot(op_b); | ||
| 57 | } | ||
| 58 | |||
| 59 | const IR::U32 result{LogicalOperation(v.ir, op_a, op_b, lop.bit_op)}; | ||
| 60 | const IR::U1 pred_result{PredicateOperation(v.ir, result, lop.pred_op)}; | ||
| 61 | v.X(lop.dest_reg, result); | ||
| 62 | v.ir.SetPred(lop.pred, pred_result); | ||
| 63 | } | ||
| 64 | } // Anonymous namespace | ||
| 65 | |||
| 66 | void TranslatorVisitor::LOP_reg(u64 insn) { | ||
| 67 | LOP(*this, insn, GetReg20(insn)); | ||
| 68 | } | ||
| 69 | |||
| 70 | void TranslatorVisitor::LOP_cbuf(u64 insn) { | ||
| 71 | LOP(*this, insn, GetCbuf(insn)); | ||
| 72 | } | ||
| 73 | |||
| 74 | void TranslatorVisitor::LOP_imm(u64 insn) { | ||
| 75 | LOP(*this, insn, GetImm20(insn)); | ||
| 76 | } | ||
| 77 | } // namespace Shader::Maxwell | ||
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/logic_operation_three_input.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/logic_operation_three_input.cpp new file mode 100644 index 000000000..256c47504 --- /dev/null +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/logic_operation_three_input.cpp | |||
| @@ -0,0 +1,117 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/bit_field.h" | ||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "shader_recompiler/frontend/maxwell/translate/impl/common_funcs.h" | ||
| 8 | #include "shader_recompiler/frontend/maxwell/translate/impl/impl.h" | ||
| 9 | |||
| 10 | namespace Shader::Maxwell { | ||
| 11 | namespace { | ||
| 12 | // https://forums.developer.nvidia.com/t/reverse-lut-for-lop3-lut/110651 | ||
| 13 | // Emulate GPU's LOP3.LUT (three-input logic op with 8-bit truth table) | ||
| 14 | IR::U32 ApplyLUT(IR::IREmitter& ir, const IR::U32& a, const IR::U32& b, const IR::U32& c, | ||
| 15 | u64 ttbl) { | ||
| 16 | IR::U32 r{ir.Imm32(0)}; | ||
| 17 | const IR::U32 not_a{ir.BitwiseNot(a)}; | ||
| 18 | const IR::U32 not_b{ir.BitwiseNot(b)}; | ||
| 19 | const IR::U32 not_c{ir.BitwiseNot(c)}; | ||
| 20 | if (ttbl & 0x01) { | ||
| 21 | // r |= ~a & ~b & ~c; | ||
| 22 | const auto lhs{ir.BitwiseAnd(not_a, not_b)}; | ||
| 23 | const auto rhs{ir.BitwiseAnd(lhs, not_c)}; | ||
| 24 | r = ir.BitwiseOr(r, rhs); | ||
| 25 | } | ||
| 26 | if (ttbl & 0x02) { | ||
| 27 | // r |= ~a & ~b & c; | ||
| 28 | const auto lhs{ir.BitwiseAnd(not_a, not_b)}; | ||
| 29 | const auto rhs{ir.BitwiseAnd(lhs, c)}; | ||
| 30 | r = ir.BitwiseOr(r, rhs); | ||
| 31 | } | ||
| 32 | if (ttbl & 0x04) { | ||
| 33 | // r |= ~a & b & ~c; | ||
| 34 | const auto lhs{ir.BitwiseAnd(not_a, b)}; | ||
| 35 | const auto rhs{ir.BitwiseAnd(lhs, not_c)}; | ||
| 36 | r = ir.BitwiseOr(r, rhs); | ||
| 37 | } | ||
| 38 | if (ttbl & 0x08) { | ||
| 39 | // r |= ~a & b & c; | ||
| 40 | const auto lhs{ir.BitwiseAnd(not_a, b)}; | ||
| 41 | const auto rhs{ir.BitwiseAnd(lhs, c)}; | ||
| 42 | r = ir.BitwiseOr(r, rhs); | ||
| 43 | } | ||
| 44 | if (ttbl & 0x10) { | ||
| 45 | // r |= a & ~b & ~c; | ||
| 46 | const auto lhs{ir.BitwiseAnd(a, not_b)}; | ||
| 47 | const auto rhs{ir.BitwiseAnd(lhs, not_c)}; | ||
| 48 | r = ir.BitwiseOr(r, rhs); | ||
| 49 | } | ||
| 50 | if (ttbl & 0x20) { | ||
| 51 | // r |= a & ~b & c; | ||
| 52 | const auto lhs{ir.BitwiseAnd(a, not_b)}; | ||
| 53 | const auto rhs{ir.BitwiseAnd(lhs, c)}; | ||
| 54 | r = ir.BitwiseOr(r, rhs); | ||
| 55 | } | ||
| 56 | if (ttbl & 0x40) { | ||
| 57 | // r |= a & b & ~c; | ||
| 58 | const auto lhs{ir.BitwiseAnd(a, b)}; | ||
| 59 | const auto rhs{ir.BitwiseAnd(lhs, not_c)}; | ||
| 60 | r = ir.BitwiseOr(r, rhs); | ||
| 61 | } | ||
| 62 | if (ttbl & 0x80) { | ||
| 63 | // r |= a & b & c; | ||
| 64 | const auto lhs{ir.BitwiseAnd(a, b)}; | ||
| 65 | const auto rhs{ir.BitwiseAnd(lhs, c)}; | ||
| 66 | r = ir.BitwiseOr(r, rhs); | ||
| 67 | } | ||
| 68 | return r; | ||
| 69 | } | ||
| 70 | |||
| 71 | IR::U32 LOP3(TranslatorVisitor& v, u64 insn, const IR::U32& op_b, const IR::U32& op_c, u64 lut) { | ||
| 72 | union { | ||
| 73 | u64 insn; | ||
| 74 | BitField<0, 8, IR::Reg> dest_reg; | ||
| 75 | BitField<8, 8, IR::Reg> src_reg; | ||
| 76 | } const lop3{insn}; | ||
| 77 | |||
| 78 | const IR::U32 op_a{v.X(lop3.src_reg)}; | ||
| 79 | const IR::U32 result{ApplyLUT(v.ir, op_a, op_b, op_c, lut)}; | ||
| 80 | v.X(lop3.dest_reg, result); | ||
| 81 | return result; | ||
| 82 | } | ||
| 83 | |||
| 84 | u64 GetLut48(u64 insn) { | ||
| 85 | union { | ||
| 86 | u64 raw; | ||
| 87 | BitField<48, 8, u64> lut; | ||
| 88 | } const lut{insn}; | ||
| 89 | return lut.lut; | ||
| 90 | } | ||
| 91 | } // Anonymous namespace | ||
| 92 | |||
| 93 | void TranslatorVisitor::LOP3_reg(u64 insn) { | ||
| 94 | union { | ||
| 95 | u64 insn; | ||
| 96 | BitField<28, 8, u64> lut; | ||
| 97 | BitField<38, 1, u64> x; | ||
| 98 | BitField<36, 2, PredicateOp> pred_op; | ||
| 99 | BitField<48, 3, IR::Pred> pred; | ||
| 100 | } const lop3{insn}; | ||
| 101 | |||
| 102 | if (lop3.x != 0) { | ||
| 103 | throw NotImplementedException("LOP3 X"); | ||
| 104 | } | ||
| 105 | const IR::U32 result{LOP3(*this, insn, GetReg20(insn), GetReg39(insn), lop3.lut)}; | ||
| 106 | const IR::U1 pred_result{PredicateOperation(ir, result, lop3.pred_op)}; | ||
| 107 | ir.SetPred(lop3.pred, pred_result); | ||
| 108 | } | ||
| 109 | |||
| 110 | void TranslatorVisitor::LOP3_cbuf(u64 insn) { | ||
| 111 | LOP3(*this, insn, GetCbuf(insn), GetReg39(insn), GetLut48(insn)); | ||
| 112 | } | ||
| 113 | |||
| 114 | void TranslatorVisitor::LOP3_imm(u64 insn) { | ||
| 115 | LOP3(*this, insn, GetImm20(insn), GetReg39(insn), GetLut48(insn)); | ||
| 116 | } | ||
| 117 | } // namespace Shader::Maxwell | ||
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp index c93304a67..a0535f1c2 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp | |||
| @@ -493,30 +493,6 @@ void TranslatorVisitor::LONGJMP(u64) { | |||
| 493 | ThrowNotImplemented(Opcode::LONGJMP); | 493 | ThrowNotImplemented(Opcode::LONGJMP); |
| 494 | } | 494 | } |
| 495 | 495 | ||
| 496 | void TranslatorVisitor::LOP_reg(u64) { | ||
| 497 | ThrowNotImplemented(Opcode::LOP_reg); | ||
| 498 | } | ||
| 499 | |||
| 500 | void TranslatorVisitor::LOP_cbuf(u64) { | ||
| 501 | ThrowNotImplemented(Opcode::LOP_cbuf); | ||
| 502 | } | ||
| 503 | |||
| 504 | void TranslatorVisitor::LOP_imm(u64) { | ||
| 505 | ThrowNotImplemented(Opcode::LOP_imm); | ||
| 506 | } | ||
| 507 | |||
| 508 | void TranslatorVisitor::LOP3_reg(u64) { | ||
| 509 | ThrowNotImplemented(Opcode::LOP3_reg); | ||
| 510 | } | ||
| 511 | |||
| 512 | void TranslatorVisitor::LOP3_cbuf(u64) { | ||
| 513 | ThrowNotImplemented(Opcode::LOP3_cbuf); | ||
| 514 | } | ||
| 515 | |||
| 516 | void TranslatorVisitor::LOP3_imm(u64) { | ||
| 517 | ThrowNotImplemented(Opcode::LOP3_imm); | ||
| 518 | } | ||
| 519 | |||
| 520 | void TranslatorVisitor::LOP32I(u64) { | 496 | void TranslatorVisitor::LOP32I(u64) { |
| 521 | ThrowNotImplemented(Opcode::LOP32I); | 497 | ThrowNotImplemented(Opcode::LOP32I); |
| 522 | } | 498 | } |