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

---
 .../backend/spirv/emit_context.cpp                 |  29 ++++--
 src/shader_recompiler/backend/spirv/emit_context.h |   6 +-
 src/shader_recompiler/backend/spirv/emit_spirv.cpp |   2 +
 src/shader_recompiler/backend/spirv/emit_spirv.h   | 103 +++++++++++----------
 .../spirv/emit_spirv_bitwise_conversion.cpp        |  28 ++++--
 .../backend/spirv/emit_spirv_composite.cpp         |  48 +++++-----
 .../backend/spirv/emit_spirv_control_flow.cpp      |   2 +-
 .../backend/spirv/emit_spirv_convert.cpp           |  89 ++++++++++++++++++
 .../backend/spirv/emit_spirv_floating_point.cpp    |  48 +++++-----
 .../backend/spirv/emit_spirv_integer.cpp           |  16 ----
 .../backend/spirv/emit_spirv_logical.cpp           |  72 +-------------
 .../backend/spirv/emit_spirv_memory.cpp            |  22 +++--
 12 files changed, 255 insertions(+), 210 deletions(-)
 create mode 100644 src/shader_recompiler/backend/spirv/emit_spirv_convert.cpp

(limited to 'src/shader_recompiler/backend')

diff --git a/src/shader_recompiler/backend/spirv/emit_context.cpp b/src/shader_recompiler/backend/spirv/emit_context.cpp
index 770067d988..ea1c8a3be1 100644
--- a/src/shader_recompiler/backend/spirv/emit_context.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_context.cpp
@@ -30,8 +30,11 @@ EmitContext::EmitContext(IR::Program& program) : Sirit::Module(0x00010000) {
     DefineCommonTypes(program.info);
     DefineCommonConstants();
     DefineSpecialVariables(program.info);
-    DefineConstantBuffers(program.info);
-    DefineStorageBuffers(program.info);
+
+    u32 binding{};
+    DefineConstantBuffers(program.info, binding);
+    DefineStorageBuffers(program.info, binding);
+
     DefineLabels(program);
 }
 
@@ -58,6 +61,12 @@ void EmitContext::DefineCommonTypes(const Info& info) {
 
     U1 = Name(TypeBool(), "u1");
 
+    // TODO: Conditionally define these
+    AddCapability(spv::Capability::Int16);
+    AddCapability(spv::Capability::Int64);
+    U16 = Name(TypeInt(16, false), "u16");
+    U64 = Name(TypeInt(64, false), "u64");
+
     F32.Define(*this, TypeFloat(32), "f32");
     U32.Define(*this, TypeInt(32, false), "u32");
 
@@ -95,12 +104,12 @@ void EmitContext::DefineSpecialVariables(const Info& info) {
     }
 }
 
