From 255197e64363f9286ed145cafdeb129c85c16621 Mon Sep 17 00:00:00 2001
From: ReinUsesLisp <reinuseslisp@airmail.cc>
Date: Sat, 25 Apr 2020 21:56:11 -0300
Subject: [PATCH] shader/arithmetic_integer: Implement CC for IADD

---
 externals/sirit                               |  2 +-
 .../renderer_opengl/gl_shader_decompiler.cpp  | 10 +++++++++
 .../renderer_vulkan/vk_shader_decompiler.cpp  | 11 ++++++++++
 .../shader/decode/arithmetic_integer.cpp      | 22 ++++++++++++++++---
 src/video_core/shader/node.h                  |  2 ++
 5 files changed, 43 insertions(+), 4 deletions(-)

diff --git a/externals/sirit b/externals/sirit
index a712959f1e..414fc4dbd2 160000
--- a/externals/sirit
+++ b/externals/sirit
@@ -1 +1 @@
-Subproject commit a712959f1e373a33b48042b5934e288a243d5954
+Subproject commit 414fc4dbd28d8fe48f735a0c389db8a234f733c0
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 0cd3ad7e13..3803a6f3ae 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -1870,6 +1870,14 @@ private:
         return GenerateBinaryInfix(operation, ">=", Type::Bool, type, type);
     }
 
+    Expression LogicalAddCarry(Operation operation) {
+        const std::string carry = code.GenerateTemporary();
+        code.AddLine("uint {};", carry);
+        code.AddLine("uaddCarry({}, {}, {});", VisitOperand(operation, 0).AsUint(),
+                     VisitOperand(operation, 1).AsUint(), carry);
+        return {fmt::format("({} != 0)", carry), Type::Bool};
+    }
+
     Expression LogicalFIsNan(Operation operation) {
         return GenerateUnary(operation, "isnan", Type::Bool, Type::Float);
     }
@@ -2441,6 +2449,8 @@ private:
         &GLSLDecompiler::LogicalNotEqual<Type::Uint>,
         &GLSLDecompiler::LogicalGreaterEqual<Type::Uint>,
 
+        &GLSLDecompiler::LogicalAddCarry,
+
         &GLSLDecompiler::Logical2HLessThan<false>,
         &GLSLDecompiler::Logical2HEqual<false>,
         &GLSLDecompiler::Logical2HLessEqual<false>,
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
index aaa138f527..20b6ca0ad7 100644
--- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
+++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
@@ -1584,6 +1584,15 @@ private:
         return {OpCompositeConstruct(t_half, low, high), Type::HalfFloat};
     }
 
+    Expression LogicalAddCarry(Operation operation) {
+        const Id op_a = AsUint(Visit(operation[0]));
+        const Id op_b = AsUint(Visit(operation[1]));
+
+        const Id result = OpIAddCarry(TypeStruct({t_uint, t_uint}), op_a, op_b);
+        const Id carry = OpCompositeExtract(t_uint, result, 1);
+        return {OpINotEqual(t_bool, carry, Constant(t_uint, 0)), Type::Bool};
+    }
+
     Expression LogicalAssign(Operation operation) {
         const Node& dest = operation[0];
         const Node& src = operation[1];
@@ -2518,6 +2527,8 @@ private:
         &SPIRVDecompiler::Binary<&Module::OpINotEqual, Type::Bool, Type::Uint>,
         &SPIRVDecompiler::Binary<&Module::OpUGreaterThanEqual, Type::Bool, Type::Uint>,
 
+        &SPIRVDecompiler::LogicalAddCarry,
+
         &SPIRVDecompiler::Binary<&Module::OpFOrdLessThan, Type::Bool2, Type::HalfFloat>,
         &SPIRVDecompiler::Binary<&Module::OpFOrdEqual, Type::Bool2, Type::HalfFloat>,
         &SPIRVDecompiler::Binary<&Module::OpFOrdLessThanEqual, Type::Bool2, Type::HalfFloat>,
diff --git a/src/video_core/shader/decode/arithmetic_integer.cpp b/src/video_core/shader/decode/arithmetic_integer.cpp
index 9af8c606d6..99b4b6342f 100644
--- a/src/video_core/shader/decode/arithmetic_integer.cpp
+++ b/src/video_core/shader/decode/arithmetic_integer.cpp
@@ -40,10 +40,26 @@ u32 ShaderIR::DecodeArithmeticInteger(NodeBlock& bb, u32 pc) {
         op_a = GetOperandAbsNegInteger(op_a, false, instr.alu_integer.negate_a, true);
         op_b = GetOperandAbsNegInteger(op_b, false, instr.alu_integer.negate_b, true);
 
-        const Node value = Operation(OperationCode::IAdd, PRECISE, op_a, op_b);
+        Node value = Operation(OperationCode::IAdd, op_a, op_b);
 
-        SetInternalFlagsFromInteger(bb, value, instr.generates_cc);
-        SetRegister(bb, instr.gpr0, value);
+        if (instr.generates_cc) {
+            const Node i0 = Immediate(0);
+
+            Node zero = Operation(OperationCode::LogicalIEqual, value, i0);
+            Node sign = Operation(OperationCode::LogicalILessThan, value, i0);
+            Node carry = Operation(OperationCode::LogicalAddCarry, op_a, op_b);
+
+            Node pos_a = Operation(OperationCode::LogicalIGreaterThan, op_a, i0);
+            Node pos_b = Operation(OperationCode::LogicalIGreaterThan, op_b, i0);
+            Node pos = Operation(OperationCode::LogicalAnd, std::move(pos_a), std::move(pos_b));
+            Node overflow = Operation(OperationCode::LogicalAnd, pos, sign);
+
+            SetInternalFlag(bb, InternalFlag::Zero, std::move(zero));
+            SetInternalFlag(bb, InternalFlag::Sign, std::move(sign));
+            SetInternalFlag(bb, InternalFlag::Carry, std::move(carry));
+            SetInternalFlag(bb, InternalFlag::Overflow, std::move(overflow));
+        }
+        SetRegister(bb, instr.gpr0, std::move(value));
         break;
     }
     case OpCode::Id::IADD3_C:
diff --git a/src/video_core/shader/node.h b/src/video_core/shader/node.h
index 3eee961f53..3f5a7bc7af 100644
--- a/src/video_core/shader/node.h
+++ b/src/video_core/shader/node.h
@@ -132,6 +132,8 @@ enum class OperationCode {
     LogicalUNotEqual,     /// (uint a, uint b) -> bool
     LogicalUGreaterEqual, /// (uint a, uint b) -> bool
 
+    LogicalAddCarry, /// (uint a, uint b) -> bool
+
     Logical2HLessThan,            /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
     Logical2HEqual,               /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
     Logical2HLessEqual,           /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2