diff options
| author | 2021-04-11 02:08:15 -0300 | |
|---|---|---|
| committer | 2021-07-22 21:51:27 -0400 | |
| commit | 2e71e4c5c02d133e3e85597b7eb52b88084a31fe (patch) | |
| tree | b647aa935a5fe42e39bbc7cd89d0ed52600eecce /src/shader_recompiler/backend/spirv | |
| parent | shader: Mark ImageWrite with side effects (diff) | |
| download | yuzu-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.cpp | 72 |
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 | ||
| 31 | template <auto func, typename... Args> | 31 | template <auto func, typename... Args> |
| 32 | void SetDefinition(EmitContext& ctx, IR::Inst* inst, Args... args) { | 32 | void 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 | ||
| 47 | template <typename ArgType> | 36 | template <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 | |||
| 259 | Id 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 | ||
| 285 | std::vector<u32> EmitSPIRV(const Profile& profile, IR::Program& program, u32& binding) { | 249 | std::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 | ||
| 298 | Id EmitPhi(EmitContext& ctx, IR::Inst* inst) { | 278 | Id 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 | ||
| 311 | void EmitVoid(EmitContext&) {} | 290 | void EmitVoid(EmitContext&) {} |
| 312 | 291 | ||
| 313 | Id EmitIdentity(EmitContext& ctx, const IR::Value& value) { | 292 | Id 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 | ||
| 322 | void EmitGetZeroFromOp(EmitContext&) { | 300 | void EmitGetZeroFromOp(EmitContext&) { |