From 6db69990da9f232e6d982cdcb69c2e27d93075cf Mon Sep 17 00:00:00 2001
From: ReinUsesLisp <reinuseslisp@airmail.cc>
Date: Fri, 19 Feb 2021 18:10:18 -0300
Subject: spirv: Add lower fp16 to fp32 pass

---
 src/shader_recompiler/frontend/maxwell/program.cpp |  2 +
 .../impl/floating_point_conversion_integer.cpp     | 62 ++++++++++++++++------
 .../frontend/maxwell/translate/impl/impl.h         |  2 +-
 3 files changed, 50 insertions(+), 16 deletions(-)

(limited to 'src/shader_recompiler/frontend/maxwell')

diff --git a/src/shader_recompiler/frontend/maxwell/program.cpp b/src/shader_recompiler/frontend/maxwell/program.cpp
index 8c44ebb29d..16cdc12e2a 100644
--- a/src/shader_recompiler/frontend/maxwell/program.cpp
+++ b/src/shader_recompiler/frontend/maxwell/program.cpp
@@ -56,6 +56,7 @@ IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Blo
             .post_order_blocks{},
         });
     }
+    Optimization::LowerFp16ToFp32(program);
     for (IR::Function& function : functions) {
         function.post_order_blocks = PostOrder(function.blocks);
         Optimization::SsaRewritePass(function.post_order_blocks);
@@ -69,6 +70,7 @@ IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Blo
         Optimization::VerificationPass(function);
     }
     Optimization::CollectShaderInfoPass(program);
+
     fmt::print(stdout, "{}\n", IR::DumpProgram(program));
     return program;
 }
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_conversion_integer.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_conversion_integer.cpp
index 3d0c48457c..ae2d37405f 100644
--- a/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_conversion_integer.cpp
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_conversion_integer.cpp
@@ -34,7 +34,7 @@ union F2I {
     BitField<8, 2, DestFormat> dest_format;
     BitField<10, 2, SrcFormat> src_format;
     BitField<12, 1, u64> is_signed;
-    BitField<39, 1, Rounding> rounding;
+    BitField<39, 2, Rounding> rounding;
     BitField<49, 1, u64> half;
     BitField<44, 1, u64> ftz;
     BitField<45, 1, u64> abs;
@@ -55,6 +55,28 @@ size_t BitSize(DestFormat dest_format) {
     }
 }
 
+IR::F64 UnpackCbuf(TranslatorVisitor& v, u64 insn) {
+    union {
+        u64 raw;
+        BitField<20, 14, s64> offset;
+        BitField<34, 5, u64> binding;
+    } const cbuf{insn};
+    if (cbuf.binding >= 18) {
+        throw NotImplementedException("Out of bounds constant buffer binding {}", cbuf.binding);
+    }
+    if (cbuf.offset >= 0x4'000 || cbuf.offset < 0) {
+        throw NotImplementedException("Out of bounds constant buffer offset {}", cbuf.offset * 4);
+    }
+    if (cbuf.offset % 2 != 0) {
+        throw NotImplementedException("Unaligned F64 constant buffer offset {}", cbuf.offset * 4);
+    }
+    const IR::U32 binding{v.ir.Imm32(static_cast<u32>(cbuf.binding))};
+    const IR::U32 byte_offset{v.ir.Imm32(static_cast<u32>(cbuf.offset) * 4 + 4)};
+    const IR::U32 cbuf_data{v.ir.GetCbuf(binding, byte_offset)};
+    const IR::Value vector{v.ir.CompositeConstruct(v.ir.Imm32(0U), cbuf_data)};
+    return v.ir.PackDouble2x32(vector);
+}
+
 void TranslateF2I(TranslatorVisitor& v, u64 insn, const IR::F16F32F64& src_a) {
     // F2I is used to convert from a floating point value to an integer
     const F2I f2i{insn};
@@ -82,19 +104,16 @@ void TranslateF2I(TranslatorVisitor& v, u64 insn, const IR::F16F32F64& src_a) {
     const size_t bitsize{BitSize(f2i.dest_format)};
     const IR::U16U32U64 result{v.ir.ConvertFToI(bitsize, is_signed, rounded_value)};
 
-    v.X(f2i.dest_reg, result);
+    if (bitsize == 64) {
+        const IR::Value vector{v.ir.UnpackUint2x32(result)};
+        v.X(f2i.dest_reg + 0, IR::U32{v.ir.CompositeExtract(vector, 0)});
+        v.X(f2i.dest_reg + 1, IR::U32{v.ir.CompositeExtract(vector, 1)});
+    } else {
+        v.X(f2i.dest_reg, result);
+    }
 
     if (f2i.cc != 0) {
-        v.SetZFlag(v.ir.GetZeroFromOp(result));
-        if (is_signed) {
-            v.SetSFlag(v.ir.GetSignFromOp(result));
-        } else {
-            v.ResetSFlag();
-        }
-        v.ResetCFlag();
-
-        // TODO: Investigate if out of bound conversions sets the overflow flag
-        v.ResetOFlag();
+        throw NotImplementedException("F2I CC");
     }
 }
 } // Anonymous namespace
@@ -118,12 +137,25 @@ void TranslatorVisitor::F2I_reg(u64 insn) {
                                           f2i.base.src_format.Value());
         }
     }()};
-
     TranslateF2I(*this, insn, op_a);
 }
 
-void TranslatorVisitor::F2I_cbuf(u64) {
-    throw NotImplementedException("{}", Opcode::F2I_cbuf);
+void TranslatorVisitor::F2I_cbuf(u64 insn) {
+    const F2I f2i{insn};
+    const IR::F16F32F64 op_a{[&]() -> IR::F16F32F64 {
+        switch (f2i.src_format) {
+        case SrcFormat::F16:
+            return IR::F16{ir.CompositeExtract(ir.UnpackFloat2x16(GetCbuf(insn)), f2i.half)};
+        case SrcFormat::F32:
+            return GetCbufF(insn);
+        case SrcFormat::F64: {
+            return UnpackCbuf(*this, insn);
+        }
+        default:
+            throw NotImplementedException("Invalid F2I source format {}", f2i.src_format.Value());
+        }
+    }()};
+    TranslateF2I(*this, insn, op_a);
 }
 
 void TranslatorVisitor::F2I_imm(u64) {
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h b/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h
index 8bd468244e..27aba2cf87 100644
--- a/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h
@@ -11,7 +11,7 @@ namespace Shader::Maxwell {
 
 class TranslatorVisitor {
 public:
-    explicit TranslatorVisitor(Environment& env_, IR::Block& block) : env{env_} ,ir(block) {}
+    explicit TranslatorVisitor(Environment& env_, IR::Block& block) : env{env_}, ir(block) {}
 
     Environment& env;
     IR::IREmitter ir;
-- 
cgit v1.2.3-70-g09d2