From 6edc9298944d16c29e7423da5b1f3ce3e1025ac7 Mon Sep 17 00:00:00 2001
From: gdkchan <gab.dark.100@gmail.com>
Date: Mon, 23 Mar 2020 13:32:30 -0300
Subject: [PATCH] Implement ICMP shader instruction (#1010)

---
 .../Decoders/OpCodeTable.cs                   |  4 ++
 .../Instructions/InstEmitAlu.cs               | 42 ++++++++++++-------
 .../Instructions/InstEmitMove.cs              |  2 -
 3 files changed, 32 insertions(+), 16 deletions(-)

diff --git a/Ryujinx.Graphics.Shader/Decoders/OpCodeTable.cs b/Ryujinx.Graphics.Shader/Decoders/OpCodeTable.cs
index 72f66f4aa3..3878dd8727 100644
--- a/Ryujinx.Graphics.Shader/Decoders/OpCodeTable.cs
+++ b/Ryujinx.Graphics.Shader/Decoders/OpCodeTable.cs
@@ -120,6 +120,10 @@ namespace Ryujinx.Graphics.Shader.Decoders
             Set("010011001100xx", InstEmit.Iadd3,   typeof(OpCodeAluCbuf));
             Set("0011100x1100xx", InstEmit.Iadd3,   typeof(OpCodeAluImm));
             Set("010111001100xx", InstEmit.Iadd3,   typeof(OpCodeAluReg));
+            Set("010010110100xx", InstEmit.Icmp,    typeof(OpCodeAluCbuf));
+            Set("0011011x0100xx", InstEmit.Icmp,    typeof(OpCodeAluImm));
+            Set("010110110100xx", InstEmit.Icmp,    typeof(OpCodeAluReg));
+            Set("010100110100xx", InstEmit.Icmp,    typeof(OpCodeAluRegCbuf));
             Set("010010100xxxxx", InstEmit.Imad,    typeof(OpCodeAluCbuf));
             Set("0011010x0xxxxx", InstEmit.Imad,    typeof(OpCodeAluImm));
             Set("010110100xxxxx", InstEmit.Imad,    typeof(OpCodeAluReg));
diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitAlu.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitAlu.cs
index 92354cece3..5a919c7710 100644
--- a/Ryujinx.Graphics.Shader/Instructions/InstEmitAlu.cs
+++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitAlu.cs
@@ -200,10 +200,27 @@ namespace Ryujinx.Graphics.Shader.Instructions
             // TODO: CC, X, corner cases
         }
 
+        public static void Icmp(EmitterContext context)
+        {
+            OpCode op = context.CurrOp;
+
+            bool isSigned = op.RawOpCode.Extract(48);
+
+            IntegerCondition cmpOp = (IntegerCondition)op.RawOpCode.Extract(49, 3);
+
+            Operand srcA = GetSrcA(context);
+            Operand srcB = GetSrcB(context);
+            Operand srcC = GetSrcC(context);
+
+            Operand cmpRes = GetIntComparison(context, cmpOp, srcC, Const(0), isSigned);
+
+            Operand res = context.ConditionalSelect(cmpRes, srcA, srcB);
+
+            context.Copy(GetDest(context), res);
+        }
+
         public static void Imad(EmitterContext context)
         {
-            OpCodeAlu op = (OpCodeAlu)context.CurrOp;
-
             bool signedA = context.CurrOp.RawOpCode.Extract(48);
             bool signedB = context.CurrOp.RawOpCode.Extract(53);
             bool high    = context.CurrOp.RawOpCode.Extract(54);
@@ -731,19 +748,16 @@ namespace Ryujinx.Graphics.Shader.Instructions
             }
             else
             {
-                Instruction inst;
-
-                switch (cond)
+                var inst = cond switch
                 {
-                    case IntegerCondition.Less:           inst = Instruction.CompareLessU32;           break;
-                    case IntegerCondition.Equal:          inst = Instruction.CompareEqual;             break;
-                    case IntegerCondition.LessOrEqual:    inst = Instruction.CompareLessOrEqualU32;    break;
-                    case IntegerCondition.Greater:        inst = Instruction.CompareGreaterU32;        break;
-                    case IntegerCondition.NotEqual:       inst = Instruction.CompareNotEqual;          break;
-                    case IntegerCondition.GreaterOrEqual: inst = Instruction.CompareGreaterOrEqualU32; break;
-
-                    default: throw new InvalidOperationException($"Unexpected condition \"{cond}\".");
-                }
+                    IntegerCondition.Less => Instruction.CompareLessU32,
+                    IntegerCondition.Equal => Instruction.CompareEqual,
+                    IntegerCondition.LessOrEqual => Instruction.CompareLessOrEqualU32,
+                    IntegerCondition.Greater => Instruction.CompareGreaterU32,
+                    IntegerCondition.NotEqual => Instruction.CompareNotEqual,
+                    IntegerCondition.GreaterOrEqual => Instruction.CompareGreaterOrEqualU32,
+                    _ => throw new InvalidOperationException($"Unexpected condition \"{cond}\".")
+                };
 
                 if (isSigned)
                 {
diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitMove.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitMove.cs
index ffc4c430f5..efc80b0cb6 100644
--- a/Ryujinx.Graphics.Shader/Instructions/InstEmitMove.cs
+++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitMove.cs
@@ -97,8 +97,6 @@ namespace Ryujinx.Graphics.Shader.Instructions
 
         public static void Sel(EmitterContext context)
         {
-            OpCodeAlu op = (OpCodeAlu)context.CurrOp;
-
             Operand pred = GetPredicate39(context);
 
             Operand srcA = GetSrcA(context);