From 21a878237bcc6f19f41a4bce156714fd76be9d58 Mon Sep 17 00:00:00 2001
From: FernandoS27 <fsahmkow27@gmail.com>
Date: Wed, 14 Apr 2021 03:41:37 +0200
Subject: [PATCH] shader: Implement IADD3.CC/.X

---
 .../impl/integer_add_three_input.cpp          | 29 ++++++++++++++-----
 1 file changed, 22 insertions(+), 7 deletions(-)

diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/integer_add_three_input.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/integer_add_three_input.cpp
index c2dbd79981..e88c0ffb6d 100644
--- a/src/shader_recompiler/frontend/maxwell/translate/impl/integer_add_three_input.cpp
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/integer_add_three_input.cpp
@@ -58,13 +58,6 @@ void IADD3(TranslatorVisitor& v, u64 insn, IR::U32 op_b, IR::U32 op_c) {
         BitField<51, 1, u64> neg_a;
     } iadd3{insn};
 
-    if (iadd3.x != 0) {
-        throw NotImplementedException("IADD3 X");
-    }
-    if (iadd3.cc != 0) {
-        throw NotImplementedException("IADD3 CC");
-    }
-
     IR::U32 op_a{v.X(iadd3.src_a)};
     op_a = IntegerHalf(v.ir, op_a, iadd3.half_a);
     op_b = IntegerHalf(v.ir, op_b, iadd3.half_b);
@@ -81,10 +74,32 @@ void IADD3(TranslatorVisitor& v, u64 insn, IR::U32 op_b, IR::U32 op_c) {
     }
 
     IR::U32 lhs{v.ir.IAdd(op_a, op_b)};
+    IR::U1 of_1;
+    if (iadd3.cc != 0) {
+        of_1 = v.ir.GetOverflowFromOp(lhs);
+    }
+    if (iadd3.x != 0) {
+        const IR::U32 carry{v.ir.Select(v.ir.GetCFlag(), v.ir.Imm32(1), v.ir.Imm32(0))};
+        lhs = v.ir.IAdd(lhs, carry);
+    }
+    if (iadd3.cc != 0 && iadd3.shift == Shift::Left) {
+        IR::U32 high_bits{v.ir.ShiftRightLogical(lhs, v.ir.Imm32(16))};
+        of_1 = v.ir.LogicalOr(of_1, v.ir.INotEqual(v.ir.Imm32(0), high_bits));
+    }
     lhs = IntegerShift(v.ir, lhs, iadd3.shift);
     const IR::U32 result{v.ir.IAdd(lhs, op_c)};
 
     v.X(iadd3.dest_reg, result);
+    if (iadd3.cc != 0) {
+        // TODO: How does CC behave when X is set?
+        if (iadd3.x != 0) {
+            throw NotImplementedException("IADD3 X+CC");
+        }
+        v.SetZFlag(v.ir.GetZeroFromOp(result));
+        v.SetSFlag(v.ir.GetSignFromOp(result));
+        v.SetCFlag(v.ir.GetCarryFromOp(result));
+        v.SetOFlag(v.ir.LogicalOr(v.ir.GetOverflowFromOp(result), of_1));
+    }
 }
 } // Anonymous namespace