From 2930dccecc933d6748772e9f51a5724fe1e6771b Mon Sep 17 00:00:00 2001
From: ReinUsesLisp <reinuseslisp@airmail.cc>
Date: Mon, 8 Feb 2021 02:54:35 -0300
Subject: spirv: Initial SPIR-V support

---
 src/shader_recompiler/backend/spirv/emit_spirv.cpp | 134 +++++++++
 src/shader_recompiler/backend/spirv/emit_spirv.h   | 314 ++++++++++++++++++++-
 .../spirv/emit_spirv_bitwise_conversion.cpp        |  57 ++++
 .../backend/spirv/emit_spirv_composite.cpp         | 105 +++++++
 .../backend/spirv/emit_spirv_context_get_set.cpp   | 102 +++++++
 .../backend/spirv/emit_spirv_control_flow.cpp      |  30 ++
 .../backend/spirv/emit_spirv_floating_point.cpp    | 220 +++++++++++++++
 .../backend/spirv/emit_spirv_integer.cpp           | 132 +++++++++
 .../backend/spirv/emit_spirv_logical.cpp           |  89 ++++++
 .../backend/spirv/emit_spirv_memory.cpp            | 125 ++++++++
 .../backend/spirv/emit_spirv_select.cpp            |  25 ++
 .../backend/spirv/emit_spirv_undefined.cpp         |  29 ++
 12 files changed, 1359 insertions(+), 3 deletions(-)
 create mode 100644 src/shader_recompiler/backend/spirv/emit_spirv.cpp
 create mode 100644 src/shader_recompiler/backend/spirv/emit_spirv_bitwise_conversion.cpp
 create mode 100644 src/shader_recompiler/backend/spirv/emit_spirv_composite.cpp
 create mode 100644 src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp
 create mode 100644 src/shader_recompiler/backend/spirv/emit_spirv_control_flow.cpp
 create mode 100644 src/shader_recompiler/backend/spirv/emit_spirv_floating_point.cpp
 create mode 100644 src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp
 create mode 100644 src/shader_recompiler/backend/spirv/emit_spirv_logical.cpp
 create mode 100644 src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp
 create mode 100644 src/shader_recompiler/backend/spirv/emit_spirv_select.cpp
 create mode 100644 src/shader_recompiler/backend/spirv/emit_spirv_undefined.cpp

(limited to 'src/shader_recompiler/backend')

diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.cpp b/src/shader_recompiler/backend/spirv/emit_spirv.cpp
new file mode 100644
index 0000000000..7c4269fad4
--- /dev/null
+++ b/src/shader_recompiler/backend/spirv/emit_spirv.cpp
@@ -0,0 +1,134 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <numeric>
+#include <type_traits>
+
+#include "shader_recompiler/backend/spirv/emit_spirv.h"
+#include "shader_recompiler/frontend/ir/basic_block.h"
+#include "shader_recompiler/frontend/ir/function.h"
+#include "shader_recompiler/frontend/ir/microinstruction.h"
+#include "shader_recompiler/frontend/ir/program.h"
+
+namespace Shader::Backend::SPIRV {
+
+EmitContext::EmitContext(IR::Program& program) {
+    AddCapability(spv::Capability::Shader);
+    AddCapability(spv::Capability::Float16);
+    AddCapability(spv::Capability::Float64);
+    void_id = TypeVoid();
+
+    u1 = Name(TypeBool(), "u1");
+    f32.Define(*this, TypeFloat(32), "f32");
+    u32.Define(*this, TypeInt(32, false), "u32");
+    f16.Define(*this, TypeFloat(16), "f16");
+    f64.Define(*this, TypeFloat(64), "f64");
+
+    for (const IR::Function& function : program.functions) {
+        for (IR::Block* const block : function.blocks) {
+            block_label_map.emplace_back(block, OpLabel());
+        }
+    }
+    std::ranges::sort(block_label_map, {}, &std::pair<IR::Block*, Id>::first);
+}
+
+EmitContext::~EmitContext() = default;
+
+EmitSPIRV::EmitSPIRV(IR::Program& program) {
+    EmitContext ctx{program};
+    const Id void_function{ctx.TypeFunction(ctx.void_id)};
+    // FIXME: Forward declare functions (needs sirit support)
+    Id func{};
+    for (IR::Function& function : program.functions) {
+        func = ctx.OpFunction(ctx.void_id, spv::FunctionControlMask::MaskNone, void_function);
+        for (IR::Block* const block : function.blocks) {
+            ctx.AddLabel(ctx.BlockLabel(block));
+            for (IR::Inst& inst : block->Instructions()) {
+                EmitInst(ctx, &inst);
+            }
+        }
+        ctx.OpFunctionEnd();
+    }
+    ctx.AddEntryPoint(spv::ExecutionModel::GLCompute, func, "main");
+
+    std::vector<u32> result{ctx.Assemble()};
+    std::FILE* file{std::fopen("shader.spv", "wb")};
+    std::fwrite(result.data(), sizeof(u32), result.size(), file);
+    std::fclose(file);
+    std::system("spirv-dis shader.spv");
+    std::system("spirv-val shader.spv");
+}
+
+template <auto method>
+static void Invoke(EmitSPIRV& emit, EmitContext& ctx, IR::Inst* inst) {
+    using M = decltype(method);
+    using std::is_invocable_r_v;
+    if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&>) {
+        ctx.Define(inst, (emit.*method)(ctx));
+    } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, Id>) {
+        ctx.Define(inst, (emit.*method)(ctx, ctx.Def(inst->Arg(0))));
+    } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, Id, Id>) {
+        ctx.Define(inst, (emit.*method)(ctx, ctx.Def(inst->Arg(0)), ctx.Def(inst->Arg(1))));
+    } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, Id, Id, Id>) {
+        ctx.Define(inst, (emit.*method)(ctx, ctx.Def(inst->Arg(0)), ctx.Def(inst->Arg(1)),
+                                        ctx.Def(inst->Arg(2))));
+    } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, IR::Inst*, Id, Id>) {
+        ctx.Define(inst, (emit.*method)(ctx, inst, ctx.Def(inst->Arg(0)), ctx.Def(inst->Arg(1))));
+    } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, IR::Inst*, Id, Id, Id>) {
+        ctx.Define(inst, (emit.*method)(ctx, inst, ctx.Def(inst->Arg(0)), ctx.Def(inst->Arg(1)),
+                                        ctx.Def(inst->Arg(2))));
+    } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, Id, u32>) {
+        ctx.Define(inst, (emit.*method)(ctx, ctx.Def(inst->Arg(0)), inst->Arg(1).U32()));
+    } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, const IR::Value&>) {
+        ctx.Define(inst, (emit.*method)(ctx, inst->Arg(0)));
+    } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, const IR::Value&,
+                                          const IR::Value&>) {
+        ctx.Define(inst, (emit.*method)(ctx, inst->Arg(0), inst->Arg(1)));
+    } else if constexpr (is_invocable_r_v<void, M, EmitSPIRV&, EmitContext&, IR::Inst*>) {
+        (emit.*method)(ctx, inst);
+    } else if constexpr (is_invocable_r_v<void, M, EmitSPIRV&, EmitContext&>) {
+        (emit.*method)(ctx);
+    } else {
+        static_assert(false, "Bad format");
+    }
+}
+
+void EmitSPIRV::EmitInst(EmitContext& ctx, IR::Inst* inst) {
+    switch (inst->Opcode()) {
+#define OPCODE(name, result_type, ...)                                                             \
+    case IR::Opcode::name:                                                                         \
+        return Invoke<&EmitSPIRV::Emit##name>(*this, ctx, inst);
+#include "shader_recompiler/frontend/ir/opcodes.inc"
+#undef OPCODE
+    }
+    throw LogicError("Invalid opcode {}", inst->Opcode());
+}
+
+void EmitSPIRV::EmitPhi(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitVoid(EmitContext&) {}
+
+void EmitSPIRV::EmitIdentity(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitGetZeroFromOp(EmitContext&) {
+    throw LogicError("Unreachable instruction");
+}
+
+void EmitSPIRV::EmitGetSignFromOp(EmitContext&) {
+    throw LogicError("Unreachable instruction");
+}
+
+void EmitSPIRV::EmitGetCarryFromOp(EmitContext&) {
+    throw LogicError("Unreachable instruction");
+}
+
+void EmitSPIRV::EmitGetOverflowFromOp(EmitContext&) {
+    throw LogicError("Unreachable instruction");
+}
+
+} // namespace Shader::Backend::SPIRV
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.h b/src/shader_recompiler/backend/spirv/emit_spirv.h
index 99cc8e08ad..3f4b68a7d1 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv.h
+++ b/src/shader_recompiler/backend/spirv/emit_spirv.h
@@ -4,18 +4,326 @@
 
 #pragma once
 
+#include <sirit/sirit.h>
+
+#include <boost/container/flat_map.hpp>
+
+#include "common/common_types.h"
 #include "shader_recompiler/frontend/ir/microinstruction.h"
 #include "shader_recompiler/frontend/ir/program.h"
 
 namespace Shader::Backend::SPIRV {
 
+using Sirit::Id;
+
+class DefMap {
+public:
+    void Define(IR::Inst* inst, Id def_id) {
+        const InstInfo info{.use_count{inst->UseCount()}, .def_id{def_id}};
+        const auto it{map.insert(map.end(), std::make_pair(inst, info))};
+        if (it == map.end()) {
+            throw LogicError("Defining already defined instruction");
+        }
+    }
+
+    [[nodiscard]] Id Consume(IR::Inst* inst) {
+        const auto it{map.find(inst)};
+        if (it == map.end()) {
+            throw LogicError("Consuming undefined instruction");
+        }
+        const Id def_id{it->second.def_id};
+        if (--it->second.use_count == 0) {
+            map.erase(it);
+        }
+        return def_id;
+    }
+
+private:
+    struct InstInfo {
+        int use_count;
+        Id def_id;
+    };
+
+    boost::container::flat_map<IR::Inst*, InstInfo> map;
+};
+
+class VectorTypes {
+public:
+    void Define(Sirit::Module& sirit_ctx, Id base_type, std::string_view name) {
+        defs[0] = sirit_ctx.Name(base_type, name);
+
+        std::array<char, 6> def_name;
+        for (int i = 1; i < 4; ++i) {
+            const std::string_view def_name_view(
+                def_name.data(),
+                fmt::format_to_n(def_name.data(), def_name.size(), "{}x{}", name, i + 1).size);
+            defs[i] = sirit_ctx.Name(sirit_ctx.TypeVector(base_type, i + 1), def_name_view);
+        }
+    }
+
+    [[nodiscard]] Id operator[](size_t size) const noexcept {
+        return defs[size - 1];
+    }
+
+private:
+    std::array<Id, 4> defs;
+};
+
+class EmitContext final : public Sirit::Module {
+public:
+    explicit EmitContext(IR::Program& program);
+    ~EmitContext();
+
+    [[nodiscard]] Id Def(const IR::Value& value) {
+        if (!value.IsImmediate()) {
+            return def_map.Consume(value.Inst());
+        }
+        switch (value.Type()) {
+        case IR::Type::U32:
+            return Constant(u32[1], value.U32());
+        case IR::Type::F32:
+            return Constant(f32[1], value.F32());
+        default:
+            throw NotImplementedException("Immediate type {}", value.Type());
+        }
+    }
+
+    void Define(IR::Inst* inst, Id def_id) {
+        def_map.Define(inst, def_id);
+    }
+
+    [[nodiscard]] Id BlockLabel(IR::Block* block) const {
+        const auto it{std::ranges::lower_bound(block_label_map, block, {},
+                                               &std::pair<IR::Block*, Id>::first)};
+        if (it == block_label_map.end()) {
+            throw LogicError("Undefined block");
+        }
+        return it->second;
+    }
+
+    Id void_id{};
+    Id u1{};
+    VectorTypes f32;
+    VectorTypes u32;
+    VectorTypes f16;
+    VectorTypes f64;
+
+    Id workgroup_id{};
+    Id local_invocation_id{};
+
+private:
+    DefMap def_map;
+    std::vector<std::pair<IR::Block*, Id>> block_label_map;
+};
+
 class EmitSPIRV {
 public:
+    explicit EmitSPIRV(IR::Program& program);
+
 private:
+    void EmitInst(EmitContext& ctx, IR::Inst* inst);
+
     // Microinstruction emitters
-#define OPCODE(name, result_type, ...) void Emit##name(EmitContext& ctx, IR::Inst* inst);
-#include "shader_recompiler/frontend/ir/opcodes.inc"
-#undef OPCODE
+    void EmitPhi(EmitContext& ctx);
+    void EmitVoid(EmitContext& ctx);
+    void EmitIdentity(EmitContext& ctx);
+    void EmitBranch(EmitContext& ctx, IR::Inst* inst);
+    void EmitBranchConditional(EmitContext& ctx, IR::Inst* inst);
+    void EmitExit(EmitContext& ctx);
+    void EmitReturn(EmitContext& ctx);
+    void EmitUnreachable(EmitContext& ctx);
+    void EmitGetRegister(EmitContext& ctx);
+    void EmitSetRegister(EmitContext& ctx);
+    void EmitGetPred(EmitContext& ctx);
+    void EmitSetPred(EmitContext& ctx);
+    Id EmitGetCbuf(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset);
+    void EmitGetAttribute(EmitContext& ctx);
+    void EmitSetAttribute(EmitContext& ctx);
+    void EmitGetAttributeIndexed(EmitContext& ctx);
+    void EmitSetAttributeIndexed(EmitContext& ctx);
+    void EmitGetZFlag(EmitContext& ctx);
+    void EmitGetSFlag(EmitContext& ctx);
+    void EmitGetCFlag(EmitContext& ctx);
+    void EmitGetOFlag(EmitContext& ctx);
+    void EmitSetZFlag(EmitContext& ctx);
+    void EmitSetSFlag(EmitContext& ctx);
+    void EmitSetCFlag(EmitContext& ctx);
+    void EmitSetOFlag(EmitContext& ctx);
+    Id EmitWorkgroupId(EmitContext& ctx);
+    Id EmitLocalInvocationId(EmitContext& ctx);
+    void EmitUndef1(EmitContext& ctx);
+    void EmitUndef8(EmitContext& ctx);
+    void EmitUndef16(EmitContext& ctx);
+    void EmitUndef32(EmitContext& ctx);
+    void EmitUndef64(EmitContext& ctx);
+    void EmitLoadGlobalU8(EmitContext& ctx);
+    void EmitLoadGlobalS8(EmitContext& ctx);
+    void EmitLoadGlobalU16(EmitContext& ctx);
+    void EmitLoadGlobalS16(EmitContext& ctx);
+    void EmitLoadGlobal32(EmitContext& ctx);
+    void EmitLoadGlobal64(EmitContext& ctx);
+    void EmitLoadGlobal128(EmitContext& ctx);
+    void EmitWriteGlobalU8(EmitContext& ctx);
+    void EmitWriteGlobalS8(EmitContext& ctx);
+    void EmitWriteGlobalU16(EmitContext& ctx);
+    void EmitWriteGlobalS16(EmitContext& ctx);
+    void EmitWriteGlobal32(EmitContext& ctx);
+    void EmitWriteGlobal64(EmitContext& ctx);
+    void EmitWriteGlobal128(EmitContext& ctx);
+    void EmitLoadStorageU8(EmitContext& ctx);
+    void EmitLoadStorageS8(EmitContext& ctx);
+    void EmitLoadStorageU16(EmitContext& ctx);
+    void EmitLoadStorageS16(EmitContext& ctx);
+    Id EmitLoadStorage32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset);
+    void EmitLoadStorage64(EmitContext& ctx);
+    void EmitLoadStorage128(EmitContext& ctx);
+    void EmitWriteStorageU8(EmitContext& ctx);
+    void EmitWriteStorageS8(EmitContext& ctx);
+    void EmitWriteStorageU16(EmitContext& ctx);
+    void EmitWriteStorageS16(EmitContext& ctx);
+    void EmitWriteStorage32(EmitContext& ctx);
+    void EmitWriteStorage64(EmitContext& ctx);
+    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);
+    void EmitCompositeConstructF16x2(EmitContext& ctx);
+    void EmitCompositeConstructF16x3(EmitContext& ctx);
+    void EmitCompositeConstructF16x4(EmitContext& ctx);
+    void EmitCompositeExtractF16x2(EmitContext& ctx);
+    void EmitCompositeExtractF16x3(EmitContext& ctx);
+    void EmitCompositeExtractF16x4(EmitContext& ctx);
+    void EmitCompositeConstructF32x2(EmitContext& ctx);
+    void EmitCompositeConstructF32x3(EmitContext& ctx);
+    void EmitCompositeConstructF32x4(EmitContext& ctx);
+    void EmitCompositeExtractF32x2(EmitContext& ctx);
+    void EmitCompositeExtractF32x3(EmitContext& ctx);
+    void EmitCompositeExtractF32x4(EmitContext& ctx);
+    void EmitCompositeConstructF64x2(EmitContext& ctx);
+    void EmitCompositeConstructF64x3(EmitContext& ctx);
+    void EmitCompositeConstructF64x4(EmitContext& ctx);
+    void EmitCompositeExtractF64x2(EmitContext& ctx);
+    void EmitCompositeExtractF64x3(EmitContext& ctx);
+    void EmitCompositeExtractF64x4(EmitContext& ctx);
+    void EmitSelect8(EmitContext& ctx);
+    void EmitSelect16(EmitContext& ctx);
+    void EmitSelect32(EmitContext& ctx);
+    void EmitSelect64(EmitContext& ctx);
+    void EmitBitCastU16F16(EmitContext& ctx);
+    Id EmitBitCastU32F32(EmitContext& ctx, Id value);
+    void EmitBitCastU64F64(EmitContext& ctx);
+    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);
+    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 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);
+    Id EmitFPFma16(EmitContext& ctx, IR::Inst* inst, Id a, Id b, Id c);
+    Id EmitFPFma32(EmitContext& ctx, IR::Inst* inst, Id a, Id b, Id c);
+    Id EmitFPFma64(EmitContext& ctx, IR::Inst* inst, Id a, Id b, Id c);
+    void EmitFPMax32(EmitContext& ctx);
+    void EmitFPMax64(EmitContext& ctx);
+    void EmitFPMin32(EmitContext& ctx);
+    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);
+    void EmitFPRecip32(EmitContext& ctx);
+    void EmitFPRecip64(EmitContext& ctx);
+    void EmitFPRecipSqrt32(EmitContext& ctx);
+    void EmitFPRecipSqrt64(EmitContext& ctx);
+    void EmitFPSqrt(EmitContext& ctx);
+    void EmitFPSin(EmitContext& ctx);
+    void EmitFPSinNotReduced(EmitContext& ctx);
+    void EmitFPExp2(EmitContext& ctx);
+    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);
+    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 EmitIAdd32(EmitContext& ctx, IR::Inst* inst, Id a, Id b);
+    void EmitIAdd64(EmitContext& ctx);
+    Id EmitISub32(EmitContext& ctx, Id a, Id b);
+    void EmitISub64(EmitContext& ctx);
+    Id EmitIMul32(EmitContext& ctx, Id a, Id b);
+    void EmitINeg32(EmitContext& ctx);
+    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);
+    void EmitBitFieldInsert(EmitContext& ctx);
+    void EmitBitFieldSExtract(EmitContext& ctx);
+    Id EmitBitFieldUExtract(EmitContext& ctx, Id base, Id offset, Id count);
+    void EmitSLessThan(EmitContext& ctx);
+    void EmitULessThan(EmitContext& ctx);
+    void EmitIEqual(EmitContext& ctx);
+    void EmitSLessThanEqual(EmitContext& ctx);
+    void EmitULessThanEqual(EmitContext& ctx);
+    void EmitSGreaterThan(EmitContext& ctx);
+    void EmitUGreaterThan(EmitContext& ctx);
+    void EmitINotEqual(EmitContext& ctx);
+    void EmitSGreaterThanEqual(EmitContext& ctx);
+    Id EmitUGreaterThanEqual(EmitContext& ctx, Id lhs, Id rhs);
+    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);
 };
 
 } // 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