-void EmitContext::DefineConstantBuffers(const Info& info) {
+void EmitContext::DefineConstantBuffers(const Info& info, u32& binding) {
     if (info.constant_buffer_descriptors.empty()) {
         return;
     }
     const Id array_type{TypeArray(U32[1], Constant(U32[1], 4096))};
-    Decorate(array_type, spv::Decoration::ArrayStride, 16U);
+    Decorate(array_type, spv::Decoration::ArrayStride, 4U);
 
     const Id struct_type{TypeStruct(array_type)};
     Name(struct_type, "cbuf_block");
@@ -111,18 +120,19 @@ void EmitContext::DefineConstantBuffers(const Info& info) {
     const Id uniform_type{TypePointer(spv::StorageClass::Uniform, struct_type)};
     uniform_u32 = TypePointer(spv::StorageClass::Uniform, U32[1]);
 
-    u32 binding{};
+    u32 index{};
     for (const Info::ConstantBufferDescriptor& desc : info.constant_buffer_descriptors) {
         const Id id{AddGlobalVariable(uniform_type, spv::StorageClass::Uniform)};
         Decorate(id, spv::Decoration::Binding, binding);
         Decorate(id, spv::Decoration::DescriptorSet, 0U);
         Name(id, fmt::format("c{}", desc.index));
         std::fill_n(cbufs.data() + desc.index, desc.count, id);
+        index += desc.count;
         binding += desc.count;
     }
 }
 
-void EmitContext::DefineStorageBuffers(const Info& info) {
+void EmitContext::DefineStorageBuffers(const Info& info, u32& binding) {
     if (info.storage_buffers_descriptors.empty()) {
         return;
     }
@@ -140,13 +150,14 @@ void EmitContext::DefineStorageBuffers(const Info& info) {
     const Id storage_type{TypePointer(spv::StorageClass::StorageBuffer, struct_type)};
     storage_u32 = TypePointer(spv::StorageClass::StorageBuffer, U32[1]);
 
-    u32 binding{};
+    u32 index{};
     for (const Info::StorageBufferDescriptor& desc : info.storage_buffers_descriptors) {
         const Id id{AddGlobalVariable(storage_type, spv::StorageClass::StorageBuffer)};
         Decorate(id, spv::Decoration::Binding, binding);
         Decorate(id, spv::Decoration::DescriptorSet, 0U);
-        Name(id, fmt::format("ssbo{}", binding));
-        std::fill_n(ssbos.data() + binding, desc.count, id);
+        Name(id, fmt::format("ssbo{}", index));
+        std::fill_n(ssbos.data() + index, desc.count, id);
+        index += desc.count;
         binding += desc.count;
     }
 }
diff --git a/src/shader_recompiler/backend/spirv/emit_context.h b/src/shader_recompiler/backend/spirv/emit_context.h
index c4b84759dc..8de203da2a 100644
--- a/src/shader_recompiler/backend/spirv/emit_context.h
+++ b/src/shader_recompiler/backend/spirv/emit_context.h
@@ -37,6 +37,8 @@ public:
 
     Id void_id{};
     Id U1{};
+    Id U16{};
+    Id U64{};
     VectorTypes F32;
     VectorTypes U32;
     VectorTypes F16;
@@ -59,8 +61,8 @@ private:
     void DefineCommonTypes(const Info& info);
     void DefineCommonConstants();
     void DefineSpecialVariables(const Info& info);
-    void DefineConstantBuffers(const Info& info);
-    void DefineStorageBuffers(const Info& info);
+    void DefineConstantBuffers(const Info& info, u32& binding);
+    void DefineStorageBuffers(const Info& info, u32& binding);
     void DefineLabels(IR::Program& program);
 };
 
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.cpp b/src/shader_recompiler/backend/spirv/emit_spirv.cpp
index d597184359..4ce07c2814 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv.cpp
@@ -14,6 +14,8 @@
 #include "shader_recompiler/frontend/ir/microinstruction.h"
 #include "shader_recompiler/frontend/ir/program.h"
 
+#pragma optimize("", off)
+
 namespace Shader::Backend::SPIRV {
 namespace {
 template <class Func>
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.h b/src/shader_recompiler/backend/spirv/emit_spirv.h
index 5813f51ff1..2b59c0b726 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv.h
+++ b/src/shader_recompiler/backend/spirv/emit_spirv.h
@@ -79,26 +79,27 @@ void EmitWriteStorageU16(EmitContext& ctx);
 void EmitWriteStorageS16(EmitContext& ctx);
 void EmitWriteStorage32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
                         Id value);
-void EmitWriteStorage64(EmitContext& ctx);
+void EmitWriteStorage64(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
+                        Id value);
 void EmitWriteStorage128(EmitContext& ctx);
-void EmitCompositeConstructU32x2(EmitContext& ctx);
-void EmitCompositeConstructU32x3(EmitContext& ctx);
-void EmitCompositeConstructU32x4(EmitContext& ctx);
-void EmitCompositeExtractU32x2(EmitContext& ctx);
-Id EmitCompositeExtractU32x3(EmitContext& ctx, Id vector, u32 index);
-void EmitCompositeExtractU32x4(EmitContext& ctx);
+Id EmitCompositeConstructU32x2(EmitContext& ctx, Id e1, Id e2);
+Id EmitCompositeConstructU32x3(EmitContext& ctx, Id e1, Id e2, Id e3);
+Id EmitCompositeConstructU32x4(EmitContext& ctx, Id e1, Id e2, Id e3, Id e4);
+Id EmitCompositeExtractU32x2(EmitContext& ctx, Id composite, u32 index);
+Id EmitCompositeExtractU32x3(EmitContext& ctx, Id composite, u32 index);
+Id EmitCompositeExtractU32x4(EmitContext& ctx, Id composite, u32 index);
 void EmitCompositeConstructF16x2(EmitContext& ctx);
 void EmitCompositeConstructF16x3(EmitContext& ctx);
 void EmitCompositeConstructF16x4(EmitContext& ctx);
-void EmitCompositeExtractF16x2(EmitContext& ctx);
-void EmitCompositeExtractF16x3(EmitContext& ctx);
-void EmitCompositeExtractF16x4(EmitContext& ctx);
+Id EmitCompositeExtractF16x2(EmitContext& ctx, Id composite, u32 index);
+Id EmitCompositeExtractF16x3(EmitContext& ctx, Id composite, u32 index);
+Id EmitCompositeExtractF16x4(EmitContext& ctx, Id composite, u32 index);
 void EmitCompositeConstructF32x2(EmitContext& ctx);
 void EmitCompositeConstructF32x3(EmitContext& ctx);
 void EmitCompositeConstructF32x4(EmitContext& ctx);
-void EmitCompositeExtractF32x2(EmitContext& ctx);
-void EmitCompositeExtractF32x3(EmitContext& ctx);
-void EmitCompositeExtractF32x4(EmitContext& ctx);
+Id EmitCompositeExtractF32x2(EmitContext& ctx, Id composite, u32 index);
+Id EmitCompositeExtractF32x3(EmitContext& ctx, Id composite, u32 index);
+Id EmitCompositeExtractF32x4(EmitContext& ctx, Id composite, u32 index);
 void EmitCompositeConstructF64x2(EmitContext& ctx);
 void EmitCompositeConstructF64x3(EmitContext& ctx);
 void EmitCompositeConstructF64x4(EmitContext& ctx);
@@ -116,11 +117,13 @@ void EmitBitCastF16U16(EmitContext& ctx);
 Id EmitBitCastF32U32(EmitContext& ctx, Id value);
 void EmitBitCastF64U64(EmitContext& ctx);
 void EmitPackUint2x32(EmitContext& ctx);
-void EmitUnpackUint2x32(EmitContext& ctx);
-void EmitPackFloat2x16(EmitContext& ctx);
-void EmitUnpackFloat2x16(EmitContext& ctx);
-void EmitPackDouble2x32(EmitContext& ctx);
-void EmitUnpackDouble2x32(EmitContext& ctx);
+Id EmitUnpackUint2x32(EmitContext& ctx, Id value);
+Id EmitPackFloat2x16(EmitContext& ctx, Id value);
+Id EmitUnpackFloat2x16(EmitContext& ctx, Id value);
+Id EmitPackHalf2x16(EmitContext& ctx, Id value);
+Id EmitUnpackHalf2x16(EmitContext& ctx, Id value);
+Id EmitPackDouble2x32(EmitContext& ctx, Id value);
+Id EmitUnpackDouble2x32(EmitContext& ctx, Id value);
 void EmitGetZeroFromOp(EmitContext& ctx);
 void EmitGetSignFromOp(EmitContext& ctx);
 void EmitGetCarryFromOp(EmitContext& ctx);
@@ -159,18 +162,18 @@ void EmitFPLog2(EmitContext& ctx);
 void EmitFPSaturate16(EmitContext& ctx);
 void EmitFPSaturate32(EmitContext& ctx);
 void EmitFPSaturate64(EmitContext& ctx);
-void EmitFPRoundEven16(EmitContext& ctx);
-void EmitFPRoundEven32(EmitContext& ctx);
-void EmitFPRoundEven64(EmitContext& ctx);
-void EmitFPFloor16(EmitContext& ctx);
-void EmitFPFloor32(EmitContext& ctx);
-void EmitFPFloor64(EmitContext& ctx);
-void EmitFPCeil16(EmitContext& ctx);
-void EmitFPCeil32(EmitContext& ctx);
-void EmitFPCeil64(EmitContext& ctx);
-void EmitFPTrunc16(EmitContext& ctx);
-void EmitFPTrunc32(EmitContext& ctx);
-void EmitFPTrunc64(EmitContext& ctx);
+Id EmitFPRoundEven16(EmitContext& ctx, Id value);
+Id EmitFPRoundEven32(EmitContext& ctx, Id value);
+Id EmitFPRoundEven64(EmitContext& ctx, Id value);
+Id EmitFPFloor16(EmitContext& ctx, Id value);
+Id EmitFPFloor32(EmitContext& ctx, Id value);
+Id EmitFPFloor64(EmitContext& ctx, Id value);
+Id EmitFPCeil16(EmitContext& ctx, Id value);
+Id EmitFPCeil32(EmitContext& ctx, Id value);
+Id EmitFPCeil64(EmitContext& ctx, Id value);
+Id EmitFPTrunc16(EmitContext& ctx, Id value);
+Id EmitFPTrunc32(EmitContext& ctx, Id value);
+Id EmitFPTrunc64(EmitContext& ctx, Id value);
 Id EmitIAdd32(EmitContext& ctx, IR::Inst* inst, Id a, Id b);
 void EmitIAdd64(EmitContext& ctx);
 Id EmitISub32(EmitContext& ctx, Id a, Id b);
@@ -201,25 +204,25 @@ void EmitLogicalOr(EmitContext& ctx);
 void EmitLogicalAnd(EmitContext& ctx);
 void EmitLogicalXor(EmitContext& ctx);
 void EmitLogicalNot(EmitContext& ctx);
-void EmitConvertS16F16(EmitContext& ctx);
-void EmitConvertS16F32(EmitContext& ctx);
-void EmitConvertS16F64(EmitContext& ctx);
-void EmitConvertS32F16(EmitContext& ctx);
-void EmitConvertS32F32(EmitContext& ctx);
-void EmitConvertS32F64(EmitContext& ctx);
-void EmitConvertS64F16(EmitContext& ctx);
-void EmitConvertS64F32(EmitContext& ctx);
-void EmitConvertS64F64(EmitContext& ctx);
-void EmitConvertU16F16(EmitContext& ctx);
-void EmitConvertU16F32(EmitContext& ctx);
-void EmitConvertU16F64(EmitContext& ctx);
-void EmitConvertU32F16(EmitContext& ctx);
-void EmitConvertU32F32(EmitContext& ctx);
-void EmitConvertU32F64(EmitContext& ctx);
-void EmitConvertU64F16(EmitContext& ctx);
-void EmitConvertU64F32(EmitContext& ctx);
-void EmitConvertU64F64(EmitContext& ctx);
-void EmitConvertU64U32(EmitContext& ctx);
-void EmitConvertU32U64(EmitContext& ctx);
+Id EmitConvertS16F16(EmitContext& ctx, Id value);
+Id EmitConvertS16F32(EmitContext& ctx, Id value);
+Id EmitConvertS16F64(EmitContext& ctx, Id value);
+Id EmitConvertS32F16(EmitContext& ctx, Id value);
+Id EmitConvertS32F32(EmitContext& ctx, Id value);
+Id EmitConvertS32F64(EmitContext& ctx, Id value);
+Id EmitConvertS64F16(EmitContext& ctx, Id value);
+Id EmitConvertS64F32(EmitContext& ctx, Id value);
+Id EmitConvertS64F64(EmitContext& ctx, Id value);
+Id EmitConvertU16F16(EmitContext& ctx, Id value);
+Id EmitConvertU16F32(EmitContext& ctx, Id value);
+Id EmitConvertU16F64(EmitContext& ctx, Id value);
+Id EmitConvertU32F16(EmitContext& ctx, Id value);
+Id EmitConvertU32F32(EmitContext& ctx, Id value);
+Id EmitConvertU32F64(EmitContext& ctx, Id value);
+Id EmitConvertU64F16(EmitContext& ctx, Id value);
+Id EmitConvertU64F32(EmitContext& ctx, Id value);
+Id EmitConvertU64F64(EmitContext& ctx, Id value);
+Id EmitConvertU64U32(EmitContext& ctx, Id value);
+Id EmitConvertU32U64(EmitContext& ctx, Id value);
 
 } // namespace Shader::Backend::SPIRV
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_bitwise_conversion.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_bitwise_conversion.cpp
index 49c2004987..e0d1ba413f 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_bitwise_conversion.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_bitwise_conversion.cpp
@@ -34,24 +34,32 @@ void EmitPackUint2x32(EmitContext&) {
     throw NotImplementedException("SPIR-V Instruction");
 }
 
-void EmitUnpackUint2x32(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitUnpackUint2x32(EmitContext& ctx, Id value) {
+    return ctx.OpBitcast(ctx.U32[2], value);
 }
 
-void EmitPackFloat2x16(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitPackFloat2x16(EmitContext& ctx, Id value) {
+    return ctx.OpBitcast(ctx.U32[1], value);
 }
 
-void EmitUnpackFloat2x16(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitUnpackFloat2x16(EmitContext& ctx, Id value) {
+    return ctx.OpBitcast(ctx.F16[2], value);
 }
 
-void EmitPackDouble2x32(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitPackHalf2x16(EmitContext& ctx, Id value) {
+    return ctx.OpPackHalf2x16(ctx.U32[1], value);
 }
 
-void EmitUnpackDouble2x32(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitUnpackHalf2x16(EmitContext& ctx, Id value) {
+    return ctx.OpUnpackHalf2x16(ctx.F32[2], value);
+}
+
+Id EmitPackDouble2x32(EmitContext& ctx, Id value) {
+    return ctx.OpBitcast(ctx.F64[1], value);
+}
+
+Id EmitUnpackDouble2x32(EmitContext& ctx, Id value) {
+    return ctx.OpBitcast(ctx.U32[2], value);
 }
 
 } // namespace Shader::Backend::SPIRV
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_composite.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_composite.cpp
index 348e4796d5..c950854a00 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_composite.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_composite.cpp
@@ -6,28 +6,28 @@
 
 namespace Shader::Backend::SPIRV {
 
-void EmitCompositeConstructU32x2(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitCompositeConstructU32x2(EmitContext& ctx, Id e1, Id e2) {
+    return ctx.OpCompositeConstruct(ctx.U32[2], e1, e2);
 }
 
-void EmitCompositeConstructU32x3(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitCompositeConstructU32x3(EmitContext& ctx, Id e1, Id e2, Id e3) {
+    return ctx.OpCompositeConstruct(ctx.U32[3], e1, e2, e3);
 }
 
-void EmitCompositeConstructU32x4(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitCompositeConstructU32x4(EmitContext& ctx, Id e1, Id e2, Id e3, Id e4) {
+    return ctx.OpCompositeConstruct(ctx.U32[4], e1, e2, e3, e4);
 }
 
-void EmitCompositeExtractU32x2(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitCompositeExtractU32x2(EmitContext& ctx, Id composite, u32 index) {
+    return ctx.OpCompositeExtract(ctx.U32[1], composite, index);
 }
 
-Id EmitCompositeExtractU32x3(EmitContext& ctx, Id vector, u32 index) {
-    return ctx.OpCompositeExtract(ctx.U32[1], vector, index);
+Id EmitCompositeExtractU32x3(EmitContext& ctx, Id composite, u32 index) {
+    return ctx.OpCompositeExtract(ctx.U32[1], composite, index);
 }
 
-void EmitCompositeExtractU32x4(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitCompositeExtractU32x4(EmitContext& ctx, Id composite, u32 index) {
+    return ctx.OpCompositeExtract(ctx.U32[1], composite, index);
 }
 
 void EmitCompositeConstructF16x2(EmitContext&) {
@@ -42,16 +42,16 @@ void EmitCompositeConstructF16x4(EmitContext&) {
     throw NotImplementedException("SPIR-V Instruction");
 }
 
-void EmitCompositeExtractF16x2(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitCompositeExtractF16x2(EmitContext& ctx, Id composite, u32 index) {
+    return ctx.OpCompositeExtract(ctx.F16[1], composite, index);
 }
 
-void EmitCompositeExtractF16x3(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitCompositeExtractF16x3(EmitContext& ctx, Id composite, u32 index) {
+    return ctx.OpCompositeExtract(ctx.F16[1], composite, index);
 }
 
-void EmitCompositeExtractF16x4(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitCompositeExtractF16x4(EmitContext& ctx, Id composite, u32 index) {
+    return ctx.OpCompositeExtract(ctx.F16[1], composite, index);
 }
 
 void EmitCompositeConstructF32x2(EmitContext&) {
@@ -66,16 +66,16 @@ void EmitCompositeConstructF32x4(EmitContext&) {
     throw NotImplementedException("SPIR-V Instruction");
 }
 
-void EmitCompositeExtractF32x2(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitCompositeExtractF32x2(EmitContext& ctx, Id composite, u32 index) {
+    return ctx.OpCompositeExtract(ctx.F32[1], composite, index);
 }
 
-void EmitCompositeExtractF32x3(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitCompositeExtractF32x3(EmitContext& ctx, Id composite, u32 index) {
+    return ctx.OpCompositeExtract(ctx.F32[1], composite, index);
 }
 
-void EmitCompositeExtractF32x4(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitCompositeExtractF32x4(EmitContext& ctx, Id composite, u32 index) {
+    return ctx.OpCompositeExtract(ctx.F32[1], composite, index);
 }
 
 void EmitCompositeConstructF64x2(EmitContext&) {
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_control_flow.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_control_flow.cpp
index 6c4199664f..48755b8278 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_control_flow.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_control_flow.cpp
@@ -11,7 +11,7 @@ void EmitBranch(EmitContext& ctx, IR::Block* label) {
 }
 
 void EmitBranchConditional(EmitContext& ctx, Id condition, IR::Block* true_label,
-                                      IR::Block* false_label) {
+                           IR::Block* false_label) {
     ctx.OpBranchConditional(condition, true_label->Definition<Id>(), false_label->Definition<Id>());
 }
 
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_convert.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_convert.cpp
new file mode 100644
index 0000000000..76ccaffcef
--- /dev/null
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_convert.cpp
@@ -0,0 +1,89 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "shader_recompiler/backend/spirv/emit_spirv.h"
+
+namespace Shader::Backend::SPIRV {
+
+Id EmitConvertS16F16(EmitContext& ctx, Id value) {
+    return ctx.OpUConvert(ctx.U32[1], ctx.OpConvertFToS(ctx.U16, value));
+}
+
+Id EmitConvertS16F32(EmitContext& ctx, Id value) {
+    return ctx.OpUConvert(ctx.U32[1], ctx.OpConvertFToS(ctx.U16, value));
+}
+
+Id EmitConvertS16F64(EmitContext& ctx, Id value) {
+    return ctx.OpUConvert(ctx.U32[1], ctx.OpConvertFToS(ctx.U16, value));
+}
+
+Id EmitConvertS32F16(EmitContext& ctx, Id value) {
+    return ctx.OpConvertFToS(ctx.U32[1], value);
+}
+
+Id EmitConvertS32F32(EmitContext& ctx, Id value) {
+    return ctx.OpConvertFToS(ctx.U32[1], value);
+}
+
+Id EmitConvertS32F64(EmitContext& ctx, Id value) {
+    return ctx.OpConvertFToS(ctx.U32[1], value);
+}
+
+Id EmitConvertS64F16(EmitContext& ctx, Id value) {
+    return ctx.OpConvertFToS(ctx.U64, value);
+}
+
+Id EmitConvertS64F32(EmitContext& ctx, Id value) {
+    return ctx.OpConvertFToS(ctx.U64, value);
+}
+
+Id EmitConvertS64F64(EmitContext& ctx, Id value) {
+    return ctx.OpConvertFToS(ctx.U64, value);
+}
+
+Id EmitConvertU16F16(EmitContext& ctx, Id value) {
+    return ctx.OpUConvert(ctx.U32[1], ctx.OpConvertFToU(ctx.U16, value));
+}
+
+Id EmitConvertU16F32(EmitContext& ctx, Id value) {
+    return ctx.OpUConvert(ctx.U32[1], ctx.OpConvertFToU(ctx.U16, value));
+}
+
+Id EmitConvertU16F64(EmitContext& ctx, Id value) {
+    return ctx.OpUConvert(ctx.U32[1], ctx.OpConvertFToU(ctx.U16, value));
+}
+
+Id EmitConvertU32F16(EmitContext& ctx, Id value) {
+    return ctx.OpConvertFToU(ctx.U32[1], value);
+}
+
+Id EmitConvertU32F32(EmitContext& ctx, Id value) {
+    return ctx.OpConvertFToU(ctx.U32[1], value);
+}
+
+Id EmitConvertU32F64(EmitContext& ctx, Id value) {
+    return ctx.OpConvertFToU(ctx.U32[1], value);
+}
+
+Id EmitConvertU64F16(EmitContext& ctx, Id value) {
+    return ctx.OpConvertFToU(ctx.U64, value);
+}
+
+Id EmitConvertU64F32(EmitContext& ctx, Id value) {
+    return ctx.OpConvertFToU(ctx.U64, value);
+}
+
+Id EmitConvertU64F64(EmitContext& ctx, Id value) {
+    return ctx.OpConvertFToU(ctx.U64, value);
+}
+
+Id EmitConvertU64U32(EmitContext& ctx, Id value) {
+    return ctx.OpUConvert(ctx.U64, value);
+}
+
+Id EmitConvertU32U64(EmitContext& ctx, Id value) {
+    return ctx.OpUConvert(ctx.U32[1], value);
+}
+
+} // namespace Shader::Backend::SPIRV
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 d24fbb353e..9ef1805310 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_floating_point.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_floating_point.cpp
@@ -169,52 +169,52 @@ void EmitFPSaturate64(EmitContext&) {
     throw NotImplementedException("SPIR-V Instruction");
 }
 
-void EmitFPRoundEven16(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitFPRoundEven16(EmitContext& ctx, Id value) {
+    return ctx.OpRoundEven(ctx.F16[1], value);
 }
 
-void EmitFPRoundEven32(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitFPRoundEven32(EmitContext& ctx, Id value) {
+    return ctx.OpRoundEven(ctx.F32[1], value);
 }
 
-void EmitFPRoundEven64(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitFPRoundEven64(EmitContext& ctx, Id value) {
+    return ctx.OpRoundEven(ctx.F64[1], value);
 }
 
-void EmitFPFloor16(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitFPFloor16(EmitContext& ctx, Id value) {
+    return ctx.OpFloor(ctx.F16[1], value);
 }
 
-void EmitFPFloor32(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitFPFloor32(EmitContext& ctx, Id value) {
+    return ctx.OpFloor(ctx.F32[1], value);
 }
 
-void EmitFPFloor64(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitFPFloor64(EmitContext& ctx, Id value) {
+    return ctx.OpFloor(ctx.F64[1], value);
 }
 
-void EmitFPCeil16(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitFPCeil16(EmitContext& ctx, Id value) {
+    return ctx.OpCeil(ctx.F16[1], value);
 }
 
-void EmitFPCeil32(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitFPCeil32(EmitContext& ctx, Id value) {
+    return ctx.OpCeil(ctx.F32[1], value);
 }
 
-void EmitFPCeil64(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitFPCeil64(EmitContext& ctx, Id value) {
+    return ctx.OpCeil(ctx.F64[1], value);
 }
 
-void EmitFPTrunc16(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitFPTrunc16(EmitContext& ctx, Id value) {
+    return ctx.OpTrunc(ctx.F16[1], value);
 }
 
-void EmitFPTrunc32(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitFPTrunc32(EmitContext& ctx, Id value) {
+    return ctx.OpTrunc(ctx.F32[1], value);
 }
 
-void EmitFPTrunc64(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitFPTrunc64(EmitContext& ctx, Id value) {
+    return ctx.OpTrunc(ctx.F64[1], value);
 }
 
 } // namespace Shader::Backend::SPIRV
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp
index a1d16b81e4..22117a4ee9 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp
@@ -113,20 +113,4 @@ Id EmitUGreaterThanEqual(EmitContext& ctx, Id lhs, Id rhs) {
     return ctx.OpUGreaterThanEqual(ctx.U1, lhs, rhs);
 }
 
-void EmitLogicalOr(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
-}
-
-void EmitLogicalAnd(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
-}
-
-void EmitLogicalXor(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
-}
-
-void EmitLogicalNot(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
-}
-
 } // namespace Shader::Backend::SPIRV
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_logical.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_logical.cpp
index ff2f4fb744..c5a07252f1 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_logical.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_logical.cpp
@@ -6,83 +6,19 @@
 
 namespace Shader::Backend::SPIRV {
 
-void EmitConvertS16F16(EmitContext&) {
+void EmitLogicalOr(EmitContext&) {
     throw NotImplementedException("SPIR-V Instruction");
 }
 
-void EmitConvertS16F32(EmitContext&) {
+void EmitLogicalAnd(EmitContext&) {
     throw NotImplementedException("SPIR-V Instruction");
 }
 
-void EmitConvertS16F64(EmitContext&) {
+void EmitLogicalXor(EmitContext&) {
     throw NotImplementedException("SPIR-V Instruction");
 }
 
-void EmitConvertS32F16(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
-}
-
-void EmitConvertS32F32(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
-}
-
-void EmitConvertS32F64(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
-}
-
-void EmitConvertS64F16(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
-}
-
-void EmitConvertS64F32(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
-}
-
-void EmitConvertS64F64(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
-}
-
-void EmitConvertU16F16(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
-}
-
-void EmitConvertU16F32(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
-}
-
-void EmitConvertU16F64(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
-}
-
-void EmitConvertU32F16(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
-}
-
-void EmitConvertU32F32(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
-}
-
-void EmitConvertU32F64(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
-}
-
-void EmitConvertU64F16(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
-}
-
-void EmitConvertU64F32(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
-}
-
-void EmitConvertU64F64(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
-}
-
-void EmitConvertU64U32(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
-}
-
-void EmitConvertU32U64(EmitContext&) {
+void EmitLogicalNot(EmitContext&) {
     throw NotImplementedException("SPIR-V Instruction");
 }
 
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp
index 77d698ffd4..808c1b4016 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp
@@ -94,8 +94,7 @@ void EmitLoadStorageS16(EmitContext&) {
     throw NotImplementedException("SPIR-V Instruction");
 }
 
-Id EmitLoadStorage32(EmitContext& ctx, const IR::Value& binding,
-                                const IR::Value& offset) {
+Id EmitLoadStorage32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
     if (!binding.IsImmediate()) {
         throw NotImplementedException("Dynamic storage buffer indexing");
     }
@@ -129,8 +128,8 @@ void EmitWriteStorageS16(EmitContext&) {
     throw NotImplementedException("SPIR-V Instruction");
 }
 
-void EmitWriteStorage32(EmitContext& ctx, const IR::Value& binding,
-                                   const IR::Value& offset, Id value) {
+void EmitWriteStorage32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
+                        Id value) {
     if (!binding.IsImmediate()) {
         throw NotImplementedException("Dynamic storage buffer indexing");
     }
@@ -140,8 +139,19 @@ void EmitWriteStorage32(EmitContext& ctx, const IR::Value& binding,
     ctx.OpStore(pointer, value);
 }
 
-void EmitWriteStorage64(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+void EmitWriteStorage64(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
+                        Id value) {
+    if (!binding.IsImmediate()) {
+        throw NotImplementedException("Dynamic storage buffer indexing");
+    }
+    // TODO: Support reinterpreting bindings, guaranteed to be aligned
+    const Id ssbo{ctx.ssbos[binding.U32()]};
+    const Id low_index{StorageIndex(ctx, offset, sizeof(u32))};
+    const Id high_index{ctx.OpIAdd(ctx.U32[1], low_index, ctx.Constant(ctx.U32[1], 1U))};
+    const Id low_pointer{ctx.OpAccessChain(ctx.storage_u32, ssbo, ctx.u32_zero_value, low_index)};
+    const Id high_pointer{ctx.OpAccessChain(ctx.storage_u32, ssbo, ctx.u32_zero_value, high_index)};
+    ctx.OpStore(low_pointer, ctx.OpCompositeExtract(ctx.U32[1], value, 0U));
+    ctx.OpStore(high_pointer, ctx.OpCompositeExtract(ctx.U32[1], value, 1U));
 }
 
 void EmitWriteStorage128(EmitContext&) {
-- 
cgit v1.2.3-70-g09d2