[tint][msl] Implement chromium_experimental_framebuffer_fetch

Change the order of MSL writer's transforms so that it comes before the
CanonicalizeEntryPointIO transform.

Have the PixelLocal transform emit @color attributes instead of the
PixelLocal::Attachment internal attribute. Have this transform replace
the chromium_experimental_pixel_local enable with
chromium_experimental_framebuffer_fetch.

Bug: tint:2085
Change-Id: I7102a176fec9a60e20a7a2aafe6c7003a7a943af
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/159603
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: James Price <jrprice@google.com>
diff --git a/src/tint/cmd/tint/main.cc b/src/tint/cmd/tint/main.cc
index cc3aba1..19a9c85 100644
--- a/src/tint/cmd/tint/main.cc
+++ b/src/tint/cmd/tint/main.cc
@@ -734,7 +734,8 @@
         if (enable->HasExtension(tint::wgsl::Extension::kChromiumExperimentalSubgroups)) {
             msl_version = std::max(msl_version, tint::msl::validate::MslVersion::kMsl_2_1);
         }
-        if (enable->HasExtension(tint::wgsl::Extension::kChromiumExperimentalPixelLocal)) {
+        if (enable->HasExtension(tint::wgsl::Extension::kChromiumExperimentalPixelLocal) ||
+            enable->HasExtension(tint::wgsl::Extension::kChromiumExperimentalFramebufferFetch)) {
             msl_version = std::max(msl_version, tint::msl::validate::MslVersion::kMsl_2_3);
         }
     }
diff --git a/src/tint/lang/msl/writer/ast_printer/ast_printer.cc b/src/tint/lang/msl/writer/ast_printer/ast_printer.cc
index 230cb58..3b09a66 100644
--- a/src/tint/lang/msl/writer/ast_printer/ast_printer.cc
+++ b/src/tint/lang/msl/writer/ast_printer/ast_printer.cc
@@ -208,6 +208,15 @@
         manager.Add<ast::transform::ZeroInitWorkgroupMemory>();
     }
 
+    {
+        PixelLocal::Config cfg;
+        for (auto it : options.pixel_local_options.attachments) {
+            cfg.attachments.Add(it.first, it.second);
+        }
+        data.Add<PixelLocal::Config>(cfg);
+        manager.Add<PixelLocal>();
+    }
+
     // CanonicalizeEntryPointIO must come after Robustness
     manager.Add<ast::transform::CanonicalizeEntryPointIO>();
     data.Add<ast::transform::CanonicalizeEntryPointIO::Config>(std::move(entry_point_io_cfg));
@@ -225,15 +234,6 @@
     // SubgroupBallot() must come after CanonicalizeEntryPointIO.
     manager.Add<SubgroupBallot>();
 
-    {
-        PixelLocal::Config cfg;
-        for (auto it : options.pixel_local_options.attachments) {
-            cfg.attachments.Add(it.first, it.second);
-        }
-        data.Add<PixelLocal::Config>(cfg);
-        manager.Add<PixelLocal>();
-    }
-
     // ArrayLengthFromUniform must come after SimplifyPointers, as
     // it assumes that the form of the array length argument is &var.array.
     manager.Add<ast::transform::ArrayLengthFromUniform>();
@@ -275,6 +275,7 @@
                 wgsl::Extension::kChromiumExperimentalPixelLocal,
                 wgsl::Extension::kChromiumExperimentalReadWriteStorageTexture,
                 wgsl::Extension::kChromiumExperimentalSubgroups,
+                wgsl::Extension::kChromiumExperimentalFramebufferFetch,
                 wgsl::Extension::kChromiumInternalDualSourceBlending,
                 wgsl::Extension::kChromiumInternalRelaxedUniformLayout,
                 wgsl::Extension::kF16,
@@ -2005,20 +2006,8 @@
 
             bool ok = Switch(
                 type,  //
-                [&](const core::type::Struct* str) {
-                    bool is_pixel_local = false;
-                    if (auto* sem_str = str->As<sem::Struct>()) {
-                        for (auto* member : sem_str->Members()) {
-                            if (ast::HasAttribute<PixelLocal::Attachment>(
-                                    member->Declaration()->attributes)) {
-                                is_pixel_local = true;
-                                break;
-                            }
-                        }
-                    }
-                    if (!is_pixel_local) {
-                        out << " [[stage_in]]";
-                    }
+                [&](const core::type::Struct*) {
+                    out << " [[stage_in]]";
                     return true;
                 },
                 [&](const core::type::Texture*) {
@@ -2856,13 +2845,6 @@
             out << " " << invariant_define_name_;
         }
 
-        if (auto* sem_mem = mem->As<sem::StructMember>()) {
-            if (auto* attachment =
-                    ast::GetAttribute<PixelLocal::Attachment>(sem_mem->Declaration()->attributes)) {
-                out << " [[color(" << attachment->index << ")]]";
-            }
-        }
-
         out << ";";
 
         if (is_host_shareable) {
diff --git a/src/tint/lang/msl/writer/ast_raise/pixel_local.cc b/src/tint/lang/msl/writer/ast_raise/pixel_local.cc
index 55d110b..1d6fb0a 100644
--- a/src/tint/lang/msl/writer/ast_raise/pixel_local.cc
+++ b/src/tint/lang/msl/writer/ast_raise/pixel_local.cc
@@ -39,7 +39,6 @@
 #include "src/tint/utils/containers/transform.h"
 
 TINT_INSTANTIATE_TYPEINFO(tint::msl::writer::PixelLocal);
-TINT_INSTANTIATE_TYPEINFO(tint::msl::writer::PixelLocal::Attachment);
 TINT_INSTANTIATE_TYPEINFO(tint::msl::writer::PixelLocal::Config);
 
 using namespace tint::core::number_suffixes;  // NOLINT
@@ -110,10 +109,10 @@
                     // Obtain struct of the pixel local.
                     auto* pixel_local_str = global->Type()->UnwrapRef()->As<sem::Struct>();
 
-                    // Add an attachment decoration to each member of the pixel_local structure.
+                    // Add an Color attribute to each member of the pixel_local structure.
                     for (auto* member : pixel_local_str->Members()) {
                         ctx.InsertBack(member->Declaration()->attributes,
-                                       Attachment(AttachmentIndex(member->Index())));
+                                       b.Color(u32(AttachmentIndex(member->Index()))));
                         ctx.InsertBack(member->Declaration()->attributes,
                                        b.Disable(ast::DisabledValidation::kEntryPointParameter));
                     }
@@ -130,6 +129,19 @@
             return SkipTransform;
         }
 
+        // At this point, the `var<pixel_local>` will have been replaced with `var<private>`, and
+        // the entry point will use `@color`, which requires the framebuffer fetch extension.
+        // Replace the `chromium_experimental_pixel_local` enable with
+        // `chromium_experimental_framebuffer_fetch`.
+        for (auto* enable : src.AST().Enables()) {
+            for (auto* ext : enable->extensions) {
+                if (ext->name == wgsl::Extension::kChromiumExperimentalPixelLocal) {
+                    ctx.Replace(ext, b.create<ast::Extension>(
+                                         wgsl::Extension::kChromiumExperimentalFramebufferFetch));
+                }
+            }
+        }
+
         ctx.Clone();
         return resolver::Resolve(b);
     }
@@ -240,12 +252,6 @@
                Vector{b.Stage(ast::PipelineStage::kFragment)});
     }
 
-    /// @returns a new Attachment attribute
-    /// @param index the index of the attachment
-    PixelLocal::Attachment* Attachment(uint32_t index) {
-        return b.ASTNodes().Create<PixelLocal::Attachment>(b.ID(), b.AllocateNodeID(), index);
-    }
-
     /// @returns the attachment index for the pixel local field with the given index
     /// @param field_index the pixel local field index
     uint32_t AttachmentIndex(uint32_t field_index) {
@@ -284,17 +290,4 @@
 
 PixelLocal::Config::~Config() = default;
 
-PixelLocal::Attachment::Attachment(GenerationID pid, ast::NodeID nid, uint32_t idx)
-    : Base(pid, nid, Empty), index(idx) {}
-
-PixelLocal::Attachment::~Attachment() = default;
-
-std::string PixelLocal::Attachment::InternalName() const {
-    return "attachment(" + std::to_string(index) + ")";
-}
-
-const PixelLocal::Attachment* PixelLocal::Attachment::Clone(ast::CloneContext& ctx) const {
-    return ctx.dst->ASTNodes().Create<Attachment>(ctx.dst->ID(), ctx.dst->AllocateNodeID(), index);
-}
-
 }  // namespace tint::msl::writer
diff --git a/src/tint/lang/msl/writer/ast_raise/pixel_local.h b/src/tint/lang/msl/writer/ast_raise/pixel_local.h
index 4808a33..4459e59 100644
--- a/src/tint/lang/msl/writer/ast_raise/pixel_local.h
+++ b/src/tint/lang/msl/writer/ast_raise/pixel_local.h
@@ -39,6 +39,9 @@
 /// PixelLocal transforms module-scope `var<pixel_local>`s and fragment entry point functions that
 /// use them:
 /// * `var<pixel_local>` will be transformed to `var<private>`.
+/// * All of the members of the pixel local struct will have an additional `@color` attribute added.
+/// * The chromium_experimental_pixel_local extension enable will be replaced with an enable for
+///   chromium_experimental_framebuffer_fetch.
 /// * The entry point function will be wrapped with another function ('outer') that calls the
 ///  'inner' function.
 /// * The outer function will have an additional parameter of the pixel local struct type, which is
@@ -63,32 +66,6 @@
         Hashmap<uint32_t, uint32_t, 8> attachments;
     };
 
-    /// Intrinsic is an InternalAttribute that's used to decorate a pixel local attachment
-    /// parameter, return value or structure member.
-    class Attachment final : public Castable<Attachment, ast::InternalAttribute> {
-      public:
-        /// Constructor
-        /// @param pid the identifier of the program that owns this node
-        /// @param nid the unique node identifier
-        /// @param idx the attachment index
-        Attachment(GenerationID pid, ast::NodeID nid, uint32_t idx);
-
-        /// Destructor
-        ~Attachment() override;
-
-        /// @return a short description of the internal attribute which will be
-        /// displayed as `@internal(<name>)`
-        std::string InternalName() const override;
-
-        /// Performs a deep clone of this object using the program::CloneContext `ctx`.
-        /// @param ctx the clone context
-        /// @return the newly cloned object
-        const Attachment* Clone(ast::CloneContext& ctx) const override;
-
-        /// The attachment index
-        const uint32_t index;
-    };
-
     /// Constructor
     PixelLocal();
 
diff --git a/src/tint/lang/msl/writer/ast_raise/pixel_local_test.cc b/src/tint/lang/msl/writer/ast_raise/pixel_local_test.cc
index 1d2c51b..fba0af3 100644
--- a/src/tint/lang/msl/writer/ast_raise/pixel_local_test.cc
+++ b/src/tint/lang/msl/writer/ast_raise/pixel_local_test.cc
@@ -70,7 +70,7 @@
 
     auto* expect =
         R"(
