[ir][spirv-writer] Emit shader IO without structs Some implementations cannot handle built-ins inside structures, so emit every IO variable as a separate module-scope variable instead. Adds an IOAttributes field to the core Var instruction, as the GLSL backend will also need this. Bug: tint:1906 Change-Id: Ic2508ceaa16ada377ebcc154c6fcb1b91c09350e Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/151583 Kokoro: Kokoro <noreply+kokoro@google.com> Reviewed-by: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/lang/core/ir/disassembler.cc b/src/tint/lang/core/ir/disassembler.cc index 5a9d29c..66ce989 100644 --- a/src/tint/lang/core/ir/disassembler.cc +++ b/src/tint/lang/core/ir/disassembler.cc
@@ -480,6 +480,23 @@ out_ << " "; EmitBindingPoint(v->BindingPoint().value()); } + if (v->Attributes().invariant) { + out_ << " @invariant"; + } + if (v->Attributes().location.has_value()) { + out_ << " @location(" << v->Attributes().location.value() << ")"; + } + if (v->Attributes().interpolation.has_value()) { + auto& interp = v->Attributes().interpolation.value(); + out_ << " @interpolate(" << interp.type; + if (interp.sampling != core::InterpolationSampling::kUndefined) { + out_ << ", " << interp.sampling; + } + out_ << ")"; + } + if (v->Attributes().builtin.has_value()) { + out_ << " @builtin(" << v->Attributes().builtin.value() << ")"; + } }, [&](Swizzle* s) { EmitValueWithType(s);
diff --git a/src/tint/lang/core/ir/var.cc b/src/tint/lang/core/ir/var.cc index 1042786..501d6af 100644 --- a/src/tint/lang/core/ir/var.cc +++ b/src/tint/lang/core/ir/var.cc
@@ -15,6 +15,7 @@ #include "src/tint/lang/core/ir/var.h" #include "src/tint/lang/core/ir/store.h" +#include "src/tint/lang/core/type/pointer.h" #include "src/tint/utils/ice/ice.h" TINT_INSTANTIATE_TYPEINFO(tint::core::ir::Var);
diff --git a/src/tint/lang/core/ir/var.h b/src/tint/lang/core/ir/var.h index c10adf3..384f7b1 100644 --- a/src/tint/lang/core/ir/var.h +++ b/src/tint/lang/core/ir/var.h
@@ -18,15 +18,27 @@ #include <string> #include "src/tint/api/common/binding_point.h" -#include "src/tint/lang/core/access.h" -#include "src/tint/lang/core/address_space.h" +#include "src/tint/lang/core/builtin_value.h" +#include "src/tint/lang/core/interpolation.h" #include "src/tint/lang/core/ir/operand_instruction.h" -#include "src/tint/lang/core/type/pointer.h" -#include "src/tint/utils/containers/vector.h" #include "src/tint/utils/rtti/castable.h" namespace tint::core::ir { +/// Attributes that can be applied to a variable that will be used for shader IO. +struct IOAttributes { + /// The value of a `@location` attribute. + std::optional<uint32_t> location; + /// The value of a `@index` attribute. + std::optional<uint32_t> index; + /// The value of a `@builtin` attribute. + std::optional<core::BuiltinValue> builtin; + /// The values of a `@interpolate` attribute. + std::optional<core::Interpolation> interpolation; + /// True if the variable is annotated with `@invariant`. + bool invariant = false; +}; + /// A var instruction in the IR. class Var : public Castable<Var, OperandInstruction<1, 1>> { public: @@ -51,6 +63,12 @@ /// @returns the binding points if `Attributes` contains `kBindingPoint` std::optional<struct BindingPoint> BindingPoint() { return binding_point_; } + /// Sets the IO attributes + /// @param attrs the attributes + void SetAttributes(const IOAttributes& attrs) { attributes_ = attrs; } + /// @returns the IO attributes + const IOAttributes& Attributes() { return attributes_; } + /// Destroys this instruction along with any assignment instructions, if the var is never read. void DestroyIfOnlyAssigned(); @@ -59,6 +77,7 @@ private: std::optional<struct BindingPoint> binding_point_; + IOAttributes attributes_; }; } // namespace tint::core::ir
diff --git a/src/tint/lang/spirv/writer/discard_test.cc b/src/tint/lang/spirv/writer/discard_test.cc index 5fe3f7c..cf190b9 100644 --- a/src/tint/lang/spirv/writer/discard_test.cc +++ b/src/tint/lang/spirv/writer/discard_test.cc
@@ -43,30 +43,30 @@ ASSERT_TRUE(Generate()) << Error() << output_; EXPECT_INST(R"( - %ep_inner = OpFunction %float None %18 + %ep_inner = OpFunction %float None %16 %front_facing = OpFunctionParameter %bool + %17 = OpLabel + OpSelectionMerge %18 None + OpBranchConditional %front_facing %19 %18 %19 = OpLabel - OpSelectionMerge %20 None - OpBranchConditional %front_facing %21 %20 - %21 = OpLabel OpStore %continue_execution %false - OpBranch %20 - %20 = OpLabel - %23 = OpAccessChain %_ptr_StorageBuffer_int %1 %uint_0 - %27 = OpLoad %bool %continue_execution - OpSelectionMerge %28 None - OpBranchConditional %27 %29 %28 - %29 = OpLabel - OpStore %23 %int_42 - OpBranch %28 - %28 = OpLabel - %31 = OpLoad %bool %continue_execution - %32 = OpLogicalEqual %bool %31 %false - OpSelectionMerge %33 None - OpBranchConditional %32 %34 %33 - %34 = OpLabel + OpBranch %18 + %18 = OpLabel + %21 = OpAccessChain %_ptr_StorageBuffer_int %1 %uint_0 + %25 = OpLoad %bool %continue_execution + OpSelectionMerge %26 None + OpBranchConditional %25 %27 %26 + %27 = OpLabel + OpStore %21 %int_42 + OpBranch %26 + %26 = OpLabel + %29 = OpLoad %bool %continue_execution + %30 = OpLogicalEqual %bool %29 %false + OpSelectionMerge %31 None + OpBranchConditional %30 %32 %31 + %32 = OpLabel OpKill - %33 = OpLabel + %31 = OpLabel OpReturnValue %float_0_5 OpFunctionEnd )");
diff --git a/src/tint/lang/spirv/writer/printer/printer.cc b/src/tint/lang/spirv/writer/printer/printer.cc index b098a86..856d5d3 100644 --- a/src/tint/lang/spirv/writer/printer/printer.cc +++ b/src/tint/lang/spirv/writer/printer/printer.cc
@@ -324,8 +324,7 @@ }); } -uint32_t Printer::Type(const core::type::Type* ty, - core::AddressSpace addrspace /* = kUndefined */) { +uint32_t Printer::Type(const core::type::Type* ty) { ty = DedupType(ty, ir_->Types()); return types_.GetOrCreate(ty, [&] { auto id = module_.NextId(); @@ -369,11 +368,11 @@ {id, U32Operand(SpvDecorationArrayStride), arr->Stride()}); }, [&](const core::type::Pointer* ptr) { - module_.PushType(spv::Op::OpTypePointer, - {id, U32Operand(StorageClass(ptr->AddressSpace())), - Type(ptr->StoreType(), ptr->AddressSpace())}); + module_.PushType( + spv::Op::OpTypePointer, + {id, U32Operand(StorageClass(ptr->AddressSpace())), Type(ptr->StoreType())}); }, - [&](const core::type::Struct* str) { EmitStructType(id, str, addrspace); }, + [&](const core::type::Struct* str) { EmitStructType(id, str); }, [&](const core::type::Texture* tex) { EmitTextureType(id, tex); }, [&](const core::type::Sampler*) { module_.PushType(spv::Op::OpTypeSampler, {id}); }, [&](const raise::SampledImage* s) { @@ -401,9 +400,7 @@ return block_labels_.GetOrCreate(block, [&] { return module_.NextId(); }); } -void Printer::EmitStructType(uint32_t id, - const core::type::Struct* str, - core::AddressSpace addrspace /* = kUndefined */) { +void Printer::EmitStructType(uint32_t id, const core::type::Struct* str) { // Helper to return `type` or a potentially nested array element type within `type` as a matrix // type, or nullptr if no such matrix type is present. auto get_nested_matrix_type = [&](const core::type::Type* type) { @@ -422,56 +419,6 @@ spv::Op::OpMemberDecorate, {operands[0], member->Index(), U32Operand(SpvDecorationOffset), member->Offset()}); - // Generate shader IO decorations. - const auto& attrs = member->Attributes(); - if (attrs.location) { - module_.PushAnnot( - spv::Op::OpMemberDecorate, - {operands[0], member->Index(), U32Operand(SpvDecorationLocation), *attrs.location}); - if (attrs.interpolation) { - switch (attrs.interpolation->type) { - case core::InterpolationType::kLinear: - module_.PushAnnot( - spv::Op::OpMemberDecorate, - {operands[0], member->Index(), U32Operand(SpvDecorationNoPerspective)}); - break; - case core::InterpolationType::kFlat: - module_.PushAnnot( - spv::Op::OpMemberDecorate, - {operands[0], member->Index(), U32Operand(SpvDecorationFlat)}); - break; - case core::InterpolationType::kPerspective: - case core::InterpolationType::kUndefined: - break; - } - switch (attrs.interpolation->sampling) { - case core::InterpolationSampling::kCentroid: - module_.PushAnnot( - spv::Op::OpMemberDecorate, - {operands[0], member->Index(), U32Operand(SpvDecorationCentroid)}); - break; - case core::InterpolationSampling::kSample: - module_.PushCapability(SpvCapabilitySampleRateShading); - module_.PushAnnot( - spv::Op::OpMemberDecorate, - {operands[0], member->Index(), U32Operand(SpvDecorationSample)}); - break; - case core::InterpolationSampling::kCenter: - case core::InterpolationSampling::kUndefined: - break; - } - } - } - if (attrs.builtin) { - module_.PushAnnot(spv::Op::OpMemberDecorate, - {operands[0], member->Index(), U32Operand(SpvDecorationBuiltIn), - Builtin(*attrs.builtin, addrspace)}); - } - if (attrs.invariant) { - module_.PushAnnot(spv::Op::OpMemberDecorate, - {operands[0], member->Index(), U32Operand(SpvDecorationInvariant)}); - } - // Emit matrix layout decorations if necessary. if (auto* matrix_type = get_nested_matrix_type(member->Type())) { const uint32_t effective_row_count = (matrix_type->rows() == 2) ? 2 : 4; @@ -691,13 +638,9 @@ operands.push_back(Value(var)); // Add the `DepthReplacing` execution mode if `frag_depth` is used. - if (auto* str = ptr->StoreType()->As<core::type::Struct>()) { - for (auto* member : str->Members()) { - if (member->Attributes().builtin == core::BuiltinValue::kFragDepth) { - module_.PushExecutionMode(spv::Op::OpExecutionMode, - {id, U32Operand(SpvExecutionModeDepthReplacing)}); - } - } + if (var->Attributes().builtin == core::BuiltinValue::kFragDepth) { + module_.PushExecutionMode(spv::Op::OpExecutionMode, + {id, U32Operand(SpvExecutionModeDepthReplacing)}); } } } @@ -1835,6 +1778,48 @@ current_function_.push_inst(spv::Op::OpFunctionCall, operands); } +void Printer::EmitIOAttributes(uint32_t id, + const core::ir::IOAttributes& attrs, + core::AddressSpace addrspace) { + if (attrs.location) { + module_.PushAnnot(spv::Op::OpDecorate, + {id, U32Operand(SpvDecorationLocation), *attrs.location}); + } + if (attrs.interpolation) { + switch (attrs.interpolation->type) { + case core::InterpolationType::kLinear: + module_.PushAnnot(spv::Op::OpDecorate, + {id, U32Operand(SpvDecorationNoPerspective)}); + break; + case core::InterpolationType::kFlat: + module_.PushAnnot(spv::Op::OpDecorate, {id, U32Operand(SpvDecorationFlat)}); + break; + case core::InterpolationType::kPerspective: + case core::InterpolationType::kUndefined: + break; + } + switch (attrs.interpolation->sampling) { + case core::InterpolationSampling::kCentroid: + module_.PushAnnot(spv::Op::OpDecorate, {id, U32Operand(SpvDecorationCentroid)}); + break; + case core::InterpolationSampling::kSample: + module_.PushCapability(SpvCapabilitySampleRateShading); + module_.PushAnnot(spv::Op::OpDecorate, {id, U32Operand(SpvDecorationSample)}); + break; + case core::InterpolationSampling::kCenter: + case core::InterpolationSampling::kUndefined: + break; + } + } + if (attrs.builtin) { + module_.PushAnnot(spv::Op::OpDecorate, {id, U32Operand(SpvDecorationBuiltIn), + Builtin(*attrs.builtin, addrspace)}); + } + if (attrs.invariant) { + module_.PushAnnot(spv::Op::OpDecorate, {id, U32Operand(SpvDecorationInvariant)}); + } +} + void Printer::EmitVar(core::ir::Var* var) { auto id = Value(var); auto* ptr = var->Result()->Type()->As<core::type::Pointer>(); @@ -1855,6 +1840,7 @@ case core::AddressSpace::kIn: { TINT_ASSERT(!current_function_); module_.PushType(spv::Op::OpVariable, {ty, id, U32Operand(SpvStorageClassInput)}); + EmitIOAttributes(id, var->Attributes(), core::AddressSpace::kIn); break; } case core::AddressSpace::kPrivate: { @@ -1878,6 +1864,7 @@ case core::AddressSpace::kOut: { TINT_ASSERT(!current_function_); module_.PushType(spv::Op::OpVariable, {ty, id, U32Operand(SpvStorageClassOutput)}); + EmitIOAttributes(id, var->Attributes(), core::AddressSpace::kOut); break; } case core::AddressSpace::kHandle:
diff --git a/src/tint/lang/spirv/writer/printer/printer.h b/src/tint/lang/spirv/writer/printer/printer.h index 2f0d53a..4071ab0 100644 --- a/src/tint/lang/spirv/writer/printer/printer.h +++ b/src/tint/lang/spirv/writer/printer/printer.h
@@ -98,10 +98,8 @@ /// Get the result ID of the type `ty`, emitting a type declaration instruction if necessary. /// @param ty the type to get the ID for - /// @param addrspace the optional address space that this type is being used for /// @returns the result ID of the type - uint32_t Type(const core::type::Type* ty, - core::AddressSpace addrspace = core::AddressSpace::kUndefined); + uint32_t Type(const core::type::Type* ty); private: /// Convert a builtin to the corresponding SPIR-V enum value, taking into account the target @@ -148,11 +146,8 @@ /// Emit a struct type. /// @param id the result ID to use - /// @param addrspace the optional address space that this type is being used for /// @param str the struct type to emit - void EmitStructType(uint32_t id, - const core::type::Struct* str, - core::AddressSpace addrspace = core::AddressSpace::kUndefined); + void EmitStructType(uint32_t id, const core::type::Struct* str); /// Emit a texture type. /// @param id the result ID to use @@ -220,6 +215,14 @@ /// @param call the intrinsic call instruction to emit void EmitIntrinsicCall(spirv::ir::IntrinsicCall* call); + /// Emit IO attributes. + /// @param id the ID of the variable to decorate + /// @param attrs the shader IO attrs + /// @param addrspace the address of the variable + void EmitIOAttributes(uint32_t id, + const core::ir::IOAttributes& attrs, + core::AddressSpace addrspace); + /// Emit a load instruction. /// @param load the load instruction to emit void EmitLoad(core::ir::Load* load);
diff --git a/src/tint/lang/spirv/writer/raise/shader_io.cc b/src/tint/lang/spirv/writer/raise/shader_io.cc index 2716b67..b6cab42 100644 --- a/src/tint/lang/spirv/writer/raise/shader_io.cc +++ b/src/tint/lang/spirv/writer/raise/shader_io.cc
@@ -22,7 +22,6 @@ #include "src/tint/lang/core/ir/transform/shader_io.h" #include "src/tint/lang/core/ir/validator.h" #include "src/tint/lang/core/type/array.h" -#include "src/tint/lang/core/type/struct.h" using namespace tint::core::fluent_types; // NOLINT using namespace tint::core::number_suffixes; // NOLINT @@ -32,23 +31,14 @@ namespace { /// PIMPL state for the parts of the shader IO transform specific to SPIR-V. -/// For SPIR-V, we split builtins and locations into two separate structures each for input and -/// output, and declare global variables for them. The wrapper entry point then loads from and -/// stores to these variables. -/// We also modify the type of the SampleMask builtin to be an array, as required by Vulkan. +/// For SPIR-V, we declare a global variable for each input and output. The wrapper entry point then +/// loads from and stores to these variables. We also modify the type of the SampleMask builtin to +/// be an array, as required by Vulkan. struct StateImpl : core::ir::transform::ShaderIOBackendState { - /// The global variable for input builtins. - core::ir::Var* builtin_input_var = nullptr; - /// The global variable for input locations. - core::ir::Var* location_input_var = nullptr; - /// The global variable for output builtins. - core::ir::Var* builtin_output_var = nullptr; - /// The global variable for output locations. - core::ir::Var* location_output_var = nullptr; - /// The member indices for inputs. - Vector<uint32_t, 4> input_indices; - /// The member indices for outputs. - Vector<uint32_t, 4> output_indices; + /// The input variables. + Vector<core::ir::Var*, 4> input_vars; + /// The output variables. + Vector<core::ir::Var*, 4> output_vars; /// The configuration options. const ShaderIOConfig& config; @@ -63,69 +53,63 @@ /// Destructor ~StateImpl() override {} - /// Split the members listed in @p entries into two separate structures for builtins and - /// locations, and make global variables for them. Record the new member indices in @p indices. - /// @param builtin_var the generated global variable for builtins - /// @param location_var the generated global variable for locations - /// @param indices the new member indices - /// @param entries the entries to split + /// Declare a global variable for each IO entry listed in @p entries. + /// @param vars the list of variables + /// @param entries the entries to emit /// @param addrspace the address to use for the global variables /// @param access the access mode to use for the global variables /// @param name_suffix the suffix to add to struct and variable names - void MakeStructs(core::ir::Var*& builtin_var, - core::ir::Var*& location_var, - Vector<uint32_t, 4>* indices, - Vector<core::type::Manager::StructMemberDesc, 4>& entries, - core::AddressSpace addrspace, - core::Access access, - const char* name_suffix) { - // Build separate lists of builtin and location entries and record their new indices. - uint32_t next_builtin_idx = 0; - uint32_t next_location_idx = 0; - Vector<core::type::Manager::StructMemberDesc, 4> builtin_members; - Vector<core::type::Manager::StructMemberDesc, 4> location_members; + void MakeVars(Vector<core::ir::Var*, 4>& vars, + Vector<core::type::Manager::StructMemberDesc, 4>& entries, + core::AddressSpace addrspace, + core::Access access, + const char* name_suffix) { for (auto io : entries) { + StringStream name; + name << ir->NameOf(func).Name(); + if (io.attributes.builtin) { // SampleMask must be an array for Vulkan. if (io.attributes.builtin.value() == core::BuiltinValue::kSampleMask) { io.type = ty.array<u32, 1>(); } - builtin_members.Push(io); - indices->Push(next_builtin_idx++); - } else { - location_members.Push(io); - indices->Push(next_location_idx++); - } - } + name << "_" << io.attributes.builtin.value(); - // Declare the structs and variables if needed. - auto make_struct = [&](auto& members, const char* iotype) { - auto name = ir->NameOf(func).Name() + iotype + name_suffix; - auto* str = ty.Struct(ir->symbols.New(name + "Struct"), std::move(members)); - auto* var = b.Var(name, ty.ptr(addrspace, str, access)); - str->SetStructFlag(core::type::kBlock); + // Vulkan requires that fragment integer builtin inputs be Flat decorated. + if (func->Stage() == core::ir::Function::PipelineStage::kFragment && + addrspace == core::AddressSpace::kIn && + io.type->is_integer_scalar_or_vector()) { + io.attributes.interpolation = {core::InterpolationType::kFlat}; + } + } else { + name << "_loc" << io.attributes.location.value(); + } + name << name_suffix; + + // Create an IO variable and add it to the root block. + auto* ptr = ty.ptr(addrspace, io.type, access); + auto* var = b.Var(name.str(), ptr); + var->SetAttributes(core::ir::IOAttributes{ + io.attributes.location, + io.attributes.index, + io.attributes.builtin, + io.attributes.interpolation, + io.attributes.invariant, + }); b.RootBlock()->Append(var); - return var; - }; - if (!builtin_members.IsEmpty()) { - builtin_var = make_struct(builtin_members, "_Builtin"); - } - if (!location_members.IsEmpty()) { - location_var = make_struct(location_members, "_Location"); + vars.Push(var); } } /// @copydoc ShaderIO::BackendState::FinalizeInputs Vector<core::ir::FunctionParam*, 4> FinalizeInputs() override { - MakeStructs(builtin_input_var, location_input_var, &input_indices, inputs, - core::AddressSpace::kIn, core::Access::kRead, "Inputs"); + MakeVars(input_vars, inputs, core::AddressSpace::kIn, core::Access::kRead, "_Input"); return tint::Empty; } /// @copydoc ShaderIO::BackendState::FinalizeOutputs core::ir::Value* FinalizeOutputs() override { - MakeStructs(builtin_output_var, location_output_var, &output_indices, outputs, - core::AddressSpace::kOut, core::Access::kWrite, "Outputs"); + MakeVars(output_vars, outputs, core::AddressSpace::kOut, core::Access::kWrite, "_Output"); return nullptr; } @@ -133,16 +117,12 @@ core::ir::Value* GetInput(core::ir::Builder& builder, uint32_t idx) override { // Load the input from the global variable declared earlier. auto* ptr = ty.ptr(core::AddressSpace::kIn, inputs[idx].type, core::Access::kRead); - core::ir::Access* from = nullptr; + auto* from = input_vars[idx]->Result(); if (inputs[idx].attributes.builtin) { if (inputs[idx].attributes.builtin.value() == core::BuiltinValue::kSampleMask) { // SampleMask becomes an array for SPIR-V, so load from the first element. - from = builder.Access(ptr, builtin_input_var, u32(input_indices[idx]), 0_u); - } else { - from = builder.Access(ptr, builtin_input_var, u32(input_indices[idx])); + from = builder.Access(ptr, input_vars[idx], 0_u)->Result(); } - } else { - from = builder.Access(ptr, location_input_var, u32(input_indices[idx])); } return builder.Load(from)->Result(); } @@ -151,21 +131,17 @@ void SetOutput(core::ir::Builder& builder, uint32_t idx, core::ir::Value* value) override { // Store the output to the global variable declared earlier. auto* ptr = ty.ptr(core::AddressSpace::kOut, outputs[idx].type, core::Access::kWrite); - core::ir::Access* to = nullptr; + auto* to = output_vars[idx]->Result(); if (outputs[idx].attributes.builtin) { if (outputs[idx].attributes.builtin.value() == core::BuiltinValue::kSampleMask) { // SampleMask becomes an array for SPIR-V, so store to the first element. - to = builder.Access(ptr, builtin_output_var, u32(output_indices[idx]), 0_u); - } else { - to = builder.Access(ptr, builtin_output_var, u32(output_indices[idx])); + to = builder.Access(ptr, to, 0_u)->Result(); } // Clamp frag_depth values if necessary. if (outputs[idx].attributes.builtin.value() == core::BuiltinValue::kFragDepth) { value = ClampFragDepth(builder, value); } - } else { - to = builder.Access(ptr, location_output_var, u32(output_indices[idx])); } builder.Store(to, value); }
diff --git a/src/tint/lang/spirv/writer/raise/shader_io.h b/src/tint/lang/spirv/writer/raise/shader_io.h index 5924c12..29d9e73 100644 --- a/src/tint/lang/spirv/writer/raise/shader_io.h +++ b/src/tint/lang/spirv/writer/raise/shader_io.h
@@ -32,8 +32,8 @@ bool clamp_frag_depth = false; }; -/// ShaderIO is a transform that modifies each entry point function's parameters and return -/// value to prepare them for SPIR-V codegen. +/// ShaderIO is a transform that moves each entry point function's parameters and return value to +/// global variables to prepare them for SPIR-V codegen. /// @param module the module to transform /// @param config the configuration /// @returns an error string on failure
diff --git a/src/tint/lang/spirv/writer/raise/shader_io_test.cc b/src/tint/lang/spirv/writer/raise/shader_io_test.cc index 0638d50..8814aee 100644 --- a/src/tint/lang/spirv/writer/raise/shader_io_test.cc +++ b/src/tint/lang/spirv/writer/raise/shader_io_test.cc
@@ -94,27 +94,19 @@ EXPECT_EQ(src, str()); auto* expect = R"( -foo_BuiltinInputsStruct = struct @align(16), @block { - front_facing:bool @offset(0), @builtin(front_facing) - position:vec4<f32> @offset(16), @invariant, @builtin(position) -} - -foo_LocationInputsStruct = struct @align(4), @block { - color1:f32 @offset(0), @location(0) - color2:f32 @offset(4), @location(1), @interpolate(linear, sample) -} - %b1 = block { # root - %foo_BuiltinInputs:ptr<__in, foo_BuiltinInputsStruct, read> = var - %foo_LocationInputs:ptr<__in, foo_LocationInputsStruct, read> = var + %foo_front_facing_Input:ptr<__in, bool, read> = var @builtin(front_facing) + %foo_position_Input:ptr<__in, vec4<f32>, read> = var @invariant @builtin(position) + %foo_loc0_Input:ptr<__in, f32, read> = var @location(0) + %foo_loc1_Input:ptr<__in, f32, read> = var @location(1) @interpolate(linear, sample) } %foo_inner = func(%front_facing:bool, %position:vec4<f32>, %color1:f32, %color2:f32):void -> %b2 { %b2 = block { if %front_facing [t: %b3] { # if_1 %b3 = block { # true - %8:f32 = add %color1, %color2 - %9:vec4<f32> = mul %position, %8 + %10:f32 = add %color1, %color2 + %11:vec4<f32> = mul %position, %10 exit_if # if_1 } } @@ -123,15 +115,11 @@ } %foo = @fragment func():void -> %b4 { %b4 = block { - %11:ptr<__in, bool, read> = access %foo_BuiltinInputs, 0u - %12:bool = load %11 - %13:ptr<__in, vec4<f32>, read> = access %foo_BuiltinInputs, 1u - %14:vec4<f32> = load %13 - %15:ptr<__in, f32, read> = access %foo_LocationInputs, 0u - %16:f32 = load %15 - %17:ptr<__in, f32, read> = access %foo_LocationInputs, 1u - %18:f32 = load %17 - %19:void = call %foo_inner, %12, %14, %16, %18 + %13:bool = load %foo_front_facing_Input + %14:vec4<f32> = load %foo_position_Input + %15:f32 = load %foo_loc0_Input + %16:f32 = load %foo_loc1_Input + %17:void = call %foo_inner, %13, %14, %15, %16 ret } } @@ -226,31 +214,23 @@ color2:f32 @offset(36) } -foo_BuiltinInputsStruct = struct @align(16), @block { - Inputs_front_facing:bool @offset(0), @builtin(front_facing) - Inputs_position:vec4<f32> @offset(16), @invariant, @builtin(position) -} - -foo_LocationInputsStruct = struct @align(4), @block { - Inputs_color1:f32 @offset(0), @location(0) - Inputs_color2:f32 @offset(4), @location(1), @interpolate(linear, sample) -} - %b1 = block { # root - %foo_BuiltinInputs:ptr<__in, foo_BuiltinInputsStruct, read> = var - %foo_LocationInputs:ptr<__in, foo_LocationInputsStruct, read> = var + %foo_front_facing_Input:ptr<__in, bool, read> = var @builtin(front_facing) + %foo_position_Input:ptr<__in, vec4<f32>, read> = var @invariant @builtin(position) + %foo_loc0_Input:ptr<__in, f32, read> = var @location(0) + %foo_loc1_Input:ptr<__in, f32, read> = var @location(1) @interpolate(linear, sample) } %foo_inner = func(%inputs:Inputs):void -> %b2 { %b2 = block { - %5:bool = access %inputs, 0i - if %5 [t: %b3] { # if_1 + %7:bool = access %inputs, 0i + if %7 [t: %b3] { # if_1 %b3 = block { # true - %6:vec4<f32> = access %inputs, 1i - %7:f32 = access %inputs, 2i - %8:f32 = access %inputs, 3i - %9:f32 = add %7, %8 - %10:vec4<f32> = mul %6, %9 + %8:vec4<f32> = access %inputs, 1i + %9:f32 = access %inputs, 2i + %10:f32 = access %inputs, 3i + %11:f32 = add %9, %10 + %12:vec4<f32> = mul %8, %11 exit_if # if_1 } } @@ -259,16 +239,12 @@ } %foo = @fragment func():void -> %b4 { %b4 = block { - %12:ptr<__in, bool, read> = access %foo_BuiltinInputs, 0u - %13:bool = load %12 - %14:ptr<__in, vec4<f32>, read> = access %foo_BuiltinInputs, 1u - %15:vec4<f32> = load %14 - %16:ptr<__in, f32, read> = access %foo_LocationInputs, 0u - %17:f32 = load %16 - %18:ptr<__in, f32, read> = access %foo_LocationInputs, 1u - %19:f32 = load %18 - %20:Inputs = construct %13, %15, %17, %19 - %21:void = call %foo_inner, %20 + %14:bool = load %foo_front_facing_Input + %15:vec4<f32> = load %foo_position_Input + %16:f32 = load %foo_loc0_Input + %17:f32 = load %foo_loc1_Input + %18:Inputs = construct %14, %15, %16, %17 + %19:void = call %foo_inner, %18 ret } } @@ -347,29 +323,21 @@ color1:f32 @offset(16) } -foo_BuiltinInputsStruct = struct @align(16), @block { - front_facing:bool @offset(0), @builtin(front_facing) - Inputs_position:vec4<f32> @offset(16), @invariant, @builtin(position) -} - -foo_LocationInputsStruct = struct @align(4), @block { - Inputs_color1:f32 @offset(0), @location(0) - color2:f32 @offset(4), @location(1), @interpolate(linear, sample) -} - %b1 = block { # root - %foo_BuiltinInputs:ptr<__in, foo_BuiltinInputsStruct, read> = var - %foo_LocationInputs:ptr<__in, foo_LocationInputsStruct, read> = var + %foo_front_facing_Input:ptr<__in, bool, read> = var @builtin(front_facing) + %foo_position_Input:ptr<__in, vec4<f32>, read> = var @invariant @builtin(position) + %foo_loc0_Input:ptr<__in, f32, read> = var @location(0) + %foo_loc1_Input:ptr<__in, f32, read> = var @location(1) @interpolate(linear, sample) } %foo_inner = func(%front_facing:bool, %inputs:Inputs, %color2:f32):void -> %b2 { %b2 = block { if %front_facing [t: %b3] { # if_1 %b3 = block { # true - %7:vec4<f32> = access %inputs, 0i - %8:f32 = access %inputs, 1i - %9:f32 = add %8, %color2 - %10:vec4<f32> = mul %7, %9 + %9:vec4<f32> = access %inputs, 0i + %10:f32 = access %inputs, 1i + %11:f32 = add %10, %color2 + %12:vec4<f32> = mul %9, %11 exit_if # if_1 } } @@ -378,16 +346,12 @@ } %foo = @fragment func():void -> %b4 { %b4 = block { - %12:ptr<__in, bool, read> = access %foo_BuiltinInputs, 0u - %13:bool = load %12 - %14:ptr<__in, vec4<f32>, read> = access %foo_BuiltinInputs, 1u - %15:vec4<f32> = load %14 - %16:ptr<__in, f32, read> = access %foo_LocationInputs, 0u - %17:f32 = load %16 - %18:Inputs = construct %15, %17 - %19:ptr<__in, f32, read> = access %foo_LocationInputs, 1u - %20:f32 = load %19 - %21:void = call %foo_inner, %13, %18, %20 + %14:bool = load %foo_front_facing_Input + %15:vec4<f32> = load %foo_position_Input + %16:f32 = load %foo_loc0_Input + %17:Inputs = construct %15, %16 + %18:f32 = load %foo_loc1_Input + %19:void = call %foo_inner, %14, %17, %18 ret } } @@ -421,12 +385,8 @@ EXPECT_EQ(src, str()); auto* expect = R"( -foo_BuiltinOutputsStruct = struct @align(16), @block { - tint_symbol:vec4<f32> @offset(0), @invariant, @builtin(position) -} - %b1 = block { # root - %foo_BuiltinOutputs:ptr<__out, foo_BuiltinOutputsStruct, write> = var + %foo_position_Output:ptr<__out, vec4<f32>, write> = var @invariant @builtin(position) } %foo_inner = func():vec4<f32> -> %b2 { @@ -438,8 +398,7 @@ %foo = @vertex func():void -> %b3 { %b3 = block { %5:vec4<f32> = call %foo_inner - %6:ptr<__out, vec4<f32>, write> = access %foo_BuiltinOutputs, 0u - store %6, %5 + store %foo_position_Output, %5 ret } } @@ -472,12 +431,8 @@ EXPECT_EQ(src, str()); auto* expect = R"( -foo_LocationOutputsStruct = struct @align(16), @block { - tint_symbol:vec4<f32> @offset(0), @location(1) -} - %b1 = block { # root - %foo_LocationOutputs:ptr<__out, foo_LocationOutputsStruct, write> = var + %foo_loc1_Output:ptr<__out, vec4<f32>, write> = var @location(1) } %foo_inner = func():vec4<f32> -> %b2 { @@ -489,8 +444,7 @@ %foo = @fragment func():void -> %b3 { %b3 = block { %5:vec4<f32> = call %foo_inner - %6:ptr<__out, vec4<f32>, write> = access %foo_LocationOutputs, 0u - store %6, %5 + store %foo_loc1_Output, %5 ret } } @@ -559,39 +513,28 @@ color2:f32 @offset(20) } -foo_BuiltinOutputsStruct = struct @align(16), @block { - Outputs_position:vec4<f32> @offset(0), @invariant, @builtin(position) -} - -foo_LocationOutputsStruct = struct @align(4), @block { - Outputs_color1:f32 @offset(0), @location(0) - Outputs_color2:f32 @offset(4), @location(1), @interpolate(linear, sample) -} - %b1 = block { # root - %foo_BuiltinOutputs:ptr<__out, foo_BuiltinOutputsStruct, write> = var - %foo_LocationOutputs:ptr<__out, foo_LocationOutputsStruct, write> = var + %foo_position_Output:ptr<__out, vec4<f32>, write> = var @invariant @builtin(position) + %foo_loc0_Output:ptr<__out, f32, write> = var @location(0) + %foo_loc1_Output:ptr<__out, f32, write> = var @location(1) @interpolate(linear, sample) } %foo_inner = func():Outputs -> %b2 { %b2 = block { - %4:vec4<f32> = construct 0.0f - %5:Outputs = construct %4, 0.25f, 0.75f - ret %5 + %5:vec4<f32> = construct 0.0f + %6:Outputs = construct %5, 0.25f, 0.75f + ret %6 } } %foo = @vertex func():void -> %b3 { %b3 = block { - %7:Outputs = call %foo_inner - %8:vec4<f32> = access %7, 0u - %9:ptr<__out, vec4<f32>, write> = access %foo_BuiltinOutputs, 0u - store %9, %8 - %10:f32 = access %7, 1u - %11:ptr<__out, f32, write> = access %foo_LocationOutputs, 0u - store %11, %10 - %12:f32 = access %7, 2u - %13:ptr<__out, f32, write> = access %foo_LocationOutputs, 1u - store %13, %12 + %8:Outputs = call %foo_inner + %9:vec4<f32> = access %8, 0u + store %foo_position_Output, %9 + %10:f32 = access %8, 1u + store %foo_loc0_Output, %10 + %11:f32 = access %8, 2u + store %foo_loc1_Output, %11 ret } } @@ -638,6 +581,7 @@ auto* inputs = b.FunctionParam("inputs", str_ty); ep->SetStage(core::ir::Function::PipelineStage::kFragment); ep->SetParams({inputs}); + ep->SetReturnLocation(0u, {}); b.Append(ep->Block(), [&] { // auto* position = b.Access(vec4f, inputs, 0_u); @@ -660,7 +604,7 @@ ret %4 } } -%frag = @fragment func(%inputs:Interface):vec4<f32> -> %b2 { +%frag = @fragment func(%inputs:Interface):vec4<f32> [@location(0)] -> %b2 { %b2 = block { %7:vec4<f32> = access %inputs, 0u %8:vec4<f32> = access %inputs, 1u @@ -677,32 +621,12 @@ color:vec4<f32> @offset(16) } -vert_BuiltinOutputsStruct = struct @align(16), @block { - Interface_position:vec4<f32> @offset(0), @builtin(position) -} - -vert_LocationOutputsStruct = struct @align(16), @block { - Interface_color:vec4<f32> @offset(0), @location(0) -} - -frag_BuiltinInputsStruct = struct @align(16), @block { - Interface_position:vec4<f32> @offset(0), @builtin(position) -} - -frag_LocationInputsStruct = struct @align(16), @block { - Interface_color:vec4<f32> @offset(0), @location(0) -} - -frag_LocationOutputsStruct = struct @align(16), @block { - tint_symbol:vec4<f32> @offset(0) -} - %b1 = block { # root - %vert_BuiltinOutputs:ptr<__out, vert_BuiltinOutputsStruct, write> = var - %vert_LocationOutputs:ptr<__out, vert_LocationOutputsStruct, write> = var - %frag_BuiltinInputs:ptr<__in, frag_BuiltinInputsStruct, read> = var - %frag_LocationInputs:ptr<__in, frag_LocationInputsStruct, read> = var - %frag_LocationOutputs:ptr<__out, frag_LocationOutputsStruct, write> = var + %vert_position_Output:ptr<__out, vec4<f32>, write> = var @builtin(position) + %vert_loc0_Output:ptr<__out, vec4<f32>, write> = var @location(0) + %frag_position_Input:ptr<__in, vec4<f32>, read> = var @builtin(position) + %frag_loc0_Input:ptr<__in, vec4<f32>, read> = var @location(0) + %frag_loc0_Output:ptr<__out, vec4<f32>, write> = var @location(0) } %vert_inner = func():Interface -> %b2 { @@ -725,24 +649,19 @@ %b4 = block { %16:Interface = call %vert_inner %17:vec4<f32> = access %16, 0u - %18:ptr<__out, vec4<f32>, write> = access %vert_BuiltinOutputs, 0u - store %18, %17 - %19:vec4<f32> = access %16, 1u - %20:ptr<__out, vec4<f32>, write> = access %vert_LocationOutputs, 0u - store %20, %19 + store %vert_position_Output, %17 + %18:vec4<f32> = access %16, 1u + store %vert_loc0_Output, %18 ret } } %frag = @fragment func():void -> %b5 { %b5 = block { - %22:ptr<__in, vec4<f32>, read> = access %frag_BuiltinInputs, 0u - %23:vec4<f32> = load %22 - %24:ptr<__in, vec4<f32>, read> = access %frag_LocationInputs, 0u - %25:vec4<f32> = load %24 - %26:Interface = construct %23, %25 - %27:vec4<f32> = call %frag_inner, %26 - %28:ptr<__out, vec4<f32>, write> = access %frag_LocationOutputs, 0u - store %28, %27 + %20:vec4<f32> = load %frag_position_Input + %21:vec4<f32> = load %frag_loc0_Input + %22:Interface = construct %20, %21 + %23:vec4<f32> = call %frag_inner, %22 + store %frag_loc0_Output, %23 ret } } @@ -805,18 +724,10 @@ color:vec4<f32> @offset(16) } -vert_BuiltinOutputsStruct = struct @align(16), @block { - Outputs_position:vec4<f32> @offset(0), @builtin(position) -} - -vert_LocationOutputsStruct = struct @align(16), @block { - Outputs_color:vec4<f32> @offset(0), @location(0) -} - %b1 = block { # root %1:ptr<storage, Outputs, read> = var - %vert_BuiltinOutputs:ptr<__out, vert_BuiltinOutputsStruct, write> = var - %vert_LocationOutputs:ptr<__out, vert_LocationOutputsStruct, write> = var + %vert_position_Output:ptr<__out, vec4<f32>, write> = var @builtin(position) + %vert_loc0_Output:ptr<__out, vec4<f32>, write> = var @location(0) } %vert_inner = func():Outputs -> %b2 { @@ -829,11 +740,9 @@ %b3 = block { %7:Outputs = call %vert_inner %8:vec4<f32> = access %7, 0u - %9:ptr<__out, vec4<f32>, write> = access %vert_BuiltinOutputs, 0u - store %9, %8 - %10:vec4<f32> = access %7, 1u - %11:ptr<__out, vec4<f32>, write> = access %vert_LocationOutputs, 0u - store %11, %10 + store %vert_position_Output, %8 + %9:vec4<f32> = access %7, 1u + store %vert_loc0_Output, %9 ret } } @@ -894,22 +803,10 @@ mask:u32 @offset(4) } -foo_BuiltinInputsStruct = struct @align(4), @block { - mask_in:array<u32, 1> @offset(0), @builtin(sample_mask) -} - -foo_BuiltinOutputsStruct = struct @align(4), @block { - Outputs_mask:array<u32, 1> @offset(0), @builtin(sample_mask) -} - -foo_LocationOutputsStruct = struct @align(4), @block { - Outputs_color:f32 @offset(0), @location(0) -} - %b1 = block { # root - %foo_BuiltinInputs:ptr<__in, foo_BuiltinInputsStruct, read> = var - %foo_BuiltinOutputs:ptr<__out, foo_BuiltinOutputsStruct, write> = var - %foo_LocationOutputs:ptr<__out, foo_LocationOutputsStruct, write> = var + %foo_sample_mask_Input:ptr<__in, array<u32, 1>, read> = var @builtin(sample_mask) + %foo_loc0_Output:ptr<__out, f32, write> = var @location(0) + %foo_sample_mask_Output:ptr<__out, array<u32, 1>, write> = var @builtin(sample_mask) } %foo_inner = func(%mask_in:u32):Outputs -> %b2 { @@ -920,15 +817,14 @@ } %foo = @fragment func():void -> %b3 { %b3 = block { - %8:ptr<__in, u32, read> = access %foo_BuiltinInputs, 0u, 0u + %8:ptr<__in, u32, read> = access %foo_sample_mask_Input, 0u %9:u32 = load %8 %10:Outputs = call %foo_inner, %9 %11:f32 = access %10, 0u - %12:ptr<__out, f32, write> = access %foo_LocationOutputs, 0u - store %12, %11 - %13:u32 = access %10, 1u - %14:ptr<__out, u32, write> = access %foo_BuiltinOutputs, 0u, 0u - store %14, %13 + store %foo_loc0_Output, %11 + %12:u32 = access %10, 1u + %13:ptr<__out, u32, write> = access %foo_sample_mask_Output, 0u + store %13, %12 ret } } @@ -984,22 +880,14 @@ depth:f32 @offset(4) } -foo_BuiltinOutputsStruct = struct @align(4), @block { - Outputs_depth:f32 @offset(0), @builtin(frag_depth) -} - -foo_LocationOutputsStruct = struct @align(4), @block { - Outputs_color:f32 @offset(0), @location(0) -} - FragDepthClampArgs = struct @align(4), @block { min:f32 @offset(0) max:f32 @offset(4) } %b1 = block { # root - %foo_BuiltinOutputs:ptr<__out, foo_BuiltinOutputsStruct, write> = var - %foo_LocationOutputs:ptr<__out, foo_LocationOutputsStruct, write> = var + %foo_loc0_Output:ptr<__out, f32, write> = var @location(0) + %foo_frag_depth_Output:ptr<__out, f32, write> = var @builtin(frag_depth) %tint_frag_depth_clamp_args:ptr<push_constant, FragDepthClampArgs, read_write> = var } @@ -1013,15 +901,13 @@ %b3 = block { %7:Outputs = call %foo_inner %8:f32 = access %7, 0u - %9:ptr<__out, f32, write> = access %foo_LocationOutputs, 0u - store %9, %8 - %10:f32 = access %7, 1u - %11:ptr<__out, f32, write> = access %foo_BuiltinOutputs, 0u - %12:FragDepthClampArgs = load %tint_frag_depth_clamp_args - %13:f32 = access %12, 0u - %14:f32 = access %12, 1u - %15:f32 = clamp %10, %13, %14 - store %11, %15 + store %foo_loc0_Output, %8 + %9:f32 = access %7, 1u + %10:FragDepthClampArgs = load %tint_frag_depth_clamp_args + %11:f32 = access %10, 0u + %12:f32 = access %10, 1u + %13:f32 = clamp %9, %11, %12 + store %foo_frag_depth_Output, %13 ret } }
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.cc b/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.cc index 0d61b8a..7ef8cf8 100644 --- a/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.cc +++ b/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.cc
@@ -25,6 +25,7 @@ #include "src/tint/lang/core/ir/validator.h" #include "src/tint/lang/core/ir/var.h" #include "src/tint/lang/core/type/matrix.h" +#include "src/tint/lang/core/type/pointer.h" #include "src/tint/lang/core/type/scalar.h" #include "src/tint/lang/core/type/struct.h" #include "src/tint/lang/core/type/vector.h"