From 704c6f353f68745168902c6c66c04bb730bd30e6 Mon Sep 17 00:00:00 2001
From: ReinUsesLisp <reinuseslisp@airmail.cc>
Date: Sun, 21 Feb 2021 17:50:14 -0300
Subject: shader: Rename, implement FADD.SAT and P2R (imm)

---
 src/shader_recompiler/backend/spirv/emit_spirv.h   | 40 ++++++------
 .../backend/spirv/emit_spirv_floating_point.cpp    | 58 +++++++----------
 .../backend/spirv/emit_spirv_integer.cpp           | 75 +++++++++++++++-------
 .../backend/spirv/emit_spirv_select.cpp            |  4 +-
 4 files changed, 98 insertions(+), 79 deletions(-)

(limited to 'src/shader_recompiler/backend')

diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.h b/src/shader_recompiler/backend/spirv/emit_spirv.h
index de624a1510..922e294a78 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv.h
+++ b/src/shader_recompiler/backend/spirv/emit_spirv.h
@@ -110,7 +110,7 @@ void EmitCompositeExtractF64x3(EmitContext& ctx);
 void EmitCompositeExtractF64x4(EmitContext& ctx);
 void EmitSelect8(EmitContext& ctx);
 void EmitSelect16(EmitContext& ctx);
-void EmitSelect32(EmitContext& ctx);
+Id EmitSelect32(EmitContext& ctx, Id cond, Id true_value, Id false_value);
 void EmitSelect64(EmitContext& ctx);
 void EmitBitCastU16F16(EmitContext& ctx);
 Id EmitBitCastU32F32(EmitContext& ctx, Id value);
@@ -130,9 +130,9 @@ void EmitGetZeroFromOp(EmitContext& ctx);
 void EmitGetSignFromOp(EmitContext& ctx);
 void EmitGetCarryFromOp(EmitContext& ctx);
 void EmitGetOverflowFromOp(EmitContext& ctx);
-void EmitFPAbs16(EmitContext& ctx);
-void EmitFPAbs32(EmitContext& ctx);
-void EmitFPAbs64(EmitContext& ctx);
+Id EmitFPAbs16(EmitContext& ctx, Id value);
+Id EmitFPAbs32(EmitContext& ctx, Id value);
+Id EmitFPAbs64(EmitContext& ctx, Id value);
 Id EmitFPAdd16(EmitContext& ctx, IR::Inst* inst, Id a, Id b);
 Id EmitFPAdd32(EmitContext& ctx, IR::Inst* inst, Id a, Id b);
 Id EmitFPAdd64(EmitContext& ctx, IR::Inst* inst, Id a, Id b);
@@ -146,9 +146,9 @@ void EmitFPMin64(EmitContext& ctx);
 Id EmitFPMul16(EmitContext& ctx, IR::Inst* inst, Id a, Id b);
 Id EmitFPMul32(EmitContext& ctx, IR::Inst* inst, Id a, Id b);
 Id EmitFPMul64(EmitContext& ctx, IR::Inst* inst, Id a, Id b);
-void EmitFPNeg16(EmitContext& ctx);
-void EmitFPNeg32(EmitContext& ctx);
-void EmitFPNeg64(EmitContext& ctx);
+Id EmitFPNeg16(EmitContext& ctx, Id value);
+Id EmitFPNeg32(EmitContext& ctx, Id value);
+Id EmitFPNeg64(EmitContext& ctx, Id value);
 void EmitFPRecip32(EmitContext& ctx);
 void EmitFPRecip64(EmitContext& ctx);
 void EmitFPRecipSqrt32(EmitContext& ctx);
@@ -161,9 +161,9 @@ void EmitFPExp2NotReduced(EmitContext& ctx);
 void EmitFPCos(EmitContext& ctx);
 void EmitFPCosNotReduced(EmitContext& ctx);
 void EmitFPLog2(EmitContext& ctx);
-void EmitFPSaturate16(EmitContext& ctx);
-void EmitFPSaturate32(EmitContext& ctx);
-void EmitFPSaturate64(EmitContext& ctx);
+Id EmitFPSaturate16(EmitContext& ctx, Id value);
+Id EmitFPSaturate32(EmitContext& ctx, Id value);
+Id EmitFPSaturate64(EmitContext& ctx, Id value);
 Id EmitFPRoundEven16(EmitContext& ctx, Id value);
 Id EmitFPRoundEven32(EmitContext& ctx, Id value);
 Id EmitFPRoundEven64(EmitContext& ctx, Id value);
