From e3c55e31d7d15066d565e6cd728d12526e91d8e2 Mon Sep 17 00:00:00 2001
From: ReinUsesLisp <reinuseslisp@airmail.cc>
Date: Thu, 20 Dec 2018 22:57:16 -0300
Subject: [PATCH] shader_ir: Add integer helpers

---
 src/video_core/shader/shader_ir.cpp | 35 +++++++++++++++++++++++++++++
 src/video_core/shader/shader_ir.h   |  5 +++++
 2 files changed, 40 insertions(+)

diff --git a/src/video_core/shader/shader_ir.cpp b/src/video_core/shader/shader_ir.cpp
index af95e54ef..e4b81040d 100644
--- a/src/video_core/shader/shader_ir.cpp
+++ b/src/video_core/shader/shader_ir.cpp
@@ -140,6 +140,41 @@ Node ShaderIR::GetSaturatedFloat(Node value, bool saturate) {
     return Operation(OperationCode::FClamp, NO_PRECISE, value, positive_zero, positive_one);
 }
 
+Node ShaderIR::ConvertIntegerSize(Node value, Tegra::Shader::Register::Size size, bool is_signed) {
+    switch (size) {
+    case Register::Size::Byte:
+        value = SignedOperation(OperationCode::ILogicalShiftLeft, is_signed, NO_PRECISE, value,
+                                Immediate(24));
+        value = SignedOperation(OperationCode::IArithmeticShiftRight, is_signed, NO_PRECISE, value,
+                                Immediate(24));
+        return value;
+    case Register::Size::Short:
+        value = SignedOperation(OperationCode::ILogicalShiftLeft, is_signed, NO_PRECISE, value,
+                                Immediate(16));
+        value = SignedOperation(OperationCode::IArithmeticShiftRight, is_signed, NO_PRECISE, value,
+                                Immediate(16));
+    case Register::Size::Word:
+        // Default - do nothing
+        return value;
+    default:
+        UNREACHABLE_MSG("Unimplemented conversion size: {}", static_cast<u32>(size));
+    }
+}
+
+Node ShaderIR::GetOperandAbsNegInteger(Node value, bool absolute, bool negate, bool is_signed) {
+    if (!is_signed) {
+        // Absolute or negate on an unsigned is pointless
+        return value;
+    }
+    if (absolute) {
+        value = Operation(OperationCode::IAbsolute, NO_PRECISE, value);
+    }
+    if (negate) {
+        value = Operation(OperationCode::INegate, NO_PRECISE, value);
+    }
+    return value;
+}
+
 void ShaderIR::SetRegister(BasicBlock& bb, Register dest, Node src) {
     bb.push_back(Operation(OperationCode::Assign, GetRegister(dest), src));
 }
diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h
index 93455412f..84c016da6 100644
--- a/src/video_core/shader/shader_ir.h
+++ b/src/video_core/shader/shader_ir.h
@@ -648,6 +648,11 @@ private:
     /// Conditionally saturates a float
     Node GetSaturatedFloat(Node value, bool saturate = true);
 
+    /// Converts an integer to different sizes.
+    Node ConvertIntegerSize(Node value, Tegra::Shader::Register::Size size, bool is_signed);
+    /// Conditionally absolute/negated integer. Absolute is applied first
+    Node GetOperandAbsNegInteger(Node value, bool absolute, bool negate, bool is_signed);
+
     template <typename... T>
     inline Node Operation(OperationCode code, const T*... operands) {
         return StoreNode(OperationNode(code, operands...));