summaryrefslogtreecommitdiff
path: root/src/shader_recompiler/backend/spirv
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2021-04-11 02:08:15 -0300
committerGravatar ameerj2021-07-22 21:51:27 -0400
commit2e71e4c5c02d133e3e85597b7eb52b88084a31fe (patch)
treeb647aa935a5fe42e39bbc7cd89d0ed52600eecce /src/shader_recompiler/backend/spirv
parentshader: Mark ImageWrite with side effects (diff)
downloadyuzu-2e71e4c5c02d133e3e85597b7eb52b88084a31fe.tar.gz
yuzu-2e71e4c5c02d133e3e85597b7eb52b88084a31fe.tar.xz
yuzu-2e71e4c5c02d133e3e85597b7eb52b88084a31fe.zip
spirv: Fix forward declarations on phi nodes
Diffstat (limited to 'src/shader_recompiler/backend/spirv')
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv.cpp72
1 files changed, 25 insertions, 47 deletions
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.cpp b/src/shader_recompiler/backend/spirv/emit_spirv.cpp
index ecd0fac5c..63ed92a5d 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv.cpp
@@ -30,18 +30,7 @@ struct FuncTraits<ReturnType_ (*)(Args...)> {
30 30
31template <auto func, typename... Args> 31template <auto func, typename... Args>
32void SetDefinition(EmitContext& ctx, IR::Inst* inst, Args... args) { 32void SetDefinition(EmitContext& ctx, IR::Inst* inst, Args... args) {
33 const Id forward_id{inst->Definition<Id>()}; 33 inst->SetDefinition<Id>(func(ctx, std::forward<Args>(args)...));
34 const bool has_forward_id{Sirit::ValidId(forward_id)};
35 Id current_id{};
36 if (has_forward_id) {
37 current_id = ctx.ExchangeCurrentId(forward_id);
38 }
39 const Id new_id{func(ctx, std::forward<Args>(args)...)};
40 if (has_forward_id) {
41 ctx.ExchangeCurrentId(current_id);
42 } else {
43 inst->SetDefinition<Id>(new_id);
44 }
45} 34}
46 35
47template <typename ArgType> 36template <typename ArgType>
@@ -255,31 +244,6 @@ void SetupCapabilities(const Profile& profile, const Info& info, EmitContext& ct
255 ctx.AddCapability(spv::Capability::SampledBuffer); 244 ctx.AddCapability(spv::Capability::SampledBuffer);
256 ctx.AddCapability(spv::Capability::StorageImageReadWithoutFormat); 245 ctx.AddCapability(spv::Capability::StorageImageReadWithoutFormat);
257} 246}
258
259Id PhiArgDef(EmitContext& ctx, IR::Inst* inst, size_t index) {
260 // Phi nodes can have forward declarations, if an argument is not defined provide a forward
261 // declaration of it. Invoke will take care of giving it the right definition when it's
262 // actually defined.
263 const IR::Value arg{inst->Arg(index)};
264 if (arg.IsImmediate()) {
265 // Let the context handle immediate definitions, as it already knows how
266 return ctx.Def(arg);
267 }
268 IR::Inst* const arg_inst{arg.InstRecursive()};
269 if (const Id def{arg_inst->Definition<Id>()}; Sirit::ValidId(def)) {
270 // Return the current definition if it exists
271 return def;
272 }
273 if (arg_inst == inst) {
274 // This is a self referencing phi node
275 // Self-referencing definition will be set by the caller, so just grab the current id
276 return ctx.CurrentId();
277 }
278 // If it hasn't been defined and it's not a self reference, get a forward declaration
279 const Id def{ctx.ForwardDeclarationId()};
280 arg_inst->SetDefinition<Id>(def);
281 return def;
282}
283} // Anonymous namespace 247} // Anonymous namespace
284 248
285std::vector<u32> EmitSPIRV(const Profile& profile, IR::Program& program, u32& binding) { 249std::vector<u32> EmitSPIRV(const Profile& profile, IR::Program& program, u32& binding) {
@@ -292,31 +256,45 @@ std::vector<u32> EmitSPIRV(const Profile& profile, IR::Program& program, u32& bi
292 SetupSignedNanCapabilities(profile, program, ctx, main); 256 SetupSignedNanCapabilities(profile, program, ctx, main);
293 } 257 }
294 SetupCapabilities(profile, program.info, ctx); 258 SetupCapabilities(profile, program.info, ctx);
259
260 auto inst{program.blocks.front()->begin()};
261 size_t block_index{};
262 ctx.PatchDeferredPhi([&](size_t phi_arg) {
263 if (phi_arg == 0) {
264 ++inst;
265 if (inst == program.blocks[block_index]->end() ||
266 inst->GetOpcode() != IR::Opcode::Phi) {
267 do {
268 ++block_index;
269 inst = program.blocks[block_index]->begin();
270 } while (inst->GetOpcode() != IR::Opcode::Phi);
271 }
272 }
273 return ctx.Def(inst->Arg(phi_arg));
274 });
295 return ctx.Assemble(); 275 return ctx.Assemble();
296} 276}
297 277
298Id EmitPhi(EmitContext& ctx, IR::Inst* inst) { 278Id EmitPhi(EmitContext& ctx, IR::Inst* inst) {
299 const size_t num_args{inst->NumArgs()}; 279 const size_t num_args{inst->NumArgs()};
300 boost::container::small_vector<Id, 32> operands; 280 boost::container::small_vector<Id, 32> blocks;
301 operands.reserve(num_args * 2); 281 blocks.reserve(num_args);
302 for (size_t index = 0; index < num_args; ++index) { 282 for (size_t index = 0; index < num_args; ++index) {
303 operands.push_back(PhiArgDef(ctx, inst, index)); 283 blocks.push_back(inst->PhiBlock(index)->Definition<Id>());
304 operands.push_back(inst->PhiBlock(index)->Definition<Id>());
305 } 284 }
306 // The type of a phi instruction is stored in its flags 285 // The type of a phi instruction is stored in its flags
307 const Id result_type{TypeId(ctx, inst->Flags<IR::Type>())}; 286 const Id result_type{TypeId(ctx, inst->Flags<IR::Type>())};
308 return ctx.OpPhi(result_type, std::span(operands.data(), operands.size())); 287 return ctx.DeferredOpPhi(result_type, std::span(blocks.data(), blocks.size()));
309} 288}
310 289
311void EmitVoid(EmitContext&) {} 290void EmitVoid(EmitContext&) {}
312 291
313Id EmitIdentity(EmitContext& ctx, const IR::Value& value) { 292Id EmitIdentity(EmitContext& ctx, const IR::Value& value) {
314 if (const Id id = ctx.Def(value); Sirit::ValidId(id)) { 293 const Id id{ctx.Def(value)};
315 return id; 294 if (!Sirit::ValidId(id)) {
295 throw NotImplementedException("Forward identity declaration");
316 } 296 }
317 const Id def{ctx.ForwardDeclarationId()}; 297 return id;
318 value.InstRecursive()->SetDefinition<Id>(def);
319 return def;
320} 298}
321 299
322void EmitGetZeroFromOp(EmitContext&) { 300void EmitGetZeroFromOp(EmitContext&) {