@@ -186,21 +186,21 @@ void EmitIAbs32(EmitContext& ctx);
 Id EmitShiftLeftLogical32(EmitContext& ctx, Id base, Id shift);
 void EmitShiftRightLogical32(EmitContext& ctx);
 void EmitShiftRightArithmetic32(EmitContext& ctx);
-void EmitBitwiseAnd32(EmitContext& ctx);
-void EmitBitwiseOr32(EmitContext& ctx);
-void EmitBitwiseXor32(EmitContext& ctx);
+Id EmitBitwiseAnd32(EmitContext& ctx, Id a, Id b);
+Id EmitBitwiseOr32(EmitContext& ctx, Id a, Id b);
+Id EmitBitwiseXor32(EmitContext& ctx, Id a, Id b);
 void EmitBitFieldInsert(EmitContext& ctx);
 void EmitBitFieldSExtract(EmitContext& ctx);
 Id EmitBitFieldUExtract(EmitContext& ctx, Id base, Id offset, Id count);
 Id EmitSLessThan(EmitContext& ctx, Id lhs, Id rhs);
-void EmitULessThan(EmitContext& ctx);
-void EmitIEqual(EmitContext& ctx);
-void EmitSLessThanEqual(EmitContext& ctx);
-void EmitULessThanEqual(EmitContext& ctx);
+Id EmitULessThan(EmitContext& ctx, Id lhs, Id rhs);
+Id EmitIEqual(EmitContext& ctx, Id lhs, Id rhs);
+Id EmitSLessThanEqual(EmitContext& ctx, Id lhs, Id rhs);
+Id EmitULessThanEqual(EmitContext& ctx, Id lhs, Id rhs);
 Id EmitSGreaterThan(EmitContext& ctx, Id lhs, Id rhs);
-void EmitUGreaterThan(EmitContext& ctx);
-void EmitINotEqual(EmitContext& ctx);
-void EmitSGreaterThanEqual(EmitContext& ctx);
+Id EmitUGreaterThan(EmitContext& ctx, Id lhs, Id rhs);
+Id EmitINotEqual(EmitContext& ctx, Id lhs, Id rhs);
+Id EmitSGreaterThanEqual(EmitContext& ctx, Id lhs, Id rhs);
 Id EmitUGreaterThanEqual(EmitContext& ctx, Id lhs, Id rhs);
 void EmitLogicalOr(EmitContext& ctx);
 void EmitLogicalAnd(EmitContext& ctx);
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_floating_point.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_floating_point.cpp
index c9687de377..47f87054b4 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_floating_point.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_floating_point.cpp
@@ -12,37 +12,21 @@ Id Decorate(EmitContext& ctx, IR::Inst* inst, Id op) {
     if (flags.no_contraction) {
         ctx.Decorate(op, spv::Decoration::NoContraction);
     }
-    switch (flags.rounding) {
-    case IR::FpRounding::DontCare:
-        break;
-    case IR::FpRounding::RN:
-        ctx.Decorate(op, spv::Decoration::FPRoundingMode, spv::FPRoundingMode::RTE);
-        break;
-    case IR::FpRounding::RM:
-        ctx.Decorate(op, spv::Decoration::FPRoundingMode, spv::FPRoundingMode::RTN);
-        break;
-    case IR::FpRounding::RP:
-        ctx.Decorate(op, spv::Decoration::FPRoundingMode, spv::FPRoundingMode::RTP);
-        break;
-    case IR::FpRounding::RZ:
-        ctx.Decorate(op, spv::Decoration::FPRoundingMode, spv::FPRoundingMode::RTZ);
-        break;
-    }
     return op;
 }
 
 } // Anonymous namespace
 