-enable chromium_experimental_pixel_local;
+enable chromium_experimental_framebuffer_fetch;
 
 struct PixelLocal {
   a : i32,
@@ -102,7 +102,7 @@
 
     auto* expect =
         R"(
-enable chromium_experimental_pixel_local;
+enable chromium_experimental_framebuffer_fetch;
 
 struct F_res {
   @location(1)
@@ -117,7 +117,7 @@
 }
 
 struct PixelLocal {
-  @internal(attachment(1)) @internal(disable_validation__entry_point_parameter)
+  @color(1u) @internal(disable_validation__entry_point_parameter)
   a : u32,
 }
 
@@ -155,7 +155,7 @@
 
     auto* expect =
         R"(
-enable chromium_experimental_pixel_local;
+enable chromium_experimental_framebuffer_fetch;
 
 struct F_res {
   @location(1)
@@ -170,7 +170,7 @@
 }
 
 struct PixelLocal {
-  @internal(attachment(1)) @internal(disable_validation__entry_point_parameter)
+  @color(1u) @internal(disable_validation__entry_point_parameter)
   a : u32,
 }
 
@@ -211,7 +211,7 @@
 
     auto* expect =
         R"(
-enable chromium_experimental_pixel_local;
+enable chromium_experimental_framebuffer_fetch;
 
 struct F_res {
   @location(1)
@@ -230,11 +230,11 @@
 }
 
 struct PixelLocal {
-  @internal(attachment(1)) @internal(disable_validation__entry_point_parameter)
+  @color(1u) @internal(disable_validation__entry_point_parameter)
   a : u32,
-  @internal(attachment(0)) @internal(disable_validation__entry_point_parameter)
+  @color(0u) @internal(disable_validation__entry_point_parameter)
   b : i32,
-  @internal(attachment(10)) @internal(disable_validation__entry_point_parameter)
+  @color(10u) @internal(disable_validation__entry_point_parameter)
   c : f32,
 }
 
@@ -269,7 +269,7 @@
 
     auto* expect =
         R"(
-enable chromium_experimental_pixel_local;
+enable chromium_experimental_framebuffer_fetch;
 
 struct F_res {
   @location(1)
@@ -284,7 +284,7 @@
 }
 
 struct PixelLocal {
-  @internal(attachment(1)) @internal(disable_validation__entry_point_parameter)
+  @color(1u) @internal(disable_validation__entry_point_parameter)
   a : u32,
 }
 
@@ -318,7 +318,7 @@
 
     auto* expect =
         R"(
-enable chromium_experimental_pixel_local;
+enable chromium_experimental_framebuffer_fetch;
 
 struct F_res {
   @location(1)
@@ -333,7 +333,7 @@
 }
 
 struct PixelLocal {
-  @internal(attachment(1)) @internal(disable_validation__entry_point_parameter)
+  @color(1u) @internal(disable_validation__entry_point_parameter)
   a : u32,
 }
 
@@ -371,7 +371,7 @@
 
     auto* expect =
         R"(
-enable chromium_experimental_pixel_local;
+enable chromium_experimental_framebuffer_fetch;
 
 struct F_res {
   @location(1)
@@ -386,7 +386,7 @@
 }
 
 struct PixelLocal {
-  @internal(attachment(1)) @internal(disable_validation__entry_point_parameter)
+  @color(1u) @internal(disable_validation__entry_point_parameter)
   a : u32,
 }
 
@@ -429,7 +429,7 @@
 
     auto* expect =
         R"(
-enable chromium_experimental_pixel_local;
+enable chromium_experimental_framebuffer_fetch;
 
 struct F_res {
   @location(1)
@@ -444,7 +444,7 @@
 }
 
 struct PixelLocal {
-  @internal(attachment(1)) @internal(disable_validation__entry_point_parameter)
+  @color(1u) @internal(disable_validation__entry_point_parameter)
   a : u32,
 }
 
@@ -483,7 +483,7 @@
 
     auto* expect =
         R"(
-enable chromium_experimental_pixel_local;
+enable chromium_experimental_framebuffer_fetch;
 
 struct F_res {
   @location(1)
@@ -498,7 +498,7 @@
 }
 
 struct PixelLocal {
-  @internal(attachment(1)) @internal(disable_validation__entry_point_parameter)
+  @color(1u) @internal(disable_validation__entry_point_parameter)
   a : u32,
 }
 
@@ -537,7 +537,7 @@
 
     auto* expect =
         R"(
-enable chromium_experimental_pixel_local;
+enable chromium_experimental_framebuffer_fetch;
 
 struct F_res {
   @location(1)
@@ -552,7 +552,7 @@
 }
 
 struct PixelLocal {
-  @internal(attachment(1)) @internal(disable_validation__entry_point_parameter)
+  @color(1u) @internal(disable_validation__entry_point_parameter)
   a : u32,
 }
 
@@ -593,7 +593,7 @@
 
     auto* expect =
         R"(
-enable chromium_experimental_pixel_local;
+enable chromium_experimental_framebuffer_fetch;
 
 struct F_res {
   @location(1)
@@ -608,7 +608,7 @@
 }
 
 struct PixelLocal {
-  @internal(attachment(1)) @internal(disable_validation__entry_point_parameter)
+  @color(1u) @internal(disable_validation__entry_point_parameter)
   a : u32,
 }
 
@@ -647,7 +647,7 @@
 
     auto* expect =
         R"(
-enable chromium_experimental_pixel_local;
+enable chromium_experimental_framebuffer_fetch;
 
 struct F_res {
   @location(1)
@@ -662,7 +662,7 @@
 }
 
 struct PixelLocal {
-  @internal(attachment(1)) @internal(disable_validation__entry_point_parameter)
+  @color(1u) @internal(disable_validation__entry_point_parameter)
   a : u32,
 }
 
@@ -704,7 +704,7 @@
 
     auto* expect =
         R"(
-enable chromium_experimental_pixel_local;
+enable chromium_experimental_framebuffer_fetch;
 
 struct F_res {
   @location(1)
@@ -721,7 +721,7 @@
 }
 
 struct PixelLocal {
-  @internal(attachment(1)) @internal(disable_validation__entry_point_parameter)
+  @color(1u) @internal(disable_validation__entry_point_parameter)
   a : u32,
 }
 
@@ -763,7 +763,7 @@
 
     auto* expect =
         R"(
-enable chromium_experimental_pixel_local;
+enable chromium_experimental_framebuffer_fetch;
 
 struct F_res {
   @location(1)
@@ -784,9 +784,9 @@
 }
 
 struct PixelLocal {
-  @internal(attachment(1)) @internal(disable_validation__entry_point_parameter)
+  @color(1u) @internal(disable_validation__entry_point_parameter)
   a : u32,
-  @internal(attachment(5)) @internal(disable_validation__entry_point_parameter)
+  @color(5u) @internal(disable_validation__entry_point_parameter)
   b : u32,
 }
 
diff --git a/src/tint/lang/spirv/writer/raise/shader_io.cc b/src/tint/lang/spirv/writer/raise/shader_io.cc
index cc6d506..c44fdee 100644
--- a/src/tint/lang/spirv/writer/raise/shader_io.cc
+++ b/src/tint/lang/spirv/writer/raise/shader_io.cc
@@ -103,7 +103,8 @@
                     io.type->is_integer_scalar_or_vector()) {
                     io.attributes.interpolation = {core::InterpolationType::kFlat};
                 }
-            } else {
+            }
+            if (io.attributes.location) {
                 name << "_loc" << io.attributes.location.value();
                 if (io.attributes.index.has_value()) {
                     name << "_idx" << io.attributes.index.value();
diff --git a/src/tint/lang/wgsl/ast/transform/canonicalize_entry_point_io.cc b/src/tint/lang/wgsl/ast/transform/canonicalize_entry_point_io.cc
index 45c270c..1408dcc 100644
--- a/src/tint/lang/wgsl/ast/transform/canonicalize_entry_point_io.cc
+++ b/src/tint/lang/wgsl/ast/transform/canonicalize_entry_point_io.cc
@@ -41,6 +41,7 @@
 #include "src/tint/lang/wgsl/program/program_builder.h"
 #include "src/tint/lang/wgsl/resolver/resolve.h"
 #include "src/tint/lang/wgsl/sem/function.h"
+#include "src/tint/utils/containers/transform.h"
 
 using namespace tint::core::number_suffixes;  // NOLINT
 using namespace tint::core::fluent_types;     // NOLINT
@@ -64,6 +65,8 @@
     std::optional<uint32_t> location;
     /// The struct member index if provided
     std::optional<uint32_t> index;
+    /// The struct member color if provided
+    std::optional<uint32_t> color;
 };
 
 /// FXC is sensitive to field order in structures, this is used by StructMemberComparator to ensure
@@ -105,7 +108,7 @@
 // Returns true if `attr` is a shader IO attribute.
 bool IsShaderIOAttribute(const Attribute* attr) {
     return attr->IsAnyOf<BuiltinAttribute, InterpolateAttribute, InvariantAttribute,
-                         LocationAttribute, IndexAttribute>();
+                         LocationAttribute, ColorAttribute, IndexAttribute>();
 }
 
 }  // namespace
@@ -284,11 +287,13 @@
     /// @param name the name of the shader input
     /// @param type the type of the shader input
     /// @param location the location if provided
+    /// @param color the color if provided
     /// @param attrs the attributes to apply to the shader input
     /// @returns an expression which evaluates to the value of the shader input
     const Expression* AddInput(std::string name,
                                const core::type::Type* type,
                                std::optional<uint32_t> location,
+                               std::optional<uint32_t> color,
                                tint::Vector<const Attribute*, 8> attrs) {
         auto ast_type = CreateASTTypeFor(ctx, type);
 
@@ -347,8 +352,8 @@
             // Otherwise, move it to the new structure member list.
             Symbol symbol = input_names.emplace(name).second ? b.Symbols().Register(name)
                                                              : b.Symbols().New(name);
-            wrapper_struct_param_members.Push(
-                {b.Member(symbol, ast_type, std::move(attrs)), location, std::nullopt});
+            wrapper_struct_param_members.Push({b.Member(symbol, ast_type, std::move(attrs)),
+                                               location, /* index */ std::nullopt, color});
             return b.MemberAccessor(InputStructSymbol(), symbol);
         }
     }
@@ -428,8 +433,8 @@
         }
 
         auto name = param->Declaration()->name->symbol.Name();
-        auto* input_expr =
-            AddInput(name, param->Type(), param->Attributes().location, std::move(attributes));
+        auto* input_expr = AddInput(name, param->Type(), param->Attributes().location,
+                                    param->Attributes().color, std::move(attributes));
         inner_call_parameters.Push(input_expr);
     }
 
@@ -463,7 +468,7 @@
             auto attributes =
                 CloneShaderIOAttributes(member->Declaration()->attributes, do_interpolate);
             auto* input_expr = AddInput(name, member->Type(), member->Attributes().location,
-                                        std::move(attributes));
+                                        member->Attributes().color, std::move(attributes));
             inner_struct_values.Push(input_expr);
         }
 
@@ -546,44 +551,57 @@
     }
 
     /// Comparison function used to reorder struct members such that all members with
-    /// location attributes appear first (ordered by location slot), followed by
-    /// those with builtin attributes.
+    /// color attributes appear first (ordered by color slot), then location attributes (ordered by
+    /// location slot), followed by those with builtin attributes (ordered by BuiltinOrder).
     /// @param x a struct member
     /// @param y another struct member
     /// @returns true if a comes before b
     bool StructMemberComparator(const MemberInfo& x, const MemberInfo& y) {
-        auto* x_loc = GetAttribute<LocationAttribute>(x.member->attributes);
-        auto* y_loc = GetAttribute<LocationAttribute>(y.member->attributes);
-        auto* x_blt = GetAttribute<BuiltinAttribute>(x.member->attributes);
-        auto* y_blt = GetAttribute<BuiltinAttribute>(y.member->attributes);
-        if (x_loc) {
-            if (!y_loc) {
-                // `a` has location attribute and `b` does not: `a` goes first.
-                return true;
-            }
+        if (x.color.has_value() && y.color.has_value()) {
+            // Both have color attributes: smallest goes first.
+            return x.color < y.color;
+        }
+        if (x.color.has_value() != y.color.has_value()) {
+            // The member with the color goes first
+            return x.color.has_value();
+        }
+
+        if (x.location.has_value() && y.location.has_value()) {
             // Both have location attributes: smallest goes first.
             return x.location < y.location;
-        } else {
-            if (y_loc) {
-                // `b` has location attribute and `a` does not: `b` goes first.
-                return false;
-            }
-            // Both are builtins: order matters for FXC.
-            auto builtin_a = BuiltinOf(x_blt);
-            auto builtin_b = BuiltinOf(y_blt);
-            return BuiltinOrder(builtin_a) < BuiltinOrder(builtin_b);
         }
+        if (x.location.has_value() != y.location.has_value()) {
+            // The member with the location goes first
+            return x.location.has_value();
+        }
+
+        {
+            auto* x_blt = GetAttribute<BuiltinAttribute>(x.member->attributes);
+            auto* y_blt = GetAttribute<BuiltinAttribute>(y.member->attributes);
+            if (x_blt && y_blt) {
+                // Both are builtins: order matters for FXC.
+                auto builtin_a = BuiltinOf(x_blt);
+                auto builtin_b = BuiltinOf(y_blt);
+                return BuiltinOrder(builtin_a) < BuiltinOrder(builtin_b);
+            }
+            if ((x_blt != nullptr) != (y_blt != nullptr)) {
+                // The member with the builtin goes first
+                return x_blt != nullptr;
+            }
+        }
+
+        TINT_UNREACHABLE();
+        return false;
     }
+
     /// Create the wrapper function's struct parameter and type objects.
     void CreateInputStruct() {
         // Sort the struct members to satisfy HLSL interfacing matching rules.
         std::sort(wrapper_struct_param_members.begin(), wrapper_struct_param_members.end(),
                   [&](auto& x, auto& y) { return StructMemberComparator(x, y); });
 
-        tint::Vector<const StructMember*, 8> members;
-        for (auto& mem : wrapper_struct_param_members) {
-            members.Push(mem.member);
-        }
+        auto members =
+            tint::Transform(wrapper_struct_param_members, [](auto& info) { return info.member; });
 
         // Create the new struct type.
         auto struct_name = b.Sym();
@@ -614,9 +632,12 @@
             }
             member_names.insert(name.Name());
 
-            wrapper_struct_output_members.Push(
-                {b.Member(name, outval.type, std::move(outval.attributes)), outval.location,
-                 std::nullopt});
+            wrapper_struct_output_members.Push({
+                /* member */ b.Member(name, outval.type, std::move(outval.attributes)),
+                /* location */ outval.location,
+                /* color */ std::nullopt,
+                /* index */ std::nullopt,
+            });
             assignments.Push(b.Assign(b.MemberAccessor(wrapper_result, name), outval.value));
         }
 
