From abdbafbc203b6dbb8e690d9dda02fc423608401f Mon Sep 17 00:00:00 2001
From: ReinUsesLisp <reinuseslisp@airmail.cc>
Date: Sat, 15 Dec 2018 02:07:46 -0300
Subject: [PATCH] shader_decode: Implement PSETP

---
 .../shader/decode/predicate_set_predicate.cpp | 22 ++++++++++++++++++-
 1 file changed, 21 insertions(+), 1 deletion(-)

diff --git a/src/video_core/shader/decode/predicate_set_predicate.cpp b/src/video_core/shader/decode/predicate_set_predicate.cpp
index 1ad853fda..24352170d 100644
--- a/src/video_core/shader/decode/predicate_set_predicate.cpp
+++ b/src/video_core/shader/decode/predicate_set_predicate.cpp
@@ -11,12 +11,32 @@ namespace VideoCommon::Shader {
 
 using Tegra::Shader::Instruction;
 using Tegra::Shader::OpCode;
+using Tegra::Shader::Pred;
 
 u32 ShaderIR::DecodePredicateSetPredicate(BasicBlock& bb, u32 pc) {
     const Instruction instr = {program_code[pc]};
     const auto opcode = OpCode::Decode(instr);
 
-    UNIMPLEMENTED();
+    const Node op_a = GetPredicate(instr.psetp.pred12, instr.psetp.neg_pred12 != 0);
+    const Node op_b = GetPredicate(instr.psetp.pred29, instr.psetp.neg_pred29 != 0);
+
+    // We can't use the constant predicate as destination.
+    ASSERT(instr.psetp.pred3 != static_cast<u64>(Pred::UnusedIndex));
+
+    const Node second_pred = GetPredicate(instr.psetp.pred39, instr.psetp.neg_pred39 != 0);
+
+    const OperationCode combiner = GetPredicateCombiner(instr.psetp.op);
+    const Node predicate = Operation(combiner, op_a, op_b);
+
+    // Set the primary predicate to the result of Predicate OP SecondPredicate
+    SetPredicate(bb, instr.psetp.pred3, Operation(combiner, predicate, second_pred));
+
+    if (instr.psetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) {
+        // Set the secondary predicate to the result of !Predicate OP SecondPredicate, if enabled
+        SetPredicate(
+            bb, instr.psetp.pred0,
+            Operation(combiner, Operation(OperationCode::LogicalNegate, predicate), second_pred));
+    }
 
     return pc;
 }