diff options
Diffstat (limited to 'src/shader_recompiler/backend/spirv')
| -rw-r--r-- | src/shader_recompiler/backend/spirv/emit_spirv.cpp | 61 | ||||
| -rw-r--r-- | src/shader_recompiler/backend/spirv/emit_spirv.h | 40 |
2 files changed, 49 insertions, 52 deletions
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.cpp b/src/shader_recompiler/backend/spirv/emit_spirv.cpp index e29e448c7..0895414b4 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv.cpp | |||
| @@ -64,31 +64,49 @@ EmitSPIRV::EmitSPIRV(IR::Program& program) { | |||
| 64 | std::system("spirv-cross shader.spv"); | 64 | std::system("spirv-cross shader.spv"); |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | template <auto method, typename... Args> | ||
| 68 | static void SetDefinition(EmitSPIRV& emit, EmitContext& ctx, IR::Inst* inst, Args... args) { | ||
| 69 | const Id forward_id{inst->Definition<Id>()}; | ||
| 70 | const bool has_forward_id{Sirit::ValidId(forward_id)}; | ||
| 71 | Id current_id{}; | ||
| 72 | if (has_forward_id) { | ||
| 73 | current_id = ctx.ExchangeCurrentId(forward_id); | ||
| 74 | } | ||
| 75 | const Id new_id{(emit.*method)(ctx, std::forward<Args>(args)...)}; | ||
| 76 | if (has_forward_id) { | ||
| 77 | ctx.ExchangeCurrentId(current_id); | ||
| 78 | } else { | ||
| 79 | inst->SetDefinition<Id>(new_id); | ||
| 80 | } | ||
| 81 | } | ||
| 82 | |||
| 67 | template <auto method> | 83 | template <auto method> |
| 68 | static void Invoke(EmitSPIRV& emit, EmitContext& ctx, IR::Inst* inst) { | 84 | static void Invoke(EmitSPIRV& emit, EmitContext& ctx, IR::Inst* inst) { |
| 69 | using M = decltype(method); | 85 | using M = decltype(method); |
| 70 | using std::is_invocable_r_v; | 86 | using std::is_invocable_r_v; |
| 71 | if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&>) { | 87 | if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&>) { |
| 72 | ctx.Define(inst, (emit.*method)(ctx)); | 88 | SetDefinition<method>(emit, ctx, inst); |
| 73 | } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, Id>) { | 89 | } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, Id>) { |
| 74 | ctx.Define(inst, (emit.*method)(ctx, ctx.Def(inst->Arg(0)))); | 90 | SetDefinition<method>(emit, ctx, inst, ctx.Def(inst->Arg(0))); |
| 75 | } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, Id, Id>) { | 91 | } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, Id, Id>) { |
| 76 | ctx.Define(inst, (emit.*method)(ctx, ctx.Def(inst->Arg(0)), ctx.Def(inst->Arg(1)))); | 92 | SetDefinition<method>(emit, ctx, inst, ctx.Def(inst->Arg(0)), ctx.Def(inst->Arg(1))); |
| 77 | } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, Id, Id, Id>) { | 93 | } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, Id, Id, Id>) { |
| 78 | ctx.Define(inst, (emit.*method)(ctx, ctx.Def(inst->Arg(0)), ctx.Def(inst->Arg(1)), | 94 | SetDefinition<method>(emit, ctx, inst, ctx.Def(inst->Arg(0)), ctx.Def(inst->Arg(1)), |
| 79 | ctx.Def(inst->Arg(2)))); | 95 | ctx.Def(inst->Arg(2))); |
| 96 | } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, IR::Inst*>) { | ||
| 97 | SetDefinition<method>(emit, ctx, inst, inst); | ||
| 80 | } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, IR::Inst*, Id, Id>) { | 98 | } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, IR::Inst*, Id, Id>) { |
| 81 | ctx.Define(inst, (emit.*method)(ctx, inst, ctx.Def(inst->Arg(0)), ctx.Def(inst->Arg(1)))); | 99 | SetDefinition<method>(emit, ctx, inst, inst, ctx.Def(inst->Arg(0)), ctx.Def(inst->Arg(1))); |
| 82 | } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, IR::Inst*, Id, Id, Id>) { | 100 | } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, IR::Inst*, Id, Id, Id>) { |
| 83 | ctx.Define(inst, (emit.*method)(ctx, inst, ctx.Def(inst->Arg(0)), ctx.Def(inst->Arg(1)), | 101 | SetDefinition<method>(emit, ctx, inst, inst, ctx.Def(inst->Arg(0)), ctx.Def(inst->Arg(1)), |
| 84 | ctx.Def(inst->Arg(2)))); | 102 | ctx.Def(inst->Arg(2))); |
| 85 | } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, Id, u32>) { | 103 | } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, Id, u32>) { |
| 86 | ctx.Define(inst, (emit.*method)(ctx, ctx.Def(inst->Arg(0)), inst->Arg(1).U32())); | 104 | SetDefinition<method>(emit, ctx, inst, ctx.Def(inst->Arg(0)), inst->Arg(1).U32()); |
| 87 | } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, const IR::Value&>) { | 105 | } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, const IR::Value&>) { |
| 88 | ctx.Define(inst, (emit.*method)(ctx, inst->Arg(0))); | 106 | SetDefinition<method>(emit, ctx, inst, inst->Arg(0)); |
| 89 | } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, const IR::Value&, | 107 | } else if constexpr (is_invocable_r_v<Id, M, EmitSPIRV&, EmitContext&, const IR::Value&, |
| 90 | const IR::Value&>) { | 108 | const IR::Value&>) { |
| 91 | ctx.Define(inst, (emit.*method)(ctx, inst->Arg(0), inst->Arg(1))); | 109 | SetDefinition<method>(emit, ctx, inst, inst->Arg(0), inst->Arg(1)); |
| 92 | } else if constexpr (is_invocable_r_v<void, M, EmitSPIRV&, EmitContext&, IR::Inst*>) { | 110 | } else if constexpr (is_invocable_r_v<void, M, EmitSPIRV&, EmitContext&, IR::Inst*>) { |
| 93 | (emit.*method)(ctx, inst); | 111 | (emit.*method)(ctx, inst); |
| 94 | } else if constexpr (is_invocable_r_v<void, M, EmitSPIRV&, EmitContext&>) { | 112 | } else if constexpr (is_invocable_r_v<void, M, EmitSPIRV&, EmitContext&>) { |
| @@ -122,11 +140,28 @@ static Id TypeId(const EmitContext& ctx, IR::Type type) { | |||
| 122 | 140 | ||
| 123 | Id EmitSPIRV::EmitPhi(EmitContext& ctx, IR::Inst* inst) { | 141 | Id EmitSPIRV::EmitPhi(EmitContext& ctx, IR::Inst* inst) { |
| 124 | const size_t num_args{inst->NumArgs()}; | 142 | const size_t num_args{inst->NumArgs()}; |
| 125 | boost::container::small_vector<Id, 64> operands; | 143 | boost::container::small_vector<Id, 32> operands; |
| 126 | operands.reserve(num_args * 2); | 144 | operands.reserve(num_args * 2); |
| 127 | for (size_t index = 0; index < num_args; ++index) { | 145 | for (size_t index = 0; index < num_args; ++index) { |
| 146 | // Phi nodes can have forward declarations, if an argument is not defined provide a forward | ||
| 147 | // declaration of it. Invoke will take care of giving it the right definition when it's | ||
| 148 | // actually defined. | ||
| 149 | const IR::Value arg{inst->Arg(index)}; | ||
| 150 | Id def{}; | ||
| 151 | if (arg.IsImmediate()) { | ||
| 152 | // Let the context handle immediate definitions, as it already knows how | ||
| 153 | def = ctx.Def(arg); | ||
| 154 | } else { | ||
| 155 | IR::Inst* const arg_inst{arg.Inst()}; | ||
| 156 | def = arg_inst->Definition<Id>(); | ||
| 157 | if (!Sirit::ValidId(def)) { | ||
| 158 | // If it hasn't been defined, get a forward declaration | ||
| 159 | def = ctx.ForwardDeclarationId(); | ||
| 160 | arg_inst->SetDefinition<Id>(def); | ||
| 161 | } | ||
| 162 | } | ||
| 128 | IR::Block* const phi_block{inst->PhiBlock(index)}; | 163 | IR::Block* const phi_block{inst->PhiBlock(index)}; |
| 129 | operands.push_back(ctx.Def(inst->Arg(index))); | 164 | operands.push_back(def); |
| 130 | operands.push_back(ctx.BlockLabel(phi_block)); | 165 | operands.push_back(ctx.BlockLabel(phi_block)); |
| 131 | } | 166 | } |
| 132 | const Id result_type{TypeId(ctx, inst->Arg(0).Type())}; | 167 | const Id result_type{TypeId(ctx, inst->Arg(0).Type())}; |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.h b/src/shader_recompiler/backend/spirv/emit_spirv.h index 6b09757d1..7d76377b5 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv.h +++ b/src/shader_recompiler/backend/spirv/emit_spirv.h | |||
| @@ -6,8 +6,6 @@ | |||
| 6 | 6 | ||
| 7 | #include <sirit/sirit.h> | 7 | #include <sirit/sirit.h> |
| 8 | 8 | ||
| 9 | #include <boost/container/flat_map.hpp> | ||
| 10 | |||
| 11 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 12 | #include "shader_recompiler/frontend/ir/microinstruction.h" | 10 | #include "shader_recompiler/frontend/ir/microinstruction.h" |
| 13 | #include "shader_recompiler/frontend/ir/program.h" | 11 | #include "shader_recompiler/frontend/ir/program.h" |
| @@ -16,37 +14,6 @@ namespace Shader::Backend::SPIRV { | |||
| 16 | 14 | ||
| 17 | using Sirit::Id; | 15 | using Sirit::Id; |
| 18 | 16 | ||
| 19 | class DefMap { | ||
| 20 | public: | ||
| 21 | void Define(IR::Inst* inst, Id def_id) { | ||
| 22 | const InstInfo info{.use_count{inst->UseCount()}, .def_id{def_id}}; | ||
| 23 | const auto it{map.insert(map.end(), std::make_pair(inst, info))}; | ||
| 24 | if (it == map.end()) { | ||
| 25 | throw LogicError("Defining already defined instruction"); | ||
| 26 | } | ||
| 27 | } | ||
| 28 | |||
| 29 | [[nodiscard]] Id Consume(IR::Inst* inst) { | ||
| 30 | const auto it{map.find(inst)}; | ||
| 31 | if (it == map.end()) { | ||
| 32 | throw LogicError("Consuming undefined instruction"); | ||
| 33 | } | ||
| 34 | const Id def_id{it->second.def_id}; | ||
| 35 | if (--it->second.use_count == 0) { | ||
| 36 | map.erase(it); | ||
| 37 | } | ||
| 38 | return def_id; | ||
| 39 | } | ||
| 40 | |||
| 41 | private: | ||
| 42 | struct InstInfo { | ||
| 43 | int use_count; | ||
| 44 | Id def_id; | ||
| 45 | }; | ||
| 46 | |||
| 47 | boost::container::flat_map<IR::Inst*, InstInfo> map; | ||
| 48 | }; | ||
| 49 | |||
| 50 | class VectorTypes { | 17 | class VectorTypes { |
| 51 | public: | 18 | public: |
| 52 | void Define(Sirit::Module& sirit_ctx, Id base_type, std::string_view name) { | 19 | void Define(Sirit::Module& sirit_ctx, Id base_type, std::string_view name) { |
| @@ -76,7 +43,7 @@ public: | |||
| 76 | 43 | ||
| 77 | [[nodiscard]] Id Def(const IR::Value& value) { | 44 | [[nodiscard]] Id Def(const IR::Value& value) { |
| 78 | if (!value.IsImmediate()) { | 45 | if (!value.IsImmediate()) { |
| 79 | return def_map.Consume(value.Inst()); | 46 | return value.Inst()->Definition<Id>(); |
| 80 | } | 47 | } |
| 81 | switch (value.Type()) { | 48 | switch (value.Type()) { |
| 82 | case IR::Type::U1: | 49 | case IR::Type::U1: |
| @@ -90,10 +57,6 @@ public: | |||
| 90 | } | 57 | } |
| 91 | } | 58 | } |
| 92 | 59 | ||
| 93 | void Define(IR::Inst* inst, Id def_id) { | ||
| 94 | def_map.Define(inst, def_id); | ||
| 95 | } | ||
| 96 | |||
| 97 | [[nodiscard]] Id BlockLabel(IR::Block* block) const { | 60 | [[nodiscard]] Id BlockLabel(IR::Block* block) const { |
| 98 | const auto it{std::ranges::lower_bound(block_label_map, block, {}, | 61 | const auto it{std::ranges::lower_bound(block_label_map, block, {}, |
| 99 | &std::pair<IR::Block*, Id>::first)}; | 62 | &std::pair<IR::Block*, Id>::first)}; |
| @@ -117,7 +80,6 @@ public: | |||
| 117 | Id local_invocation_id{}; | 80 | Id local_invocation_id{}; |
| 118 | 81 | ||
| 119 | private: | 82 | private: |
| 120 | DefMap def_map; | ||
| 121 | std::vector<std::pair<IR::Block*, Id>> block_label_map; | 83 | std::vector<std::pair<IR::Block*, Id>> block_label_map; |
| 122 | }; | 84 | }; |
| 123 | 85 | ||