diff --git a/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.cc b/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.cc
index 5e99225..e2c1c43 100644
--- a/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.cc
+++ b/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.cc
@@ -459,6 +459,9 @@
                 if (param_sem->Attributes().location.has_value()) {
                     param->SetLocation(param_sem->Attributes().location.value(), interpolation);
                 }
+                if (param_sem->Attributes().color.has_value()) {
+                    TINT_UNIMPLEMENTED() << "IR does not currently support texel fetch extension";
+                }
             }
 
             scopes_.Set(p->name->symbol, param);
diff --git a/src/tint/lang/wgsl/writer/ast_printer/ast_printer.cc b/src/tint/lang/wgsl/writer/ast_printer/ast_printer.cc
index ec38e3d..12688b4 100644
--- a/src/tint/lang/wgsl/writer/ast_printer/ast_printer.cc
+++ b/src/tint/lang/wgsl/writer/ast_printer/ast_printer.cc
@@ -40,6 +40,7 @@
 #include "src/tint/lang/wgsl/ast/break_statement.h"
 #include "src/tint/lang/wgsl/ast/call_expression.h"
 #include "src/tint/lang/wgsl/ast/call_statement.h"
+#include "src/tint/lang/wgsl/ast/color_attribute.h"
 #include "src/tint/lang/wgsl/ast/compound_assignment_statement.h"
 #include "src/tint/lang/wgsl/ast/const.h"
 #include "src/tint/lang/wgsl/ast/continue_statement.h"
@@ -505,6 +506,11 @@
                 EmitExpression(out, location->expr);
                 out << ")";
             },
