summaryrefslogtreecommitdiff
path: root/src/shader_recompiler/backend/spirv/emit_spirv.cpp
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2021-02-08 02:54:35 -0300
committerGravatar ameerj2021-07-22 21:51:22 -0400
commit2930dccecc933d6748772e9f51a5724fe1e6771b (patch)
treeec4aa48062f8a2fcba31b1c64f769ddf25a87832 /src/shader_recompiler/backend/spirv/emit_spirv.cpp
parentshader: Better constant folding (diff)
downloadyuzu-2930dccecc933d6748772e9f51a5724fe1e6771b.tar.gz
yuzu-2930dccecc933d6748772e9f51a5724fe1e6771b.tar.xz
yuzu-2930dccecc933d6748772e9f51a5724fe1e6771b.zip
spirv: Initial SPIR-V support
Diffstat (limited to 'src/shader_recompiler/backend/spirv/emit_spirv.cpp')
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv.cpp134
1 files changed, 134 insertions, 0 deletions
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 000000000..7c4269fad
--- /dev/null
+++ b/src/shader_recompiler/backend/spirv/emit_spirv.cpp
@@ -0,0 +1,134 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <numeric>
6#include <type_traits>
7
8#include "shader_recompiler/backend/spirv/emit_spirv.h"
9#include "shader_recompiler/frontend/ir/basic_block.h"
10#include "shader_recompiler/frontend/ir/function.h"
11#include "shader_recompiler/frontend/ir/microinstruction.h"
12#include "shader_recompiler/frontend/ir/program.h"
13
14namespace Shader::Backend::SPIRV {
15
16EmitContext::EmitContext(IR::Program& program) {
17 AddCapability(spv::Capability::Shader);
18 AddCapability(spv::Capability::Float16);
19 AddCapability(spv::Capability::Float64);
20 void_id = TypeVoid();
21
22 u1 = Name(TypeBool(), "u1");
23 f32.Define(*this, TypeFloat(32), "f32");
24 u32.Define(*this, TypeInt(32, false), "u32");
25 f16.Define(*this, TypeFloat(16), "f16");
26 f64.Define(*this, TypeFloat(64), "f64");
27
28 for (const IR::Function& function : program.functions) {
29 for (IR::Block* const block : function.blocks) {
30 block_label_map.emplace_back(block, OpLabel());
31 }
32 }
33 std::ranges::sort(block_label_map, {}, &std::pair<IR::Block*, Id>::first);
34}
35
36EmitContext::~EmitContext() = default;
37
38EmitSPIRV::EmitSPIRV(IR::Program& program) {
39 EmitContext ctx{program};
40 const Id void_function{ctx.TypeFunction(ctx.void_id)};
41 // FIXME: Forward declare functions (needs sirit support)
42 Id func{};
43 for (IR::Function& function : program.functions) {
44 func = ctx.OpFunction(ctx.void_id, spv::FunctionControlMask::MaskNone, void_function);
45 for (IR::Block* const block : function.blocks) {
46 ctx.AddLabel(ctx.BlockLabel(block));
47 for (IR::Inst& inst : block->Instructions()) {
48 EmitInst(ctx, &inst);
49 }
50 }
51 ctx.OpFunctionEnd();
52 }
53 ctx.AddEntryPoint(spv::ExecutionModel::GLCompute, func, "main");
54
55 std::vector<u32> result{ctx.Assemble()};
56 std::FILE* file{std::fopen("shader.spv", "wb")};
57 std::fwrite(result.data(), sizeof(u32), result.size(), file);
58 std::fclose(file);
59 std::system("spirv-dis shader.spv");
60 std::system("spirv-val shader.spv");
61}
62
63template <auto method>
64static void Invoke(EmitSPIRV& emit, EmitContext& ctx, IR::Inst* inst) {
65 using M = decltype(method);
66 using std::is_invocable_r_v;
67 if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&>) {
68 ctx.Define(inst, (emit.*method)(ctx));
69 } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, Id>) {
70 ctx.Define(inst, (emit.*method)(ctx, ctx.Def(inst->Arg(0))));
71 } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, Id, Id>) {
72 ctx.Define(inst, (emit.*method)(ctx, ctx.Def(inst->Arg(0)), ctx.Def(inst->Arg(1))));
73 } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, Id, Id, Id>) {
74 ctx.Define(inst, (emit.*method)(ctx, ctx.Def(inst->Arg(0)), ctx.Def(inst->Arg(1)),
75 ctx.Def(inst->Arg(2))));
76 } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, IR::Inst*, Id, Id>) {
77 ctx.Define(inst, (emit.*method)(ctx, inst, ctx.Def(inst->Arg(0)), ctx.Def(inst->Arg(1))));
78 } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, IR::Inst*, Id, Id, Id>) {
79 ctx.Define(inst, (emit.*method)(ctx, inst, ctx.Def(inst->Arg(0)), ctx.Def(inst->Arg(1)),
80 ctx.Def(inst->Arg(2))));
81 } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, Id, u32>) {
82 ctx.Define(inst, (emit.*method)(ctx, ctx.Def(inst->Arg(0)), inst->Arg(1).U32()));
83 } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, const IR::Value&>) {
84 ctx.Define(inst, (emit.*method)(ctx, inst->Arg(0)));
85 } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, const IR::Value&,
86 const IR::Value&>) {
87 ctx.Define(inst, (emit.*method)(ctx, inst->Arg(0), inst->Arg(1)));
88 } else if constexpr (is_invocable_r_v<void, M, EmitSPIRV&, EmitContext&, IR::Inst*>) {
89 (emit.*method)(ctx, inst);
90 } else if constexpr (is_invocable_r_v<void, M, EmitSPIRV&, EmitContext&>) {
91 (emit.*method)(ctx);
92 } else {
93 static_assert(false, "Bad format");
94 }
95}
96
97void EmitSPIRV::EmitInst(EmitContext& ctx, IR::Inst* inst) {
98 switch (inst->Opcode()) {
99#define OPCODE(name, result_type, ...) \
100 case IR::Opcode::name: \
101 return Invoke<&EmitSPIRV::Emit##name>(*this, ctx, inst);
102#include "shader_recompiler/frontend/ir/opcodes.inc"
103#undef OPCODE
104 }
105 throw LogicError("Invalid opcode {}", inst->Opcode());
106}
107
108void EmitSPIRV::EmitPhi(EmitContext&) {
109 throw NotImplementedException("SPIR-V Instruction");
110}
111
112void EmitSPIRV::EmitVoid(EmitContext&) {}
113
114void EmitSPIRV::EmitIdentity(EmitContext&) {
115 throw NotImplementedException("SPIR-V Instruction");
116}
117
118void EmitSPIRV::EmitGetZeroFromOp(EmitContext&) {
119 throw LogicError("Unreachable instruction");
120}
121
122void EmitSPIRV::EmitGetSignFromOp(EmitContext&) {
123 throw LogicError("Unreachable instruction");
124}
125
126void EmitSPIRV::EmitGetCarryFromOp(EmitContext&) {
127 throw LogicError("Unreachable instruction");
128}
129
130void EmitSPIRV::EmitGetOverflowFromOp(EmitContext&) {
131 throw LogicError("Unreachable instruction");
132}
133
134} // namespace Shader::Backend::SPIRV