spirv: Fix forward declarations on phi nodes
This commit is contained in:
		| @@ -30,18 +30,7 @@ struct FuncTraits<ReturnType_ (*)(Args...)> { | |||||||
|  |  | ||||||
| template <auto func, typename... Args> | template <auto func, typename... Args> | ||||||
| void SetDefinition(EmitContext& ctx, IR::Inst* inst, Args... args) { | void SetDefinition(EmitContext& ctx, IR::Inst* inst, Args... args) { | ||||||
|     const Id forward_id{inst->Definition<Id>()}; |     inst->SetDefinition<Id>(func(ctx, std::forward<Args>(args)...)); | ||||||
|     const bool has_forward_id{Sirit::ValidId(forward_id)}; |  | ||||||
|     Id current_id{}; |  | ||||||
|     if (has_forward_id) { |  | ||||||
|         current_id = ctx.ExchangeCurrentId(forward_id); |  | ||||||
|     } |  | ||||||
|     const Id new_id{func(ctx, std::forward<Args>(args)...)}; |  | ||||||
|     if (has_forward_id) { |  | ||||||
|         ctx.ExchangeCurrentId(current_id); |  | ||||||
|     } else { |  | ||||||
|         inst->SetDefinition<Id>(new_id); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename ArgType> | template <typename ArgType> | ||||||
| @@ -255,31 +244,6 @@ void SetupCapabilities(const Profile& profile, const Info& info, EmitContext& ct | |||||||
|     ctx.AddCapability(spv::Capability::SampledBuffer); |     ctx.AddCapability(spv::Capability::SampledBuffer); | ||||||
|     ctx.AddCapability(spv::Capability::StorageImageReadWithoutFormat); |     ctx.AddCapability(spv::Capability::StorageImageReadWithoutFormat); | ||||||
| } | } | ||||||
|  |  | ||||||
| Id PhiArgDef(EmitContext& ctx, IR::Inst* inst, size_t index) { |  | ||||||
|     // Phi nodes can have forward declarations, if an argument is not defined provide a forward |  | ||||||
|     // declaration of it. Invoke will take care of giving it the right definition when it's |  | ||||||
|     // actually defined. |  | ||||||
|     const IR::Value arg{inst->Arg(index)}; |  | ||||||
|     if (arg.IsImmediate()) { |  | ||||||
|         // Let the context handle immediate definitions, as it already knows how |  | ||||||
|         return ctx.Def(arg); |  | ||||||
|     } |  | ||||||
|     IR::Inst* const arg_inst{arg.InstRecursive()}; |  | ||||||
|     if (const Id def{arg_inst->Definition<Id>()}; Sirit::ValidId(def)) { |  | ||||||
|         // Return the current definition if it exists |  | ||||||
|         return def; |  | ||||||
|     } |  | ||||||
|     if (arg_inst == inst) { |  | ||||||
|         // This is a self referencing phi node |  | ||||||
|         // Self-referencing definition will be set by the caller, so just grab the current id |  | ||||||
|         return ctx.CurrentId(); |  | ||||||
|     } |  | ||||||
|     // If it hasn't been defined and it's not a self reference, get a forward declaration |  | ||||||
|     const Id def{ctx.ForwardDeclarationId()}; |  | ||||||
|     arg_inst->SetDefinition<Id>(def); |  | ||||||
|     return def; |  | ||||||
| } |  | ||||||
| } // Anonymous namespace | } // Anonymous namespace | ||||||
|  |  | ||||||
| std::vector<u32> EmitSPIRV(const Profile& profile, IR::Program& program, u32& binding) { | 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 | |||||||
|         SetupSignedNanCapabilities(profile, program, ctx, main); |         SetupSignedNanCapabilities(profile, program, ctx, main); | ||||||
|     } |     } | ||||||
|     SetupCapabilities(profile, program.info, ctx); |     SetupCapabilities(profile, program.info, ctx); | ||||||
|  |  | ||||||
|  |     auto inst{program.blocks.front()->begin()}; | ||||||
|  |     size_t block_index{}; | ||||||
|  |     ctx.PatchDeferredPhi([&](size_t phi_arg) { | ||||||
|  |         if (phi_arg == 0) { | ||||||
|  |             ++inst; | ||||||
|  |             if (inst == program.blocks[block_index]->end() || | ||||||
|  |                 inst->GetOpcode() != IR::Opcode::Phi) { | ||||||
|  |                 do { | ||||||
|  |                     ++block_index; | ||||||
|  |                     inst = program.blocks[block_index]->begin(); | ||||||
|  |                 } while (inst->GetOpcode() != IR::Opcode::Phi); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return ctx.Def(inst->Arg(phi_arg)); | ||||||
|  |     }); | ||||||
|     return ctx.Assemble(); |     return ctx.Assemble(); | ||||||
| } | } | ||||||
|  |  | ||||||
| Id EmitPhi(EmitContext& ctx, IR::Inst* inst) { | Id EmitPhi(EmitContext& ctx, IR::Inst* inst) { | ||||||
|     const size_t num_args{inst->NumArgs()}; |     const size_t num_args{inst->NumArgs()}; | ||||||
|     boost::container::small_vector<Id, 32> operands; |     boost::container::small_vector<Id, 32> blocks; | ||||||
|     operands.reserve(num_args * 2); |     blocks.reserve(num_args); | ||||||
|     for (size_t index = 0; index < num_args; ++index) { |     for (size_t index = 0; index < num_args; ++index) { | ||||||
|         operands.push_back(PhiArgDef(ctx, inst, index)); |         blocks.push_back(inst->PhiBlock(index)->Definition<Id>()); | ||||||
|         operands.push_back(inst->PhiBlock(index)->Definition<Id>()); |  | ||||||
|     } |     } | ||||||
|     // The type of a phi instruction is stored in its flags |     // The type of a phi instruction is stored in its flags | ||||||
|     const Id result_type{TypeId(ctx, inst->Flags<IR::Type>())}; |     const Id result_type{TypeId(ctx, inst->Flags<IR::Type>())}; | ||||||
|     return ctx.OpPhi(result_type, std::span(operands.data(), operands.size())); |     return ctx.DeferredOpPhi(result_type, std::span(blocks.data(), blocks.size())); | ||||||
| } | } | ||||||
|  |  | ||||||
| void EmitVoid(EmitContext&) {} | void EmitVoid(EmitContext&) {} | ||||||
|  |  | ||||||
| Id EmitIdentity(EmitContext& ctx, const IR::Value& value) { | Id EmitIdentity(EmitContext& ctx, const IR::Value& value) { | ||||||
|     if (const Id id = ctx.Def(value); Sirit::ValidId(id)) { |     const Id id{ctx.Def(value)}; | ||||||
|         return id; |     if (!Sirit::ValidId(id)) { | ||||||
|  |         throw NotImplementedException("Forward identity declaration"); | ||||||
|     } |     } | ||||||
|     const Id def{ctx.ForwardDeclarationId()}; |     return id; | ||||||
|     value.InstRecursive()->SetDefinition<Id>(def); |  | ||||||
|     return def; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| void EmitGetZeroFromOp(EmitContext&) { | void EmitGetZeroFromOp(EmitContext&) { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user