+            [&](const ast::ColorAttribute* color) {
+                out << "color(";
+                EmitExpression(out, color->expr);
+                out << ")";
+            },
             [&](const ast::IndexAttribute* index) {
                 out << "index(";
                 EmitExpression(out, index->expr);
diff --git a/test/tint/extensions/pixel_local/entry_point_use/additional_params/builtin.wgsl.expected.msl b/test/tint/extensions/pixel_local/entry_point_use/additional_params/builtin.wgsl.expected.msl
index 50d6a5b..22f07c2 100644
--- a/test/tint/extensions/pixel_local/entry_point_use/additional_params/builtin.wgsl.expected.msl
+++ b/test/tint/extensions/pixel_local/entry_point_use/additional_params/builtin.wgsl.expected.msl
@@ -2,9 +2,9 @@
 
 using namespace metal;
 struct PixelLocal {
-  uint a [[color(1)]];
-  int b [[color(6)]];
-  float c [[color(3)]];
+  uint a;
+  int b;
+  float c;
 };
 
 struct tint_private_vars_struct {
@@ -12,9 +12,21 @@
 };
 
 struct f_res {
+  uint output_0;
+  int output_1;
+  float output_2;
+};
+
+struct tint_symbol_1 {
+  uint a [[color(1)]];
+  float c [[color(3)]];
+  int b [[color(6)]];
+};
+
+struct tint_symbol_2 {
   uint output_0 [[color(1)]];
-  int output_1 [[color(6)]];
   float output_2 [[color(3)]];
+  int output_1 [[color(6)]];
 };
 
 uint tint_ftou(float v) {
@@ -25,14 +37,21 @@
   (*(tint_private_vars)).P.a = ((*(tint_private_vars)).P.a + tint_ftou(pos[0]));
 }
 
-void f_inner_1(float4 pos, thread tint_private_vars_struct* const tint_private_vars) {
+f_res f_inner_1(float4 pos, PixelLocal pixel_local_1, thread tint_private_vars_struct* const tint_private_vars) {
+  (*(tint_private_vars)).P = pixel_local_1;
   f_inner(pos, tint_private_vars);
+  f_res const tint_symbol_4 = {.output_0=(*(tint_private_vars)).P.a, .output_1=(*(tint_private_vars)).P.b, .output_2=(*(tint_private_vars)).P.c};
+  return tint_symbol_4;
 }
 
-fragment f_res f(float4 pos [[position]], PixelLocal pixel_local_1) {
+fragment tint_symbol_2 f(float4 pos [[position]], tint_symbol_1 tint_symbol [[stage_in]]) {
   thread tint_private_vars_struct tint_private_vars = {};
-  tint_private_vars.P = pixel_local_1;
-  f_inner_1(pos, &(tint_private_vars));
-  return {.output_0=tint_private_vars.P.a, .output_1=tint_private_vars.P.b, .output_2=tint_private_vars.P.c};
+  PixelLocal const tint_symbol_3 = {.a=tint_symbol.a, .b=tint_symbol.b, .c=tint_symbol.c};
+  f_res const inner_result = f_inner_1(pos, tint_symbol_3, &(tint_private_vars));
+  tint_symbol_2 wrapper_result = {};
+  wrapper_result.output_0 = inner_result.output_0;
+  wrapper_result.output_1 = inner_result.output_1;
+  wrapper_result.output_2 = inner_result.output_2;
+  return wrapper_result;
 }
 
diff --git a/test/tint/extensions/pixel_local/entry_point_use/additional_params/builtin_and_location.wgsl.expected.msl b/test/tint/extensions/pixel_local/entry_point_use/additional_params/builtin_and_location.wgsl.expected.msl
index 45aa35f..e4e53f6 100644
--- a/test/tint/extensions/pixel_local/entry_point_use/additional_params/builtin_and_location.wgsl.expected.msl
+++ b/test/tint/extensions/pixel_local/entry_point_use/additional_params/builtin_and_location.wgsl.expected.msl
@@ -2,9 +2,9 @@
 
 using namespace metal;
 struct PixelLocal {
-  uint a [[color(1)]];
-  int b [[color(6)]];
-  float c [[color(3)]];
+  uint a;
+  int b;
+  float c;
 };
 
 struct tint_private_vars_struct {
@@ -12,15 +12,24 @@
 };
 
 struct f_res {
-  uint output_0 [[color(1)]];
-  int output_1 [[color(6)]];
-  float output_2 [[color(3)]];
+  uint output_0;
+  int output_1;
+  float output_2;
 };
 
 struct tint_symbol_1 {
+  uint a [[color(1)]];
+  float c [[color(3)]];
+  int b [[color(6)]];
   float4 uv [[user(locn0)]];
 };
 
+struct tint_symbol_2 {
+  uint output_0 [[color(1)]];
+  float output_2 [[color(3)]];
+  int output_1 [[color(6)]];
+};
+
 uint tint_ftou(float v) {
   return select(4294967295u, select(uint(v), 0u, (v < 0.0f)), (v < 4294967040.0f));
 }
@@ -29,14 +38,21 @@
   (*(tint_private_vars)).P.a = ((*(tint_private_vars)).P.a + (tint_ftou(pos[0]) + tint_ftou(uv[0])));
 }
 
-void f_inner_1(float4 pos, tint_symbol_1 tint_symbol, thread tint_private_vars_struct* const tint_private_vars) {
-  f_inner(pos, tint_symbol.uv, tint_private_vars);
+f_res f_inner_1(float4 pos, float4 uv, PixelLocal pixel_local_1, thread tint_private_vars_struct* const tint_private_vars) {
+  (*(tint_private_vars)).P = pixel_local_1;
+  f_inner(pos, uv, tint_private_vars);
+  f_res const tint_symbol_4 = {.output_0=(*(tint_private_vars)).P.a, .output_1=(*(tint_private_vars)).P.b, .output_2=(*(tint_private_vars)).P.c};
+  return tint_symbol_4;
 }
 
-fragment f_res f(float4 pos [[position]], tint_symbol_1 tint_symbol [[stage_in]], PixelLocal pixel_local_1) {
+fragment tint_symbol_2 f(float4 pos [[position]], tint_symbol_1 tint_symbol [[stage_in]]) {
   thread tint_private_vars_struct tint_private_vars = {};
-  tint_private_vars.P = pixel_local_1;
-  f_inner_1(pos, tint_symbol, &(tint_private_vars));
-  return {.output_0=tint_private_vars.P.a, .output_1=tint_private_vars.P.b, .output_2=tint_private_vars.P.c};
+  PixelLocal const tint_symbol_3 = {.a=tint_symbol.a, .b=tint_symbol.b, .c=tint_symbol.c};
+  f_res const inner_result = f_inner_1(pos, tint_symbol.uv, tint_symbol_3, &(tint_private_vars));
+  tint_symbol_2 wrapper_result = {};
+  wrapper_result.output_0 = inner_result.output_0;
+  wrapper_result.output_1 = inner_result.output_1;
+  wrapper_result.output_2 = inner_result.output_2;
+  return wrapper_result;
 }
 
diff --git a/test/tint/extensions/pixel_local/entry_point_use/additional_params/builtin_and_location_in_struct.wgsl.expected.msl b/test/tint/extensions/pixel_local/entry_point_use/additional_params/builtin_and_location_in_struct.wgsl.expected.msl
index 1273933..3702226 100644
--- a/test/tint/extensions/pixel_local/entry_point_use/additional_params/builtin_and_location_in_struct.wgsl.expected.msl
+++ b/test/tint/extensions/pixel_local/entry_point_use/additional_params/builtin_and_location_in_struct.wgsl.expected.msl
@@ -2,9 +2,9 @@
 
 using namespace metal;
 struct PixelLocal {
-  uint a [[color(1)]];
-  int b [[color(6)]];
-  float c [[color(3)]];
+  uint a;
+  int b;
+  float c;
 };
 
 struct tint_private_vars_struct {
@@ -12,15 +12,24 @@
 };
 
 struct f_res {
-  uint output_0 [[color(1)]];
-  int output_1 [[color(6)]];
-  float output_2 [[color(3)]];
+  uint output_0;
+  int output_1;
+  float output_2;
 };
 
 struct tint_symbol_1 {
+  uint a [[color(1)]];
+  float c [[color(3)]];
+  int b [[color(6)]];
   float4 uv [[user(locn0)]];
 };
 
+struct tint_symbol_2 {
+  uint output_0 [[color(1)]];
+  float output_2 [[color(3)]];
+  int output_1 [[color(6)]];
+};
+
 struct In {
   float4 uv;
 };
@@ -33,15 +42,22 @@
   (*(tint_private_vars)).P.a = ((*(tint_private_vars)).P.a + (tint_ftou(pos[0]) + tint_ftou(in.uv[0])));
 }
 
-void f_inner_1(float4 pos, tint_symbol_1 tint_symbol, thread tint_private_vars_struct* const tint_private_vars) {
-  In const tint_symbol_2 = {.uv=tint_symbol.uv};
-  f_inner(pos, tint_symbol_2, tint_private_vars);
+f_res f_inner_1(float4 pos, In in, PixelLocal pixel_local_1, thread tint_private_vars_struct* const tint_private_vars) {
+  (*(tint_private_vars)).P = pixel_local_1;
+  f_inner(pos, in, tint_private_vars);
+  f_res const tint_symbol_5 = {.output_0=(*(tint_private_vars)).P.a, .output_1=(*(tint_private_vars)).P.b, .output_2=(*(tint_private_vars)).P.c};
+  return tint_symbol_5;
 }
 
-fragment f_res f(float4 pos [[position]], tint_symbol_1 tint_symbol [[stage_in]], PixelLocal pixel_local_1) {
+fragment tint_symbol_2 f(float4 pos [[position]], tint_symbol_1 tint_symbol [[stage_in]]) {
   thread tint_private_vars_struct tint_private_vars = {};
-  tint_private_vars.P = pixel_local_1;
-  f_inner_1(pos, tint_symbol, &(tint_private_vars));
-  return {.output_0=tint_private_vars.P.a, .output_1=tint_private_vars.P.b, .output_2=tint_private_vars.P.c};
+  In const tint_symbol_3 = {.uv=tint_symbol.uv};
+  PixelLocal const tint_symbol_4 = {.a=tint_symbol.a, .b=tint_symbol.b, .c=tint_symbol.c};
+  f_res const inner_result = f_inner_1(pos, tint_symbol_3, tint_symbol_4, &(tint_private_vars));
+  tint_symbol_2 wrapper_result = {};
+  wrapper_result.output_0 = inner_result.output_0;
+  wrapper_result.output_1 = inner_result.output_1;
+  wrapper_result.output_2 = inner_result.output_2;
+  return wrapper_result;
 }
 
diff --git a/test/tint/extensions/pixel_local/entry_point_use/additional_params/builtin_in_struct.wgsl.expected.msl b/test/tint/extensions/pixel_local/entry_point_use/additional_params/builtin_in_struct.wgsl.expected.msl
index c34efb8..b268226 100644
--- a/test/tint/extensions/pixel_local/entry_point_use/additional_params/builtin_in_struct.wgsl.expected.msl
+++ b/test/tint/extensions/pixel_local/entry_point_use/additional_params/builtin_in_struct.wgsl.expected.msl
@@ -2,9 +2,9 @@
 
 using namespace metal;
 struct PixelLocal {
-  uint a [[color(1)]];
-  int b [[color(6)]];
-  float c [[color(3)]];
+  uint a;
+  int b;
+  float c;
 };
 
 struct tint_private_vars_struct {
@@ -12,9 +12,21 @@
 };
 
 struct f_res {
+  uint output_0;
+  int output_1;
+  float output_2;
+};
+
+struct tint_symbol_1 {
+  uint a [[color(1)]];
+  float c [[color(3)]];
+  int b [[color(6)]];
+};
+
+struct tint_symbol_2 {
   uint output_0 [[color(1)]];
-  int output_1 [[color(6)]];
   float output_2 [[color(3)]];
+  int output_1 [[color(6)]];
 };
 
 struct In {
@@ -29,15 +41,22 @@
   (*(tint_private_vars)).P.a = ((*(tint_private_vars)).P.a + tint_ftou(in.pos[0]));
 }
 
-void f_inner_1(float4 pos, thread tint_private_vars_struct* const tint_private_vars) {
-  In const tint_symbol = {.pos=pos};
-  f_inner(tint_symbol, tint_private_vars);
+f_res f_inner_1(In in, PixelLocal pixel_local_1, thread tint_private_vars_struct* const tint_private_vars) {
+  (*(tint_private_vars)).P = pixel_local_1;
+  f_inner(in, tint_private_vars);
+  f_res const tint_symbol_5 = {.output_0=(*(tint_private_vars)).P.a, .output_1=(*(tint_private_vars)).P.b, .output_2=(*(tint_private_vars)).P.c};
+  return tint_symbol_5;
 }
 
-fragment f_res f(float4 pos [[position]], PixelLocal pixel_local_1) {
+fragment tint_symbol_2 f(float4 pos [[position]], tint_symbol_1 tint_symbol [[stage_in]]) {
   thread tint_private_vars_struct tint_private_vars = {};
-  tint_private_vars.P = pixel_local_1;
-  f_inner_1(pos, &(tint_private_vars));
-  return {.output_0=tint_private_vars.P.a, .output_1=tint_private_vars.P.b, .output_2=tint_private_vars.P.c};
+  In const tint_symbol_3 = {.pos=pos};
+  PixelLocal const tint_symbol_4 = {.a=tint_symbol.a, .b=tint_symbol.b, .c=tint_symbol.c};
+  f_res const inner_result = f_inner_1(tint_symbol_3, tint_symbol_4, &(tint_private_vars));
+  tint_symbol_2 wrapper_result = {};
+  wrapper_result.output_0 = inner_result.output_0;
+  wrapper_result.output_1 = inner_result.output_1;
+  wrapper_result.output_2 = inner_result.output_2;
+  return wrapper_result;
 }
 
diff --git a/test/tint/extensions/pixel_local/entry_point_use/additional_params/builtin_in_struct_and_location.wgsl.expected.msl b/test/tint/extensions/pixel_local/entry_point_use/additional_params/builtin_in_struct_and_location.wgsl.expected.msl
index 36509ab..912cda3 100644
--- a/test/tint/extensions/pixel_local/entry_point_use/additional_params/builtin_in_struct_and_location.wgsl.expected.msl
+++ b/test/tint/extensions/pixel_local/entry_point_use/additional_params/builtin_in_struct_and_location.wgsl.expected.msl
@@ -2,9 +2,9 @@
 
 using namespace metal;
 struct PixelLocal {
-  uint a [[color(1)]];
-  int b [[color(6)]];
-  float c [[color(3)]];
+  uint a;
+  int b;
+  float c;
 };
 
 struct tint_private_vars_struct {
@@ -12,15 +12,24 @@
 };
 
 struct f_res {
-  uint output_0 [[color(1)]];
-  int output_1 [[color(6)]];
-  float output_2 [[color(3)]];
+  uint output_0;
+  int output_1;
+  float output_2;
 };
 
 struct tint_symbol_1 {
+  uint a [[color(1)]];
+  float c [[color(3)]];
+  int b [[color(6)]];
   float4 uv [[user(locn0)]];
 };
 
+struct tint_symbol_2 {
+  uint output_0 [[color(1)]];
+  float output_2 [[color(3)]];
+  int output_1 [[color(6)]];
+};
+
 struct In {
   float4 pos;
 };
@@ -33,15 +42,22 @@
   (*(tint_private_vars)).P.a = ((*(tint_private_vars)).P.a + (tint_ftou(in.pos[0]) + tint_ftou(uv[0])));
 }
 
-void f_inner_1(float4 pos, tint_symbol_1 tint_symbol, thread tint_private_vars_struct* const tint_private_vars) {
-  In const tint_symbol_2 = {.pos=pos};
-  f_inner(tint_symbol_2, tint_symbol.uv, tint_private_vars);
+f_res f_inner_1(In in, float4 uv, PixelLocal pixel_local_1, thread tint_private_vars_struct* const tint_private_vars) {
+  (*(tint_private_vars)).P = pixel_local_1;
+  f_inner(in, uv, tint_private_vars);
+  f_res const tint_symbol_5 = {.output_0=(*(tint_private_vars)).P.a, .output_1=(*(tint_private_vars)).P.b, .output_2=(*(tint_private_vars)).P.c};
+  return tint_symbol_5;
 }
 
-fragment f_res f(float4 pos [[position]], tint_symbol_1 tint_symbol [[stage_in]], PixelLocal pixel_local_1) {
+fragment tint_symbol_2 f(float4 pos [[position]], tint_symbol_1 tint_symbol [[stage_in]]) {
   thread tint_private_vars_struct tint_private_vars = {};
-  tint_private_vars.P = pixel_local_1;
-  f_inner_1(pos, tint_symbol, &(tint_private_vars));
-  return {.output_0=tint_private_vars.P.a, .output_1=tint_private_vars.P.b, .output_2=tint_private_vars.P.c};
+  In const tint_symbol_3 = {.pos=pos};
+  PixelLocal const tint_symbol_4 = {.a=tint_symbol.a, .b=tint_symbol.b, .c=tint_symbol.c};
+  f_res const inner_result = f_inner_1(tint_symbol_3, tint_symbol.uv, tint_symbol_4, &(tint_private_vars));
+  tint_symbol_2 wrapper_result = {};
+  wrapper_result.output_0 = inner_result.output_0;
+  wrapper_result.output_1 = inner_result.output_1;
+  wrapper_result.output_2 = inner_result.output_2;
+  return wrapper_result;
 }
 
diff --git a/test/tint/extensions/pixel_local/entry_point_use/additional_params/builtin_in_struct_and_location_in_struct.wgsl.expected.msl b/test/tint/extensions/pixel_local/entry_point_use/additional_params/builtin_in_struct_and_location_in_struct.wgsl.expected.msl
index bfabcb6..ca1c170 100644
--- a/test/tint/extensions/pixel_local/entry_point_use/additional_params/builtin_in_struct_and_location_in_struct.wgsl.expected.msl
+++ b/test/tint/extensions/pixel_local/entry_point_use/additional_params/builtin_in_struct_and_location_in_struct.wgsl.expected.msl
@@ -2,9 +2,9 @@
 
 using namespace metal;
 struct PixelLocal {
-  uint a [[color(1)]];
-  int b [[color(6)]];
-  float c [[color(3)]];
+  uint a;
+  int b;
+  float c;
 };
 
 struct tint_private_vars_struct {
@@ -12,15 +12,24 @@
 };
 
 struct f_res {
-  uint output_0 [[color(1)]];
-  int output_1 [[color(6)]];
-  float output_2 [[color(3)]];
+  uint output_0;
+  int output_1;
+  float output_2;
 };
 
 struct tint_symbol_1 {
+  uint a [[color(1)]];
+  float c [[color(3)]];
+  int b [[color(6)]];
   float4 uv [[user(locn0)]];
 };
 
+struct tint_symbol_2 {
+  uint output_0 [[color(1)]];
+  float output_2 [[color(3)]];
+  int output_1 [[color(6)]];
+};
+
 struct In {
   float4 pos;
   float4 uv;
@@ -34,15 +43,22 @@
   (*(tint_private_vars)).P.a = ((*(tint_private_vars)).P.a + (tint_ftou(in.pos[0]) + tint_ftou(in.uv[0])));
 }
 
-void f_inner_1(float4 pos, tint_symbol_1 tint_symbol, thread tint_private_vars_struct* const tint_private_vars) {
-  In const tint_symbol_2 = {.pos=pos, .uv=tint_symbol.uv};
-  f_inner(tint_symbol_2, tint_private_vars);
+f_res f_inner_1(In in, PixelLocal pixel_local_1, thread tint_private_vars_struct* const tint_private_vars) {
+  (*(tint_private_vars)).P = pixel_local_1;
+  f_inner(in, tint_private_vars);
+  f_res const tint_symbol_5 = {.output_0=(*(tint_private_vars)).P.a, .output_1=(*(tint_private_vars)).P.b, .output_2=(*(tint_private_vars)).P.c};
+  return tint_symbol_5;
 }
 
-fragment f_res f(float4 pos [[position]], tint_symbol_1 tint_symbol [[stage_in]], PixelLocal pixel_local_1) {
+fragment tint_symbol_2 f(float4 pos [[position]], tint_symbol_1 tint_symbol [[stage_in]]) {
   thread tint_private_vars_struct tint_private_vars = {};
-  tint_private_vars.P = pixel_local_1;
-  f_inner_1(pos, tint_symbol, &(tint_private_vars));
-  return {.output_0=tint_private_vars.P.a, .output_1=tint_private_vars.P.b, .output_2=tint_private_vars.P.c};
+  In const tint_symbol_3 = {.pos=pos, .uv=tint_symbol.uv};
+  PixelLocal const tint_symbol_4 = {.a=tint_symbol.a, .b=tint_symbol.b, .c=tint_symbol.c};
+  f_res const inner_result = f_inner_1(tint_symbol_3, tint_symbol_4, &(tint_private_vars));
+  tint_symbol_2 wrapper_result = {};
+  wrapper_result.output_0 = inner_result.output_0;
+  wrapper_result.output_1 = inner_result.output_1;
+  wrapper_result.output_2 = inner_result.output_2;
+  return wrapper_result;
 }
 
diff --git a/test/tint/extensions/pixel_local/entry_point_use/additional_params/invariant_builtin.wgsl.expected.msl b/test/tint/extensions/pixel_local/entry_point_use/additional_params/invariant_builtin.wgsl.expected.msl
index 50d6a5b..22f07c2 100644
--- a/test/tint/extensions/pixel_local/entry_point_use/additional_params/invariant_builtin.wgsl.expected.msl
+++ b/test/tint/extensions/pixel_local/entry_point_use/additional_params/invariant_builtin.wgsl.expected.msl
@@ -2,9 +2,9 @@
 
 using namespace metal;
 struct PixelLocal {
-  uint a [[color(1)]];
-  int b [[color(6)]];
-  float c [[color(3)]];
+  uint a;
+  int b;
+  float c;
 };
 
 struct tint_private_vars_struct {
@@ -12,9 +12,21 @@
 };
 
 struct f_res {
+  uint output_0;
+  int output_1;
+  float output_2;
+};
+
+struct tint_symbol_1 {
+  uint a [[color(1)]];
+  float c [[color(3)]];
+  int b [[color(6)]];
+};
+
+struct tint_symbol_2 {
   uint output_0 [[color(1)]];
-  int output_1 [[color(6)]];
   float output_2 [[color(3)]];
+  int output_1 [[color(6)]];
 };
 
 uint tint_ftou(float v) {
@@ -25,14 +37,21 @@
   (*(tint_private_vars)).P.a = ((*(tint_private_vars)).P.a + tint_ftou(pos[0]));
 }
 
-void f_inner_1(float4 pos, thread tint_private_vars_struct* const tint_private_vars) {
+f_res f_inner_1(float4 pos, PixelLocal pixel_local_1, thread tint_private_vars_struct* const tint_private_vars) {
+  (*(tint_private_vars)).P = pixel_local_1;
   f_inner(pos, tint_private_vars);
+  f_res const tint_symbol_4 = {.output_0=(*(tint_private_vars)).P.a, .output_1=(*(tint_private_vars)).P.b, .output_2=(*(tint_private_vars)).P.c};
+  return tint_symbol_4;
 }
 
-fragment f_res f(float4 pos [[position]], PixelLocal pixel_local_1) {
+fragment tint_symbol_2 f(float4 pos [[position]], tint_symbol_1 tint_symbol [[stage_in]]) {
   thread tint_private_vars_struct tint_private_vars = {};
-  tint_private_vars.P = pixel_local_1;
-  f_inner_1(pos, &(tint_private_vars));
-  return {.output_0=tint_private_vars.P.a, .output_1=tint_private_vars.P.b, .output_2=tint_private_vars.P.c};
+  PixelLocal const tint_symbol_3 = {.a=tint_symbol.a, .b=tint_symbol.b, .c=tint_symbol.c};
+  f_res const inner_result = f_inner_1(pos, tint_symbol_3, &(tint_private_vars));
+  tint_symbol_2 wrapper_result = {};
+  wrapper_result.output_0 = inner_result.output_0;
+  wrapper_result.output_1 = inner_result.output_1;
+  wrapper_result.output_2 = inner_result.output_2;
+  return wrapper_result;
 }
 
diff --git a/test/tint/extensions/pixel_local/entry_point_use/additional_params/invariant_builtin_in_struct.wgsl.expected.msl b/test/tint/extensions/pixel_local/entry_point_use/additional_params/invariant_builtin_in_struct.wgsl.expected.msl
index c34efb8..b268226 100644
--- a/test/tint/extensions/pixel_local/entry_point_use/additional_params/invariant_builtin_in_struct.wgsl.expected.msl
+++ b/test/tint/extensions/pixel_local/entry_point_use/additional_params/invariant_builtin_in_struct.wgsl.expected.msl
@@ -2,9 +2,9 @@
 
 using namespace metal;
 struct PixelLocal {
-  uint a [[color(1)]];
-  int b [[color(6)]];
-  float c [[color(3)]];
+  uint a;
+  int b;
+  float c;
 };
 
 struct tint_private_vars_struct {
@@ -12,9 +12,21 @@
 };
 
 struct f_res {
+  uint output_0;
+  int output_1;
+  float output_2;
+};
+
+struct tint_symbol_1 {
+  uint a [[color(1)]];
+  float c [[color(3)]];
+  int b [[color(6)]];
+};
+
+struct tint_symbol_2 {
   uint output_0 [[color(1)]];
-  int output_1 [[color(6)]];
   float output_2 [[color(3)]];
+  int output_1 [[color(6)]];
 };
 
 struct In {
@@ -29,15 +41,22 @@
   (*(tint_private_vars)).P.a = ((*(tint_private_vars)).P.a + tint_ftou(in.pos[0]));
 }
 
-void f_inner_1(float4 pos, thread tint_private_vars_struct* const tint_private_vars) {
-  In const tint_symbol = {.pos=pos};
-  f_inner(tint_symbol, tint_private_vars);
+f_res f_inner_1(In in, PixelLocal pixel_local_1, thread tint_private_vars_struct* const tint_private_vars) {
+  (*(tint_private_vars)).P = pixel_local_1;
+  f_inner(in, tint_private_vars);
+  f_res const tint_symbol_5 = {.output_0=(*(tint_private_vars)).P.a, .output_1=(*(tint_private_vars)).P.b, .output_2=(*(tint_private_vars)).P.c};
+  return tint_symbol_5;
 }
 
-fragment f_res f(float4 pos [[position]], PixelLocal pixel_local_1) {
+fragment tint_symbol_2 f(float4 pos [[position]], tint_symbol_1 tint_symbol [[stage_in]]) {
   thread tint_private_vars_struct tint_private_vars = {};
-  tint_private_vars.P = pixel_local_1;
-  f_inner_1(pos, &(tint_private_vars));
-  return {.output_0=tint_private_vars.P.a, .output_1=tint_private_vars.P.b, .output_2=tint_private_vars.P.c};
+  In const tint_symbol_3 = {.pos=pos};
+  PixelLocal const tint_symbol_4 = {.a=tint_symbol.a, .b=tint_symbol.b, .c=tint_symbol.c};
+  f_res const inner_result = f_inner_1(tint_symbol_3, tint_symbol_4, &(tint_private_vars));
+  tint_symbol_2 wrapper_result = {};
+  wrapper_result.output_0 = inner_result.output_0;
+  wrapper_result.output_1 = inner_result.output_1;
+  wrapper_result.output_2 = inner_result.output_2;
+  return wrapper_result;
 }
 
diff --git a/test/tint/extensions/pixel_local/entry_point_use/additional_params/location.wgsl.expected.msl b/test/tint/extensions/pixel_local/entry_point_use/additional_params/location.wgsl.expected.msl
index 8061bf4..44a3bec 100644
--- a/test/tint/extensions/pixel_local/entry_point_use/additional_params/location.wgsl.expected.msl
+++ b/test/tint/extensions/pixel_local/entry_point_use/additional_params/location.wgsl.expected.msl
@@ -2,9 +2,9 @@
 
 using namespace metal;
 struct PixelLocal {
-  uint a [[color(1)]];
-  int b [[color(6)]];
-  float c [[color(3)]];
+  uint a;
+  int b;
+  float c;
 };
 
 struct tint_private_vars_struct {
@@ -12,16 +12,25 @@
 };
 
 struct f_res {
-  uint output_0 [[color(1)]];
-  int output_1 [[color(6)]];
-  float output_2 [[color(3)]];
+  uint output_0;
+  int output_1;
+  float output_2;
 };
 
 struct tint_symbol_1 {
+  uint a_1 [[color(1)]];
+  float c [[color(3)]];
+  int b_1 [[color(6)]];
   float4 a [[user(locn0)]];
   float4 b [[user(locn1)]] [[flat]];
 };
 
+struct tint_symbol_2 {
+  uint output_0 [[color(1)]];
+  float output_2 [[color(3)]];
+  int output_1 [[color(6)]];
+};
+
 uint tint_ftou(float v) {
   return select(4294967295u, select(uint(v), 0u, (v < 0.0f)), (v < 4294967040.0f));
 }
@@ -30,14 +39,21 @@
   (*(tint_private_vars)).P.a = ((*(tint_private_vars)).P.a + (tint_ftou(a[0]) + tint_ftou(b[1])));
 }
 
-void f_inner_1(tint_symbol_1 tint_symbol, thread tint_private_vars_struct* const tint_private_vars) {
-  f_inner(tint_symbol.a, tint_symbol.b, tint_private_vars);
+f_res f_inner_1(float4 a, float4 b, PixelLocal pixel_local_1, thread tint_private_vars_struct* const tint_private_vars) {
+  (*(tint_private_vars)).P = pixel_local_1;
+  f_inner(a, b, tint_private_vars);
+  f_res const tint_symbol_4 = {.output_0=(*(tint_private_vars)).P.a, .output_1=(*(tint_private_vars)).P.b, .output_2=(*(tint_private_vars)).P.c};
+  return tint_symbol_4;
 }
 
-fragment f_res f(tint_symbol_1 tint_symbol [[stage_in]], PixelLocal pixel_local_1) {
+fragment tint_symbol_2 f(tint_symbol_1 tint_symbol [[stage_in]]) {
   thread tint_private_vars_struct tint_private_vars = {};
-  tint_private_vars.P = pixel_local_1;
-  f_inner_1(tint_symbol, &(tint_private_vars));
-  return {.output_0=tint_private_vars.P.a, .output_1=tint_private_vars.P.b, .output_2=tint_private_vars.P.c};
+  PixelLocal const tint_symbol_3 = {.a=tint_symbol.a_1, .b=tint_symbol.b_1, .c=tint_symbol.c};
+  f_res const inner_result = f_inner_1(tint_symbol.a, tint_symbol.b, tint_symbol_3, &(tint_private_vars));
+  tint_symbol_2 wrapper_result = {};
+  wrapper_result.output_0 = inner_result.output_0;
+  wrapper_result.output_1 = inner_result.output_1;
+  wrapper_result.output_2 = inner_result.output_2;
+  return wrapper_result;
 }
 
diff --git a/test/tint/extensions/pixel_local/entry_point_use/additional_params/location_in_struct.wgsl.expected.msl b/test/tint/extensions/pixel_local/entry_point_use/additional_params/location_in_struct.wgsl.expected.msl
index faec0aa..4fe9b49 100644
--- a/test/tint/extensions/pixel_local/entry_point_use/additional_params/location_in_struct.wgsl.expected.msl
+++ b/test/tint/extensions/pixel_local/entry_point_use/additional_params/location_in_struct.wgsl.expected.msl
@@ -2,9 +2,9 @@
 
 using namespace metal;
 struct PixelLocal {
-  uint a [[color(1)]];
-  int b [[color(6)]];
-  float c [[color(3)]];
+  uint a;
+  int b;
+  float c;
 };
 
 struct tint_private_vars_struct {
@@ -12,16 +12,25 @@
 };
 
 struct f_res {
-  uint output_0 [[color(1)]];
-  int output_1 [[color(6)]];
-  float output_2 [[color(3)]];
+  uint output_0;
+  int output_1;
+  float output_2;
 };
 
 struct tint_symbol_1 {
+  uint a_1 [[color(1)]];
+  float c [[color(3)]];
+  int b_1 [[color(6)]];
   float4 a [[user(locn0)]];
   float4 b [[user(locn1)]] [[flat]];
 };
 
+struct tint_symbol_2 {
+  uint output_0 [[color(1)]];
+  float output_2 [[color(3)]];
+  int output_1 [[color(6)]];
+};
+
 struct In {
   float4 a;
   float4 b;
@@ -35,15 +44,22 @@
   (*(tint_private_vars)).P.a = ((*(tint_private_vars)).P.a + (tint_ftou(in.a[0]) + tint_ftou(in.b[1])));
 }
 
-void f_inner_1(tint_symbol_1 tint_symbol, thread tint_private_vars_struct* const tint_private_vars) {
-  In const tint_symbol_2 = {.a=tint_symbol.a, .b=tint_symbol.b};
-  f_inner(tint_symbol_2, tint_private_vars);
+f_res f_inner_1(In in, PixelLocal pixel_local_1, thread tint_private_vars_struct* const tint_private_vars) {
+  (*(tint_private_vars)).P = pixel_local_1;
+  f_inner(in, tint_private_vars);
+  f_res const tint_symbol_5 = {.output_0=(*(tint_private_vars)).P.a, .output_1=(*(tint_private_vars)).P.b, .output_2=(*(tint_private_vars)).P.c};
+  return tint_symbol_5;
 }
 
-fragment f_res f(tint_symbol_1 tint_symbol [[stage_in]], PixelLocal pixel_local_1) {
+fragment tint_symbol_2 f(tint_symbol_1 tint_symbol [[stage_in]]) {
   thread tint_private_vars_struct tint_private_vars = {};
-  tint_private_vars.P = pixel_local_1;
-  f_inner_1(tint_symbol, &(tint_private_vars));
-  return {.output_0=tint_private_vars.P.a, .output_1=tint_private_vars.P.b, .output_2=tint_private_vars.P.c};
+  In const tint_symbol_3 = {.a=tint_symbol.a, .b=tint_symbol.b};
+  PixelLocal const tint_symbol_4 = {.a=tint_symbol.a_1, .b=tint_symbol.b_1, .c=tint_symbol.c};
+  f_res const inner_result = f_inner_1(tint_symbol_3, tint_symbol_4, &(tint_private_vars));
+  tint_symbol_2 wrapper_result = {};
+  wrapper_result.output_0 = inner_result.output_0;
+  wrapper_result.output_1 = inner_result.output_1;
+  wrapper_result.output_2 = inner_result.output_2;
+  return wrapper_result;
 }
 
diff --git a/test/tint/extensions/pixel_local/entry_point_use/multiple_outputs/multiple_attachments.wgsl.expected.msl b/test/tint/extensions/pixel_local/entry_point_use/multiple_outputs/multiple_attachments.wgsl.expected.msl
index fb1717d..ab70287 100644
--- a/test/tint/extensions/pixel_local/entry_point_use/multiple_outputs/multiple_attachments.wgsl.expected.msl
+++ b/test/tint/extensions/pixel_local/entry_point_use/multiple_outputs/multiple_attachments.wgsl.expected.msl
@@ -2,9 +2,9 @@
 
 using namespace metal;
 struct PixelLocal {
-  uint a [[color(1)]];
-  int b [[color(6)]];
-  float c [[color(3)]];
+  uint a;
+  int b;
+  float c;
 };
 
 struct tint_private_vars_struct {
@@ -12,18 +12,27 @@
 };
 
 struct f_res {
-  uint output_0 [[color(1)]];
-  int output_1 [[color(6)]];
-  float output_2 [[color(3)]];
-  float4 output_3 [[color(0)]];
-  float4 output_4 [[color(2)]];
-  float4 output_5 [[color(4)]];
+  uint output_0;
+  int output_1;
+  float output_2;
+  float4 output_3;
+  float4 output_4;
+  float4 output_5;
 };
 
-struct tint_symbol {
-  float4 x;
-  float4 y;
-  float4 z;
+struct tint_symbol_1 {
+  uint a [[color(1)]];
+  float c [[color(3)]];
+  int b [[color(6)]];
+};
+
+struct tint_symbol_2 {
+  float4 output_3 [[color(0)]];
+  uint output_0 [[color(1)]];
+  float4 output_4 [[color(2)]];
+  float output_2 [[color(3)]];
+  float4 output_5 [[color(4)]];
+  int output_1 [[color(6)]];
 };
 
 struct Out {
@@ -34,23 +43,28 @@
 
 Out f_inner(thread tint_private_vars_struct* const tint_private_vars) {
   (*(tint_private_vars)).P.a = ((*(tint_private_vars)).P.a + 42u);
-  Out const tint_symbol_1 = Out{.x=float4(10.0f), .y=float4(20.0f), .z=float4(30.0f)};
-  return tint_symbol_1;
+  Out const tint_symbol_5 = Out{.x=float4(10.0f), .y=float4(20.0f), .z=float4(30.0f)};
+  return tint_symbol_5;
 }
 
-tint_symbol f_inner_1(thread tint_private_vars_struct* const tint_private_vars) {
-  Out const inner_result = f_inner(tint_private_vars);
-  tint_symbol wrapper_result = {};
-  wrapper_result.x = inner_result.x;
-  wrapper_result.y = inner_result.y;
-  wrapper_result.z = inner_result.z;
-  return wrapper_result;
+f_res f_inner_1(PixelLocal pixel_local_1, thread tint_private_vars_struct* const tint_private_vars) {
+  (*(tint_private_vars)).P = pixel_local_1;
+  Out const result = f_inner(tint_private_vars);
+  f_res const tint_symbol_4 = {.output_0=(*(tint_private_vars)).P.a, .output_1=(*(tint_private_vars)).P.b, .output_2=(*(tint_private_vars)).P.c, .output_3=result.x, .output_4=result.y, .output_5=result.z};
+  return tint_symbol_4;
 }
 
-fragment f_res f(PixelLocal pixel_local_1) {
+fragment tint_symbol_2 f(tint_symbol_1 tint_symbol [[stage_in]]) {
   thread tint_private_vars_struct tint_private_vars = {};
-  tint_private_vars.P = pixel_local_1;
-  tint_symbol const result = f_inner_1(&(tint_private_vars));
-  return {.output_0=tint_private_vars.P.a, .output_1=tint_private_vars.P.b, .output_2=tint_private_vars.P.c, .output_3=result.x, .output_4=result.y, .output_5=result.z};
+  PixelLocal const tint_symbol_3 = {.a=tint_symbol.a, .b=tint_symbol.b, .c=tint_symbol.c};
+  f_res const inner_result = f_inner_1(tint_symbol_3, &(tint_private_vars));
+  tint_symbol_2 wrapper_result = {};
+  wrapper_result.output_0 = inner_result.output_0;
+  wrapper_result.output_1 = inner_result.output_1;
+  wrapper_result.output_2 = inner_result.output_2;
+  wrapper_result.output_3 = inner_result.output_3;
+  wrapper_result.output_4 = inner_result.output_4;
+  wrapper_result.output_5 = inner_result.output_5;
+  return wrapper_result;
 }
 
diff --git a/test/tint/extensions/pixel_local/entry_point_use/multiple_outputs/single_attachment.wgsl.expected.msl b/test/tint/extensions/pixel_local/entry_point_use/multiple_outputs/single_attachment.wgsl.expected.msl
index 5fc419e..ea74af1 100644
--- a/test/tint/extensions/pixel_local/entry_point_use/multiple_outputs/single_attachment.wgsl.expected.msl
+++ b/test/tint/extensions/pixel_local/entry_point_use/multiple_outputs/single_attachment.wgsl.expected.msl
@@ -2,7 +2,7 @@
 
 using namespace metal;
 struct PixelLocal {
-  uint a [[color(1)]];
+  uint a;
 };
 
 struct tint_private_vars_struct {
@@ -10,16 +10,21 @@
 };
 
 struct f_res {
-  uint output_0 [[color(1)]];
-  float4 output_1 [[color(0)]];
-  float4 output_2 [[color(2)]];
-  float4 output_3 [[color(3)]];
+  uint output_0;
+  float4 output_1;
+  float4 output_2;
+  float4 output_3;
 };
 
-struct tint_symbol {
-  float4 x;
-  float4 y;
-  float4 z;
+struct tint_symbol_1 {
+  uint a [[color(1)]];
+};
+
+struct tint_symbol_2 {
+  float4 output_1 [[color(0)]];
+  uint output_0 [[color(1)]];
+  float4 output_2 [[color(2)]];
+  float4 output_3 [[color(3)]];
 };
 
 struct Out {
@@ -30,23 +35,26 @@
 
 Out f_inner(thread tint_private_vars_struct* const tint_private_vars) {
   (*(tint_private_vars)).P.a = ((*(tint_private_vars)).P.a + 42u);
-  Out const tint_symbol_1 = Out{.x=float4(10.0f), .y=float4(20.0f), .z=float4(30.0f)};
-  return tint_symbol_1;
+  Out const tint_symbol_5 = Out{.x=float4(10.0f), .y=float4(20.0f), .z=float4(30.0f)};
+  return tint_symbol_5;
 }
 
-tint_symbol f_inner_1(thread tint_private_vars_struct* const tint_private_vars) {
-  Out const inner_result = f_inner(tint_private_vars);
-  tint_symbol wrapper_result = {};
-  wrapper_result.x = inner_result.x;
-  wrapper_result.y = inner_result.y;
-  wrapper_result.z = inner_result.z;
-  return wrapper_result;
+f_res f_inner_1(PixelLocal pixel_local_1, thread tint_private_vars_struct* const tint_private_vars) {
+  (*(tint_private_vars)).P = pixel_local_1;
+  Out const result = f_inner(tint_private_vars);
+  f_res const tint_symbol_4 = {.output_0=(*(tint_private_vars)).P.a, .output_1=result.x, .output_2=result.y, .output_3=result.z};
+  return tint_symbol_4;
 }
 
-fragment f_res f(PixelLocal pixel_local_1) {
+fragment tint_symbol_2 f(tint_symbol_1 tint_symbol [[stage_in]]) {
   thread tint_private_vars_struct tint_private_vars = {};
-  tint_private_vars.P = pixel_local_1;
-  tint_symbol const result = f_inner_1(&(tint_private_vars));
-  return {.output_0=tint_private_vars.P.a, .output_1=result.x, .output_2=result.y, .output_3=result.z};
+  PixelLocal const tint_symbol_3 = {.a=tint_symbol.a};
+  f_res const inner_result = f_inner_1(tint_symbol_3, &(tint_private_vars));
+  tint_symbol_2 wrapper_result = {};
+  wrapper_result.output_0 = inner_result.output_0;
+  wrapper_result.output_1 = inner_result.output_1;
+  wrapper_result.output_2 = inner_result.output_2;
+  wrapper_result.output_3 = inner_result.output_3;
+  return wrapper_result;
 }
 
diff --git a/test/tint/extensions/pixel_local/entry_point_use/one_output/multiple_attachments.wgsl.expected.msl b/test/tint/extensions/pixel_local/entry_point_use/one_output/multiple_attachments.wgsl.expected.msl
index c8a44f9..be6e407 100644
--- a/test/tint/extensions/pixel_local/entry_point_use/one_output/multiple_attachments.wgsl.expected.msl
+++ b/test/tint/extensions/pixel_local/entry_point_use/one_output/multiple_attachments.wgsl.expected.msl
@@ -2,9 +2,9 @@
 
 using namespace metal;
 struct PixelLocal {
-  uint a [[color(1)]];
-  int b [[color(6)]];
-  float c [[color(3)]];
+  uint a;
+  int b;
+  float c;
 };
 
 struct tint_private_vars_struct {
@@ -12,14 +12,23 @@
 };
 
 struct f_res {
-  uint output_0 [[color(1)]];
-  int output_1 [[color(6)]];
-  float output_2 [[color(3)]];
-  float4 output_3 [[color(0)]];
+  uint output_0;
+  int output_1;
+  float output_2;
+  float4 output_3;
 };
 
-struct tint_symbol {
-  float4 value;
+struct tint_symbol_1 {
+  uint a [[color(1)]];
+  float c [[color(3)]];
+  int b [[color(6)]];
+};
+
+struct tint_symbol_2 {
+  float4 output_3 [[color(0)]];
+  uint output_0 [[color(1)]];
+  float output_2 [[color(3)]];
+  int output_1 [[color(6)]];
 };
 
 float4 f_inner(thread tint_private_vars_struct* const tint_private_vars) {
@@ -27,17 +36,22 @@
   return float4(2.0f);
 }
 
-tint_symbol f_inner_1(thread tint_private_vars_struct* const tint_private_vars) {
-  float4 const inner_result = f_inner(tint_private_vars);
-  tint_symbol wrapper_result = {};
-  wrapper_result.value = inner_result;
-  return wrapper_result;
+f_res f_inner_1(PixelLocal pixel_local_1, thread tint_private_vars_struct* const tint_private_vars) {
+  (*(tint_private_vars)).P = pixel_local_1;
+  float4 const result = f_inner(tint_private_vars);
+  f_res const tint_symbol_4 = {.output_0=(*(tint_private_vars)).P.a, .output_1=(*(tint_private_vars)).P.b, .output_2=(*(tint_private_vars)).P.c, .output_3=result};
+  return tint_symbol_4;
 }
 
-fragment f_res f(PixelLocal pixel_local_1) {
+fragment tint_symbol_2 f(tint_symbol_1 tint_symbol [[stage_in]]) {
   thread tint_private_vars_struct tint_private_vars = {};
-  tint_private_vars.P = pixel_local_1;
-  tint_symbol const result = f_inner_1(&(tint_private_vars));
-  return {.output_0=tint_private_vars.P.a, .output_1=tint_private_vars.P.b, .output_2=tint_private_vars.P.c, .output_3=result.value};
+  PixelLocal const tint_symbol_3 = {.a=tint_symbol.a, .b=tint_symbol.b, .c=tint_symbol.c};
+  f_res const inner_result = f_inner_1(tint_symbol_3, &(tint_private_vars));
+  tint_symbol_2 wrapper_result = {};
+  wrapper_result.output_0 = inner_result.output_0;
+  wrapper_result.output_1 = inner_result.output_1;
+  wrapper_result.output_2 = inner_result.output_2;
+  wrapper_result.output_3 = inner_result.output_3;
+  return wrapper_result;
 }
 
diff --git a/test/tint/extensions/pixel_local/entry_point_use/one_output/single_attachment.wgsl.expected.msl b/test/tint/extensions/pixel_local/entry_point_use/one_output/single_attachment.wgsl.expected.msl
index 1300a70..740ffc3 100644
--- a/test/tint/extensions/pixel_local/entry_point_use/one_output/single_attachment.wgsl.expected.msl
+++ b/test/tint/extensions/pixel_local/entry_point_use/one_output/single_attachment.wgsl.expected.msl
@@ -2,7 +2,7 @@
 
 using namespace metal;
 struct PixelLocal {
-  uint a [[color(1)]];
+  uint a;
 };
 
 struct tint_private_vars_struct {
@@ -10,12 +10,17 @@
 };
 
 struct f_res {
-  uint output_0 [[color(1)]];
-  float4 output_1 [[color(0)]];
+  uint output_0;
+  float4 output_1;
 };
 
-struct tint_symbol {
-  float4 value;
+struct tint_symbol_1 {
+  uint a [[color(1)]];
+};
+
+struct tint_symbol_2 {
+  float4 output_1 [[color(0)]];
+  uint output_0 [[color(1)]];
 };
 
 float4 f_inner(thread tint_private_vars_struct* const tint_private_vars) {
@@ -23,17 +28,20 @@
   return float4(2.0f);
 }
 
-tint_symbol f_inner_1(thread tint_private_vars_struct* const tint_private_vars) {
-  float4 const inner_result = f_inner(tint_private_vars);
-  tint_symbol wrapper_result = {};
-  wrapper_result.value = inner_result;
-  return wrapper_result;
+f_res f_inner_1(PixelLocal pixel_local_1, thread tint_private_vars_struct* const tint_private_vars) {
+  (*(tint_private_vars)).P = pixel_local_1;
+  float4 const result = f_inner(tint_private_vars);
+  f_res const tint_symbol_4 = {.output_0=(*(tint_private_vars)).P.a, .output_1=result};
+  return tint_symbol_4;
 }
 
-fragment f_res f(PixelLocal pixel_local_1) {
+fragment tint_symbol_2 f(tint_symbol_1 tint_symbol [[stage_in]]) {
   thread tint_private_vars_struct tint_private_vars = {};
-  tint_private_vars.P = pixel_local_1;
-  tint_symbol const result = f_inner_1(&(tint_private_vars));
-  return {.output_0=tint_private_vars.P.a, .output_1=result.value};
+  PixelLocal const tint_symbol_3 = {.a=tint_symbol.a};
+  f_res const inner_result = f_inner_1(tint_symbol_3, &(tint_private_vars));
+  tint_symbol_2 wrapper_result = {};
+  wrapper_result.output_0 = inner_result.output_0;
+  wrapper_result.output_1 = inner_result.output_1;
+  return wrapper_result;
 }
 
diff --git a/test/tint/extensions/pixel_local/entry_point_use/zero_outputs/multiple_attachments.wgsl.expected.msl b/test/tint/extensions/pixel_local/entry_point_use/zero_outputs/multiple_attachments.wgsl.expected.msl
index b12ffe8..d379070 100644
--- a/test/tint/extensions/pixel_local/entry_point_use/zero_outputs/multiple_attachments.wgsl.expected.msl
+++ b/test/tint/extensions/pixel_local/entry_point_use/zero_outputs/multiple_attachments.wgsl.expected.msl
@@ -2,9 +2,9 @@
 
 using namespace metal;
 struct PixelLocal {
-  uint a [[color(1)]];
-  int b [[color(6)]];
-  float c [[color(3)]];
+  uint a;
+  int b;
+  float c;
 };
 
 struct tint_private_vars_struct {
@@ -12,19 +12,42 @@
 };
 
 struct f_res {
+  uint output_0;
+  int output_1;
+  float output_2;
+};
+
+struct tint_symbol_1 {
+  uint a [[color(1)]];
+  float c [[color(3)]];
+  int b [[color(6)]];
+};
+
+struct tint_symbol_2 {
   uint output_0 [[color(1)]];
-  int output_1 [[color(6)]];
   float output_2 [[color(3)]];
+  int output_1 [[color(6)]];
 };
 
 void f_inner(thread tint_private_vars_struct* const tint_private_vars) {
   (*(tint_private_vars)).P.a = ((*(tint_private_vars)).P.a + 42u);
 }
 
-fragment f_res f(PixelLocal pixel_local_1) {
+f_res f_inner_1(PixelLocal pixel_local_1, thread tint_private_vars_struct* const tint_private_vars) {
+  (*(tint_private_vars)).P = pixel_local_1;
+  f_inner(tint_private_vars);
+  f_res const tint_symbol_4 = {.output_0=(*(tint_private_vars)).P.a, .output_1=(*(tint_private_vars)).P.b, .output_2=(*(tint_private_vars)).P.c};
+  return tint_symbol_4;
+}
+
+fragment tint_symbol_2 f(tint_symbol_1 tint_symbol [[stage_in]]) {
   thread tint_private_vars_struct tint_private_vars = {};
-  tint_private_vars.P = pixel_local_1;
-  f_inner(&(tint_private_vars));
-  return {.output_0=tint_private_vars.P.a, .output_1=tint_private_vars.P.b, .output_2=tint_private_vars.P.c};
+  PixelLocal const tint_symbol_3 = {.a=tint_symbol.a, .b=tint_symbol.b, .c=tint_symbol.c};
+  f_res const inner_result = f_inner_1(tint_symbol_3, &(tint_private_vars));
+  tint_symbol_2 wrapper_result = {};
+  wrapper_result.output_0 = inner_result.output_0;
+  wrapper_result.output_1 = inner_result.output_1;
+  wrapper_result.output_2 = inner_result.output_2;
+  return wrapper_result;
 }
 
diff --git a/test/tint/extensions/pixel_local/entry_point_use/zero_outputs/single_attachment.wgsl.expected.msl b/test/tint/extensions/pixel_local/entry_point_use/zero_outputs/single_attachment.wgsl.expected.msl
index f86668b..cf26f91 100644
--- a/test/tint/extensions/pixel_local/entry_point_use/zero_outputs/single_attachment.wgsl.expected.msl
+++ b/test/tint/extensions/pixel_local/entry_point_use/zero_outputs/single_attachment.wgsl.expected.msl
@@ -2,7 +2,7 @@
 
 using namespace metal;
 struct PixelLocal {
-  uint a [[color(1)]];
+  uint a;
 };
 
 struct tint_private_vars_struct {
@@ -10,6 +10,14 @@
 };
 
 struct f_res {
+  uint output_0;
+};
+
+struct tint_symbol_1 {
+  uint a [[color(1)]];
+};
+
+struct tint_symbol_2 {
   uint output_0 [[color(1)]];
 };
 
@@ -17,10 +25,19 @@
   (*(tint_private_vars)).P.a = ((*(tint_private_vars)).P.a + 42u);
 }
 
-fragment f_res f(PixelLocal pixel_local_1) {
+f_res f_inner_1(PixelLocal pixel_local_1, thread tint_private_vars_struct* const tint_private_vars) {
+  (*(tint_private_vars)).P = pixel_local_1;
+  f_inner(tint_private_vars);
+  f_res const tint_symbol_4 = {.output_0=(*(tint_private_vars)).P.a};
+  return tint_symbol_4;
+}
+
+fragment tint_symbol_2 f(tint_symbol_1 tint_symbol [[stage_in]]) {
   thread tint_private_vars_struct tint_private_vars = {};
-  tint_private_vars.P = pixel_local_1;
-  f_inner(&(tint_private_vars));
-  return {.output_0=tint_private_vars.P.a};
+  PixelLocal const tint_symbol_3 = {.a=tint_symbol.a};
+  f_res const inner_result = f_inner_1(tint_symbol_3, &(tint_private_vars));
+  tint_symbol_2 wrapper_result = {};
+  wrapper_result.output_0 = inner_result.output_0;
+  return wrapper_result;
 }
 
diff --git a/test/tint/extensions/pixel_local/indirect_use/multiple_outputs/multiple_attachments.wgsl.expected.msl b/test/tint/extensions/pixel_local/indirect_use/multiple_outputs/multiple_attachments.wgsl.expected.msl
index 30fd975..e092b7d 100644
--- a/test/tint/extensions/pixel_local/indirect_use/multiple_outputs/multiple_attachments.wgsl.expected.msl
+++ b/test/tint/extensions/pixel_local/indirect_use/multiple_outputs/multiple_attachments.wgsl.expected.msl
@@ -2,9 +2,9 @@
 
 using namespace metal;
 struct PixelLocal {
-  uint a [[color(1)]];
-  int b [[color(6)]];
-  float c [[color(3)]];
+  uint a;
+  int b;
+  float c;
 };
 
 struct tint_private_vars_struct {
@@ -12,18 +12,27 @@
 };
 
 struct f_res {
-  uint output_0 [[color(1)]];
-  int output_1 [[color(6)]];
-  float output_2 [[color(3)]];
-  float4 output_3 [[color(0)]];
-  float4 output_4 [[color(2)]];
-  float4 output_5 [[color(4)]];
+  uint output_0;
+  int output_1;
+  float output_2;
+  float4 output_3;
+  float4 output_4;
+  float4 output_5;
 };
 
-struct tint_symbol {
-  float4 x;
-  float4 y;
-  float4 z;
+struct tint_symbol_1 {
+  uint a [[color(1)]];
+  float c [[color(3)]];
+  int b [[color(6)]];
+};
+
+struct tint_symbol_2 {
+  float4 output_3 [[color(0)]];
+  uint output_0 [[color(1)]];
+  float4 output_4 [[color(2)]];
+  float output_2 [[color(3)]];
+  float4 output_5 [[color(4)]];
+  int output_1 [[color(6)]];
 };
 
 struct Out {
@@ -48,23 +57,28 @@
 
 Out f_inner(thread tint_private_vars_struct* const tint_private_vars) {
   f2(tint_private_vars);
-  Out const tint_symbol_1 = Out{.x=float4(10.0f), .y=float4(20.0f), .z=float4(30.0f)};
-  return tint_symbol_1;
+  Out const tint_symbol_5 = Out{.x=float4(10.0f), .y=float4(20.0f), .z=float4(30.0f)};
+  return tint_symbol_5;
 }
 
-tint_symbol f_inner_1(thread tint_private_vars_struct* const tint_private_vars) {
-  Out const inner_result = f_inner(tint_private_vars);
-  tint_symbol wrapper_result = {};
-  wrapper_result.x = inner_result.x;
-  wrapper_result.y = inner_result.y;
-  wrapper_result.z = inner_result.z;
-  return wrapper_result;
+f_res f_inner_1(PixelLocal pixel_local_1, thread tint_private_vars_struct* const tint_private_vars) {
+  (*(tint_private_vars)).P = pixel_local_1;
+  Out const result = f_inner(tint_private_vars);
+  f_res const tint_symbol_4 = {.output_0=(*(tint_private_vars)).P.a, .output_1=(*(tint_private_vars)).P.b, .output_2=(*(tint_private_vars)).P.c, .output_3=result.x, .output_4=result.y, .output_5=result.z};
+  return tint_symbol_4;
 }
 
-fragment f_res f(PixelLocal pixel_local_1) {
+fragment tint_symbol_2 f(tint_symbol_1 tint_symbol [[stage_in]]) {
   thread tint_private_vars_struct tint_private_vars = {};
-  tint_private_vars.P = pixel_local_1;
-  tint_symbol const result = f_inner_1(&(tint_private_vars));
-  return {.output_0=tint_private_vars.P.a, .output_1=tint_private_vars.P.b, .output_2=tint_private_vars.P.c, .output_3=result.x, .output_4=result.y, .output_5=result.z};
+  PixelLocal const tint_symbol_3 = {.a=tint_symbol.a, .b=tint_symbol.b, .c=tint_symbol.c};
+  f_res const inner_result = f_inner_1(tint_symbol_3, &(tint_private_vars));
+  tint_symbol_2 wrapper_result = {};
+  wrapper_result.output_0 = inner_result.output_0;
+  wrapper_result.output_1 = inner_result.output_1;
+  wrapper_result.output_2 = inner_result.output_2;
+  wrapper_result.output_3 = inner_result.output_3;
+  wrapper_result.output_4 = inner_result.output_4;
+  wrapper_result.output_5 = inner_result.output_5;
+  return wrapper_result;
 }
 
diff --git a/test/tint/extensions/pixel_local/indirect_use/multiple_outputs/single_attachment.wgsl.expected.msl b/test/tint/extensions/pixel_local/indirect_use/multiple_outputs/single_attachment.wgsl.expected.msl
index 25974dd..ac023fe 100644
--- a/test/tint/extensions/pixel_local/indirect_use/multiple_outputs/single_attachment.wgsl.expected.msl
+++ b/test/tint/extensions/pixel_local/indirect_use/multiple_outputs/single_attachment.wgsl.expected.msl
@@ -2,7 +2,7 @@
 
 using namespace metal;
 struct PixelLocal {
-  uint a [[color(1)]];
+  uint a;
 };
 
 struct tint_private_vars_struct {
@@ -10,16 +10,21 @@
 };
 
 struct f_res {
-  uint output_0 [[color(1)]];
-  float4 output_1 [[color(0)]];
-  float4 output_2 [[color(2)]];
-  float4 output_3 [[color(3)]];
+  uint output_0;
+  float4 output_1;
+  float4 output_2;
+  float4 output_3;
 };
 
-struct tint_symbol {
-  float4 x;
-  float4 y;
-  float4 z;
+struct tint_symbol_1 {
+  uint a [[color(1)]];
+};
+
+struct tint_symbol_2 {
+  float4 output_1 [[color(0)]];
+  uint output_0 [[color(1)]];
+  float4 output_2 [[color(2)]];
+  float4 output_3 [[color(3)]];
 };
 
 struct Out {
@@ -44,23 +49,26 @@
 
 Out f_inner(thread tint_private_vars_struct* const tint_private_vars) {
   f2(tint_private_vars);
-  Out const tint_symbol_1 = Out{.x=float4(10.0f), .y=float4(20.0f), .z=float4(30.0f)};
-  return tint_symbol_1;
+  Out const tint_symbol_5 = Out{.x=float4(10.0f), .y=float4(20.0f), .z=float4(30.0f)};
+  return tint_symbol_5;
 }
 
-tint_symbol f_inner_1(thread tint_private_vars_struct* const tint_private_vars) {
-  Out const inner_result = f_inner(tint_private_vars);
-  tint_symbol wrapper_result = {};
-  wrapper_result.x = inner_result.x;
-  wrapper_result.y = inner_result.y;
-  wrapper_result.z = inner_result.z;
-  return wrapper_result;
+f_res f_inner_1(PixelLocal pixel_local_1, thread tint_private_vars_struct* const tint_private_vars) {
+  (*(tint_private_vars)).P = pixel_local_1;
+  Out const result = f_inner(tint_private_vars);
+  f_res const tint_symbol_4 = {.output_0=(*(tint_private_vars)).P.a, .output_1=result.x, .output_2=result.y, .output_3=result.z};
+  return tint_symbol_4;
 }
 
-fragment f_res f(PixelLocal pixel_local_1) {
+fragment tint_symbol_2 f(tint_symbol_1 tint_symbol [[stage_in]]) {
   thread tint_private_vars_struct tint_private_vars = {};
-  tint_private_vars.P = pixel_local_1;
-  tint_symbol const result = f_inner_1(&(tint_private_vars));
-  return {.output_0=tint_private_vars.P.a, .output_1=result.x, .output_2=result.y, .output_3=result.z};
+  PixelLocal const tint_symbol_3 = {.a=tint_symbol.a};
+  f_res const inner_result = f_inner_1(tint_symbol_3, &(tint_private_vars));
+  tint_symbol_2 wrapper_result = {};
+  wrapper_result.output_0 = inner_result.output_0;
+  wrapper_result.output_1 = inner_result.output_1;
+  wrapper_result.output_2 = inner_result.output_2;
+  wrapper_result.output_3 = inner_result.output_3;
+  return wrapper_result;
 }
 
diff --git a/test/tint/extensions/pixel_local/indirect_use/one_output/multiple_attachments.wgsl.expected.msl b/test/tint/extensions/pixel_local/indirect_use/one_output/multiple_attachments.wgsl.expected.msl
index 8e356a7..03cfffa 100644
--- a/test/tint/extensions/pixel_local/indirect_use/one_output/multiple_attachments.wgsl.expected.msl
+++ b/test/tint/extensions/pixel_local/indirect_use/one_output/multiple_attachments.wgsl.expected.msl
@@ -2,9 +2,9 @@
 
 using namespace metal;
 struct PixelLocal {
-  uint a [[color(1)]];
-  int b [[color(6)]];
-  float c [[color(3)]];
+  uint a;
+  int b;
+  float c;
 };
 
 struct tint_private_vars_struct {
@@ -12,14 +12,23 @@
 };
 
 struct f_res {
-  uint output_0 [[color(1)]];
-  int output_1 [[color(6)]];
-  float output_2 [[color(3)]];
-  float4 output_3 [[color(0)]];
+  uint output_0;
+  int output_1;
+  float output_2;
+  float4 output_3;
 };
 
-struct tint_symbol {
-  float4 value;
+struct tint_symbol_1 {
+  uint a [[color(1)]];
+  float c [[color(3)]];
+  int b [[color(6)]];
+};
+
+struct tint_symbol_2 {
+  float4 output_3 [[color(0)]];
+  uint output_0 [[color(1)]];
+  float output_2 [[color(3)]];
+  int output_1 [[color(6)]];
 };
 
 void f0(thread tint_private_vars_struct* const tint_private_vars) {
@@ -41,17 +50,22 @@
   return float4(2.0f);
 }
 
-tint_symbol f_inner_1(thread tint_private_vars_struct* const tint_private_vars) {
-  float4 const inner_result = f_inner(tint_private_vars);
-  tint_symbol wrapper_result = {};
-  wrapper_result.value = inner_result;
-  return wrapper_result;
+f_res f_inner_1(PixelLocal pixel_local_1, thread tint_private_vars_struct* const tint_private_vars) {
+  (*(tint_private_vars)).P = pixel_local_1;
+  float4 const result = f_inner(tint_private_vars);
+  f_res const tint_symbol_4 = {.output_0=(*(tint_private_vars)).P.a, .output_1=(*(tint_private_vars)).P.b, .output_2=(*(tint_private_vars)).P.c, .output_3=result};
+  return tint_symbol_4;
 }
 
-fragment f_res f(PixelLocal pixel_local_1) {
+fragment tint_symbol_2 f(tint_symbol_1 tint_symbol [[stage_in]]) {
   thread tint_private_vars_struct tint_private_vars = {};
-  tint_private_vars.P = pixel_local_1;
-  tint_symbol const result = f_inner_1(&(tint_private_vars));
-  return {.output_0=tint_private_vars.P.a, .output_1=tint_private_vars.P.b, .output_2=tint_private_vars.P.c, .output_3=result.value};
+  PixelLocal const tint_symbol_3 = {.a=tint_symbol.a, .b=tint_symbol.b, .c=tint_symbol.c};
+  f_res const inner_result = f_inner_1(tint_symbol_3, &(tint_private_vars));
+  tint_symbol_2 wrapper_result = {};
+  wrapper_result.output_0 = inner_result.output_0;
+  wrapper_result.output_1 = inner_result.output_1;
+  wrapper_result.output_2 = inner_result.output_2;
+  wrapper_result.output_3 = inner_result.output_3;
+  return wrapper_result;
 }
 
diff --git a/test/tint/extensions/pixel_local/indirect_use/one_output/single_attachment.wgsl.expected.msl b/test/tint/extensions/pixel_local/indirect_use/one_output/single_attachment.wgsl.expected.msl
index 8637100..e1e9416 100644
--- a/test/tint/extensions/pixel_local/indirect_use/one_output/single_attachment.wgsl.expected.msl
+++ b/test/tint/extensions/pixel_local/indirect_use/one_output/single_attachment.wgsl.expected.msl
@@ -2,7 +2,7 @@
 
 using namespace metal;
 struct PixelLocal {
-  uint a [[color(1)]];
+  uint a;
 };
 
 struct tint_private_vars_struct {
@@ -10,12 +10,17 @@
 };
 
 struct f_res {
-  uint output_0 [[color(1)]];
-  float4 output_1 [[color(0)]];
+  uint output_0;
+  float4 output_1;
 };
 
-struct tint_symbol {
-  float4 value;
+struct tint_symbol_1 {
+  uint a [[color(1)]];
+};
+
+struct tint_symbol_2 {
+  float4 output_1 [[color(0)]];
+  uint output_0 [[color(1)]];
 };
 
 void f0(thread tint_private_vars_struct* const tint_private_vars) {
@@ -37,17 +42,20 @@
   return float4(2.0f);
 }
 
-tint_symbol f_inner_1(thread tint_private_vars_struct* const tint_private_vars) {
-  float4 const inner_result = f_inner(tint_private_vars);
-  tint_symbol wrapper_result = {};
-  wrapper_result.value = inner_result;
-  return wrapper_result;
+f_res f_inner_1(PixelLocal pixel_local_1, thread tint_private_vars_struct* const tint_private_vars) {
+  (*(tint_private_vars)).P = pixel_local_1;
+  float4 const result = f_inner(tint_private_vars);
+  f_res const tint_symbol_4 = {.output_0=(*(tint_private_vars)).P.a, .output_1=result};
+  return tint_symbol_4;
 }
 
-fragment f_res f(PixelLocal pixel_local_1) {
+fragment tint_symbol_2 f(tint_symbol_1 tint_symbol [[stage_in]]) {
   thread tint_private_vars_struct tint_private_vars = {};
-  tint_private_vars.P = pixel_local_1;
-  tint_symbol const result = f_inner_1(&(tint_private_vars));
-  return {.output_0=tint_private_vars.P.a, .output_1=result.value};
+  PixelLocal const tint_symbol_3 = {.a=tint_symbol.a};
+  f_res const inner_result = f_inner_1(tint_symbol_3, &(tint_private_vars));
+  tint_symbol_2 wrapper_result = {};
+  wrapper_result.output_0 = inner_result.output_0;
+  wrapper_result.output_1 = inner_result.output_1;
+  return wrapper_result;
 }
 
diff --git a/test/tint/extensions/pixel_local/indirect_use/zero_outputs/multiple_attachments.wgsl.expected.msl b/test/tint/extensions/pixel_local/indirect_use/zero_outputs/multiple_attachments.wgsl.expected.msl
index 6e843eb..e4a325e 100644
--- a/test/tint/extensions/pixel_local/indirect_use/zero_outputs/multiple_attachments.wgsl.expected.msl
+++ b/test/tint/extensions/pixel_local/indirect_use/zero_outputs/multiple_attachments.wgsl.expected.msl
@@ -2,9 +2,9 @@
 
 using namespace metal;
 struct PixelLocal {
-  uint a [[color(1)]];
-  int b [[color(6)]];
-  float c [[color(3)]];
+  uint a;
+  int b;
+  float c;
 };
 
 struct tint_private_vars_struct {
@@ -12,9 +12,21 @@
 };
 
 struct f_res {
+  uint output_0;
+  int output_1;
+  float output_2;
+};
+
+struct tint_symbol_1 {
+  uint a [[color(1)]];
+  float c [[color(3)]];
+  int b [[color(6)]];
+};
+
+struct tint_symbol_2 {
   uint output_0 [[color(1)]];
-  int output_1 [[color(6)]];
   float output_2 [[color(3)]];
+  int output_1 [[color(6)]];
 };
 
 void f0(thread tint_private_vars_struct* const tint_private_vars) {
@@ -35,10 +47,21 @@
   f2(tint_private_vars);
 }
 
-fragment f_res f(PixelLocal pixel_local_1) {
+f_res f_inner_1(PixelLocal pixel_local_1, thread tint_private_vars_struct* const tint_private_vars) {
+  (*(tint_private_vars)).P = pixel_local_1;
+  f_inner(tint_private_vars);
+  f_res const tint_symbol_4 = {.output_0=(*(tint_private_vars)).P.a, .output_1=(*(tint_private_vars)).P.b, .output_2=(*(tint_private_vars)).P.c};
+  return tint_symbol_4;
+}
+
+fragment tint_symbol_2 f(tint_symbol_1 tint_symbol [[stage_in]]) {
   thread tint_private_vars_struct tint_private_vars = {};
-  tint_private_vars.P = pixel_local_1;
-  f_inner(&(tint_private_vars));
-  return {.output_0=tint_private_vars.P.a, .output_1=tint_private_vars.P.b, .output_2=tint_private_vars.P.c};
+  PixelLocal const tint_symbol_3 = {.a=tint_symbol.a, .b=tint_symbol.b, .c=tint_symbol.c};
+  f_res const inner_result = f_inner_1(tint_symbol_3, &(tint_private_vars));
+  tint_symbol_2 wrapper_result = {};
+  wrapper_result.output_0 = inner_result.output_0;
+  wrapper_result.output_1 = inner_result.output_1;
+  wrapper_result.output_2 = inner_result.output_2;
+  return wrapper_result;
 }
 
diff --git a/test/tint/extensions/pixel_local/indirect_use/zero_outputs/single_attachment.wgsl.expected.msl b/test/tint/extensions/pixel_local/indirect_use/zero_outputs/single_attachment.wgsl.expected.msl
index 5c5a3a2..2338030 100644
--- a/test/tint/extensions/pixel_local/indirect_use/zero_outputs/single_attachment.wgsl.expected.msl
+++ b/test/tint/extensions/pixel_local/indirect_use/zero_outputs/single_attachment.wgsl.expected.msl
@@ -2,7 +2,7 @@
 
 using namespace metal;
 struct PixelLocal {
-  uint a [[color(1)]];
+  uint a;
 };
 
 struct tint_private_vars_struct {
@@ -10,6 +10,14 @@
 };
 
 struct f_res {
+  uint output_0;
+};
+
+struct tint_symbol_1 {
+  uint a [[color(1)]];
+};
+
+struct tint_symbol_2 {
   uint output_0 [[color(1)]];
 };
 
@@ -31,10 +39,19 @@
   f2(tint_private_vars);
 }
 
-fragment f_res f(PixelLocal pixel_local_1) {
+f_res f_inner_1(PixelLocal pixel_local_1, thread tint_private_vars_struct* const tint_private_vars) {
+  (*(tint_private_vars)).P = pixel_local_1;
+  f_inner(tint_private_vars);
+  f_res const tint_symbol_4 = {.output_0=(*(tint_private_vars)).P.a};
+  return tint_symbol_4;
+}
+
+fragment tint_symbol_2 f(tint_symbol_1 tint_symbol [[stage_in]]) {
   thread tint_private_vars_struct tint_private_vars = {};
-  tint_private_vars.P = pixel_local_1;
-  f_inner(&(tint_private_vars));
-  return {.output_0=tint_private_vars.P.a};
+  PixelLocal const tint_symbol_3 = {.a=tint_symbol.a};
+  f_res const inner_result = f_inner_1(tint_symbol_3, &(tint_private_vars));
+  tint_symbol_2 wrapper_result = {};
+  wrapper_result.output_0 = inner_result.output_0;
+  return wrapper_result;
 }
 
diff --git a/test/tint/extensions/pixel_local/ptr/local.wgsl.expected.msl b/test/tint/extensions/pixel_local/ptr/local.wgsl.expected.msl
index 97a249a..b936068 100644
--- a/test/tint/extensions/pixel_local/ptr/local.wgsl.expected.msl
+++ b/test/tint/extensions/pixel_local/ptr/local.wgsl.expected.msl
@@ -2,7 +2,7 @@
 
 using namespace metal;
 struct PixelLocal {
-  uint a [[color(1)]];
+  uint a;
 };
 
 struct tint_private_vars_struct {
@@ -10,6 +10,14 @@
 };
 
 struct f_res {
+  uint output_0;
+};
+
+struct tint_symbol_1 {
+  uint a [[color(1)]];
+};
+
+struct tint_symbol_2 {
   uint output_0 [[color(1)]];
 };
 
@@ -17,10 +25,19 @@
   (*(tint_private_vars)).V.a = 42u;
 }
 
-fragment f_res f(PixelLocal pixel_local_1) {
+f_res f_inner_1(PixelLocal pixel_local_1, thread tint_private_vars_struct* const tint_private_vars) {
+  (*(tint_private_vars)).V = pixel_local_1;
+  f_inner(tint_private_vars);
+  f_res const tint_symbol_4 = {.output_0=(*(tint_private_vars)).V.a};
+  return tint_symbol_4;
+}
+
+fragment tint_symbol_2 f(tint_symbol_1 tint_symbol [[stage_in]]) {
   thread tint_private_vars_struct tint_private_vars = {};
-  tint_private_vars.V = pixel_local_1;
-  f_inner(&(tint_private_vars));
-  return {.output_0=tint_private_vars.V.a};
+  PixelLocal const tint_symbol_3 = {.a=tint_symbol.a};
+  f_res const inner_result = f_inner_1(tint_symbol_3, &(tint_private_vars));
+  tint_symbol_2 wrapper_result = {};
+  wrapper_result.output_0 = inner_result.output_0;
+  return wrapper_result;
 }