From cf27b59493501787320764889a0375711c3f68e1 Mon Sep 17 00:00:00 2001
From: ReinUsesLisp <reinuseslisp@airmail.cc>
Date: Fri, 20 Dec 2019 17:41:27 -0300
Subject: [PATCH 1/2] shader/r2p: Refactor P2R to support P2R

---
 src/video_core/engines/shader_bytecode.h      |  4 +-
 .../shader/decode/register_set_predicate.cpp  | 46 ++++++++++++-------
 2 files changed, 33 insertions(+), 17 deletions(-)

diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index dfb12cd2d5..269ed61274 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -1051,7 +1051,7 @@ union Instruction {
         BitField<40, 1, R2pMode> mode;
         BitField<41, 2, u64> byte;
         BitField<20, 7, u64> immediate_mask;
-    } r2p;
+    } p2r_r2p;
 
     union {
         BitField<39, 3, u64> pred39;
@@ -1801,6 +1801,7 @@ public:
         PSET,
         CSETP,
         R2P_IMM,
+        P2R_IMM,
         XMAD_IMM,
         XMAD_CR,
         XMAD_RC,
@@ -2106,6 +2107,7 @@ private:
             INST("0101000010010---", Id::PSETP, Type::PredicateSetPredicate, "PSETP"),
             INST("010100001010----", Id::CSETP, Type::PredicateSetPredicate, "CSETP"),
             INST("0011100-11110---", Id::R2P_IMM, Type::RegisterSetPredicate, "R2P_IMM"),
+            INST("0011100-11101---", Id::P2R_IMM, Type::RegisterSetPredicate, "P2R_IMM"),
             INST("0011011-00------", Id::XMAD_IMM, Type::Xmad, "XMAD_IMM"),
             INST("0100111---------", Id::XMAD_CR, Type::Xmad, "XMAD_CR"),
             INST("010100010-------", Id::XMAD_RC, Type::Xmad, "XMAD_RC"),
diff --git a/src/video_core/shader/decode/register_set_predicate.cpp b/src/video_core/shader/decode/register_set_predicate.cpp
index e6c9d287ef..ff82450205 100644
--- a/src/video_core/shader/decode/register_set_predicate.cpp
+++ b/src/video_core/shader/decode/register_set_predicate.cpp
@@ -13,37 +13,51 @@ namespace VideoCommon::Shader {
 using Tegra::Shader::Instruction;
 using Tegra::Shader::OpCode;
 
+namespace {
+constexpr u64 NUM_PROGRAMMABLE_PREDICATES = 7;
+}
+
 u32 ShaderIR::DecodeRegisterSetPredicate(NodeBlock& bb, u32 pc) {
     const Instruction instr = {program_code[pc]};
     const auto opcode = OpCode::Decode(instr);
 
-    UNIMPLEMENTED_IF(instr.r2p.mode != Tegra::Shader::R2pMode::Pr);
+    UNIMPLEMENTED_IF(instr.p2r_r2p.mode != Tegra::Shader::R2pMode::Pr);
 
-    const Node apply_mask = [&]() {
+    const Node apply_mask = [&] {
         switch (opcode->get().GetId()) {
         case OpCode::Id::R2P_IMM:
-            return Immediate(static_cast<u32>(instr.r2p.immediate_mask));
+        case OpCode::Id::P2R_IMM:
+            return Immediate(static_cast<u32>(instr.p2r_r2p.immediate_mask));
         default:
             UNREACHABLE();
-            return Immediate(static_cast<u32>(instr.r2p.immediate_mask));
+            return Immediate(0);
         }
     }();
-    const Node mask = GetRegister(instr.gpr8);
-    const auto offset = static_cast<u32>(instr.r2p.byte) * 8;
 
-    constexpr u32 programmable_preds = 7;
-    for (u64 pred = 0; pred < programmable_preds; ++pred) {
-        const auto shift = static_cast<u32>(pred);
+    switch (opcode->get().GetId()) {
+    case OpCode::Id::R2P_IMM: {
+        const Node mask = GetRegister(instr.gpr8);
+        const auto offset = static_cast<u32>(instr.p2r_r2p.byte) * 8;
 
-        const Node apply_compare = BitfieldExtract(apply_mask, shift, 1);
-        const Node condition =
-            Operation(OperationCode::LogicalUNotEqual, apply_compare, Immediate(0));
+        for (u64 pred = 0; pred < NUM_PROGRAMMABLE_PREDICATES; ++pred) {
+            const auto shift = static_cast<u32>(pred);
 
-        const Node value_compare = BitfieldExtract(mask, offset + shift, 1);
-        const Node value = Operation(OperationCode::LogicalUNotEqual, value_compare, Immediate(0));
+            const Node apply_compare = BitfieldExtract(apply_mask, shift, 1);
+            const Node condition =
+                Operation(OperationCode::LogicalUNotEqual, apply_compare, Immediate(0));
 
-        const Node code = Operation(OperationCode::LogicalAssign, GetPredicate(pred), value);
-        bb.push_back(Conditional(condition, {code}));
+            const Node value_compare = BitfieldExtract(mask, offset + shift, 1);
+            const Node value =
+                Operation(OperationCode::LogicalUNotEqual, value_compare, Immediate(0));
+
+            const Node code = Operation(OperationCode::LogicalAssign, GetPredicate(pred), value);
+            bb.push_back(Conditional(condition, {code}));
+        }
+        break;
+    }
+    default:
+        UNIMPLEMENTED_MSG("Unhandled P2R/R2R instruction: {}", opcode->get().GetName());
+        break;
     }
 
     return pc;

From 38d3a4887359b55193b57f31a80921b956c90443 Mon Sep 17 00:00:00 2001
From: ReinUsesLisp <reinuseslisp@airmail.cc>
Date: Fri, 20 Dec 2019 17:56:30 -0300
Subject: [PATCH 2/2] shader/p2r: Implement P2R Pr

P2R dumps predicate or condition codes state to a register. This is
useful for unit testing.
---
 .../shader/decode/register_set_predicate.cpp     | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/src/video_core/shader/decode/register_set_predicate.cpp b/src/video_core/shader/decode/register_set_predicate.cpp
index ff82450205..8d54cce34e 100644
--- a/src/video_core/shader/decode/register_set_predicate.cpp
+++ b/src/video_core/shader/decode/register_set_predicate.cpp
@@ -34,10 +34,11 @@ u32 ShaderIR::DecodeRegisterSetPredicate(NodeBlock& bb, u32 pc) {
         }
     }();
 
+    const auto offset = static_cast<u32>(instr.p2r_r2p.byte) * 8;
+
     switch (opcode->get().GetId()) {
     case OpCode::Id::R2P_IMM: {
         const Node mask = GetRegister(instr.gpr8);
-        const auto offset = static_cast<u32>(instr.p2r_r2p.byte) * 8;
 
         for (u64 pred = 0; pred < NUM_PROGRAMMABLE_PREDICATES; ++pred) {
             const auto shift = static_cast<u32>(pred);
@@ -55,6 +56,19 @@ u32 ShaderIR::DecodeRegisterSetPredicate(NodeBlock& bb, u32 pc) {
         }
         break;
     }
+    case OpCode::Id::P2R_IMM: {
+        Node value = Immediate(0);
+        for (u64 pred = 0; pred < NUM_PROGRAMMABLE_PREDICATES; ++pred) {
+            Node bit = Operation(OperationCode::Select, GetPredicate(pred), Immediate(1U << pred),
+                                 Immediate(0));
+            value = Operation(OperationCode::UBitwiseOr, std::move(value), std::move(bit));
+        }
+        value = Operation(OperationCode::UBitwiseAnd, std::move(value), apply_mask);
+        value = BitfieldInsert(GetRegister(instr.gpr8), std::move(value), offset, 8);
+
+        SetRegister(bb, instr.gpr0, std::move(value));
+        break;
+    }
     default:
         UNIMPLEMENTED_MSG("Unhandled P2R/R2R instruction: {}", opcode->get().GetName());
         break;