diff options
Diffstat (limited to 'src/shader_recompiler/backend/spirv/emit_spirv.cpp')
| -rw-r--r-- | src/shader_recompiler/backend/spirv/emit_spirv.cpp | 61 |
1 files changed, 48 insertions, 13 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())}; |