-void EmitFPAbs16(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitFPAbs16(EmitContext& ctx, Id value) {
+    return ctx.OpFAbs(ctx.F16[1], value);
 }
 
-void EmitFPAbs32(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitFPAbs32(EmitContext& ctx, Id value) {
+    return ctx.OpFAbs(ctx.F32[1], value);
 }
 
-void EmitFPAbs64(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitFPAbs64(EmitContext& ctx, Id value) {
+    return ctx.OpFAbs(ctx.F64[1], value);
 }
 
 Id EmitFPAdd16(EmitContext& ctx, IR::Inst* inst, Id a, Id b) {
@@ -97,16 +81,16 @@ Id EmitFPMul64(EmitContext& ctx, IR::Inst* inst, Id a, Id b) {
     return Decorate(ctx, inst, ctx.OpFMul(ctx.F64[1], a, b));
 }
 
-void EmitFPNeg16(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitFPNeg16(EmitContext& ctx, Id value) {
+    return ctx.OpFNegate(ctx.F16[1], value);
 }
 
-void EmitFPNeg32(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitFPNeg32(EmitContext& ctx, Id value) {
+    return ctx.OpFNegate(ctx.F32[1], value);
 }
 
-void EmitFPNeg64(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitFPNeg64(EmitContext& ctx, Id value) {
+    return ctx.OpFNegate(ctx.F64[1], value);
 }
 
 void EmitFPRecip32(EmitContext&) {
@@ -157,16 +141,22 @@ void EmitFPLog2(EmitContext&) {
     throw NotImplementedException("SPIR-V Instruction");
 }
 
-void EmitFPSaturate16(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitFPSaturate16(EmitContext& ctx, Id value) {
+    const Id zero{ctx.Constant(ctx.F16[1], u16{0})};
+    const Id one{ctx.Constant(ctx.F16[1], u16{0x3c00})};
+    return ctx.OpFClamp(ctx.F32[1], value, zero, one);
 }
 
-void EmitFPSaturate32(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitFPSaturate32(EmitContext& ctx, Id value) {
+    const Id zero{ctx.Constant(ctx.F32[1], f32{0.0})};
+    const Id one{ctx.Constant(ctx.F32[1], f32{1.0})};
+    return ctx.OpFClamp(ctx.F32[1], value, zero, one);
 }
 
-void EmitFPSaturate64(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitFPSaturate64(EmitContext& ctx, Id value) {
+    const Id zero{ctx.Constant(ctx.F64[1], f64{0.0})};
+    const Id one{ctx.Constant(ctx.F64[1], f64{1.0})};
+    return ctx.OpFClamp(ctx.F64[1], value, zero, one);
 }
 
 Id EmitFPRoundEven16(EmitContext& ctx, Id value) {
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp
index 22117a4ee9..4c0b5990dc 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp
@@ -7,10 +7,39 @@
 namespace Shader::Backend::SPIRV {
 
 Id EmitIAdd32(EmitContext& ctx, IR::Inst* inst, Id a, Id b) {
-    if (inst->HasAssociatedPseudoOperation()) {
-        throw NotImplementedException("Pseudo-operations on IAdd32");
+    Id result{};
+    if (IR::Inst* const carry{inst->GetAssociatedPseudoOperation(IR::Opcode::GetCarryFromOp)}) {
+        const Id carry_type{ctx.TypeStruct(ctx.U32[1], ctx.U32[1])};
+        const Id carry_result{ctx.OpIAddCarry(carry_type, a, b)};
+        result = ctx.OpCompositeExtract(ctx.U32[1], carry_result, 0U);
+
+        const Id carry_value{ctx.OpCompositeExtract(ctx.U32[1], carry_result, 1U)};
+        carry->SetDefinition(ctx.OpINotEqual(ctx.U1, carry_value, ctx.u32_zero_value));
+        carry->Invalidate();
+    } else {
+        result = ctx.OpIAdd(ctx.U32[1], a, b);
     }
-    return ctx.OpIAdd(ctx.U32[1], a, b);
+    if (IR::Inst* const zero{inst->GetAssociatedPseudoOperation(IR::Opcode::GetZeroFromOp)}) {
+        zero->SetDefinition(ctx.OpIEqual(ctx.U1, result, ctx.u32_zero_value));
+        zero->Invalidate();
+    }
+    if (IR::Inst* const sign{inst->GetAssociatedPseudoOperation(IR::Opcode::GetSignFromOp)}) {
+        sign->SetDefinition(ctx.OpSLessThan(ctx.U1, result, ctx.u32_zero_value));
+        sign->Invalidate();
+    }
+    if (IR::Inst * overflow{inst->GetAssociatedPseudoOperation(IR::Opcode::GetOverflowFromOp)}) {
+        // https://stackoverflow.com/questions/55468823/how-to-detect-integer-overflow-in-c
+        constexpr u32 s32_max{static_cast<u32>(std::numeric_limits<s32>::max())};
+        const Id is_positive{ctx.OpSGreaterThanEqual(ctx.U1, a, ctx.u32_zero_value)};
+        const Id sub_a{ctx.OpISub(ctx.U32[1], ctx.Constant(ctx.U32[1], s32_max), a)};
+
+        const Id positive_test{ctx.OpSGreaterThan(ctx.U1, b, sub_a)};
+        const Id negative_test{ctx.OpSLessThan(ctx.U1, b, sub_a)};
+        const Id carry_flag{ctx.OpSelect(ctx.U1, is_positive, positive_test, negative_test)};
+        overflow->SetDefinition(carry_flag);
+        overflow->Invalidate();
+    }
+    return result;
 }
 
 void EmitIAdd64(EmitContext&) {
@@ -49,16 +78,16 @@ void EmitShiftRightArithmetic32(EmitContext&) {
     throw NotImplementedException("SPIR-V Instruction");
 }
 
-void EmitBitwiseAnd32(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitBitwiseAnd32(EmitContext& ctx, Id a, Id b) {
+    return ctx.OpBitwiseAnd(ctx.U32[1], a, b);
 }
 
-void EmitBitwiseOr32(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitBitwiseOr32(EmitContext& ctx, Id a, Id b) {
+    return ctx.OpBitwiseOr(ctx.U32[1], a, b);
 }
 
-void EmitBitwiseXor32(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitBitwiseXor32(EmitContext& ctx, Id a, Id b) {
+    return ctx.OpBitwiseXor(ctx.U32[1], a, b);
 }
 
 void EmitBitFieldInsert(EmitContext&) {
@@ -77,36 +106,36 @@ Id EmitSLessThan(EmitContext& ctx, Id lhs, Id rhs) {
     return ctx.OpSLessThan(ctx.U1, lhs, rhs);
 }
 
-void EmitULessThan(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitULessThan(EmitContext& ctx, Id lhs, Id rhs) {
+    return ctx.OpULessThan(ctx.U1, lhs, rhs);
 }
 
-void EmitIEqual(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitIEqual(EmitContext& ctx, Id lhs, Id rhs) {
+    return ctx.OpIEqual(ctx.U1, lhs, rhs);
 }
 
-void EmitSLessThanEqual(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitSLessThanEqual(EmitContext& ctx, Id lhs, Id rhs) {
+    return ctx.OpSLessThanEqual(ctx.U1, lhs, rhs);
 }
 
-void EmitULessThanEqual(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitULessThanEqual(EmitContext& ctx, Id lhs, Id rhs) {
+    return ctx.OpULessThanEqual(ctx.U1, lhs, rhs);
 }
 
 Id EmitSGreaterThan(EmitContext& ctx, Id lhs, Id rhs) {
     return ctx.OpSGreaterThan(ctx.U1, lhs, rhs);
 }
 
-void EmitUGreaterThan(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitUGreaterThan(EmitContext& ctx, Id lhs, Id rhs) {
+    return ctx.OpUGreaterThan(ctx.U1, lhs, rhs);
 }
 
-void EmitINotEqual(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitINotEqual(EmitContext& ctx, Id lhs, Id rhs) {
+    return ctx.OpINotEqual(ctx.U1, lhs, rhs);
 }
 
-void EmitSGreaterThanEqual(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitSGreaterThanEqual(EmitContext& ctx, Id lhs, Id rhs) {
+    return ctx.OpSGreaterThanEqual(ctx.U1, lhs, rhs);
 }
 
 Id EmitUGreaterThanEqual(EmitContext& ctx, Id lhs, Id rhs) {
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_select.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_select.cpp
index 8d50627247..eb1926a4db 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_select.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_select.cpp
@@ -14,8 +14,8 @@ void EmitSelect16(EmitContext&) {
     throw NotImplementedException("SPIR-V Instruction");
 }
 
-void EmitSelect32(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitSelect32(EmitContext& ctx, Id cond, Id true_value, Id false_value) {
+    return ctx.OpSelect(ctx.U32[1], cond, true_value, false_value);
 }
 
 void EmitSelect64(EmitContext&) {
-- 
cgit v1.2.3-70-g09d2