new file mode 100644
index 0000000000..447df5b8c4
--- /dev/null
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_bitwise_conversion.cpp
@@ -0,0 +1,57 @@
+// 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 {
+
+void EmitSPIRV::EmitBitCastU16F16(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+Id EmitSPIRV::EmitBitCastU32F32(EmitContext& ctx, Id value) {
+    return ctx.OpBitcast(ctx.u32[1], value);
+}
+
+void EmitSPIRV::EmitBitCastU64F64(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitBitCastF16U16(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+Id EmitSPIRV::EmitBitCastF32U32(EmitContext& ctx, Id value) {
+    return ctx.OpBitcast(ctx.f32[1], value);
+}
+
+void EmitSPIRV::EmitBitCastF64U64(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitPackUint2x32(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitUnpackUint2x32(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitPackFloat2x16(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitUnpackFloat2x16(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitPackDouble2x32(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitUnpackDouble2x32(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+} // 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
new file mode 100644
index 0000000000..b190cf876c
--- /dev/null
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_composite.cpp
@@ -0,0 +1,105 @@
+// 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 {
+
+void EmitSPIRV::EmitCompositeConstructU32x2(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitCompositeConstructU32x3(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitCompositeConstructU32x4(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitCompositeExtractU32x2(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+Id EmitSPIRV::EmitCompositeExtractU32x3(EmitContext& ctx, Id vector, u32 index) {
+    return ctx.OpCompositeExtract(ctx.u32[1], vector, index);
+}
+
+void EmitSPIRV::EmitCompositeExtractU32x4(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitCompositeConstructF16x2(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitCompositeConstructF16x3(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitCompositeConstructF16x4(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitCompositeExtractF16x2(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitCompositeExtractF16x3(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitCompositeExtractF16x4(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitCompositeConstructF32x2(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitCompositeConstructF32x3(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitCompositeConstructF32x4(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitCompositeExtractF32x2(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitCompositeExtractF32x3(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitCompositeExtractF32x4(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitCompositeConstructF64x2(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitCompositeConstructF64x3(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitCompositeConstructF64x4(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitCompositeExtractF64x2(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitCompositeExtractF64x3(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitCompositeExtractF64x4(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+} // namespace Shader::Backend::SPIRV
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp
new file mode 100644
index 0000000000..b121305ea9
--- /dev/null
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp
@@ -0,0 +1,102 @@
+// 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 {
+
+void EmitSPIRV::EmitGetRegister(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitSetRegister(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitGetPred(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitSetPred(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+Id EmitSPIRV::EmitGetCbuf(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
+    if (!binding.IsImmediate()) {
+        throw NotImplementedException("Constant buffer indexing");
+    }
+    if (!offset.IsImmediate()) {
+        throw NotImplementedException("Variable constant buffer offset");
+    }
+    return ctx.Name(ctx.OpUndef(ctx.u32[1]), "unimplemented_cbuf");
+}
+
+void EmitSPIRV::EmitGetAttribute(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitSetAttribute(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitGetAttributeIndexed(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitSetAttributeIndexed(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitGetZFlag(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitGetSFlag(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitGetCFlag(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitGetOFlag(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitSetZFlag(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitSetSFlag(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitSetCFlag(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitSetOFlag(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+Id EmitSPIRV::EmitWorkgroupId(EmitContext& ctx) {
+    if (ctx.workgroup_id.value == 0) {
+        ctx.workgroup_id = ctx.AddGlobalVariable(
+            ctx.TypePointer(spv::StorageClass::Input, ctx.u32[3]), spv::StorageClass::Input);
+        ctx.Decorate(ctx.workgroup_id, spv::Decoration::BuiltIn, spv::BuiltIn::WorkgroupId);
+    }
+    return ctx.OpLoad(ctx.u32[3], ctx.workgroup_id);
+}
+
+Id EmitSPIRV::EmitLocalInvocationId(EmitContext& ctx) {
+    if (ctx.local_invocation_id.value == 0) {
+        ctx.local_invocation_id = ctx.AddGlobalVariable(
+            ctx.TypePointer(spv::StorageClass::Input, ctx.u32[3]), spv::StorageClass::Input);
+        ctx.Decorate(ctx.local_invocation_id, spv::Decoration::BuiltIn,
+                     spv::BuiltIn::LocalInvocationId);
+    }
+    return ctx.OpLoad(ctx.u32[3], ctx.local_invocation_id);
+}
+
+} // namespace Shader::Backend::SPIRV
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_control_flow.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_control_flow.cpp
new file mode 100644
index 0000000000..770fe113c8
--- /dev/null
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_control_flow.cpp
@@ -0,0 +1,30 @@
+// 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 {
+
+void EmitSPIRV::EmitBranch(EmitContext& ctx, IR::Inst* inst) {
+    ctx.OpBranch(ctx.BlockLabel(inst->Arg(0).Label()));
+}
+
+void EmitSPIRV::EmitBranchConditional(EmitContext& ctx, IR::Inst* inst) {
+    ctx.OpBranchConditional(ctx.Def(inst->Arg(0)), ctx.BlockLabel(inst->Arg(1).Label()),
+                            ctx.BlockLabel(inst->Arg(2).Label()));
+}
+
+void EmitSPIRV::EmitExit(EmitContext& ctx) {
+    ctx.OpReturn();
+}
+
+void EmitSPIRV::EmitReturn(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitUnreachable(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+} // 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
new file mode 100644
index 0000000000..9c39537e23
--- /dev/null
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_floating_point.cpp
@@ -0,0 +1,220 @@
+// 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"
+#include "shader_recompiler/frontend/ir/modifiers.h"
+
+namespace Shader::Backend::SPIRV {
+namespace {
+Id Decorate(EmitContext& ctx, IR::Inst* inst, Id op) {
+    const auto flags{inst->Flags<IR::FpControl>()};
+    if (flags.no_contraction) {
+        ctx.Decorate(op, spv::Decoration::NoContraction);
+    }
+    switch (flags.rounding) {
+    case IR::FpRounding::RN:
+        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;
+    }
+    if (flags.fmz_mode != IR::FmzMode::FTZ) {
+        throw NotImplementedException("Denorm management not implemented");
+    }
+    return op;
+}
+
+} // Anonymous namespace
+
+void EmitSPIRV::EmitFPAbs16(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitFPAbs32(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitFPAbs64(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+Id EmitSPIRV::EmitFPAdd16(EmitContext& ctx, IR::Inst* inst, Id a, Id b) {
+    return Decorate(ctx, inst, ctx.OpFAdd(ctx.f16[1], a, b));
+}
+
+Id EmitSPIRV::EmitFPAdd32(EmitContext& ctx, IR::Inst* inst, Id a, Id b) {
+    return Decorate(ctx, inst, ctx.OpFAdd(ctx.f32[1], a, b));
+}
+
+Id EmitSPIRV::EmitFPAdd64(EmitContext& ctx, IR::Inst* inst, Id a, Id b) {
+    return Decorate(ctx, inst, ctx.OpFAdd(ctx.f64[1], a, b));
+}
+
+Id EmitSPIRV::EmitFPFma16(EmitContext& ctx, IR::Inst* inst, Id a, Id b, Id c) {
+    return Decorate(ctx, inst, ctx.OpFma(ctx.f16[1], a, b, c));
+}
+
+Id EmitSPIRV::EmitFPFma32(EmitContext& ctx, IR::Inst* inst, Id a, Id b, Id c) {
+    return Decorate(ctx, inst, ctx.OpFma(ctx.f32[1], a, b, c));
+}
+
+Id EmitSPIRV::EmitFPFma64(EmitContext& ctx, IR::Inst* inst, Id a, Id b, Id c) {
+    return Decorate(ctx, inst, ctx.OpFma(ctx.f64[1], a, b, c));
+}
+
+void EmitSPIRV::EmitFPMax32(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitFPMax64(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitFPMin32(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitFPMin64(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+Id EmitSPIRV::EmitFPMul16(EmitContext& ctx, IR::Inst* inst, Id a, Id b) {
+    return Decorate(ctx, inst, ctx.OpFMul(ctx.f16[1], a, b));
+}
+
+Id EmitSPIRV::EmitFPMul32(EmitContext& ctx, IR::Inst* inst, Id a, Id b) {
+    return Decorate(ctx, inst, ctx.OpFMul(ctx.f32[1], a, b));
+}
+
+Id EmitSPIRV::EmitFPMul64(EmitContext& ctx, IR::Inst* inst, Id a, Id b) {
+    return Decorate(ctx, inst, ctx.OpFMul(ctx.f64[1], a, b));
+}
+
+void EmitSPIRV::EmitFPNeg16(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitFPNeg32(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitFPNeg64(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitFPRecip32(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitFPRecip64(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitFPRecipSqrt32(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitFPRecipSqrt64(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitFPSqrt(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitFPSin(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitFPSinNotReduced(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitFPExp2(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitFPExp2NotReduced(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitFPCos(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitFPCosNotReduced(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitFPLog2(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitFPSaturate16(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitFPSaturate32(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitFPSaturate64(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitFPRoundEven16(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitFPRoundEven32(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitFPRoundEven64(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitFPFloor16(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitFPFloor32(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitFPFloor64(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitFPCeil16(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitFPCeil32(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitFPCeil64(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitFPTrunc16(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitFPTrunc32(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitFPTrunc64(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+} // 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
new file mode 100644
index 0000000000..3ef4f3d787
--- /dev/null
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp
@@ -0,0 +1,132 @@
+// 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 EmitSPIRV::EmitIAdd32(EmitContext& ctx, IR::Inst* inst, Id a, Id b) {
+    if (inst->HasAssociatedPseudoOperation()) {
+        throw NotImplementedException("Pseudo-operations on IAdd32");
+    }
+    return ctx.OpIAdd(ctx.u32[1], a, b);
+}
+
+void EmitSPIRV::EmitIAdd64(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+Id EmitSPIRV::EmitISub32(EmitContext& ctx, Id a, Id b) {
+    return ctx.OpISub(ctx.u32[1], a, b);
+}
+
+void EmitSPIRV::EmitISub64(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+Id EmitSPIRV::EmitIMul32(EmitContext& ctx, Id a, Id b) {
+    return ctx.OpIMul(ctx.u32[1], a, b);
+}
+
+void EmitSPIRV::EmitINeg32(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitIAbs32(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+Id EmitSPIRV::EmitShiftLeftLogical32(EmitContext& ctx, Id base, Id shift) {
+    return ctx.OpShiftLeftLogical(ctx.u32[1], base, shift);
+}
+
+void EmitSPIRV::EmitShiftRightLogical32(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitShiftRightArithmetic32(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitBitwiseAnd32(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitBitwiseOr32(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitBitwiseXor32(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitBitFieldInsert(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitBitFieldSExtract(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+Id EmitSPIRV::EmitBitFieldUExtract(EmitContext& ctx, Id base, Id offset, Id count) {
+    return ctx.OpBitFieldUExtract(ctx.u32[1], base, offset, count);
+}
+
+void EmitSPIRV::EmitSLessThan(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitULessThan(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitIEqual(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitSLessThanEqual(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitULessThanEqual(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitSGreaterThan(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitUGreaterThan(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitINotEqual(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitSGreaterThanEqual(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+Id EmitSPIRV::EmitUGreaterThanEqual(EmitContext& ctx, Id lhs, Id rhs) {
+    return ctx.OpUGreaterThanEqual(ctx.u1, lhs, rhs);
+}
+
+void EmitSPIRV::EmitLogicalOr(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitLogicalAnd(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitLogicalXor(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::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
new file mode 100644
index 0000000000..7b43c4ed80
--- /dev/null
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_logical.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 {
+
+void EmitSPIRV::EmitConvertS16F16(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitConvertS16F32(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitConvertS16F64(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitConvertS32F16(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitConvertS32F32(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitConvertS32F64(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitConvertS64F16(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitConvertS64F32(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitConvertS64F64(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitConvertU16F16(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitConvertU16F32(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitConvertU16F64(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitConvertU32F16(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitConvertU32F32(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitConvertU32F64(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitConvertU64F16(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitConvertU64F32(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitConvertU64F64(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitConvertU64U32(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitConvertU32U64(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+} // namespace Shader::Backend::SPIRV
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp
new file mode 100644
index 0000000000..21a0d72fa4
--- /dev/null
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp
@@ -0,0 +1,125 @@
+// 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 {
+
+void EmitSPIRV::EmitLoadGlobalU8(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitLoadGlobalS8(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitLoadGlobalU16(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitLoadGlobalS16(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitLoadGlobal32(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitLoadGlobal64(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitLoadGlobal128(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitWriteGlobalU8(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitWriteGlobalS8(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitWriteGlobalU16(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitWriteGlobalS16(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitWriteGlobal32(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitWriteGlobal64(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitWriteGlobal128(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitLoadStorageU8(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitLoadStorageS8(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitLoadStorageU16(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitLoadStorageS16(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+Id EmitSPIRV::EmitLoadStorage32(EmitContext& ctx, const IR::Value& binding,
+                                [[maybe_unused]] const IR::Value& offset) {
+    if (!binding.IsImmediate()) {
+        throw NotImplementedException("Storage buffer indexing");
+    }
+    return ctx.Name(ctx.OpUndef(ctx.u32[1]), "unimplemented_sbuf");
+}
+
+void EmitSPIRV::EmitLoadStorage64(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitLoadStorage128(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitWriteStorageU8(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitWriteStorageS8(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitWriteStorageU16(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitWriteStorageS16(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitWriteStorage32(EmitContext& ctx) {
+    ctx.Name(ctx.OpUndef(ctx.u32[1]), "unimplemented_sbuf_store");
+}
+
+void EmitSPIRV::EmitWriteStorage64(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitWriteStorage128(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+} // namespace Shader::Backend::SPIRV
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_select.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_select.cpp
new file mode 100644
index 0000000000..40a856f72a
--- /dev/null
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_select.cpp
@@ -0,0 +1,25 @@
+// 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 {
+
+void EmitSPIRV::EmitSelect8(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitSelect16(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitSelect32(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitSelect64(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+} // namespace Shader::Backend::SPIRV
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_undefined.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_undefined.cpp
new file mode 100644
index 0000000000..3850b072ce
--- /dev/null
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_undefined.cpp
@@ -0,0 +1,29 @@
+// 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 {
+
+void EmitSPIRV::EmitUndef1(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitUndef8(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitUndef16(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitUndef32(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+void EmitSPIRV::EmitUndef64(EmitContext&) {
+    throw NotImplementedException("SPIR-V Instruction");
+}
+
+} // namespace Shader::Backend::SPIRV
-- 
cgit v1.2.3-70-g09d2