From 4fc8ad67bfc99d1c80c95c0df54360a55a6be011 Mon Sep 17 00:00:00 2001
From: ReinUsesLisp <reinuseslisp@airmail.cc>
Date: Mon, 15 Oct 2018 02:09:40 -0300
Subject: [PATCH] gl_shader_decompiler: Implement HSETP2_R

---
 src/video_core/engines/shader_bytecode.h      | 20 +++++++++
 .../renderer_opengl/gl_shader_decompiler.cpp  | 45 +++++++++++++++++++
 2 files changed, 65 insertions(+)

diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index 23bfd89885..a6e764ea44 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -800,6 +800,23 @@ union Instruction {
         BitField<45, 4, PredOperation> op; // op with pred39
     } csetp;
 
+    union {
+        BitField<35, 4, PredCondition> cond;
+        BitField<49, 1, u64> h_and;
+        BitField<6, 1, u64> ftz;
+        BitField<45, 2, PredOperation> op;
+        BitField<3, 3, u64> pred3;
+        BitField<0, 3, u64> pred0;
+        BitField<43, 1, u64> negate_a;
+        BitField<44, 1, u64> abs_a;
+        BitField<47, 2, HalfType> type_a;
+        BitField<31, 1, u64> negate_b;
+        BitField<30, 1, u64> abs_b;
+        BitField<28, 2, HalfType> type_b;
+        BitField<42, 1, u64> neg_pred;
+        BitField<39, 3, u64> pred39;
+    } hsetp2;
+
     union {
         BitField<39, 3, u64> pred39;
         BitField<42, 1, u64> neg_pred;
@@ -1239,6 +1256,7 @@ public:
         HFMA2_RC,
         HFMA2_RR,
         HFMA2_IMM_R,
+        HSETP2_R,
         POPC_C,
         POPC_R,
         POPC_IMM,
@@ -1325,6 +1343,7 @@ public:
         FloatSetPredicate,
         IntegerSet,
         IntegerSetPredicate,
+        HalfSetPredicate,
         PredicateSetPredicate,
         PredicateSetRegister,
         Conversion,
@@ -1496,6 +1515,7 @@ private:
             INST("01100---1-------", Id::HFMA2_RC, Type::Hfma2, "HFMA2_RC"),
             INST("0101110100000---", Id::HFMA2_RR, Type::Hfma2, "HFMA2_RR"),
             INST("01110---0-------", Id::HFMA2_IMM_R, Type::Hfma2, "HFMA2_R_IMM"),
+            INST("0101110100100---", Id::HSETP2_R, Type::HalfSetPredicate, "HSETP_R"),
             INST("0101000010000---", Id::MUFU, Type::Arithmetic, "MUFU"),
             INST("0100110010010---", Id::RRO_C, Type::Arithmetic, "RRO_C"),
             INST("0101110010010---", Id::RRO_R, Type::Arithmetic, "RRO_R"),
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index ca2030e975..06f85fad2a 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -2791,6 +2791,51 @@ private:
             }
             break;
         }
+        case OpCode::Type::HalfSetPredicate: {
+            ASSERT_MSG(instr.hsetp2.ftz == 0, "Unimplemented");
+
+            const std::string op_a =
+                GetHalfFloat(regs.GetRegisterAsInteger(instr.gpr8, 0, false), instr.hsetp2.type_a,
+                             instr.hsetp2.abs_a, instr.hsetp2.negate_a);
+
+            const std::string op_b = [&]() {
+                switch (opcode->GetId()) {
+                case OpCode::Id::HSETP2_R:
+                    return GetHalfFloat(regs.GetRegisterAsInteger(instr.gpr20, 0, false),
+                                        instr.hsetp2.type_b, instr.hsetp2.abs_a,
+                                        instr.hsetp2.negate_b);
+                default:
+                    UNREACHABLE();
+                    return std::string("vec2(0)");
+                }
+            }();
+
+            // We can't use the constant predicate as destination.
+            ASSERT(instr.hsetp2.pred3 != static_cast<u64>(Pred::UnusedIndex));
+
+            const std::string second_pred =
+                GetPredicateCondition(instr.hsetp2.pred39, instr.hsetp2.neg_pred != 0);
+
+            const std::string combiner = GetPredicateCombiner(instr.hsetp2.op);
+
+            const std::string component_combiner = instr.hsetp2.h_and ? "&&" : "||";
+            const std::string predicate =
+                '(' + GetPredicateComparison(instr.hsetp2.cond, op_a + ".x", op_b + ".x") + ' ' +
+                component_combiner + ' ' +
+                GetPredicateComparison(instr.hsetp2.cond, op_a + ".y", op_b + ".y") + ')';
+
+            // Set the primary predicate to the result of Predicate OP SecondPredicate
+            SetPredicate(instr.hsetp2.pred3,
+                         '(' + predicate + ") " + combiner + " (" + second_pred + ')');
+
+            if (instr.hsetp2.pred0 != static_cast<u64>(Pred::UnusedIndex)) {
+                // Set the secondary predicate to the result of !Predicate OP SecondPredicate,
+                // if enabled
+                SetPredicate(instr.hsetp2.pred0,
+                             "!(" + predicate + ") " + combiner + " (" + second_pred + ')');
+            }
+            break;
+        }
         case OpCode::Type::PredicateSetRegister: {
             const std::string op_a =
                 GetPredicateCondition(instr.pset.pred12, instr.pset.neg_pred12 != 0);