tint/transform/std140: Correctly handle nested / bare matrices

Fixed tint:1673
Fixed tint:1674

Change-Id: Ifa5d2a69131cc1e4679d4d43143f857c7ba46dbd
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/102640
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: David Neto <dneto@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/src/tint/transform/std140.cc b/src/tint/transform/std140.cc
index e6f070b..06b4f5d 100644
--- a/src/tint/transform/std140.cc
+++ b/src/tint/transform/std140.cc
@@ -34,6 +34,14 @@
 
 namespace {
 
+/// UniformVariable is used by Std140::State::AccessIndex to indicate the root uniform variable
+struct UniformVariable {};
+
+/// Inequality operator for UniformVariable
+bool operator!=(const UniformVariable&, const UniformVariable&) {
+    return false;
+}
+
 /// DynamicIndex is used by Std140::State::AccessIndex to indicate a runtime-expression index
 struct DynamicIndex {
     size_t slot;  // The index of the expression in Std140::State::AccessChain::dynamic_indices
@@ -48,6 +56,14 @@
 
 namespace tint::utils {
 
+/// Hasher specialization for UniformVariable
+template <>
+struct Hasher<UniformVariable> {
+    /// The hash function for the UniformVariable
+    /// @return the hash for the given UniformVariable
+    size_t operator()(const UniformVariable&) const { return 0; }
+};
+
 /// Hasher specialization for DynamicIndex
 template <>
 struct Hasher<DynamicIndex> {
@@ -69,9 +85,9 @@
 
     /// Runs the transform
     void Run() {
-        // Begin by creating forked structures for any struct that is used as a uniform buffer, that
+        // Begin by creating forked types for any type that is used as a uniform buffer, that
         // either directly or transitively contains a matrix that needs splitting for std140 layout.
-        ForkStructs();
+        ForkTypes();
 
         // Next, replace all the uniform variables to use the forked types.
         ReplaceUniformVarTypes();
@@ -105,19 +121,43 @@
     /// @returns true if this transform should be run for the given program
     /// @param program the program to inspect
     static bool ShouldRun(const Program* program) {
+        // Returns true if the type needs to be forked for std140 usage.
+        auto needs_fork = [&](const sem::Type* ty) {
+            while (auto* arr = ty->As<sem::Array>()) {
+                ty = arr->ElemType();
+            }
+            if (auto* mat = ty->As<sem::Matrix>()) {
+                if (MatrixNeedsDecomposing(mat)) {
+                    return true;
+                }
+            }
+            return false;
+        };
+
+        // Scan structures for members that need forking
         for (auto* ty : program->Types()) {
             if (auto* str = ty->As<sem::Struct>()) {
                 if (str->UsedAs(ast::StorageClass::kUniform)) {
                     for (auto* member : str->Members()) {
-                        if (auto* mat = member->Type()->As<sem::Matrix>()) {
-                            if (MatrixNeedsDecomposing(mat)) {
-                                return true;
-                            }
+                        if (needs_fork(member->Type())) {
+                            return true;
                         }
                     }
                 }
             }
         }
+
+        // Scan uniform variables that have types that need forking
+        for (auto* decl : program->AST().GlobalVariables()) {
+            auto* global = program->Sem().Get(decl);
+            if (global->StorageClass() == ast::StorageClass::kUniform) {
+                if (needs_fork(global->Type()->UnwrapRef())) {
+                    return true;
+                }
+            }
+        }
+
+        // If we reach here, no uniform variables use a type that needs forking for std140 layout
         return false;
     }
 
@@ -127,12 +167,11 @@
 
     /// AccessIndex describes a single access in an access chain.
     /// The access is one of:
-    /// u32          - a static member index on a struct, static array index, static matrix column
-    ///                index, static vector element index.
-    /// DynamicIndex - a runtime-expression index on an array, matrix column selection, or vector
-    ///                element index.
-    /// Swizzle      - a static vector swizzle.
-    using AccessIndex = std::variant<u32, DynamicIndex, Swizzle>;
+    /// UniformVariable - the root uniform variable.
+    /// u32             - a static index on a struct, array index, matrix column or vector element.
+    /// DynamicIndex    - a runtime index on an array, matrix column, or vector element.
+    /// Swizzle         - a static vector swizzle.
+    using AccessIndex = std::variant<UniformVariable, u32, DynamicIndex, Swizzle>;
 
     /// A vector of AccessIndex.
     using AccessIndices = utils::Vector<AccessIndex, 8>;
@@ -182,7 +221,19 @@
     // Map of structure member in ctx.src of a matrix type, to list of decomposed column
     // members in ctx.dst.
     utils::Hashmap<const sem::StructMember*, utils::Vector<const ast::StructMember*, 4>, 8>
-        std140_mats;
+        std140_mat_members;
+
+    /// Describes a matrix that has been forked to a std140-structure holding the decomposed column
+    /// vectors of the matrix.
+    struct Std140Matrix {
+        /// The decomposed structure name (in ctx.dst)
+        Symbol name;
+        /// The column vector structure member names (in ctx.dst)
+        utils::Vector<Symbol, 4> columns;
+    };
+
+    // Map of matrix type in ctx.src, to decomposed column structure in ctx.dst.
+    utils::Hashmap<const sem::Matrix*, Std140Matrix, 8> std140_mats;
 
     /// AccessChain describes a chain of access expressions to uniform buffer variable.
     struct AccessChain {
@@ -209,11 +260,11 @@
     /// TODO(crbug.com/tint/1502): This may need adjusting for `f16` matrices.
     static bool MatrixNeedsDecomposing(const sem::Matrix* mat) { return mat->ColumnStride() == 8; }
 
-    /// ForkStructs walks the structures in dependency order, forking structures that are used as
-    /// uniform buffers which (transitively) use matrices that need std140 decomposition to column
-    /// vectors.
-    /// Populates the #std140_mats map and #std140_structs set.
-    void ForkStructs() {
+    /// ForkTypes walks the user-declared types in dependency order, forking structures that are
+    /// used as uniform buffers which (transitively) use matrices that need std140 decomposition to
+    /// column vectors. Populates the #std140_mat_members map, #std140_structs set and #std140_mats
+    /// map (via Std140Type()).
+    void ForkTypes() {
         // For each module scope declaration...
         for (auto* global : ctx.src->Sem().Module()->DependencyOrderedDeclarations()) {
             // Check to see if this is a structure used by a uniform buffer...
@@ -229,51 +280,30 @@
                             // Structure member of matrix type needs decomposition.
                             fork_std140 = true;
                             // Replace the member with column vectors.
-                            const auto num_columns = mat->columns();
                             const auto name_prefix = PrefixForUniqueNames(
-                                str->Declaration(), member->Name(), num_columns);
+                                str->Declaration(), member->Name(), mat->columns());
+
                             // Build a struct member for each column of the matrix
-                            utils::Vector<const ast::StructMember*, 4> column_members;
-                            for (uint32_t i = 0; i < num_columns; i++) {
-                                utils::Vector<const ast::Attribute*, 1> attributes;
-                                if ((i == 0) && mat->Align() != member->Align()) {
-                                    // The matrix was @align() annotated with a larger alignment
-                                    // than the natural alignment for the matrix. This extra padding
-                                    // needs to be applied to the first column vector.
-                                    attributes.Push(b.MemberAlign(u32(member->Align())));
-                                }
-                                if ((i == num_columns - 1) && mat->Size() != member->Size()) {
-                                    // The matrix was @size() annotated with a larger size than the
-                                    // natural size for the matrix. This extra padding needs to be
-                                    // applied to the last column vector.
-                                    attributes.Push(b.MemberSize(
-                                        AInt(member->Size() -
-                                             mat->ColumnType()->Size() * (num_columns - 1))));
-                                }
+                            auto column_members = DecomposedMatrixStructMembers(
+                                mat, name_prefix, member->Align(), member->Size());
 
-                                // Build the member
-                                const auto col_name = name_prefix + std::to_string(i);
-                                const auto* col_ty = CreateASTTypeFor(ctx, mat->ColumnType());
-                                const auto* col_member =
-                                    ctx.dst->Member(col_name, col_ty, std::move(attributes));
-                                // Add the member to the forked structure
-                                members.Push(col_member);
-                                // Record the member for std140_mats
-                                column_members.Push(col_member);
+                            // Add the member to the forked structure
+                            for (auto* column_member : column_members) {
+                                members.Push(column_member);
                             }
-                            std140_mats.Add(member, std::move(column_members));
-                            continue;
-                        }
-                    }
+                            // Record that this matrix member was replaced with the N column
+                            // members.
+                            std140_mat_members.Add(member, std::move(column_members));
 
-                    // Is the member part of a struct that has been forked for std140-layout?
-                    if (auto* std140_ty = Std140Type(member->Type())) {
-                        // Yes - use this type for the forked structure member.
+                            continue;  // Next member
+                        }
+                    } else if (auto* std140_ty = Std140Type(member->Type())) {
+                        // Member is of a type that requires forking for std140-layout
                         fork_std140 = true;
                         auto attrs = ctx.Clone(member->Declaration()->attributes);
                         members.Push(
                             b.Member(sym.NameFor(member->Name()), std140_ty, std::move(attrs)));
-                        continue;
+                        continue;  // Next member
                     }
 
                     // Nothing special about this member.
@@ -314,6 +344,7 @@
                     if (auto* std140_ty = Std140Type(v->Type()->UnwrapRef())) {
                         ctx.Replace(global->type, std140_ty);
                         std140_uniforms.Add(v);
+                        continue;
                     }
                 }
             }
@@ -355,10 +386,11 @@
         }
     }
 
-    /// @returns a new, forked std140 AST type for the corresponding non-forked semantic type. If
-    /// the
-    ///          semantic type is not split for std140-layout, then nullptr is returned.
-    const ast::Type* Std140Type(const sem::Type* ty) const {
+    /// @returns a new, forked std140 AST type for the corresponding non-forked semantic type.
+    ///          If the semantic type is not split for std140-layout, then nullptr is returned.
+    /// @note will construct new std140 structures to hold decomposed matrices, populating
+    ///       #std140_mats.
+    const ast::Type* Std140Type(const sem::Type* ty) {
         return Switch(
             ty,  //
             [&](const sem::Struct* str) -> const ast::Type* {
@@ -367,6 +399,24 @@
                 }
                 return nullptr;
             },
+            [&](const sem::Matrix* mat) -> const ast::Type* {
+                if (MatrixNeedsDecomposing(mat)) {
+                    auto std140_mat = std140_mats.GetOrCreate(mat, [&] {
+                        auto name = b.Symbols().New("mat" + std::to_string(mat->columns()) + "x" +
+                                                    std::to_string(mat->rows()) + "_" +
+                                                    ctx.src->FriendlyName(mat->type()));
+                        auto members =
+                            DecomposedMatrixStructMembers(mat, "col", mat->Align(), mat->Size());
+                        b.Structure(name, members);
+                        return Std140Matrix{
+                            name,
+                            utils::Transform(members, [&](auto* member) { return member->symbol; }),
+                        };
+                    });
+                    return b.ty.type_name(std140_mat.name);
+                }
+                return nullptr;
+            },
             [&](const sem::Array* arr) -> const ast::Type* {
                 if (auto* std140 = Std140Type(arr->ElemType())) {
                     utils::Vector<const ast::Attribute*, 1> attrs;
@@ -380,6 +430,46 @@
             });
     }
 
+    /// @param mat the matrix to decompose (in ctx.src)
+    /// @param name_prefix the name prefix to apply to each of the returned column vector members.
+    /// @param align the alignment in bytes of the matrix.
+    /// @param size the size in bytes of the matrix.
+    /// @returns a vector of decomposed matrix column vectors as structure members (in ctx.dst).
+    utils::Vector<const ast::StructMember*, 4> DecomposedMatrixStructMembers(
+        const sem::Matrix* mat,
+        const std::string& name_prefix,
+        uint32_t align,
+        uint32_t size) {
+        // Replace the member with column vectors.
+        const auto num_columns = mat->columns();
+        // Build a struct member for each column of the matrix
+        utils::Vector<const ast::StructMember*, 4> out;
+        for (uint32_t i = 0; i < num_columns; i++) {
+            utils::Vector<const ast::Attribute*, 1> attributes;
+            if ((i == 0) && mat->Align() != align) {
+                // The matrix was @align() annotated with a larger alignment
+                // than the natural alignment for the matrix. This extra padding
+                // needs to be applied to the first column vector.
+                attributes.Push(b.MemberAlign(u32(align)));
+            }
+            if ((i == num_columns - 1) && mat->Size() != size) {
+                // The matrix was @size() annotated with a larger size than the
+                // natural size for the matrix. This extra padding needs to be
+                // applied to the last column vector.
+                attributes.Push(
+                    b.MemberSize(AInt(size - mat->ColumnType()->Size() * (num_columns - 1))));
+            }
+
+            // Build the member
+            const auto col_name = name_prefix + std::to_string(i);
+            const auto* col_ty = CreateASTTypeFor(ctx, mat->ColumnType());
+            const auto* col_member = ctx.dst->Member(col_name, col_ty, std::move(attributes));
+            // Record the member for std140_mat_members
+            out.Push(col_member);
+        }
+        return out;
+    }
+
     /// Walks the @p ast_expr, constructing and returning an AccessChain.
     /// @returns an AccessChain if the expression is an access to a std140-forked uniform buffer,
     ///          otherwise returns a std::nullopt.
@@ -406,11 +496,13 @@
                 [&](const sem::VariableUser* user) {
                     if (user->Variable() == access.var) {
                         // Walked all the way to the source variable. We're done traversing.
+                        access.indices.Push(UniformVariable{});
                         return Action::kStop;
                     }
                     if (user->Variable()->Type()->Is<sem::Pointer>()) {
                         // Found a pointer. As the source variable is a uniform buffer variable,
-                        // this must be a pointer-let. Continue traversing from the let initializer.
+                        // this must be a pointer-let. Continue traversing from the let
+                        // initializer.
                         expr = user->Variable()->Constructor();
                         return Action::kContinue;
                     }
@@ -421,7 +513,7 @@
                 },
                 [&](const sem::StructMemberAccess* a) {
                     // Is this a std140 decomposed matrix?
-                    if (!access.std140_mat_ty && std140_mats.Contains(a->Member())) {
+                    if (std140_mat_members.Contains(a->Member())) {
                         // Record this on the access.
                         access.std140_mat_idx = access.indices.Length();
                         access.std140_mat_ty = expr->Type()->UnwrapRef()->As<sem::Matrix>();
@@ -440,6 +532,15 @@
                         access.dynamic_indices.Push(a->Index());
                     }
                     expr = a->Object();
+
+                    // Is the object a std140 decomposed matrix?
+                    if (auto* mat = expr->Type()->UnwrapRef()->As<sem::Matrix>()) {
+                        if (std140_mats.Contains(mat)) {
+                            // Record this on the access.
+                            access.std140_mat_idx = access.indices.Length();
+                            access.std140_mat_ty = mat;
+                        }
+                    }
                     return Action::kContinue;
                 },
                 [&](const sem::Swizzle* s) {
@@ -512,8 +613,13 @@
             ty,  //
             [&](const sem::Struct* str) { return sym.NameFor(str->Name()); },
             [&](const sem::Array* arr) {
-                return "arr_" + std::to_string(arr->Count()) + "_" + ConvertSuffix(arr->ElemType());
+                return "arr" + std::to_string(arr->Count()) + "_" + ConvertSuffix(arr->ElemType());
             },
+            [&](const sem::Matrix* mat) {
+                return "mat" + std::to_string(mat->columns()) + "x" + std::to_string(mat->rows()) +
+                       "_" + ConvertSuffix(mat->type());
+            },
+            [&](const sem::F32*) { return "f32"; },
             [&](Default) {
                 TINT_ICE(Transform, b.Diagnostics())
                     << "unhandled type for conversion name: " << ctx.src->FriendlyName(ty);
@@ -523,15 +629,15 @@
 
     /// Generates and returns an expression that loads the value from a std140 uniform buffer,
     /// converting the final result to a non-std140 type.
-    /// @param access the access chain from a uniform buffer to the value to load.
-    const ast::Expression* LoadWithConvert(const AccessChain& access) {
-        const ast::Expression* expr = b.Expr(sym.NameFor(access.var->Declaration()->symbol));
-        const sem::Type* ty = access.var->Type()->UnwrapRef();
+    /// @param chain the access chain from a uniform buffer to the value to load.
+    const ast::Expression* LoadWithConvert(const AccessChain& chain) {
+        const ast::Expression* expr = nullptr;
+        const sem::Type* ty = nullptr;
         auto dynamic_index = [&](size_t idx) {
-            return ctx.Clone(access.dynamic_indices[idx]->Declaration());
+            return ctx.Clone(chain.dynamic_indices[idx]->Declaration());
         };
-        for (auto index : access.indices) {
-            auto [new_expr, new_ty, _] = BuildAccessExpr(expr, ty, index, dynamic_index);
+        for (size_t i = 0; i < chain.indices.Length(); i++) {
+            auto [new_expr, new_ty, _] = BuildAccessExpr(expr, ty, chain, i, dynamic_index);
             expr = new_expr;
             ty = new_ty;
         }
@@ -559,11 +665,11 @@
             Switch(
                 ty,  //
                 [&](const sem::Struct* str) {
-                    // Convert each of the structure members using either a converter function call,
-                    // or by reassembling a std140 matrix from column vector members.
+                    // Convert each of the structure members using either a converter function
+                    // call, or by reassembling a std140 matrix from column vector members.
                     utils::Vector<const ast::Expression*, 8> args;
                     for (auto* member : str->Members()) {
-                        if (auto* col_members = std140_mats.Find(member)) {
+                        if (auto* col_members = std140_mat_members.Find(member)) {
                             // std140 decomposed matrix. Reassemble.
                             auto* mat_ty = CreateASTTypeFor(ctx, member->Type());
                             auto mat_args =
@@ -578,13 +684,28 @@
                                         b.MemberAccessor(param, sym.NameFor(member->Name()))));
                         }
                     }
-                    auto* converted = b.Construct(CreateASTTypeFor(ctx, ty), std::move(args));
-                    stmts.Push(b.Return(converted));
+                    stmts.Push(b.Return(b.Construct(CreateASTTypeFor(ctx, ty), std::move(args))));
+                },  //
+                [&](const sem::Matrix* mat) {
+                    // Reassemble a std140 matrix from the structure of column vector members.
+                    if (auto std140_mat = std140_mats.Get(mat)) {
+                        utils::Vector<const ast::Expression*, 8> args;
+                        // std140 decomposed matrix. Reassemble.
+                        auto* mat_ty = CreateASTTypeFor(ctx, mat);
+                        auto mat_args = utils::Transform(std140_mat->columns, [&](Symbol name) {
+                            return b.MemberAccessor(param, name);
+                        });
+                        stmts.Push(b.Return(b.Construct(mat_ty, std::move(mat_args))));
+                    } else {
+                        TINT_ICE(Transform, b.Diagnostics())
+                            << "failed to find std140 matrix info for: "
+                            << ctx.src->FriendlyName(ty);
+                    }
                 },  //
                 [&](const sem::Array* arr) {
-                    // Converting an array. Create a function var for the converted array, and loop
-                    // over the input elements, converting each and assigning the result to the
-                    // local array.
+                    // Converting an array. Create a function var for the converted array, and
+                    // loop over the input elements, converting each and assigning the result to
+                    // the local array.
                     auto* var = b.Var("arr", CreateASTTypeFor(ctx, ty));
                     auto* i = b.Var("i", b.ty.u32());
                     auto* dst_el = b.IndexAccessor(var, i);
@@ -646,38 +767,57 @@
 
     /// Loads a part of a std140-decomposed matrix from a uniform buffer, inline (without calling a
     /// helper function).
-    /// @param access the access chain from the uniform buffer to part of the matrix (column,
+    /// @param chain the access chain from the uniform buffer to part of the matrix (column,
     ///               column-swizzle, or element).
     /// @note The matrix column must be statically indexed to use this method.
     /// @returns the loaded value expression.
-    const ast::Expression* LoadSubMatrixInline(const AccessChain& access) {
-        const ast::Expression* expr = b.Expr(ctx.Clone(access.var->Declaration()->symbol));
-        const sem::Type* ty = access.var->Type()->UnwrapRef();
+    const ast::Expression* LoadSubMatrixInline(const AccessChain& chain) {
         // Method for generating dynamic index expressions.
         // As this is inline, we can just clone the expression.
         auto dynamic_index = [&](size_t idx) {
-            return ctx.Clone(access.dynamic_indices[idx]->Declaration());
+            return ctx.Clone(chain.dynamic_indices[idx]->Declaration());
         };
-        for (size_t i = 0; i < access.indices.Length(); i++) {
-            if (i == access.std140_mat_idx) {
-                // Access is to the std140 decomposed matrix.
-                // As this is accessing only part of the matrix, we just need to pick the right
-                // column vector member.
-                auto mat_member_idx = std::get<u32>(access.indices[i]);
-                auto* mat_member = ty->As<sem::Struct>()->Members()[mat_member_idx];
-                auto mat_columns = *std140_mats.Get(mat_member);
-                auto column_idx = std::get<u32>(access.indices[i + 1]);
-                expr = b.MemberAccessor(expr, mat_columns[column_idx]->symbol);
-                ty = mat_member->Type()->As<sem::Matrix>()->ColumnType();
-                // We've consumed both the matrix member access and the column access. Increment i.
-                i++;
-            } else {
-                // Access is to something that is not a decomposed matrix.
-                auto [new_expr, new_ty, _] =
-                    BuildAccessExpr(expr, ty, access.indices[i], dynamic_index);
-                expr = new_expr;
-                ty = new_ty;
-            }
+
+        const ast::Expression* expr = nullptr;
+        const sem::Type* ty = nullptr;
+
+        // Build the expression up to, but not including the matrix member
+        auto std140_mat_idx = *chain.std140_mat_idx;
+        for (size_t i = 0; i < std140_mat_idx; i++) {
+            auto [new_expr, new_ty, _] = BuildAccessExpr(expr, ty, chain, i, dynamic_index);
+            expr = new_expr;
+            ty = new_ty;
+        }
+
+        // Access is to the std140 decomposed matrix.
+        // As this is accessing only part of the matrix, we just need to pick the right column
+        // vector member.
+        auto column_idx = std::get<u32>(chain.indices[std140_mat_idx + 1]);
+        if (auto* str = tint::As<sem::Struct>(ty)) {
+            // Structure member matrix. The columns are decomposed into the structure.
+            auto mat_member_idx = std::get<u32>(chain.indices[std140_mat_idx]);
+            auto* mat_member = str->Members()[mat_member_idx];
+            auto mat_columns = *std140_mat_members.Get(mat_member);
+            expr = b.MemberAccessor(expr, mat_columns[column_idx]->symbol);
+            ty = mat_member->Type()->As<sem::Matrix>()->ColumnType();
+        } else {
+            // Non-structure-member matrix. The columns are decomposed into a new, bespoke std140
+            // structure.
+            auto [new_expr, new_ty, _] =
+                BuildAccessExpr(expr, ty, chain, std140_mat_idx, dynamic_index);
+            expr = new_expr;
+            ty = new_ty;
+            auto* mat = ty->As<sem::Matrix>();
+            auto std140_mat = std140_mats.Get(ty->As<sem::Matrix>());
+            expr = b.MemberAccessor(expr, std140_mat->columns[column_idx]);
+            ty = mat->ColumnType();
+        }
+
+        // Build any remaining accesses into the column
+        for (size_t i = std140_mat_idx + 2; i < chain.indices.Length(); i++) {
+            auto [new_expr, new_ty, _] = BuildAccessExpr(expr, ty, chain, i, dynamic_index);
+            expr = new_expr;
+            ty = new_ty;
         }
         return expr;
     }
@@ -687,27 +827,27 @@
     /// access chain.
     /// The generated function uses a WGSL switch statement to dynamically select the decomposed
     /// matrix column.
-    /// @param access the access chain from the uniform buffer to part of the matrix (column,
+    /// @param chain the access chain from the uniform buffer to part of the matrix (column,
     ///               column-swizzle, or element).
     /// @note The matrix column must be dynamically indexed to use this method.
     /// @returns the generated function name.
-    Symbol BuildLoadPartialMatrixFn(const AccessChain& access) {
+    Symbol BuildLoadPartialMatrixFn(const AccessChain& chain) {
         // Build the dynamic index parameters
-        auto dynamic_index_params = utils::Transform(access.dynamic_indices, [&](auto*, size_t i) {
+        auto dynamic_index_params = utils::Transform(chain.dynamic_indices, [&](auto*, size_t i) {
             return b.Param("p" + std::to_string(i), b.ty.u32());
         });
         // Method for generating dynamic index expressions.
         // These are passed in as arguments to the function.
         auto dynamic_index = [&](size_t idx) { return b.Expr(dynamic_index_params[idx]->symbol); };
 
-        // Fetch the access chain indices of the matrix access and the parameter index that holds
-        // the matrix column index.
-        auto std140_mat_idx = *access.std140_mat_idx;
-        auto column_param_idx = std::get<DynamicIndex>(access.indices[std140_mat_idx + 1]).slot;
+        // Fetch the access chain indices of the matrix access and the parameter index that
+        // holds the matrix column index.
+        auto std140_mat_idx = *chain.std140_mat_idx;
+        auto column_param_idx = std::get<DynamicIndex>(chain.indices[std140_mat_idx + 1]).slot;
 
         // Begin building the function name. This is extended with logic in the loop below
         // (when column_idx == 0).
-        std::string name = "load_" + sym.NameFor(access.var->Declaration()->symbol);
+        std::string name = "load";
 
         // The switch cases
         utils::Vector<const ast::CaseStatement*, 4> cases;
@@ -716,41 +856,57 @@
         const sem::Type* ret_ty = nullptr;
 
         // Build switch() cases for each column of the matrix
-        auto num_columns = access.std140_mat_ty->columns();
+        auto num_columns = chain.std140_mat_ty->columns();
         for (uint32_t column_idx = 0; column_idx < num_columns; column_idx++) {
-            const ast::Expression* expr = b.Expr(ctx.Clone(access.var->Declaration()->symbol));
-            const sem::Type* ty = access.var->Type()->UnwrapRef();
-            // Build the expression up to, but not including the matrix member
-            for (size_t i = 0; i < access.std140_mat_idx; i++) {
+            const ast::Expression* expr = nullptr;
+            const sem::Type* ty = nullptr;
+
+            // Build the expression up to, but not including the matrix
+            for (size_t i = 0; i < std140_mat_idx; i++) {
                 auto [new_expr, new_ty, access_name] =
-                    BuildAccessExpr(expr, ty, access.indices[i], dynamic_index);
+                    BuildAccessExpr(expr, ty, chain, i, dynamic_index);
                 expr = new_expr;
                 ty = new_ty;
                 if (column_idx == 0) {
-                    name = name + "_" + access_name;
+                    name += "_" + access_name;
                 }
             }
 
-            // Get the matrix member that was dynamically accessed.
-            auto mat_member_idx = std::get<u32>(access.indices[std140_mat_idx]);
-            auto* mat_member = ty->As<sem::Struct>()->Members()[mat_member_idx];
-            auto mat_columns = *std140_mats.Get(mat_member);
-            if (column_idx == 0) {
-                name = name + +"_" + sym.NameFor(mat_member->Name()) + "_p" +
-                       std::to_string(column_param_idx);
-            }
-
-            // Build the expression to the column vector member.
-            expr = b.MemberAccessor(expr, mat_columns[column_idx]->symbol);
-            ty = mat_member->Type()->As<sem::Matrix>()->ColumnType();
-            // Build the rest of the expression, skipping over the column index.
-            for (size_t i = std140_mat_idx + 2; i < access.indices.Length(); i++) {
-                auto [new_expr, new_ty, access_name] =
-                    BuildAccessExpr(expr, ty, access.indices[i], dynamic_index);
+            if (auto* str = tint::As<sem::Struct>(ty)) {
+                // Structure member matrix. The columns are decomposed into the structure.
+                auto mat_member_idx = std::get<u32>(chain.indices[std140_mat_idx]);
+                auto* mat_member = str->Members()[mat_member_idx];
+                if (column_idx == 0) {
+                    name += "_" + sym.NameFor(mat_member->Name()) + "_p" +
+                            std::to_string(column_param_idx);
+                }
+                auto mat_columns = *std140_mat_members.Get(mat_member);
+                expr = b.MemberAccessor(expr, mat_columns[column_idx]->symbol);
+                ty = mat_member->Type()->As<sem::Matrix>()->ColumnType();
+            } else {
+                // Non-structure-member matrix. The columns are decomposed into a new, bespoke
+                // std140 structure.
+                auto [new_expr, new_ty, mat_name] =
+                    BuildAccessExpr(expr, ty, chain, std140_mat_idx, dynamic_index);
                 expr = new_expr;
                 ty = new_ty;
                 if (column_idx == 0) {
-                    name = name + "_" + access_name;
+                    name += "_" + mat_name + "_p" + std::to_string(column_param_idx);
+                }
+                auto* mat = ty->As<sem::Matrix>();
+                auto std140_mat = std140_mats.Get(ty->As<sem::Matrix>());
+                expr = b.MemberAccessor(expr, std140_mat->columns[column_idx]);
+                ty = mat->ColumnType();
+            }
+
+            // Build the rest of the expression, skipping over the column index.
+            for (size_t i = std140_mat_idx + 2; i < chain.indices.Length(); i++) {
+                auto [new_expr, new_ty, access_name] =
+                    BuildAccessExpr(expr, ty, chain, i, dynamic_index);
+                expr = new_expr;
+                ty = new_ty;
+                if (column_idx == 0) {
+                    name += "_" + access_name;
                 }
             }
 
@@ -764,7 +920,8 @@
         }
 
         // Build the default case (required in WGSL).
-        // This just returns a zero value of the return type, as the index must be out of bounds.
+        // This just returns a zero value of the return type, as the index must be out of
+        // bounds.
         cases.Push(b.DefaultCase(b.Block(b.Return(b.Construct(CreateASTTypeFor(ctx, ret_ty))))));
 
         auto* column_selector = dynamic_index(column_param_idx);
@@ -779,30 +936,30 @@
     /// Generates a function to load a whole std140-decomposed matrix from a uniform buffer.
     /// The generated function will have a parameter per dynamic (runtime-evaluated) index in the
     /// access chain.
-    /// @param access the access chain from the uniform buffer to the whole std140-decomposed
+    /// @param chain the access chain from the uniform buffer to the whole std140-decomposed
     ///        matrix.
     /// @returns the generated function name.
-    Symbol BuildLoadWholeMatrixFn(const AccessChain& access) {
+    Symbol BuildLoadWholeMatrixFn(const AccessChain& chain) {
         // Build the dynamic index parameters
-        auto dynamic_index_params = utils::Transform(access.dynamic_indices, [&](auto*, size_t i) {
+        auto dynamic_index_params = utils::Transform(chain.dynamic_indices, [&](auto*, size_t i) {
             return b.Param("p" + std::to_string(i), b.ty.u32());
         });
         // Method for generating dynamic index expressions.
         // These are passed in as arguments to the function.
         auto dynamic_index = [&](size_t idx) { return b.Expr(dynamic_index_params[idx]->symbol); };
 
-        const ast::Expression* expr = b.Expr(ctx.Clone(access.var->Declaration()->symbol));
-        std::string name = sym.NameFor(access.var->Declaration()->symbol);
-        const sem::Type* ty = access.var->Type()->UnwrapRef();
+        const ast::Expression* expr = nullptr;
+        const sem::Type* ty = nullptr;
+        std::string name = "load";
 
         // Build the expression up to, but not including the matrix member
-        auto std140_mat_idx = *access.std140_mat_idx;
+        auto std140_mat_idx = *chain.std140_mat_idx;
         for (size_t i = 0; i < std140_mat_idx; i++) {
             auto [new_expr, new_ty, access_name] =
-                BuildAccessExpr(expr, ty, access.indices[i], dynamic_index);
+                BuildAccessExpr(expr, ty, chain, i, dynamic_index);
             expr = new_expr;
             ty = new_ty;
-            name = name + "_" + access_name;
+            name += "_" + access_name;
         }
 
         utils::Vector<const ast::Statement*, 2> stmts;
@@ -811,25 +968,41 @@
         auto* let = b.Let("s", b.AddressOf(expr));
         stmts.Push(b.Decl(let));
 
-        // Gather the decomposed matrix columns
-        auto mat_member_idx = std::get<u32>(access.indices[std140_mat_idx]);
-        auto* mat_member = ty->As<sem::Struct>()->Members()[mat_member_idx];
-        auto mat_columns = *std140_mats.Get(mat_member);
-        auto columns = utils::Transform(mat_columns, [&](auto* column_member) {
-            return b.MemberAccessor(b.Deref(let), column_member->symbol);
-        });
+        utils::Vector<const ast::MemberAccessorExpression*, 4> columns;
+        if (auto* str = tint::As<sem::Struct>(ty)) {
+            // Structure member matrix. The columns are decomposed into the structure.
+            auto mat_member_idx = std::get<u32>(chain.indices[std140_mat_idx]);
+            auto* mat_member = str->Members()[mat_member_idx];
+            auto mat_columns = *std140_mat_members.Get(mat_member);
+            columns = utils::Transform(mat_columns, [&](auto* column_member) {
+                return b.MemberAccessor(b.Deref(let), column_member->symbol);
+            });
+            ty = mat_member->Type();
+            name += "_" + sym.NameFor(mat_member->Name());
+        } else {
+            // Non-structure-member matrix. The columns are decomposed into a new, bespoke
+            // std140 structure.
+            auto [new_expr, new_ty, mat_name] =
+                BuildAccessExpr(expr, ty, chain, std140_mat_idx, dynamic_index);
+            expr = new_expr;
+            auto* mat = ty->As<sem::Matrix>();
+            auto std140_mat = std140_mats.Get(ty->As<sem::Matrix>());
+            columns = utils::Transform(std140_mat->columns, [&](auto column_name) {
+                return b.MemberAccessor(b.Deref(let), column_name);
+            });
+            ty = mat;
+            name += "_" + mat_name;
+        }
 
         // Reconstruct the matrix from the columns
-        expr = b.Construct(CreateASTTypeFor(ctx, access.std140_mat_ty), std::move(columns));
-        ty = mat_member->Type();
-        name = name + "_" + sym.NameFor(mat_member->Name());
+        expr = b.Construct(CreateASTTypeFor(ctx, chain.std140_mat_ty), std::move(columns));
 
         // Have the function return the constructed matrix
         stmts.Push(b.Return(expr));
 
         // Build the function
         auto* ret_ty = CreateASTTypeFor(ctx, ty);
-        auto fn_sym = b.Symbols().New("load_" + name);
+        auto fn_sym = b.Symbols().New(name);
         b.Func(fn_sym, std::move(dynamic_index_params), ret_ty, std::move(stmts));
         return fn_sym;
     }
@@ -847,14 +1020,24 @@
     /// Builds a single access in an access chain.
     /// @param lhs the expression to index using @p access
     /// @param ty the type of the expression @p lhs
-    /// @param access the access index to perform on @p lhs
+    /// @param chain the access index to perform on @p lhs
     /// @param dynamic_index a function that obtains the i'th dynamic index
     /// @returns a ExprTypeName which holds the new expression, new type and a name segment which
     ///          can be used for creating helper function names.
     ExprTypeName BuildAccessExpr(const ast::Expression* lhs,
                                  const sem::Type* ty,
-                                 AccessIndex access,
+                                 const AccessChain& chain,
+                                 size_t index,
                                  std::function<const ast::Expression*(size_t)> dynamic_index) {
+        auto& access = chain.indices[index];
+
+        if (std::get_if<UniformVariable>(&access)) {
+            const auto* expr = b.Expr(ctx.Clone(chain.var->Declaration()->symbol));
+            const auto name = ctx.src->Symbols().NameFor(chain.var->Declaration()->symbol);
+            ty = chain.var->Type()->UnwrapRef();
+            return {expr, ty, name};
+        }
+
         if (auto* dyn_idx = std::get_if<DynamicIndex>(&access)) {
             /// The access uses a dynamic (runtime-expression) index.
             auto name = "p" + std::to_string(dyn_idx->slot);
diff --git a/src/tint/transform/std140.h b/src/tint/transform/std140.h
index f987805..f41b1e3 100644
--- a/src/tint/transform/std140.h
+++ b/src/tint/transform/std140.h
@@ -19,13 +19,12 @@
 
 namespace tint::transform {
 
-/// Std140 is a transform that forks structures used in the uniform storage class that contain
-/// `matNx2<f32>` matrices into `N`x`vec2<f32>` column vectors. Structure types that transitively
-/// use these forked structures as members are also forked. `var<uniform>` variables will use these
-/// forked structures, and expressions loading from these variables will do appropriate conversions
-/// to the regular WGSL types. As `matNx2<f32>` matrices are the only type that violate
-/// std140-layout, this transformation is sufficient to have any WGSL structure be std140-layout
-/// conformant.
+/// Std140 is a transform that forks types used in the uniform storage class that contain
+/// `matNx2<f32>` matrices into `N`x`vec2<f32>` column vectors. Types that transitively use these
+/// forked types are also forked. `var<uniform>` variables will use these forked types, and
+/// expressions loading from these variables will do appropriate conversions to the regular WGSL
+/// types. As `matNx2<f32>` matrices are the only type that violate std140-layout, this
+/// transformation is sufficient to have any WGSL structure be std140-layout conformant.
 ///
 /// @note This transform requires the PromoteSideEffectsToDecl transform to have been run first.
 class Std140 final : public Castable<Std140, Transform> {
diff --git a/src/tint/transform/std140_test.cc b/src/tint/transform/std140_test.cc
index 57e23e6..97936ad 100644
--- a/src/tint/transform/std140_test.cc
+++ b/src/tint/transform/std140_test.cc
@@ -109,7 +109,7 @@
 
     src = utils::ReplaceAll(src, "${mat}", GetParam().Mat());
 
-    EXPECT_FALSE(ShouldRun<Std140>(src));
+    EXPECT_EQ(ShouldRun<Std140>(src), GetParam().should_run);
 }
 
 INSTANTIATE_TEST_SUITE_P(Std140TestShouldRun,
@@ -129,7 +129,7 @@
 TEST_F(Std140Test, EmptyModule) {
     auto* src = R"()";
 
-    auto* expect = R"()";
+    auto* expect = src;
 
     auto got = Run<Std140>(src);
 
@@ -1037,7 +1037,7 @@
   return S(mat3x2<f32>(val.m_0, val.m_1, val.m_2));
 }
 
-fn conv_arr_3_S(val : array<S_std140, 3u>) -> array<S, 3u> {
+fn conv_arr3_S(val : array<S_std140, 3u>) -> array<S, 3u> {
   var arr : array<S, 3u>;
   for(var i : u32; (i < 3u); i = (i + 1)) {
     arr[i] = conv_S(val[i]);
@@ -1046,7 +1046,7 @@
 }
 
 fn f() {
-  let l = conv_arr_3_S(a);
+  let l = conv_arr3_S(a);
 }
 )";
 
@@ -1563,6 +1563,1330 @@
     EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(Std140Test, Mat4x2Uniform_LoadMatrix) {
+    auto* src = R"(
+@group(0) @binding(0) var<uniform> m : mat4x2<f32>;
+
+fn f() {
+  let l = m;
+}
+)";
+
+    auto* expect = R"(
+struct mat4x2_f32 {
+  col0 : vec2<f32>,
+  col1 : vec2<f32>,
+  col2 : vec2<f32>,
+  col3 : vec2<f32>,
+}
+
+@group(0) @binding(0) var<uniform> m : mat4x2_f32;
+
+fn conv_mat4x2_f32(val : mat4x2_f32) -> mat4x2<f32> {
+  return mat4x2<f32>(val.col0, val.col1, val.col2, val.col3);
+}
+
+fn f() {
+  let l = conv_mat4x2_f32(m);
+}
+)";
+
+    auto got = Run<Std140>(src);
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(Std140Test, Mat2x2Uniform_LoadColumn0) {
+    auto* src = R"(
+@group(0) @binding(0) var<uniform> a : mat2x2<f32>;
+
+fn f() {
+  let l = a[0];
+}
+)";
+
+    auto* expect = R"(
+struct mat2x2_f32 {
+  col0 : vec2<f32>,
+  col1 : vec2<f32>,
+}
+
+@group(0) @binding(0) var<uniform> a : mat2x2_f32;
+
+fn f() {
+  let l = a.col0;
+}
+)";
+
+    auto got = Run<Std140>(src);
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(Std140Test, Mat4x2Uniform_LoadColumn1) {
+    auto* src = R"(
+@group(0) @binding(0) var<uniform> a : mat4x2<f32>;
+
+fn f() {
+  let l = a[1];
+}
+)";
+
+    auto* expect = R"(
+struct mat4x2_f32 {
+  col0 : vec2<f32>,
+  col1 : vec2<f32>,
+  col2 : vec2<f32>,
+  col3 : vec2<f32>,
+}
+
+@group(0) @binding(0) var<uniform> a : mat4x2_f32;
+
+fn f() {
+  let l = a.col1;
+}
+)";
+
+    auto got = Run<Std140>(src);
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(Std140Test, Mat2x2Uniform_LoadColumnI) {
+    auto* src = R"(
+@group(0) @binding(0) var<uniform> a : mat2x2<f32>;
+
+fn f() {
+  let I = 1;
+
+  let l = a[I];
+}
+)";
+
+    auto* expect = R"(
+struct mat2x2_f32 {
+  col0 : vec2<f32>,
+  col1 : vec2<f32>,
+}
+
+@group(0) @binding(0) var<uniform> a : mat2x2_f32;
+
+fn load_a_p0(p0 : u32) -> vec2<f32> {
+  switch(p0) {
+    case 0u: {
+      return a.col0;
+    }
+    case 1u: {
+      return a.col1;
+    }
+    default: {
+      return vec2<f32>();
+    }
+  }
+}
+
+fn f() {
+  let I = 1;
+  let l = load_a_p0(u32(I));
+}
+)";
+
+    auto got = Run<Std140>(src);
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(Std140Test, Mat2x2Uniform_LoadColumn1Swizzle) {
+    auto* src = R"(
+@group(0) @binding(0) var<uniform> a : mat2x2<f32>;
+
+fn f() {
+  let l = a[1].yx;
+}
+)";
+
+    auto* expect = R"(
+struct mat2x2_f32 {
+  col0 : vec2<f32>,
+  col1 : vec2<f32>,
+}
+
+@group(0) @binding(0) var<uniform> a : mat2x2_f32;
+
+fn f() {
+  let l = a.col1.yx;
+}
+)";
+
+    auto got = Run<Std140>(src);
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(Std140Test, Mat4x2Uniform_LoadColumnISwizzle) {
+    auto* src = R"(
+@group(0) @binding(0) var<uniform> a : mat4x2<f32>;
+
+fn f() {
+  let I = 1;
+
+  let l = a[I].yx;
+}
+)";
+
+    auto* expect = R"(
+struct mat4x2_f32 {
+  col0 : vec2<f32>,
+  col1 : vec2<f32>,
+  col2 : vec2<f32>,
+  col3 : vec2<f32>,
+}
+
+@group(0) @binding(0) var<uniform> a : mat4x2_f32;
+
+fn load_a_p0_yx(p0 : u32) -> vec2<f32> {
+  switch(p0) {
+    case 0u: {
+      return a.col0.yx;
+    }
+    case 1u: {
+      return a.col1.yx;
+    }
+    case 2u: {
+      return a.col2.yx;
+    }
+    case 3u: {
+      return a.col3.yx;
+    }
+    default: {
+      return vec2<f32>();
+    }
+  }
+}
+
+fn f() {
+  let I = 1;
+  let l = load_a_p0_yx(u32(I));
+}
+)";
+
+    auto got = Run<Std140>(src);
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(Std140Test, Mat2x2Uniform_LoadColumn1Element1) {
+    auto* src = R"(
+@group(0) @binding(0) var<uniform> a : mat2x2<f32>;
+
+fn f() {
+  let l = a[1][1];
+}
+)";
+
+    auto* expect = R"(
+struct mat2x2_f32 {
+  col0 : vec2<f32>,
+  col1 : vec2<f32>,
+}
+
+@group(0) @binding(0) var<uniform> a : mat2x2_f32;
+
+fn f() {
+  let l = a.col1[1u];
+}
+)";
+
+    auto got = Run<Std140>(src);
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(Std140Test, Mat4x2Uniform_LoadColumnIElementI) {
+    auto* src = R"(
+@group(0) @binding(0) var<uniform> a : mat4x2<f32>;
+
+fn f() {
+  let I = 1;
+
+  let l = a[I][I];
+}
+)";
+
+    auto* expect = R"(
+struct mat4x2_f32 {
+  col0 : vec2<f32>,
+  col1 : vec2<f32>,
+  col2 : vec2<f32>,
+  col3 : vec2<f32>,
+}
+
+@group(0) @binding(0) var<uniform> a : mat4x2_f32;
+
+fn load_a_p0_p1(p0 : u32, p1 : u32) -> f32 {
+  switch(p0) {
+    case 0u: {
+      return a.col0[p1];
+    }
+    case 1u: {
+      return a.col1[p1];
+    }
+    case 2u: {
+      return a.col2[p1];
+    }
+    case 3u: {
+      return a.col3[p1];
+    }
+    default: {
+      return f32();
+    }
+  }
+}
+
+fn f() {
+  let I = 1;
+  let l = load_a_p0_p1(u32(I), u32(I));
+}
+)";
+
+    auto got = Run<Std140>(src);
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(Std140Test, ArrayMat2x2Uniform_LoadArray) {
+    auto* src = R"(
+@group(0) @binding(0) var<uniform> a : array<mat2x2<f32>, 3>;
+
+fn f() {
+  let l = a;
+}
+)";
+
+    auto* expect = R"(
+struct mat2x2_f32 {
+  col0 : vec2<f32>,
+  col1 : vec2<f32>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<mat2x2_f32, 3u>;
+
+fn conv_mat2x2_f32(val : mat2x2_f32) -> mat2x2<f32> {
+  return mat2x2<f32>(val.col0, val.col1);
+}
+
+fn conv_arr3_mat2x2_f32(val : array<mat2x2_f32, 3u>) -> array<mat2x2<f32>, 3u> {
+  var arr : array<mat2x2<f32>, 3u>;
+  for(var i : u32; (i < 3u); i = (i + 1)) {
+    arr[i] = conv_mat2x2_f32(val[i]);
+  }
+  return arr;
+}
+
+fn f() {
+  let l = conv_arr3_mat2x2_f32(a);
+}
+)";
+
+    auto got = Run<Std140>(src);
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(Std140Test, ArrayMat4x2Uniform_LoadMatrix0) {
+    auto* src = R"(
+@group(0) @binding(0) var<uniform> a : array<mat4x2<f32>, 3>;
+
+fn f() {
+  let l = a[0];
+}
+)";
+
+    auto* expect = R"(
+struct mat4x2_f32 {
+  col0 : vec2<f32>,
+  col1 : vec2<f32>,
+  col2 : vec2<f32>,
+  col3 : vec2<f32>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<mat4x2_f32, 3u>;
+
+fn conv_mat4x2_f32(val : mat4x2_f32) -> mat4x2<f32> {
+  return mat4x2<f32>(val.col0, val.col1, val.col2, val.col3);
+}
+
+fn f() {
+  let l = conv_mat4x2_f32(a[0u]);
+}
+)";
+
+    auto got = Run<Std140>(src);
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(Std140Test, ArrayMat2x2Uniform_LoadMatrix1) {
+    auto* src = R"(
+@group(0) @binding(0) var<uniform> a : array<mat2x2<f32>, 3>;
+
+fn f() {
+  let l = a[1];
+}
+)";
+
+    auto* expect = R"(
+struct mat2x2_f32 {
+  col0 : vec2<f32>,
+  col1 : vec2<f32>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<mat2x2_f32, 3u>;
+
+fn conv_mat2x2_f32(val : mat2x2_f32) -> mat2x2<f32> {
+  return mat2x2<f32>(val.col0, val.col1);
+}
+
+fn f() {
+  let l = conv_mat2x2_f32(a[1u]);
+}
+)";
+
+    auto got = Run<Std140>(src);
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(Std140Test, ArrayMat4x2Uniform_LoadMatrixI) {
+    auto* src = R"(
+@group(0) @binding(0) var<uniform> a : array<mat4x2<f32>, 3>;
+
+fn f() {
+  let I = 1;
+  let l = a[I];
+}
+)";
+
+    auto* expect = R"(
+struct mat4x2_f32 {
+  col0 : vec2<f32>,
+  col1 : vec2<f32>,
+  col2 : vec2<f32>,
+  col3 : vec2<f32>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<mat4x2_f32, 3u>;
+
+fn conv_mat4x2_f32(val : mat4x2_f32) -> mat4x2<f32> {
+  return mat4x2<f32>(val.col0, val.col1, val.col2, val.col3);
+}
+
+fn f() {
+  let I = 1;
+  let l = conv_mat4x2_f32(a[I]);
+}
+)";
+
+    auto got = Run<Std140>(src);
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(Std140Test, ArrayMat2x2Uniform_LoadMatrix1Column0) {
+    auto* src = R"(
+@group(0) @binding(0) var<uniform> a : array<mat2x2<f32>, 3>;
+
+fn f() {
+  let l = a[1][0];
+}
+)";
+
+    auto* expect = R"(
+struct mat2x2_f32 {
+  col0 : vec2<f32>,
+  col1 : vec2<f32>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<mat2x2_f32, 3u>;
+
+fn f() {
+  let l = a[1u].col0;
+}
+)";
+
+    auto got = Run<Std140>(src);
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(Std140Test, ArrayMat4x2Uniform_LoadMatrix0Column1) {
+    auto* src = R"(
+@group(0) @binding(0) var<uniform> a : array<mat4x2<f32>, 3>;
+
+fn f() {
+  let l = a[0][1];
+}
+)";
+
+    auto* expect = R"(
+struct mat4x2_f32 {
+  col0 : vec2<f32>,
+  col1 : vec2<f32>,
+  col2 : vec2<f32>,
+  col3 : vec2<f32>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<mat4x2_f32, 3u>;
+
+fn f() {
+  let l = a[0u].col1;
+}
+)";
+
+    auto got = Run<Std140>(src);
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(Std140Test, ArrayMat2x2Uniform_LoadMatrixIColumn1) {
+    auto* src = R"(
+@group(0) @binding(0) var<uniform> a : array<mat2x2<f32>, 3>;
+
+fn f() {
+  let I = 1;
+  let l = a[I][1];
+}
+)";
+
+    auto* expect = R"(
+struct mat2x2_f32 {
+  col0 : vec2<f32>,
+  col1 : vec2<f32>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<mat2x2_f32, 3u>;
+
+fn f() {
+  let I = 1;
+  let l = a[I].col1;
+}
+)";
+
+    auto got = Run<Std140>(src);
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(Std140Test, ArrayMat4x2Uniform_LoadMatrix1ColumnI) {
+    auto* src = R"(
+@group(0) @binding(0) var<uniform> a : array<mat4x2<f32>, 3>;
+
+fn f() {
+  let I = 1;
+  let l = a[1][I];
+}
+)";
+
+    auto* expect = R"(
+struct mat4x2_f32 {
+  col0 : vec2<f32>,
+  col1 : vec2<f32>,
+  col2 : vec2<f32>,
+  col3 : vec2<f32>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<mat4x2_f32, 3u>;
+
+fn load_a_1_p0(p0 : u32) -> vec2<f32> {
+  switch(p0) {
+    case 0u: {
+      return a[1u].col0;
+    }
+    case 1u: {
+      return a[1u].col1;
+    }
+    case 2u: {
+      return a[1u].col2;
+    }
+    case 3u: {
+      return a[1u].col3;
+    }
+    default: {
+      return vec2<f32>();
+    }
+  }
+}
+
+fn f() {
+  let I = 1;
+  let l = load_a_1_p0(u32(I));
+}
+)";
+
+    auto got = Run<Std140>(src);
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(Std140Test, ArrayArrayMat2x2Uniform_LoadArrays) {
+    auto* src = R"(
+@group(0) @binding(0) var<uniform> a : array<array<mat2x2<f32>, 3>, 4>;
+
+fn f() {
+  let l = a;
+}
+)";
+
+    auto* expect = R"(
+struct mat2x2_f32 {
+  col0 : vec2<f32>,
+  col1 : vec2<f32>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<array<mat2x2_f32, 3u>, 4u>;
+
+fn conv_mat2x2_f32(val : mat2x2_f32) -> mat2x2<f32> {
+  return mat2x2<f32>(val.col0, val.col1);
+}
+
+fn conv_arr3_mat2x2_f32(val : array<mat2x2_f32, 3u>) -> array<mat2x2<f32>, 3u> {
+  var arr : array<mat2x2<f32>, 3u>;
+  for(var i : u32; (i < 3u); i = (i + 1)) {
+    arr[i] = conv_mat2x2_f32(val[i]);
+  }
+  return arr;
+}
+
+fn conv_arr4_arr3_mat2x2_f32(val : array<array<mat2x2_f32, 3u>, 4u>) -> array<array<mat2x2<f32>, 3u>, 4u> {
+  var arr : array<array<mat2x2<f32>, 3u>, 4u>;
+  for(var i : u32; (i < 4u); i = (i + 1)) {
+    arr[i] = conv_arr3_mat2x2_f32(val[i]);
+  }
+  return arr;
+}
+
+fn f() {
+  let l = conv_arr4_arr3_mat2x2_f32(a);
+}
+)";
+
+    auto got = Run<Std140>(src);
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(Std140Test, ArrayArrayMat4x2Uniform_LoadArray0) {
+    auto* src = R"(
+@group(0) @binding(0) var<uniform> a : array<array<mat4x2<f32>, 3>, 4>;
+
+fn f() {
+  let l = a[0];
+}
+)";
+
+    auto* expect = R"(
+struct mat4x2_f32 {
+  col0 : vec2<f32>,
+  col1 : vec2<f32>,
+  col2 : vec2<f32>,
+  col3 : vec2<f32>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<array<mat4x2_f32, 3u>, 4u>;
+
+fn conv_mat4x2_f32(val : mat4x2_f32) -> mat4x2<f32> {
+  return mat4x2<f32>(val.col0, val.col1, val.col2, val.col3);
+}
+
+fn conv_arr3_mat4x2_f32(val : array<mat4x2_f32, 3u>) -> array<mat4x2<f32>, 3u> {
+  var arr : array<mat4x2<f32>, 3u>;
+  for(var i : u32; (i < 3u); i = (i + 1)) {
+    arr[i] = conv_mat4x2_f32(val[i]);
+  }
+  return arr;
+}
+
+fn f() {
+  let l = conv_arr3_mat4x2_f32(a[0u]);
+}
+)";
+
+    auto got = Run<Std140>(src);
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(Std140Test, ArrayArrayMat2x2Uniform_LoadArray1) {
+    auto* src = R"(
+@group(0) @binding(0) var<uniform> a : array<array<mat2x2<f32>, 3>,4>;
+
+fn f() {
+  let l = a[1];
+}
+)";
+
+    auto* expect = R"(
+struct mat2x2_f32 {
+  col0 : vec2<f32>,
+  col1 : vec2<f32>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<array<mat2x2_f32, 3u>, 4u>;
+
+fn conv_mat2x2_f32(val : mat2x2_f32) -> mat2x2<f32> {
+  return mat2x2<f32>(val.col0, val.col1);
+}
+
+fn conv_arr3_mat2x2_f32(val : array<mat2x2_f32, 3u>) -> array<mat2x2<f32>, 3u> {
+  var arr : array<mat2x2<f32>, 3u>;
+  for(var i : u32; (i < 3u); i = (i + 1)) {
+    arr[i] = conv_mat2x2_f32(val[i]);
+  }
+  return arr;
+}
+
+fn f() {
+  let l = conv_arr3_mat2x2_f32(a[1u]);
+}
+)";
+
+    auto got = Run<Std140>(src);
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(Std140Test, ArrayArrayMat2x2Uniform_LoadArrayI) {
+    auto* src = R"(
+@group(0) @binding(0) var<uniform> a : array<array<mat2x2<f32>, 3>,4>;
+
+fn f() {
+  let I = 1;
+  let l = a[I];
+}
+)";
+
+    auto* expect = R"(
+struct mat2x2_f32 {
+  col0 : vec2<f32>,
+  col1 : vec2<f32>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<array<mat2x2_f32, 3u>, 4u>;
+
+fn conv_mat2x2_f32(val : mat2x2_f32) -> mat2x2<f32> {
+  return mat2x2<f32>(val.col0, val.col1);
+}
+
+fn conv_arr3_mat2x2_f32(val : array<mat2x2_f32, 3u>) -> array<mat2x2<f32>, 3u> {
+  var arr : array<mat2x2<f32>, 3u>;
+  for(var i : u32; (i < 3u); i = (i + 1)) {
+    arr[i] = conv_mat2x2_f32(val[i]);
+  }
+  return arr;
+}
+
+fn f() {
+  let I = 1;
+  let l = conv_arr3_mat2x2_f32(a[I]);
+}
+)";
+
+    auto got = Run<Std140>(src);
+
+    EXPECT_EQ(expect, str(got));
+}
+TEST_F(Std140Test, ArrayArrayMat2x2Uniform_LoadMatrix12Column0) {
+    auto* src = R"(
+@group(0) @binding(0) var<uniform> a : array<array<mat2x2<f32>, 3>, 4>;
+
+fn f() {
+  let l = a[1][2][0];
+}
+)";
+
+    auto* expect = R"(
+struct mat2x2_f32 {
+  col0 : vec2<f32>,
+  col1 : vec2<f32>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<array<mat2x2_f32, 3u>, 4u>;
+
+fn f() {
+  let l = a[1u][2u].col0;
+}
+)";
+
+    auto got = Run<Std140>(src);
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(Std140Test, ArrayArrayMat4x2Uniform_LoadMatrix2IColumn1) {
+    auto* src = R"(
+@group(0) @binding(0) var<uniform> a : array<array<mat4x2<f32>, 3>, 4>;
+
+fn f() {
+  let I = 1;
+  let l = a[2][I][1];
+}
+)";
+
+    auto* expect = R"(
+struct mat4x2_f32 {
+  col0 : vec2<f32>,
+  col1 : vec2<f32>,
+  col2 : vec2<f32>,
+  col3 : vec2<f32>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<array<mat4x2_f32, 3u>, 4u>;
+
+fn f() {
+  let I = 1;
+  let l = a[2u][I].col1;
+}
+)";
+
+    auto got = Run<Std140>(src);
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(Std140Test, ArrayArrayMat2x2Uniform_LoadMatrixI2Column1) {
+    auto* src = R"(
+@group(0) @binding(0) var<uniform> a : array<array<mat2x2<f32>, 3>, 4>;
+
+fn f() {
+  let I = 1;
+  let l = a[I][2][1];
+}
+)";
+
+    auto* expect = R"(
+struct mat2x2_f32 {
+  col0 : vec2<f32>,
+  col1 : vec2<f32>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<array<mat2x2_f32, 3u>, 4u>;
+
+fn f() {
+  let I = 1;
+  let l = a[I][2u].col1;
+}
+)";
+
+    auto got = Run<Std140>(src);
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(Std140Test, ArrayArrayMat2x2Uniform_LoadMatrixIIColumn1) {
+    auto* src = R"(
+@group(0) @binding(0) var<uniform> a : array<array<mat2x2<f32>, 3>, 4>;
+
+fn f() {
+  let I = 1;
+  let l = a[I][I][1];
+}
+)";
+
+    auto* expect = R"(
+struct mat2x2_f32 {
+  col0 : vec2<f32>,
+  col1 : vec2<f32>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<array<mat2x2_f32, 3u>, 4u>;
+
+fn f() {
+  let I = 1;
+  let l = a[I][I].col1;
+}
+)";
+
+    auto got = Run<Std140>(src);
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(Std140Test, ArrayArrayMat4x2Uniform_LoadMatrix12ColumnI) {
+    auto* src = R"(
+@group(0) @binding(0) var<uniform> a : array<array<mat4x2<f32>, 3>, 4>;
+
+fn f() {
+  let I = 1;
+  let l = a[1][2][I];
+}
+)";
+
+    auto* expect = R"(
+struct mat4x2_f32 {
+  col0 : vec2<f32>,
+  col1 : vec2<f32>,
+  col2 : vec2<f32>,
+  col3 : vec2<f32>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<array<mat4x2_f32, 3u>, 4u>;
+
+fn load_a_1_2_p0(p0 : u32) -> vec2<f32> {
+  switch(p0) {
+    case 0u: {
+      return a[1u][2u].col0;
+    }
+    case 1u: {
+      return a[1u][2u].col1;
+    }
+    case 2u: {
+      return a[1u][2u].col2;
+    }
+    case 3u: {
+      return a[1u][2u].col3;
+    }
+    default: {
+      return vec2<f32>();
+    }
+  }
+}
+
+fn f() {
+  let I = 1;
+  let l = load_a_1_2_p0(u32(I));
+}
+)";
+
+    auto got = Run<Std140>(src);
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(Std140Test, StructArrayMat2x2Uniform_LoadStruct) {
+    auto* src = R"(
+struct S {
+  a : array<mat2x2<f32>, 3>,
+};
+
+@group(0) @binding(0) var<uniform> s : S;
+
+fn f() {
+  let l = s;
+}
+)";
+
+    auto* expect = R"(
+struct mat2x2_f32 {
+  col0 : vec2<f32>,
+  col1 : vec2<f32>,
+}
+
+struct S {
+  a : array<mat2x2<f32>, 3>,
+}
+
+struct S_std140 {
+  a : array<mat2x2_f32, 3u>,
+}
+
+@group(0) @binding(0) var<uniform> s : S_std140;
+
+fn conv_mat2x2_f32(val : mat2x2_f32) -> mat2x2<f32> {
+  return mat2x2<f32>(val.col0, val.col1);
+}
+
+fn conv_arr3_mat2x2_f32(val : array<mat2x2_f32, 3u>) -> array<mat2x2<f32>, 3u> {
+  var arr : array<mat2x2<f32>, 3u>;
+  for(var i : u32; (i < 3u); i = (i + 1)) {
+    arr[i] = conv_mat2x2_f32(val[i]);
+  }
+  return arr;
+}
+
+fn conv_S(val : S_std140) -> S {
+  return S(conv_arr3_mat2x2_f32(val.a));
+}
+
+fn f() {
+  let l = conv_S(s);
+}
+)";
+
+    auto got = Run<Std140>(src);
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(Std140Test, StructArrayMat2x2Uniform_LoadArray) {
+    auto* src = R"(
+struct S {
+  a : array<mat2x2<f32>, 3>,
+};
+
+@group(0) @binding(0) var<uniform> s : S;
+
+fn f() {
+  let l = s.a;
+}
+)";
+
+    auto* expect = R"(
+struct mat2x2_f32 {
+  col0 : vec2<f32>,
+  col1 : vec2<f32>,
+}
+
+struct S {
+  a : array<mat2x2<f32>, 3>,
+}
+
+struct S_std140 {
+  a : array<mat2x2_f32, 3u>,
+}
+
+@group(0) @binding(0) var<uniform> s : S_std140;
+
+fn conv_mat2x2_f32(val : mat2x2_f32) -> mat2x2<f32> {
+  return mat2x2<f32>(val.col0, val.col1);
+}
+
+fn conv_arr3_mat2x2_f32(val : array<mat2x2_f32, 3u>) -> array<mat2x2<f32>, 3u> {
+  var arr : array<mat2x2<f32>, 3u>;
+  for(var i : u32; (i < 3u); i = (i + 1)) {
+    arr[i] = conv_mat2x2_f32(val[i]);
+  }
+  return arr;
+}
+
+fn f() {
+  let l = conv_arr3_mat2x2_f32(s.a);
+}
+)";
+
+    auto got = Run<Std140>(src);
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(Std140Test, StructArrayMat4x2Uniform_LoadMatrix0) {
+    auto* src = R"(
+struct S {
+  a : array<mat4x2<f32>, 3>,
+};
+
+@group(0) @binding(0) var<uniform> s : S;
+
+fn f() {
+  let l = s.a[0];
+}
+)";
+
+    auto* expect = R"(
+struct mat4x2_f32 {
+  col0 : vec2<f32>,
+  col1 : vec2<f32>,
+  col2 : vec2<f32>,
+  col3 : vec2<f32>,
+}
+
+struct S {
+  a : array<mat4x2<f32>, 3>,
+}
+
+struct S_std140 {
+  a : array<mat4x2_f32, 3u>,
+}
+
+@group(0) @binding(0) var<uniform> s : S_std140;
+
+fn conv_mat4x2_f32(val : mat4x2_f32) -> mat4x2<f32> {
+  return mat4x2<f32>(val.col0, val.col1, val.col2, val.col3);
+}
+
+fn f() {
+  let l = conv_mat4x2_f32(s.a[0u]);
+}
+)";
+
+    auto got = Run<Std140>(src);
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(Std140Test, StructArrayMat2x2Uniform_LoadMatrix1) {
+    auto* src = R"(
+struct S {
+  a : array<mat2x2<f32>, 3>,
+};
+
+@group(0) @binding(0) var<uniform> s : S;
+
+fn f() {
+  let l = s.a[1];
+}
+)";
+
+    auto* expect = R"(
+struct mat2x2_f32 {
+  col0 : vec2<f32>,
+  col1 : vec2<f32>,
+}
+
+struct S {
+  a : array<mat2x2<f32>, 3>,
+}
+
+struct S_std140 {
+  a : array<mat2x2_f32, 3u>,
+}
+
+@group(0) @binding(0) var<uniform> s : S_std140;
+
+fn conv_mat2x2_f32(val : mat2x2_f32) -> mat2x2<f32> {
+  return mat2x2<f32>(val.col0, val.col1);
+}
+
+fn f() {
+  let l = conv_mat2x2_f32(s.a[1u]);
+}
+)";
+
+    auto got = Run<Std140>(src);
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(Std140Test, StructArrayMat4x2Uniform_LoadMatrixI) {
+    auto* src = R"(
+struct S {
+  a : array<mat4x2<f32>, 3>,
+};
+
+@group(0) @binding(0) var<uniform> s : S;
+
+fn f() {
+  let I = 1;
+  let l = s.a[I];
+}
+)";
+
+    auto* expect = R"(
+struct mat4x2_f32 {
+  col0 : vec2<f32>,
+  col1 : vec2<f32>,
+  col2 : vec2<f32>,
+  col3 : vec2<f32>,
+}
+
+struct S {
+  a : array<mat4x2<f32>, 3>,
+}
+
+struct S_std140 {
+  a : array<mat4x2_f32, 3u>,
+}
+
+@group(0) @binding(0) var<uniform> s : S_std140;
+
+fn conv_mat4x2_f32(val : mat4x2_f32) -> mat4x2<f32> {
+  return mat4x2<f32>(val.col0, val.col1, val.col2, val.col3);
+}
+
+fn f() {
+  let I = 1;
+  let l = conv_mat4x2_f32(s.a[I]);
+}
+)";
+
+    auto got = Run<Std140>(src);
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(Std140Test, StructArrayMat2x2Uniform_LoadMatrix1Column0) {
+    auto* src = R"(
+struct S {
+  a : array<mat2x2<f32>, 3>,
+};
+
+@group(0) @binding(0) var<uniform> s : S;
+
+fn f() {
+  let l = s.a[1][0];
+}
+)";
+
+    auto* expect = R"(
+struct mat2x2_f32 {
+  col0 : vec2<f32>,
+  col1 : vec2<f32>,
+}
+
+struct S {
+  a : array<mat2x2<f32>, 3>,
+}
+
+struct S_std140 {
+  a : array<mat2x2_f32, 3u>,
+}
+
+@group(0) @binding(0) var<uniform> s : S_std140;
+
+fn f() {
+  let l = s.a[1u].col0;
+}
+)";
+
+    auto got = Run<Std140>(src);
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(Std140Test, StructArrayMat4x2Uniform_LoadMatrix0Column1) {
+    auto* src = R"(
+struct S {
+  a : array<mat4x2<f32>, 3>,
+};
+
+@group(0) @binding(0) var<uniform> s : S;
+
+fn f() {
+  let l = s.a[0][1];
+}
+)";
+
+    auto* expect = R"(
+struct mat4x2_f32 {
+  col0 : vec2<f32>,
+  col1 : vec2<f32>,
+  col2 : vec2<f32>,
+  col3 : vec2<f32>,
+}
+
+struct S {
+  a : array<mat4x2<f32>, 3>,
+}
+
+struct S_std140 {
+  a : array<mat4x2_f32, 3u>,
+}
+
+@group(0) @binding(0) var<uniform> s : S_std140;
+
+fn f() {
+  let l = s.a[0u].col1;
+}
+)";
+
+    auto got = Run<Std140>(src);
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(Std140Test, StructArrayMat2x2Uniform_LoadMatrixIColumn1) {
+    auto* src = R"(
+struct S {
+  a : array<mat2x2<f32>, 3>,
+};
+
+@group(0) @binding(0) var<uniform> s : S;
+
+fn f() {
+  let I = 1;
+  let l = s.a[I][1];
+}
+)";
+
+    auto* expect = R"(
+struct mat2x2_f32 {
+  col0 : vec2<f32>,
+  col1 : vec2<f32>,
+}
+
+struct S {
+  a : array<mat2x2<f32>, 3>,
+}
+
+struct S_std140 {
+  a : array<mat2x2_f32, 3u>,
+}
+
+@group(0) @binding(0) var<uniform> s : S_std140;
+
+fn f() {
+  let I = 1;
+  let l = s.a[I].col1;
+}
+)";
+
+    auto got = Run<Std140>(src);
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(Std140Test, StructArrayMat4x2Uniform_LoadMatrix1ColumnI) {
+    auto* src = R"(
+struct S {
+  a : array<mat4x2<f32>, 3>,
+};
+
+@group(0) @binding(0) var<uniform> s : S;
+
+fn f() {
+  let I = 1;
+  let l = s.a[1][I];
+}
+)";
+
+    auto* expect = R"(
+struct mat4x2_f32 {
+  col0 : vec2<f32>,
+  col1 : vec2<f32>,
+  col2 : vec2<f32>,
+  col3 : vec2<f32>,
+}
+
+struct S {
+  a : array<mat4x2<f32>, 3>,
+}
+
+struct S_std140 {
+  a : array<mat4x2_f32, 3u>,
+}
+
+@group(0) @binding(0) var<uniform> s : S_std140;
+
+fn load_s_a_1_p0(p0 : u32) -> vec2<f32> {
+  switch(p0) {
+    case 0u: {
+      return s.a[1u].col0;
+    }
+    case 1u: {
+      return s.a[1u].col1;
+    }
+    case 2u: {
+      return s.a[1u].col2;
+    }
+    case 3u: {
+      return s.a[1u].col3;
+    }
+    default: {
+      return vec2<f32>();
+    }
+  }
+}
+
+fn f() {
+  let I = 1;
+  let l = load_s_a_1_p0(u32(I));
+}
+)";
+
+    auto got = Run<Std140>(src);
+
+    EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(Std140Test, ArrayStructArrayStructMat4x2Uniform_Loads) {
     auto* src = R"(
 struct Inner {
@@ -1614,7 +2938,7 @@
   return Inner(mat4x2<f32>(val.m_0, val.m_1, val.m_2, val.m_3));
 }
 
-fn conv_arr_4_Inner(val : array<Inner_std140, 4u>) -> array<Inner, 4u> {
+fn conv_arr4_Inner(val : array<Inner_std140, 4u>) -> array<Inner, 4u> {
   var arr : array<Inner, 4u>;
   for(var i : u32; (i < 4u); i = (i + 1)) {
     arr[i] = conv_Inner(val[i]);
@@ -1623,10 +2947,10 @@
 }
 
 fn conv_Outer(val : Outer_std140) -> Outer {
-  return Outer(conv_arr_4_Inner(val.a));
+  return Outer(conv_arr4_Inner(val.a));
 }
 
-fn conv_arr_4_Outer(val : array<Outer_std140, 4u>) -> array<Outer, 4u> {
+fn conv_arr4_Outer(val : array<Outer_std140, 4u>) -> array<Outer, 4u> {
   var arr : array<Outer, 4u>;
   for(var i : u32; (i < 4u); i = (i + 1)) {
     arr[i] = conv_Outer(val[i]);
@@ -1641,9 +2965,9 @@
 
 fn f() {
   let I = 1;
-  let l_a : array<Outer, 4> = conv_arr_4_Outer(a);
+  let l_a : array<Outer, 4> = conv_arr4_Outer(a);
   let l_a_1 : Outer = conv_Outer(a[1u]);
-  let l_a_2_a : array<Inner, 4> = conv_arr_4_Inner(a[2u].a);
+  let l_a_2_a : array<Inner, 4> = conv_arr4_Inner(a[2u].a);
   let l_a_3_a_1 : Inner = conv_Inner(a[3u].a[1u]);
   let l_a_0_a_2_m : mat4x2<f32> = load_a_0_a_2_m();
   let l_a_1_a_3_m_0 : vec2<f32> = a[1u].a[3u].m_0;
@@ -1717,7 +3041,7 @@
   return Inner(mat4x2<f32>(val.m_0, val.m_1, val.m_2, val.m_3));
 }
 
-fn conv_arr_4_Inner(val : array<Inner_std140, 4u>) -> array<Inner, 4u> {
+fn conv_arr4_Inner(val : array<Inner_std140, 4u>) -> array<Inner, 4u> {
   var arr : array<Inner, 4u>;
   for(var i : u32; (i < 4u); i = (i + 1)) {
     arr[i] = conv_Inner(val[i]);
@@ -1726,10 +3050,10 @@
 }
 
 fn conv_Outer(val : Outer_std140) -> Outer {
-  return Outer(conv_arr_4_Inner(val.a));
+  return Outer(conv_arr4_Inner(val.a));
 }
 
-fn conv_arr_4_Outer(val : array<Outer_std140, 4u>) -> array<Outer, 4u> {
+fn conv_arr4_Outer(val : array<Outer_std140, 4u>) -> array<Outer, 4u> {
   var arr : array<Outer, 4u>;
   for(var i : u32; (i < 4u); i = (i + 1)) {
     arr[i] = conv_Outer(val[i]);
@@ -1744,15 +3068,15 @@
 
 fn f() {
   let I = 1;
-  let p_a = conv_arr_4_Outer(a);
+  let p_a = conv_arr4_Outer(a);
   let p_a_3 = conv_Outer(a[3u]);
-  let p_a_3_a = conv_arr_4_Inner(a[3u].a);
+  let p_a_3_a = conv_arr4_Inner(a[3u].a);
   let p_a_3_a_2 = conv_Inner(a[3u].a[2u]);
   let p_a_3_a_2_m = load_a_3_a_2_m();
   let p_a_3_a_2_m_1 = a[3u].a[2u].m_1;
-  let l_a : array<Outer, 4> = conv_arr_4_Outer(a);
+  let l_a : array<Outer, 4> = conv_arr4_Outer(a);
   let l_a_3 : Outer = conv_Outer(a[3u]);
-  let l_a_3_a : array<Inner, 4> = conv_arr_4_Inner(a[3u].a);
+  let l_a_3_a : array<Inner, 4> = conv_arr4_Inner(a[3u].a);
   let l_a_3_a_2 : Inner = conv_Inner(a[3u].a[2u]);
   let l_a_3_a_2_m : mat4x2<f32> = load_a_3_a_2_m();
   let l_a_3_a_2_m_1 : vec2<f32> = a[3u].a[2u].m_1;
@@ -1801,7 +3125,7 @@
   return S(mat3x2<f32>(val.m_0, val.m_1, val.m_2));
 }
 
-fn conv_arr_4_S(val : array<S_std140, 4u>) -> array<S, 4u> {
+fn conv_arr4_S(val : array<S_std140, 4u>) -> array<S, 4u> {
   var arr : array<S, 4u>;
   for(var i : u32; (i < 4u); i = (i + 1)) {
     arr[i] = conv_S(val[i]);
@@ -1810,7 +3134,7 @@
 }
 
 fn f() {
-  s = conv_arr_4_S(u);
+  s = conv_arr4_S(u);
 }
 )";
 
@@ -1827,7 +3151,7 @@
 }
 
 @group(0) @binding(0) var<uniform> u : array<S, 4>;
-@group(0) @binding(1) var<workgroup> w : array<S, 4>;
+var<workgroup> w : array<S, 4>;
 
 fn f() {
     w[0] = u[1];
@@ -1835,9 +3159,32 @@
 )";
 
     auto* expect =
-        R"(test:8:38 error: non-resource variables must not have @group or @binding attributes
-@group(0) @binding(1) var<workgroup> w : array<S, 4>;
-                                     ^
+        R"(
+struct S {
+  v : vec4<i32>,
+  @size(64)
+  m : mat3x2<f32>,
+}
+
+struct S_std140 {
+  v : vec4<i32>,
+  m_0 : vec2<f32>,
+  m_1 : vec2<f32>,
+  @size(48)
+  m_2 : vec2<f32>,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S_std140, 4u>;
+
+var<workgroup> w : array<S, 4>;
+
+fn conv_S(val : S_std140) -> S {
+  return S(val.v, mat3x2<f32>(val.m_0, val.m_1, val.m_2));
+}
+
+fn f() {
+  w[0] = conv_S(u[1u]);
+}
 )";
 
     auto got = Run<Std140>(src);
diff --git a/src/tint/writer/glsl/generator_impl.cc b/src/tint/writer/glsl/generator_impl.cc
index 5031329..d051981 100644
--- a/src/tint/writer/glsl/generator_impl.cc
+++ b/src/tint/writer/glsl/generator_impl.cc
@@ -244,8 +244,7 @@
     manager.Add<transform::AddEmptyEntryPoint>();
     manager.Add<transform::AddBlockAttribute>();
 
-    // Std140 must come after PromoteSideEffectsToDecl and AddBlockAttribute
-    // Std140 must come before SimplifyPointers.
+    // Std140 must come after PromoteSideEffectsToDecl and before SimplifyPointers.
     manager.Add<transform::Std140>();
 
     manager.Add<transform::SimplifyPointers>();
diff --git a/src/tint/writer/spirv/generator_impl.cc b/src/tint/writer/spirv/generator_impl.cc
index 2a2c25c..bf92bf9 100644
--- a/src/tint/writer/spirv/generator_impl.cc
+++ b/src/tint/writer/spirv/generator_impl.cc
@@ -87,7 +87,8 @@
     manager.Add<transform::AddEmptyEntryPoint>();
     manager.Add<transform::AddBlockAttribute>();
 
-    // Std140 must come after PromoteSideEffectsToDecl, AddBlockAttribute
+    // Std140 must come after PromoteSideEffectsToDecl.
+    // Std140 must come before VarForDynamicIndex and ForLoopToLoop.
     manager.Add<transform::Std140>();
 
     // VarForDynamicIndex must come after Std140
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat2x2/dynamic_index_via_ptr.wgsl.expected.glsl
index 3b56852..265b946 100644
--- a/test/tint/buffer/uniform/std140/array/mat2x2/dynamic_index_via_ptr.wgsl.expected.glsl
+++ b/test/tint/buffer/uniform/std140/array/mat2x2/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -1,7 +1,12 @@
 #version 310 es
 
-layout(binding = 0, std140) uniform a_block_ubo {
-  mat2 inner[4];
+struct mat2x2_f32 {
+  vec2 col0;
+  vec2 col1;
+};
+
+layout(binding = 0, std140) uniform a_block_std140_ubo {
+  mat2x2_f32 inner[4];
 } a;
 
 int counter = 0;
@@ -10,14 +15,46 @@
   return counter;
 }
 
+mat2 conv_mat2x2_f32(mat2x2_f32 val) {
+  return mat2(val.col0, val.col1);
+}
+
+mat2[4] conv_arr4_mat2x2_f32(mat2x2_f32 val[4]) {
+  mat2 arr[4] = mat2[4](mat2(0.0f, 0.0f, 0.0f, 0.0f), mat2(0.0f, 0.0f, 0.0f, 0.0f), mat2(0.0f, 0.0f, 0.0f, 0.0f), mat2(0.0f, 0.0f, 0.0f, 0.0f));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat2x2_f32(val[i]);
+    }
+  }
+  return arr;
+}
+
+vec2 load_a_inner_p0_p1(uint p0, uint p1) {
+  switch(p1) {
+    case 0u: {
+      return a.inner[p0].col0;
+      break;
+    }
+    case 1u: {
+      return a.inner[p0].col1;
+      break;
+    }
+    default: {
+      return vec2(0.0f);
+      break;
+    }
+  }
+}
+
 void f() {
+  mat2 p_a[4] = conv_arr4_mat2x2_f32(a.inner);
   int tint_symbol = i();
-  int p_a_i_save = tint_symbol;
+  mat2 p_a_i = conv_mat2x2_f32(a.inner[tint_symbol]);
   int tint_symbol_1 = i();
-  int p_a_i_i_save = tint_symbol_1;
-  mat2 l_a[4] = a.inner;
-  mat2 l_a_i = a.inner[p_a_i_save];
-  vec2 l_a_i_i = a.inner[p_a_i_save][p_a_i_i_save];
+  vec2 p_a_i_i = load_a_inner_p0_p1(uint(tint_symbol), uint(tint_symbol_1));
+  mat2 l_a[4] = conv_arr4_mat2x2_f32(a.inner);
+  mat2 l_a_i = conv_mat2x2_f32(a.inner[tint_symbol]);
+  vec2 l_a_i_i = load_a_inner_p0_p1(uint(tint_symbol), uint(tint_symbol_1));
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat2x2/dynamic_index_via_ptr.wgsl.expected.spvasm
index b9a3ee9..40ede28 100644
--- a/test/tint/buffer/uniform/std140/array/mat2x2/dynamic_index_via_ptr.wgsl.expected.spvasm
+++ b/test/tint/buffer/uniform/std140/array/mat2x2/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -1,47 +1,77 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 37
+; Bound: 98
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
-               OpName %a_block "a_block"
-               OpMemberName %a_block 0 "inner"
+               OpName %a_block_std140 "a_block_std140"
+               OpMemberName %a_block_std140 0 "inner"
+               OpName %mat2x2_f32 "mat2x2_f32"
+               OpMemberName %mat2x2_f32 0 "col0"
+               OpMemberName %mat2x2_f32 1 "col1"
                OpName %a "a"
                OpName %counter "counter"
                OpName %i "i"
+               OpName %conv_mat2x2_f32 "conv_mat2x2_f32"
+               OpName %val "val"
+               OpName %conv_arr4_mat2x2_f32 "conv_arr4_mat2x2_f32"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i_0 "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_a_inner_p0_p1 "load_a_inner_p0_p1"
+               OpName %p0 "p0"
+               OpName %p1 "p1"
                OpName %f "f"
-               OpDecorate %a_block Block
-               OpMemberDecorate %a_block 0 Offset 0
-               OpMemberDecorate %a_block 0 ColMajor
-               OpMemberDecorate %a_block 0 MatrixStride 8
-               OpDecorate %_arr_mat2v2float_uint_4 ArrayStride 16
+               OpDecorate %a_block_std140 Block
+               OpMemberDecorate %a_block_std140 0 Offset 0
+               OpMemberDecorate %mat2x2_f32 0 Offset 0
+               OpMemberDecorate %mat2x2_f32 1 Offset 8
+               OpDecorate %_arr_mat2x2_f32_uint_4 ArrayStride 16
                OpDecorate %a NonWritable
                OpDecorate %a DescriptorSet 0
                OpDecorate %a Binding 0
+               OpDecorate %_arr_mat2v2float_uint_4 ArrayStride 16
       %float = OpTypeFloat 32
     %v2float = OpTypeVector %float 2
-%mat2v2float = OpTypeMatrix %v2float 2
+ %mat2x2_f32 = OpTypeStruct %v2float %v2float
        %uint = OpTypeInt 32 0
      %uint_4 = OpConstant %uint 4
-%_arr_mat2v2float_uint_4 = OpTypeArray %mat2v2float %uint_4
-    %a_block = OpTypeStruct %_arr_mat2v2float_uint_4
-%_ptr_Uniform_a_block = OpTypePointer Uniform %a_block
-          %a = OpVariable %_ptr_Uniform_a_block Uniform
+%_arr_mat2x2_f32_uint_4 = OpTypeArray %mat2x2_f32 %uint_4
+%a_block_std140 = OpTypeStruct %_arr_mat2x2_f32_uint_4
+%_ptr_Uniform_a_block_std140 = OpTypePointer Uniform %a_block_std140
+          %a = OpVariable %_ptr_Uniform_a_block_std140 Uniform
         %int = OpTypeInt 32 1
          %11 = OpConstantNull %int
 %_ptr_Private_int = OpTypePointer Private %int
     %counter = OpVariable %_ptr_Private_int Private %11
          %14 = OpTypeFunction %int
       %int_1 = OpConstant %int 1
-       %void = OpTypeVoid
-         %21 = OpTypeFunction %void
+%mat2v2float = OpTypeMatrix %v2float 2
+         %21 = OpTypeFunction %mat2v2float %mat2x2_f32
+%_arr_mat2v2float_uint_4 = OpTypeArray %mat2v2float %uint_4
+         %29 = OpTypeFunction %_arr_mat2v2float_uint_4 %_arr_mat2x2_f32_uint_4
+%_ptr_Function__arr_mat2v2float_uint_4 = OpTypePointer Function %_arr_mat2v2float_uint_4
+         %36 = OpConstantNull %_arr_mat2v2float_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %39 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_mat2x2_f32_uint_4 = OpTypePointer Function %_arr_mat2x2_f32_uint_4
+         %52 = OpConstantNull %_arr_mat2x2_f32_uint_4
+%_ptr_Function_mat2v2float = OpTypePointer Function %mat2v2float
+%_ptr_Function_mat2x2_f32 = OpTypePointer Function %mat2x2_f32
+     %uint_1 = OpConstant %uint 1
+         %65 = OpTypeFunction %v2float %uint %uint
      %uint_0 = OpConstant %uint 0
-%_ptr_Uniform__arr_mat2v2float_uint_4 = OpTypePointer Uniform %_arr_mat2v2float_uint_4
-%_ptr_Uniform_mat2v2float = OpTypePointer Uniform %mat2v2float
 %_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
+         %80 = OpConstantNull %v2float
+       %void = OpTypeVoid
+         %81 = OpTypeFunction %void
+%_ptr_Uniform__arr_mat2x2_f32_uint_4 = OpTypePointer Uniform %_arr_mat2x2_f32_uint_4
+%_ptr_Uniform_mat2x2_f32 = OpTypePointer Uniform %mat2x2_f32
           %i = OpFunction %int None %14
          %16 = OpLabel
          %17 = OpLoad %int %counter
@@ -50,15 +80,82 @@
          %20 = OpLoad %int %counter
                OpReturnValue %20
                OpFunctionEnd
-          %f = OpFunction %void None %21
-         %24 = OpLabel
-         %25 = OpFunctionCall %int %i
-         %26 = OpFunctionCall %int %i
-         %29 = OpAccessChain %_ptr_Uniform__arr_mat2v2float_uint_4 %a %uint_0
-         %30 = OpLoad %_arr_mat2v2float_uint_4 %29
-         %32 = OpAccessChain %_ptr_Uniform_mat2v2float %a %uint_0 %25
-         %33 = OpLoad %mat2v2float %32
-         %35 = OpAccessChain %_ptr_Uniform_v2float %a %uint_0 %25 %26
-         %36 = OpLoad %v2float %35
+%conv_mat2x2_f32 = OpFunction %mat2v2float None %21
+        %val = OpFunctionParameter %mat2x2_f32
+         %25 = OpLabel
+         %26 = OpCompositeExtract %v2float %val 0
+         %27 = OpCompositeExtract %v2float %val 1
+         %28 = OpCompositeConstruct %mat2v2float %26 %27
+               OpReturnValue %28
+               OpFunctionEnd
+%conv_arr4_mat2x2_f32 = OpFunction %_arr_mat2v2float_uint_4 None %29
+      %val_0 = OpFunctionParameter %_arr_mat2x2_f32_uint_4
+         %33 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_mat2v2float_uint_4 Function %36
+        %i_0 = OpVariable %_ptr_Function_uint Function %39
+%var_for_index = OpVariable %_ptr_Function__arr_mat2x2_f32_uint_4 Function %52
+               OpBranch %40
+         %40 = OpLabel
+               OpLoopMerge %41 %42 None
+               OpBranch %43
+         %43 = OpLabel
+         %45 = OpLoad %uint %i_0
+         %46 = OpULessThan %bool %45 %uint_4
+         %44 = OpLogicalNot %bool %46
+               OpSelectionMerge %48 None
+               OpBranchConditional %44 %49 %48
+         %49 = OpLabel
+               OpBranch %41
+         %48 = OpLabel
+               OpStore %var_for_index %val_0
+         %53 = OpLoad %uint %i_0
+         %55 = OpAccessChain %_ptr_Function_mat2v2float %arr %53
+         %57 = OpLoad %uint %i_0
+         %59 = OpAccessChain %_ptr_Function_mat2x2_f32 %var_for_index %57
+         %60 = OpLoad %mat2x2_f32 %59
+         %56 = OpFunctionCall %mat2v2float %conv_mat2x2_f32 %60
+               OpStore %55 %56
+               OpBranch %42
+         %42 = OpLabel
+         %61 = OpLoad %uint %i_0
+         %63 = OpIAdd %uint %61 %uint_1
+               OpStore %i_0 %63
+               OpBranch %40
+         %41 = OpLabel
+         %64 = OpLoad %_arr_mat2v2float_uint_4 %arr
+               OpReturnValue %64
+               OpFunctionEnd
+%load_a_inner_p0_p1 = OpFunction %v2float None %65
+         %p0 = OpFunctionParameter %uint
+         %p1 = OpFunctionParameter %uint
+         %69 = OpLabel
+               OpSelectionMerge %70 None
+               OpSwitch %p1 %71 0 %72 1 %73
+         %72 = OpLabel
+         %76 = OpAccessChain %_ptr_Uniform_v2float %a %uint_0 %p0 %uint_0
+         %77 = OpLoad %v2float %76
+               OpReturnValue %77
+         %73 = OpLabel
+         %78 = OpAccessChain %_ptr_Uniform_v2float %a %uint_0 %p0 %uint_1
+         %79 = OpLoad %v2float %78
+               OpReturnValue %79
+         %71 = OpLabel
+               OpReturnValue %80
+         %70 = OpLabel
+               OpReturnValue %80
+               OpFunctionEnd
+          %f = OpFunction %void None %81
+         %84 = OpLabel
+         %85 = OpFunctionCall %int %i
+         %86 = OpFunctionCall %int %i
+         %89 = OpAccessChain %_ptr_Uniform__arr_mat2x2_f32_uint_4 %a %uint_0
+         %90 = OpLoad %_arr_mat2x2_f32_uint_4 %89
+         %87 = OpFunctionCall %_arr_mat2v2float_uint_4 %conv_arr4_mat2x2_f32 %90
+         %93 = OpAccessChain %_ptr_Uniform_mat2x2_f32 %a %uint_0 %85
+         %94 = OpLoad %mat2x2_f32 %93
+         %91 = OpFunctionCall %mat2v2float %conv_mat2x2_f32 %94
+         %96 = OpBitcast %uint %85
+         %97 = OpBitcast %uint %86
+         %95 = OpFunctionCall %v2float %load_a_inner_p0_p1 %96 %97
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat2x2/static_index_via_ptr.wgsl.expected.glsl
index a3d6e08..19803ad 100644
--- a/test/tint/buffer/uniform/std140/array/mat2x2/static_index_via_ptr.wgsl.expected.glsl
+++ b/test/tint/buffer/uniform/std140/array/mat2x2/static_index_via_ptr.wgsl.expected.glsl
@@ -1,13 +1,35 @@
 #version 310 es
 
-layout(binding = 0, std140) uniform a_block_ubo {
-  mat2 inner[4];
+struct mat2x2_f32 {
+  vec2 col0;
+  vec2 col1;
+};
+
+layout(binding = 0, std140) uniform a_block_std140_ubo {
+  mat2x2_f32 inner[4];
 } a;
 
+mat2 conv_mat2x2_f32(mat2x2_f32 val) {
+  return mat2(val.col0, val.col1);
+}
+
+mat2[4] conv_arr4_mat2x2_f32(mat2x2_f32 val[4]) {
+  mat2 arr[4] = mat2[4](mat2(0.0f, 0.0f, 0.0f, 0.0f), mat2(0.0f, 0.0f, 0.0f, 0.0f), mat2(0.0f, 0.0f, 0.0f, 0.0f), mat2(0.0f, 0.0f, 0.0f, 0.0f));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat2x2_f32(val[i]);
+    }
+  }
+  return arr;
+}
+
 void f() {
-  mat2 l_a[4] = a.inner;
-  mat2 l_a_i = a.inner[2];
-  vec2 l_a_i_i = a.inner[2][1];
+  mat2 p_a[4] = conv_arr4_mat2x2_f32(a.inner);
+  mat2 p_a_2 = conv_mat2x2_f32(a.inner[2u]);
+  vec2 p_a_2_1 = a.inner[2u].col1;
+  mat2 l_a[4] = conv_arr4_mat2x2_f32(a.inner);
+  mat2 l_a_i = conv_mat2x2_f32(a.inner[2u]);
+  vec2 l_a_i_i = a.inner[2u].col1;
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat2x2/static_index_via_ptr.wgsl.expected.spvasm
index 0e6ccba..1274970 100644
--- a/test/tint/buffer/uniform/std140/array/mat2x2/static_index_via_ptr.wgsl.expected.spvasm
+++ b/test/tint/buffer/uniform/std140/array/mat2x2/static_index_via_ptr.wgsl.expected.spvasm
@@ -1,49 +1,119 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 27
+; Bound: 71
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
-               OpName %a_block "a_block"
-               OpMemberName %a_block 0 "inner"
+               OpName %a_block_std140 "a_block_std140"
+               OpMemberName %a_block_std140 0 "inner"
+               OpName %mat2x2_f32 "mat2x2_f32"
+               OpMemberName %mat2x2_f32 0 "col0"
+               OpMemberName %mat2x2_f32 1 "col1"
                OpName %a "a"
+               OpName %conv_mat2x2_f32 "conv_mat2x2_f32"
+               OpName %val "val"
+               OpName %conv_arr4_mat2x2_f32 "conv_arr4_mat2x2_f32"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
                OpName %f "f"
-               OpDecorate %a_block Block
-               OpMemberDecorate %a_block 0 Offset 0
-               OpMemberDecorate %a_block 0 ColMajor
-               OpMemberDecorate %a_block 0 MatrixStride 8
-               OpDecorate %_arr_mat2v2float_uint_4 ArrayStride 16
+               OpDecorate %a_block_std140 Block
+               OpMemberDecorate %a_block_std140 0 Offset 0
+               OpMemberDecorate %mat2x2_f32 0 Offset 0
+               OpMemberDecorate %mat2x2_f32 1 Offset 8
+               OpDecorate %_arr_mat2x2_f32_uint_4 ArrayStride 16
                OpDecorate %a NonWritable
                OpDecorate %a DescriptorSet 0
                OpDecorate %a Binding 0
+               OpDecorate %_arr_mat2v2float_uint_4 ArrayStride 16
       %float = OpTypeFloat 32
     %v2float = OpTypeVector %float 2
-%mat2v2float = OpTypeMatrix %v2float 2
+ %mat2x2_f32 = OpTypeStruct %v2float %v2float
        %uint = OpTypeInt 32 0
      %uint_4 = OpConstant %uint 4
+%_arr_mat2x2_f32_uint_4 = OpTypeArray %mat2x2_f32 %uint_4
+%a_block_std140 = OpTypeStruct %_arr_mat2x2_f32_uint_4
+%_ptr_Uniform_a_block_std140 = OpTypePointer Uniform %a_block_std140
+          %a = OpVariable %_ptr_Uniform_a_block_std140 Uniform
+%mat2v2float = OpTypeMatrix %v2float 2
+         %10 = OpTypeFunction %mat2v2float %mat2x2_f32
 %_arr_mat2v2float_uint_4 = OpTypeArray %mat2v2float %uint_4
-    %a_block = OpTypeStruct %_arr_mat2v2float_uint_4
-%_ptr_Uniform_a_block = OpTypePointer Uniform %a_block
-          %a = OpVariable %_ptr_Uniform_a_block Uniform
+         %18 = OpTypeFunction %_arr_mat2v2float_uint_4 %_arr_mat2x2_f32_uint_4
+%_ptr_Function__arr_mat2v2float_uint_4 = OpTypePointer Function %_arr_mat2v2float_uint_4
+         %25 = OpConstantNull %_arr_mat2v2float_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %28 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_mat2x2_f32_uint_4 = OpTypePointer Function %_arr_mat2x2_f32_uint_4
+         %41 = OpConstantNull %_arr_mat2x2_f32_uint_4
+%_ptr_Function_mat2v2float = OpTypePointer Function %mat2v2float
+%_ptr_Function_mat2x2_f32 = OpTypePointer Function %mat2x2_f32
+     %uint_1 = OpConstant %uint 1
        %void = OpTypeVoid
-         %10 = OpTypeFunction %void
+         %54 = OpTypeFunction %void
      %uint_0 = OpConstant %uint 0
-%_ptr_Uniform__arr_mat2v2float_uint_4 = OpTypePointer Uniform %_arr_mat2v2float_uint_4
-        %int = OpTypeInt 32 1
-      %int_2 = OpConstant %int 2
-%_ptr_Uniform_mat2v2float = OpTypePointer Uniform %mat2v2float
-      %int_1 = OpConstant %int 1
+%_ptr_Uniform__arr_mat2x2_f32_uint_4 = OpTypePointer Uniform %_arr_mat2x2_f32_uint_4
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_mat2x2_f32 = OpTypePointer Uniform %mat2x2_f32
 %_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
-          %f = OpFunction %void None %10
-         %13 = OpLabel
-         %16 = OpAccessChain %_ptr_Uniform__arr_mat2v2float_uint_4 %a %uint_0
-         %17 = OpLoad %_arr_mat2v2float_uint_4 %16
-         %21 = OpAccessChain %_ptr_Uniform_mat2v2float %a %uint_0 %int_2
-         %22 = OpLoad %mat2v2float %21
-         %25 = OpAccessChain %_ptr_Uniform_v2float %a %uint_0 %int_2 %int_1
-         %26 = OpLoad %v2float %25
+%conv_mat2x2_f32 = OpFunction %mat2v2float None %10
+        %val = OpFunctionParameter %mat2x2_f32
+         %14 = OpLabel
+         %15 = OpCompositeExtract %v2float %val 0
+         %16 = OpCompositeExtract %v2float %val 1
+         %17 = OpCompositeConstruct %mat2v2float %15 %16
+               OpReturnValue %17
+               OpFunctionEnd
+%conv_arr4_mat2x2_f32 = OpFunction %_arr_mat2v2float_uint_4 None %18
+      %val_0 = OpFunctionParameter %_arr_mat2x2_f32_uint_4
+         %22 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_mat2v2float_uint_4 Function %25
+          %i = OpVariable %_ptr_Function_uint Function %28
+%var_for_index = OpVariable %_ptr_Function__arr_mat2x2_f32_uint_4 Function %41
+               OpBranch %29
+         %29 = OpLabel
+               OpLoopMerge %30 %31 None
+               OpBranch %32
+         %32 = OpLabel
+         %34 = OpLoad %uint %i
+         %35 = OpULessThan %bool %34 %uint_4
+         %33 = OpLogicalNot %bool %35
+               OpSelectionMerge %37 None
+               OpBranchConditional %33 %38 %37
+         %38 = OpLabel
+               OpBranch %30
+         %37 = OpLabel
+               OpStore %var_for_index %val_0
+         %42 = OpLoad %uint %i
+         %44 = OpAccessChain %_ptr_Function_mat2v2float %arr %42
+         %46 = OpLoad %uint %i
+         %48 = OpAccessChain %_ptr_Function_mat2x2_f32 %var_for_index %46
+         %49 = OpLoad %mat2x2_f32 %48
+         %45 = OpFunctionCall %mat2v2float %conv_mat2x2_f32 %49
+               OpStore %44 %45
+               OpBranch %31
+         %31 = OpLabel
+         %50 = OpLoad %uint %i
+         %52 = OpIAdd %uint %50 %uint_1
+               OpStore %i %52
+               OpBranch %29
+         %30 = OpLabel
+         %53 = OpLoad %_arr_mat2v2float_uint_4 %arr
+               OpReturnValue %53
+               OpFunctionEnd
+          %f = OpFunction %void None %54
+         %57 = OpLabel
+         %61 = OpAccessChain %_ptr_Uniform__arr_mat2x2_f32_uint_4 %a %uint_0
+         %62 = OpLoad %_arr_mat2x2_f32_uint_4 %61
+         %58 = OpFunctionCall %_arr_mat2v2float_uint_4 %conv_arr4_mat2x2_f32 %62
+         %66 = OpAccessChain %_ptr_Uniform_mat2x2_f32 %a %uint_0 %uint_2
+         %67 = OpLoad %mat2x2_f32 %66
+         %63 = OpFunctionCall %mat2v2float %conv_mat2x2_f32 %67
+         %69 = OpAccessChain %_ptr_Uniform_v2float %a %uint_0 %uint_2 %uint_1
+         %70 = OpLoad %v2float %69
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat2x2/to_builtin.wgsl.expected.glsl
index ffcbc7c..2bffe0d 100644
--- a/test/tint/buffer/uniform/std140/array/mat2x2/to_builtin.wgsl.expected.glsl
+++ b/test/tint/buffer/uniform/std140/array/mat2x2/to_builtin.wgsl.expected.glsl
@@ -1,13 +1,22 @@
 #version 310 es
 
-layout(binding = 0, std140) uniform u_block_ubo {
-  mat2 inner[4];
+struct mat2x2_f32 {
+  vec2 col0;
+  vec2 col1;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  mat2x2_f32 inner[4];
 } u;
 
+mat2 conv_mat2x2_f32(mat2x2_f32 val) {
+  return mat2(val.col0, val.col1);
+}
+
 void f() {
-  mat2 t = transpose(u.inner[2]);
-  float l = length(u.inner[0][1].yx);
-  float a = abs(u.inner[0][1].yx.x);
+  mat2 t = transpose(conv_mat2x2_f32(u.inner[2u]));
+  float l = length(u.inner[0u].col1.yx);
+  float a = abs(u.inner[0u].col1.yx[0u]);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat2x2/to_builtin.wgsl.expected.spvasm
index 399fe03..3890b7a 100644
--- a/test/tint/buffer/uniform/std140/array/mat2x2/to_builtin.wgsl.expected.spvasm
+++ b/test/tint/buffer/uniform/std140/array/mat2x2/to_builtin.wgsl.expected.spvasm
@@ -1,56 +1,71 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 34
+; Bound: 42
 ; Schema: 0
                OpCapability Shader
-         %22 = OpExtInstImport "GLSL.std.450"
+         %30 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
-               OpName %u_block "u_block"
-               OpMemberName %u_block 0 "inner"
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %mat2x2_f32 "mat2x2_f32"
+               OpMemberName %mat2x2_f32 0 "col0"
+               OpMemberName %mat2x2_f32 1 "col1"
                OpName %u "u"
+               OpName %conv_mat2x2_f32 "conv_mat2x2_f32"
+               OpName %val "val"
                OpName %f "f"
-               OpDecorate %u_block Block
-               OpMemberDecorate %u_block 0 Offset 0
-               OpMemberDecorate %u_block 0 ColMajor
-               OpMemberDecorate %u_block 0 MatrixStride 8
-               OpDecorate %_arr_mat2v2float_uint_4 ArrayStride 16
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %mat2x2_f32 0 Offset 0
+               OpMemberDecorate %mat2x2_f32 1 Offset 8
+               OpDecorate %_arr_mat2x2_f32_uint_4 ArrayStride 16
                OpDecorate %u NonWritable
                OpDecorate %u DescriptorSet 0
                OpDecorate %u Binding 0
       %float = OpTypeFloat 32
     %v2float = OpTypeVector %float 2
-%mat2v2float = OpTypeMatrix %v2float 2
+ %mat2x2_f32 = OpTypeStruct %v2float %v2float
        %uint = OpTypeInt 32 0
      %uint_4 = OpConstant %uint 4
-%_arr_mat2v2float_uint_4 = OpTypeArray %mat2v2float %uint_4
-    %u_block = OpTypeStruct %_arr_mat2v2float_uint_4
-%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
-          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_arr_mat2x2_f32_uint_4 = OpTypeArray %mat2x2_f32 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_mat2x2_f32_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+%mat2v2float = OpTypeMatrix %v2float 2
+         %10 = OpTypeFunction %mat2v2float %mat2x2_f32
        %void = OpTypeVoid
-         %10 = OpTypeFunction %void
+         %18 = OpTypeFunction %void
      %uint_0 = OpConstant %uint 0
-        %int = OpTypeInt 32 1
-      %int_2 = OpConstant %int 2
-%_ptr_Uniform_mat2v2float = OpTypePointer Uniform %mat2v2float
-         %23 = OpConstantNull %int
-      %int_1 = OpConstant %int 1
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_mat2x2_f32 = OpTypePointer Uniform %mat2x2_f32
+         %31 = OpConstantNull %uint
+     %uint_1 = OpConstant %uint 1
 %_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
-          %f = OpFunction %void None %10
-         %13 = OpLabel
-         %19 = OpAccessChain %_ptr_Uniform_mat2v2float %u %uint_0 %int_2
-         %20 = OpLoad %mat2v2float %19
-         %14 = OpTranspose %mat2v2float %20
-         %26 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %23 %int_1
-         %27 = OpLoad %v2float %26
-         %28 = OpVectorShuffle %v2float %27 %27 1 0
-         %21 = OpExtInst %float %22 Length %28
-         %30 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %23 %int_1
-         %31 = OpLoad %v2float %30
-         %32 = OpVectorShuffle %v2float %31 %31 1 0
-         %33 = OpCompositeExtract %float %32 0
-         %29 = OpExtInst %float %22 FAbs %33
+%conv_mat2x2_f32 = OpFunction %mat2v2float None %10
+        %val = OpFunctionParameter %mat2x2_f32
+         %14 = OpLabel
+         %15 = OpCompositeExtract %v2float %val 0
+         %16 = OpCompositeExtract %v2float %val 1
+         %17 = OpCompositeConstruct %mat2v2float %15 %16
+               OpReturnValue %17
+               OpFunctionEnd
+          %f = OpFunction %void None %18
+         %21 = OpLabel
+         %27 = OpAccessChain %_ptr_Uniform_mat2x2_f32 %u %uint_0 %uint_2
+         %28 = OpLoad %mat2x2_f32 %27
+         %23 = OpFunctionCall %mat2v2float %conv_mat2x2_f32 %28
+         %22 = OpTranspose %mat2v2float %23
+         %34 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %31 %uint_1
+         %35 = OpLoad %v2float %34
+         %36 = OpVectorShuffle %v2float %35 %35 1 0
+         %29 = OpExtInst %float %30 Length %36
+         %38 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %31 %uint_1
+         %39 = OpLoad %v2float %38
+         %40 = OpVectorShuffle %v2float %39 %39 1 0
+         %41 = OpCompositeExtract %float %40 0
+         %37 = OpExtInst %float %30 FAbs %41
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat2x2/to_fn.wgsl.expected.glsl
index bc291fd..ad45982 100644
--- a/test/tint/buffer/uniform/std140/array/mat2x2/to_fn.wgsl.expected.glsl
+++ b/test/tint/buffer/uniform/std140/array/mat2x2/to_fn.wgsl.expected.glsl
@@ -1,7 +1,12 @@
 #version 310 es
 
-layout(binding = 0, std140) uniform u_block_ubo {
-  mat2 inner[4];
+struct mat2x2_f32 {
+  vec2 col0;
+  vec2 col1;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  mat2x2_f32 inner[4];
 } u;
 
 void a(mat2 a_1[4]) {
@@ -16,11 +21,25 @@
 void d(float f_1) {
 }
 
+mat2 conv_mat2x2_f32(mat2x2_f32 val) {
+  return mat2(val.col0, val.col1);
+}
+
+mat2[4] conv_arr4_mat2x2_f32(mat2x2_f32 val[4]) {
+  mat2 arr[4] = mat2[4](mat2(0.0f, 0.0f, 0.0f, 0.0f), mat2(0.0f, 0.0f, 0.0f, 0.0f), mat2(0.0f, 0.0f, 0.0f, 0.0f), mat2(0.0f, 0.0f, 0.0f, 0.0f));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat2x2_f32(val[i]);
+    }
+  }
+  return arr;
+}
+
 void f() {
-  a(u.inner);
-  b(u.inner[1]);
-  c(u.inner[1][0].yx);
-  d(u.inner[1][0].yx.x);
+  a(conv_arr4_mat2x2_f32(u.inner));
+  b(conv_mat2x2_f32(u.inner[1u]));
+  c(u.inner[1u].col0.yx);
+  d(u.inner[1u].col0.yx[0u]);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat2x2/to_fn.wgsl.expected.spvasm
index 8f407ac..cdbf08f 100644
--- a/test/tint/buffer/uniform/std140/array/mat2x2/to_fn.wgsl.expected.spvasm
+++ b/test/tint/buffer/uniform/std140/array/mat2x2/to_fn.wgsl.expected.spvasm
@@ -1,14 +1,17 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 52
+; Bound: 95
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
-               OpName %u_block "u_block"
-               OpMemberName %u_block 0 "inner"
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %mat2x2_f32 "mat2x2_f32"
+               OpMemberName %mat2x2_f32 0 "col0"
+               OpMemberName %mat2x2_f32 1 "col1"
                OpName %u "u"
                OpName %a "a"
                OpName %a_1 "a_1"
@@ -18,73 +21,139 @@
                OpName %v "v"
                OpName %d "d"
                OpName %f_1 "f_1"
+               OpName %conv_mat2x2_f32 "conv_mat2x2_f32"
+               OpName %val "val"
+               OpName %conv_arr4_mat2x2_f32 "conv_arr4_mat2x2_f32"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
                OpName %f "f"
-               OpDecorate %u_block Block
-               OpMemberDecorate %u_block 0 Offset 0
-               OpMemberDecorate %u_block 0 ColMajor
-               OpMemberDecorate %u_block 0 MatrixStride 8
-               OpDecorate %_arr_mat2v2float_uint_4 ArrayStride 16
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %mat2x2_f32 0 Offset 0
+               OpMemberDecorate %mat2x2_f32 1 Offset 8
+               OpDecorate %_arr_mat2x2_f32_uint_4 ArrayStride 16
                OpDecorate %u NonWritable
                OpDecorate %u DescriptorSet 0
                OpDecorate %u Binding 0
+               OpDecorate %_arr_mat2v2float_uint_4 ArrayStride 16
       %float = OpTypeFloat 32
     %v2float = OpTypeVector %float 2
-%mat2v2float = OpTypeMatrix %v2float 2
+ %mat2x2_f32 = OpTypeStruct %v2float %v2float
        %uint = OpTypeInt 32 0
      %uint_4 = OpConstant %uint 4
-%_arr_mat2v2float_uint_4 = OpTypeArray %mat2v2float %uint_4
-    %u_block = OpTypeStruct %_arr_mat2v2float_uint_4
-%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
-          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_arr_mat2x2_f32_uint_4 = OpTypeArray %mat2x2_f32 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_mat2x2_f32_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
        %void = OpTypeVoid
+%mat2v2float = OpTypeMatrix %v2float 2
+%_arr_mat2v2float_uint_4 = OpTypeArray %mat2v2float %uint_4
          %10 = OpTypeFunction %void %_arr_mat2v2float_uint_4
-         %15 = OpTypeFunction %void %mat2v2float
-         %19 = OpTypeFunction %void %v2float
-         %23 = OpTypeFunction %void %float
-         %27 = OpTypeFunction %void
+         %17 = OpTypeFunction %void %mat2v2float
+         %21 = OpTypeFunction %void %v2float
+         %25 = OpTypeFunction %void %float
+         %29 = OpTypeFunction %mat2v2float %mat2x2_f32
+         %36 = OpTypeFunction %_arr_mat2v2float_uint_4 %_arr_mat2x2_f32_uint_4
+%_ptr_Function__arr_mat2v2float_uint_4 = OpTypePointer Function %_arr_mat2v2float_uint_4
+         %42 = OpConstantNull %_arr_mat2v2float_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %45 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_mat2x2_f32_uint_4 = OpTypePointer Function %_arr_mat2x2_f32_uint_4
+         %58 = OpConstantNull %_arr_mat2x2_f32_uint_4
+%_ptr_Function_mat2v2float = OpTypePointer Function %mat2v2float
+%_ptr_Function_mat2x2_f32 = OpTypePointer Function %mat2x2_f32
+     %uint_1 = OpConstant %uint 1
+         %71 = OpTypeFunction %void
      %uint_0 = OpConstant %uint 0
-%_ptr_Uniform__arr_mat2v2float_uint_4 = OpTypePointer Uniform %_arr_mat2v2float_uint_4
-        %int = OpTypeInt 32 1
-      %int_1 = OpConstant %int 1
-%_ptr_Uniform_mat2v2float = OpTypePointer Uniform %mat2v2float
-         %42 = OpConstantNull %int
+%_ptr_Uniform__arr_mat2x2_f32_uint_4 = OpTypePointer Uniform %_arr_mat2x2_f32_uint_4
+%_ptr_Uniform_mat2x2_f32 = OpTypePointer Uniform %mat2x2_f32
 %_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
           %a = OpFunction %void None %10
         %a_1 = OpFunctionParameter %_arr_mat2v2float_uint_4
-         %14 = OpLabel
+         %16 = OpLabel
                OpReturn
                OpFunctionEnd
-          %b = OpFunction %void None %15
+          %b = OpFunction %void None %17
           %m = OpFunctionParameter %mat2v2float
-         %18 = OpLabel
+         %20 = OpLabel
                OpReturn
                OpFunctionEnd
-          %c = OpFunction %void None %19
+          %c = OpFunction %void None %21
           %v = OpFunctionParameter %v2float
-         %22 = OpLabel
+         %24 = OpLabel
                OpReturn
                OpFunctionEnd
-          %d = OpFunction %void None %23
+          %d = OpFunction %void None %25
         %f_1 = OpFunctionParameter %float
-         %26 = OpLabel
+         %28 = OpLabel
                OpReturn
                OpFunctionEnd
-          %f = OpFunction %void None %27
-         %29 = OpLabel
-         %33 = OpAccessChain %_ptr_Uniform__arr_mat2v2float_uint_4 %u %uint_0
-         %34 = OpLoad %_arr_mat2v2float_uint_4 %33
-         %30 = OpFunctionCall %void %a %34
-         %39 = OpAccessChain %_ptr_Uniform_mat2v2float %u %uint_0 %int_1
-         %40 = OpLoad %mat2v2float %39
-         %35 = OpFunctionCall %void %b %40
-         %44 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %int_1 %42
-         %45 = OpLoad %v2float %44
-         %46 = OpVectorShuffle %v2float %45 %45 1 0
-         %41 = OpFunctionCall %void %c %46
-         %48 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %int_1 %42
-         %49 = OpLoad %v2float %48
-         %50 = OpVectorShuffle %v2float %49 %49 1 0
-         %51 = OpCompositeExtract %float %50 0
-         %47 = OpFunctionCall %void %d %51
+%conv_mat2x2_f32 = OpFunction %mat2v2float None %29
+        %val = OpFunctionParameter %mat2x2_f32
+         %32 = OpLabel
+         %33 = OpCompositeExtract %v2float %val 0
+         %34 = OpCompositeExtract %v2float %val 1
+         %35 = OpCompositeConstruct %mat2v2float %33 %34
+               OpReturnValue %35
+               OpFunctionEnd
+%conv_arr4_mat2x2_f32 = OpFunction %_arr_mat2v2float_uint_4 None %36
+      %val_0 = OpFunctionParameter %_arr_mat2x2_f32_uint_4
+         %39 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_mat2v2float_uint_4 Function %42
+          %i = OpVariable %_ptr_Function_uint Function %45
+%var_for_index = OpVariable %_ptr_Function__arr_mat2x2_f32_uint_4 Function %58
+               OpBranch %46
+         %46 = OpLabel
+               OpLoopMerge %47 %48 None
+               OpBranch %49
+         %49 = OpLabel
+         %51 = OpLoad %uint %i
+         %52 = OpULessThan %bool %51 %uint_4
+         %50 = OpLogicalNot %bool %52
+               OpSelectionMerge %54 None
+               OpBranchConditional %50 %55 %54
+         %55 = OpLabel
+               OpBranch %47
+         %54 = OpLabel
+               OpStore %var_for_index %val_0
+         %59 = OpLoad %uint %i
+         %61 = OpAccessChain %_ptr_Function_mat2v2float %arr %59
+         %63 = OpLoad %uint %i
+         %65 = OpAccessChain %_ptr_Function_mat2x2_f32 %var_for_index %63
+         %66 = OpLoad %mat2x2_f32 %65
+         %62 = OpFunctionCall %mat2v2float %conv_mat2x2_f32 %66
+               OpStore %61 %62
+               OpBranch %48
+         %48 = OpLabel
+         %67 = OpLoad %uint %i
+         %69 = OpIAdd %uint %67 %uint_1
+               OpStore %i %69
+               OpBranch %46
+         %47 = OpLabel
+         %70 = OpLoad %_arr_mat2v2float_uint_4 %arr
+               OpReturnValue %70
+               OpFunctionEnd
+          %f = OpFunction %void None %71
+         %73 = OpLabel
+         %78 = OpAccessChain %_ptr_Uniform__arr_mat2x2_f32_uint_4 %u %uint_0
+         %79 = OpLoad %_arr_mat2x2_f32_uint_4 %78
+         %75 = OpFunctionCall %_arr_mat2v2float_uint_4 %conv_arr4_mat2x2_f32 %79
+         %74 = OpFunctionCall %void %a %75
+         %83 = OpAccessChain %_ptr_Uniform_mat2x2_f32 %u %uint_0 %uint_1
+         %84 = OpLoad %mat2x2_f32 %83
+         %81 = OpFunctionCall %mat2v2float %conv_mat2x2_f32 %84
+         %80 = OpFunctionCall %void %b %81
+         %87 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %uint_1 %uint_0
+         %88 = OpLoad %v2float %87
+         %89 = OpVectorShuffle %v2float %88 %88 1 0
+         %85 = OpFunctionCall %void %c %89
+         %91 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %uint_1 %uint_0
+         %92 = OpLoad %v2float %91
+         %93 = OpVectorShuffle %v2float %92 %92 1 0
+         %94 = OpCompositeExtract %float %93 0
+         %90 = OpFunctionCall %void %d %94
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat2x2/to_private.wgsl.expected.glsl
index 59ec729..2118347 100644
--- a/test/tint/buffer/uniform/std140/array/mat2x2/to_private.wgsl.expected.glsl
+++ b/test/tint/buffer/uniform/std140/array/mat2x2/to_private.wgsl.expected.glsl
@@ -1,21 +1,40 @@
 #version 310 es
 
+struct mat2x2_f32 {
+  vec2 col0;
+  vec2 col1;
+};
+
 struct S {
   int before;
   mat2 m;
   int after;
 };
 
-layout(binding = 0, std140) uniform u_block_ubo {
-  mat2 inner[4];
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  mat2x2_f32 inner[4];
 } u;
 
 mat2 p[4] = mat2[4](mat2(0.0f, 0.0f, 0.0f, 0.0f), mat2(0.0f, 0.0f, 0.0f, 0.0f), mat2(0.0f, 0.0f, 0.0f, 0.0f), mat2(0.0f, 0.0f, 0.0f, 0.0f));
+mat2 conv_mat2x2_f32(mat2x2_f32 val) {
+  return mat2(val.col0, val.col1);
+}
+
+mat2[4] conv_arr4_mat2x2_f32(mat2x2_f32 val[4]) {
+  mat2 arr[4] = mat2[4](mat2(0.0f, 0.0f, 0.0f, 0.0f), mat2(0.0f, 0.0f, 0.0f, 0.0f), mat2(0.0f, 0.0f, 0.0f, 0.0f), mat2(0.0f, 0.0f, 0.0f, 0.0f));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat2x2_f32(val[i]);
+    }
+  }
+  return arr;
+}
+
 void f() {
-  p = u.inner;
-  p[1] = u.inner[2];
-  p[1][0] = u.inner[0][1].yx;
-  p[1][0].x = u.inner[0][1].x;
+  p = conv_arr4_mat2x2_f32(u.inner);
+  p[1] = conv_mat2x2_f32(u.inner[2u]);
+  p[1][0] = u.inner[0u].col1.yx;
+  p[1][0].x = u.inner[0u].col1[0u];
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat2x2/to_private.wgsl.expected.spvasm
index 922f2c7..c91d661 100644
--- a/test/tint/buffer/uniform/std140/array/mat2x2/to_private.wgsl.expected.spvasm
+++ b/test/tint/buffer/uniform/std140/array/mat2x2/to_private.wgsl.expected.spvasm
@@ -1,68 +1,139 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 41
+; Bound: 86
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
-               OpName %u_block "u_block"
-               OpMemberName %u_block 0 "inner"
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %mat2x2_f32 "mat2x2_f32"
+               OpMemberName %mat2x2_f32 0 "col0"
+               OpMemberName %mat2x2_f32 1 "col1"
                OpName %u "u"
                OpName %p "p"
+               OpName %conv_mat2x2_f32 "conv_mat2x2_f32"
+               OpName %val "val"
+               OpName %conv_arr4_mat2x2_f32 "conv_arr4_mat2x2_f32"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
                OpName %f "f"
-               OpDecorate %u_block Block
-               OpMemberDecorate %u_block 0 Offset 0
-               OpMemberDecorate %u_block 0 ColMajor
-               OpMemberDecorate %u_block 0 MatrixStride 8
-               OpDecorate %_arr_mat2v2float_uint_4 ArrayStride 16
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %mat2x2_f32 0 Offset 0
+               OpMemberDecorate %mat2x2_f32 1 Offset 8
+               OpDecorate %_arr_mat2x2_f32_uint_4 ArrayStride 16
                OpDecorate %u NonWritable
                OpDecorate %u DescriptorSet 0
                OpDecorate %u Binding 0
+               OpDecorate %_arr_mat2v2float_uint_4 ArrayStride 16
       %float = OpTypeFloat 32
     %v2float = OpTypeVector %float 2
-%mat2v2float = OpTypeMatrix %v2float 2
+ %mat2x2_f32 = OpTypeStruct %v2float %v2float
        %uint = OpTypeInt 32 0
      %uint_4 = OpConstant %uint 4
+%_arr_mat2x2_f32_uint_4 = OpTypeArray %mat2x2_f32 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_mat2x2_f32_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+%mat2v2float = OpTypeMatrix %v2float 2
 %_arr_mat2v2float_uint_4 = OpTypeArray %mat2v2float %uint_4
-    %u_block = OpTypeStruct %_arr_mat2v2float_uint_4
-%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
-          %u = OpVariable %_ptr_Uniform_u_block Uniform
 %_ptr_Private__arr_mat2v2float_uint_4 = OpTypePointer Private %_arr_mat2v2float_uint_4
-         %12 = OpConstantNull %_arr_mat2v2float_uint_4
-          %p = OpVariable %_ptr_Private__arr_mat2v2float_uint_4 Private %12
+         %14 = OpConstantNull %_arr_mat2v2float_uint_4
+          %p = OpVariable %_ptr_Private__arr_mat2v2float_uint_4 Private %14
+         %15 = OpTypeFunction %mat2v2float %mat2x2_f32
+         %22 = OpTypeFunction %_arr_mat2v2float_uint_4 %_arr_mat2x2_f32_uint_4
+%_ptr_Function__arr_mat2v2float_uint_4 = OpTypePointer Function %_arr_mat2v2float_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %30 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_mat2x2_f32_uint_4 = OpTypePointer Function %_arr_mat2x2_f32_uint_4
+         %43 = OpConstantNull %_arr_mat2x2_f32_uint_4
+%_ptr_Function_mat2v2float = OpTypePointer Function %mat2v2float
+%_ptr_Function_mat2x2_f32 = OpTypePointer Function %mat2x2_f32
+     %uint_1 = OpConstant %uint 1
        %void = OpTypeVoid
-         %13 = OpTypeFunction %void
+         %56 = OpTypeFunction %void
      %uint_0 = OpConstant %uint 0
-%_ptr_Uniform__arr_mat2v2float_uint_4 = OpTypePointer Uniform %_arr_mat2v2float_uint_4
+%_ptr_Uniform__arr_mat2x2_f32_uint_4 = OpTypePointer Uniform %_arr_mat2x2_f32_uint_4
         %int = OpTypeInt 32 1
       %int_1 = OpConstant %int 1
 %_ptr_Private_mat2v2float = OpTypePointer Private %mat2v2float
-      %int_2 = OpConstant %int 2
-%_ptr_Uniform_mat2v2float = OpTypePointer Uniform %mat2v2float
-         %29 = OpConstantNull %int
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_mat2x2_f32 = OpTypePointer Uniform %mat2x2_f32
+         %74 = OpConstantNull %int
 %_ptr_Private_v2float = OpTypePointer Private %v2float
 %_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
 %_ptr_Private_float = OpTypePointer Private %float
 %_ptr_Uniform_float = OpTypePointer Uniform %float
-          %f = OpFunction %void None %13
-         %16 = OpLabel
-         %19 = OpAccessChain %_ptr_Uniform__arr_mat2v2float_uint_4 %u %uint_0
-         %20 = OpLoad %_arr_mat2v2float_uint_4 %19
-               OpStore %p %20
-         %24 = OpAccessChain %_ptr_Private_mat2v2float %p %int_1
-         %27 = OpAccessChain %_ptr_Uniform_mat2v2float %u %uint_0 %int_2
-         %28 = OpLoad %mat2v2float %27
-               OpStore %24 %28
-         %31 = OpAccessChain %_ptr_Private_v2float %p %int_1 %29
-         %33 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %29 %int_1
-         %34 = OpLoad %v2float %33
-         %35 = OpVectorShuffle %v2float %34 %34 1 0
-               OpStore %31 %35
-         %37 = OpAccessChain %_ptr_Private_float %p %int_1 %29 %uint_0
-         %39 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %29 %int_1 %uint_0
-         %40 = OpLoad %float %39
-               OpStore %37 %40
+%conv_mat2x2_f32 = OpFunction %mat2v2float None %15
+        %val = OpFunctionParameter %mat2x2_f32
+         %18 = OpLabel
+         %19 = OpCompositeExtract %v2float %val 0
+         %20 = OpCompositeExtract %v2float %val 1
+         %21 = OpCompositeConstruct %mat2v2float %19 %20
+               OpReturnValue %21
+               OpFunctionEnd
+%conv_arr4_mat2x2_f32 = OpFunction %_arr_mat2v2float_uint_4 None %22
+      %val_0 = OpFunctionParameter %_arr_mat2x2_f32_uint_4
+         %25 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_mat2v2float_uint_4 Function %14
+          %i = OpVariable %_ptr_Function_uint Function %30
+%var_for_index = OpVariable %_ptr_Function__arr_mat2x2_f32_uint_4 Function %43
+               OpBranch %31
+         %31 = OpLabel
+               OpLoopMerge %32 %33 None
+               OpBranch %34
+         %34 = OpLabel
+         %36 = OpLoad %uint %i
+         %37 = OpULessThan %bool %36 %uint_4
+         %35 = OpLogicalNot %bool %37
+               OpSelectionMerge %39 None
+               OpBranchConditional %35 %40 %39
+         %40 = OpLabel
+               OpBranch %32
+         %39 = OpLabel
+               OpStore %var_for_index %val_0
+         %44 = OpLoad %uint %i
+         %46 = OpAccessChain %_ptr_Function_mat2v2float %arr %44
+         %48 = OpLoad %uint %i
+         %50 = OpAccessChain %_ptr_Function_mat2x2_f32 %var_for_index %48
+         %51 = OpLoad %mat2x2_f32 %50
+         %47 = OpFunctionCall %mat2v2float %conv_mat2x2_f32 %51
+               OpStore %46 %47
+               OpBranch %33
+         %33 = OpLabel
+         %52 = OpLoad %uint %i
+         %54 = OpIAdd %uint %52 %uint_1
+               OpStore %i %54
+               OpBranch %31
+         %32 = OpLabel
+         %55 = OpLoad %_arr_mat2v2float_uint_4 %arr
+               OpReturnValue %55
+               OpFunctionEnd
+          %f = OpFunction %void None %56
+         %59 = OpLabel
+         %63 = OpAccessChain %_ptr_Uniform__arr_mat2x2_f32_uint_4 %u %uint_0
+         %64 = OpLoad %_arr_mat2x2_f32_uint_4 %63
+         %60 = OpFunctionCall %_arr_mat2v2float_uint_4 %conv_arr4_mat2x2_f32 %64
+               OpStore %p %60
+         %68 = OpAccessChain %_ptr_Private_mat2v2float %p %int_1
+         %72 = OpAccessChain %_ptr_Uniform_mat2x2_f32 %u %uint_0 %uint_2
+         %73 = OpLoad %mat2x2_f32 %72
+         %69 = OpFunctionCall %mat2v2float %conv_mat2x2_f32 %73
+               OpStore %68 %69
+         %76 = OpAccessChain %_ptr_Private_v2float %p %int_1 %74
+         %78 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %30 %uint_1
+         %79 = OpLoad %v2float %78
+         %80 = OpVectorShuffle %v2float %79 %79 1 0
+               OpStore %76 %80
+         %82 = OpAccessChain %_ptr_Private_float %p %int_1 %74 %uint_0
+         %84 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %30 %uint_1 %30
+         %85 = OpLoad %float %84
+               OpStore %82 %85
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat2x2/to_storage.wgsl.expected.glsl
index 2a920f8..c6be613 100644
--- a/test/tint/buffer/uniform/std140/array/mat2x2/to_storage.wgsl.expected.glsl
+++ b/test/tint/buffer/uniform/std140/array/mat2x2/to_storage.wgsl.expected.glsl
@@ -1,24 +1,43 @@
 #version 310 es
 
+struct mat2x2_f32 {
+  vec2 col0;
+  vec2 col1;
+};
+
 struct S {
   int before;
   mat2 m;
   int after;
 };
 
-layout(binding = 0, std140) uniform u_block_ubo {
-  mat2 inner[4];
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  mat2x2_f32 inner[4];
 } u;
 
 layout(binding = 1, std430) buffer u_block_ssbo {
   mat2 inner[4];
 } s;
 
+mat2 conv_mat2x2_f32(mat2x2_f32 val) {
+  return mat2(val.col0, val.col1);
+}
+
+mat2[4] conv_arr4_mat2x2_f32(mat2x2_f32 val[4]) {
+  mat2 arr[4] = mat2[4](mat2(0.0f, 0.0f, 0.0f, 0.0f), mat2(0.0f, 0.0f, 0.0f, 0.0f), mat2(0.0f, 0.0f, 0.0f, 0.0f), mat2(0.0f, 0.0f, 0.0f, 0.0f));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat2x2_f32(val[i]);
+    }
+  }
+  return arr;
+}
+
 void f() {
-  s.inner = u.inner;
-  s.inner[1] = u.inner[2];
-  s.inner[1][0] = u.inner[0][1].yx;
-  s.inner[1][0].x = u.inner[0][1].x;
+  s.inner = conv_arr4_mat2x2_f32(u.inner);
+  s.inner[1] = conv_mat2x2_f32(u.inner[2u]);
+  s.inner[1][0] = u.inner[0u].col1.yx;
+  s.inner[1][0].x = u.inner[0u].col1[0u];
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat2x2/to_storage.wgsl.expected.spvasm
index 19eba56..1edbc86 100644
--- a/test/tint/buffer/uniform/std140/array/mat2x2/to_storage.wgsl.expected.spvasm
+++ b/test/tint/buffer/uniform/std140/array/mat2x2/to_storage.wgsl.expected.spvasm
@@ -1,71 +1,150 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 42
+; Bound: 89
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %mat2x2_f32 "mat2x2_f32"
+               OpMemberName %mat2x2_f32 0 "col0"
+               OpMemberName %mat2x2_f32 1 "col1"
+               OpName %u "u"
                OpName %u_block "u_block"
                OpMemberName %u_block 0 "inner"
-               OpName %u "u"
                OpName %s "s"
+               OpName %conv_mat2x2_f32 "conv_mat2x2_f32"
+               OpName %val "val"
+               OpName %conv_arr4_mat2x2_f32 "conv_arr4_mat2x2_f32"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
                OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %mat2x2_f32 0 Offset 0
+               OpMemberDecorate %mat2x2_f32 1 Offset 8
+               OpDecorate %_arr_mat2x2_f32_uint_4 ArrayStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
                OpDecorate %u_block Block
                OpMemberDecorate %u_block 0 Offset 0
                OpMemberDecorate %u_block 0 ColMajor
                OpMemberDecorate %u_block 0 MatrixStride 8
                OpDecorate %_arr_mat2v2float_uint_4 ArrayStride 16
-               OpDecorate %u NonWritable
-               OpDecorate %u DescriptorSet 0
-               OpDecorate %u Binding 0
                OpDecorate %s DescriptorSet 0
                OpDecorate %s Binding 1
       %float = OpTypeFloat 32
     %v2float = OpTypeVector %float 2
-%mat2v2float = OpTypeMatrix %v2float 2
+ %mat2x2_f32 = OpTypeStruct %v2float %v2float
        %uint = OpTypeInt 32 0
      %uint_4 = OpConstant %uint 4
+%_arr_mat2x2_f32_uint_4 = OpTypeArray %mat2x2_f32 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_mat2x2_f32_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+%mat2v2float = OpTypeMatrix %v2float 2
 %_arr_mat2v2float_uint_4 = OpTypeArray %mat2v2float %uint_4
     %u_block = OpTypeStruct %_arr_mat2v2float_uint_4
-%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
-          %u = OpVariable %_ptr_Uniform_u_block Uniform
 %_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
           %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+         %15 = OpTypeFunction %mat2v2float %mat2x2_f32
+         %22 = OpTypeFunction %_arr_mat2v2float_uint_4 %_arr_mat2x2_f32_uint_4
+%_ptr_Function__arr_mat2v2float_uint_4 = OpTypePointer Function %_arr_mat2v2float_uint_4
+         %28 = OpConstantNull %_arr_mat2v2float_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %31 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_mat2x2_f32_uint_4 = OpTypePointer Function %_arr_mat2x2_f32_uint_4
+         %44 = OpConstantNull %_arr_mat2x2_f32_uint_4
+%_ptr_Function_mat2v2float = OpTypePointer Function %mat2v2float
+%_ptr_Function_mat2x2_f32 = OpTypePointer Function %mat2x2_f32
+     %uint_1 = OpConstant %uint 1
        %void = OpTypeVoid
-         %12 = OpTypeFunction %void
+         %57 = OpTypeFunction %void
      %uint_0 = OpConstant %uint 0
 %_ptr_StorageBuffer__arr_mat2v2float_uint_4 = OpTypePointer StorageBuffer %_arr_mat2v2float_uint_4
-%_ptr_Uniform__arr_mat2v2float_uint_4 = OpTypePointer Uniform %_arr_mat2v2float_uint_4
+%_ptr_Uniform__arr_mat2x2_f32_uint_4 = OpTypePointer Uniform %_arr_mat2x2_f32_uint_4
         %int = OpTypeInt 32 1
       %int_1 = OpConstant %int 1
 %_ptr_StorageBuffer_mat2v2float = OpTypePointer StorageBuffer %mat2v2float
-      %int_2 = OpConstant %int 2
-%_ptr_Uniform_mat2v2float = OpTypePointer Uniform %mat2v2float
-         %30 = OpConstantNull %int
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_mat2x2_f32 = OpTypePointer Uniform %mat2x2_f32
+         %77 = OpConstantNull %int
 %_ptr_StorageBuffer_v2float = OpTypePointer StorageBuffer %v2float
 %_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
 %_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
 %_ptr_Uniform_float = OpTypePointer Uniform %float
-          %f = OpFunction %void None %12
-         %15 = OpLabel
-         %18 = OpAccessChain %_ptr_StorageBuffer__arr_mat2v2float_uint_4 %s %uint_0
-         %20 = OpAccessChain %_ptr_Uniform__arr_mat2v2float_uint_4 %u %uint_0
-         %21 = OpLoad %_arr_mat2v2float_uint_4 %20
-               OpStore %18 %21
-         %25 = OpAccessChain %_ptr_StorageBuffer_mat2v2float %s %uint_0 %int_1
-         %28 = OpAccessChain %_ptr_Uniform_mat2v2float %u %uint_0 %int_2
-         %29 = OpLoad %mat2v2float %28
-               OpStore %25 %29
-         %32 = OpAccessChain %_ptr_StorageBuffer_v2float %s %uint_0 %int_1 %30
-         %34 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %30 %int_1
-         %35 = OpLoad %v2float %34
-         %36 = OpVectorShuffle %v2float %35 %35 1 0
-               OpStore %32 %36
-         %38 = OpAccessChain %_ptr_StorageBuffer_float %s %uint_0 %int_1 %30 %uint_0
-         %40 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %30 %int_1 %uint_0
-         %41 = OpLoad %float %40
-               OpStore %38 %41
+%conv_mat2x2_f32 = OpFunction %mat2v2float None %15
+        %val = OpFunctionParameter %mat2x2_f32
+         %18 = OpLabel
+         %19 = OpCompositeExtract %v2float %val 0
+         %20 = OpCompositeExtract %v2float %val 1
+         %21 = OpCompositeConstruct %mat2v2float %19 %20
+               OpReturnValue %21
+               OpFunctionEnd
+%conv_arr4_mat2x2_f32 = OpFunction %_arr_mat2v2float_uint_4 None %22
+      %val_0 = OpFunctionParameter %_arr_mat2x2_f32_uint_4
+         %25 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_mat2v2float_uint_4 Function %28
+          %i = OpVariable %_ptr_Function_uint Function %31
+%var_for_index = OpVariable %_ptr_Function__arr_mat2x2_f32_uint_4 Function %44
+               OpBranch %32
+         %32 = OpLabel
+               OpLoopMerge %33 %34 None
+               OpBranch %35
+         %35 = OpLabel
+         %37 = OpLoad %uint %i
+         %38 = OpULessThan %bool %37 %uint_4
+         %36 = OpLogicalNot %bool %38
+               OpSelectionMerge %40 None
+               OpBranchConditional %36 %41 %40
+         %41 = OpLabel
+               OpBranch %33
+         %40 = OpLabel
+               OpStore %var_for_index %val_0
+         %45 = OpLoad %uint %i
+         %47 = OpAccessChain %_ptr_Function_mat2v2float %arr %45
+         %49 = OpLoad %uint %i
+         %51 = OpAccessChain %_ptr_Function_mat2x2_f32 %var_for_index %49
+         %52 = OpLoad %mat2x2_f32 %51
+         %48 = OpFunctionCall %mat2v2float %conv_mat2x2_f32 %52
+               OpStore %47 %48
+               OpBranch %34
+         %34 = OpLabel
+         %53 = OpLoad %uint %i
+         %55 = OpIAdd %uint %53 %uint_1
+               OpStore %i %55
+               OpBranch %32
+         %33 = OpLabel
+         %56 = OpLoad %_arr_mat2v2float_uint_4 %arr
+               OpReturnValue %56
+               OpFunctionEnd
+          %f = OpFunction %void None %57
+         %60 = OpLabel
+         %63 = OpAccessChain %_ptr_StorageBuffer__arr_mat2v2float_uint_4 %s %uint_0
+         %66 = OpAccessChain %_ptr_Uniform__arr_mat2x2_f32_uint_4 %u %uint_0
+         %67 = OpLoad %_arr_mat2x2_f32_uint_4 %66
+         %64 = OpFunctionCall %_arr_mat2v2float_uint_4 %conv_arr4_mat2x2_f32 %67
+               OpStore %63 %64
+         %71 = OpAccessChain %_ptr_StorageBuffer_mat2v2float %s %uint_0 %int_1
+         %75 = OpAccessChain %_ptr_Uniform_mat2x2_f32 %u %uint_0 %uint_2
+         %76 = OpLoad %mat2x2_f32 %75
+         %72 = OpFunctionCall %mat2v2float %conv_mat2x2_f32 %76
+               OpStore %71 %72
+         %79 = OpAccessChain %_ptr_StorageBuffer_v2float %s %uint_0 %int_1 %77
+         %81 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %31 %uint_1
+         %82 = OpLoad %v2float %81
+         %83 = OpVectorShuffle %v2float %82 %82 1 0
+               OpStore %79 %83
+         %85 = OpAccessChain %_ptr_StorageBuffer_float %s %uint_0 %int_1 %77 %uint_0
+         %87 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %31 %uint_1 %31
+         %88 = OpLoad %float %87
+               OpStore %85 %88
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat2x2/to_workgroup.wgsl.expected.glsl
index 8dcc07d..e459ce3 100644
--- a/test/tint/buffer/uniform/std140/array/mat2x2/to_workgroup.wgsl.expected.glsl
+++ b/test/tint/buffer/uniform/std140/array/mat2x2/to_workgroup.wgsl.expected.glsl
@@ -1,16 +1,35 @@
 #version 310 es
 
+struct mat2x2_f32 {
+  vec2 col0;
+  vec2 col1;
+};
+
 struct S {
   int before;
   mat2 m;
   int after;
 };
 
-layout(binding = 0, std140) uniform u_block_ubo {
-  mat2 inner[4];
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  mat2x2_f32 inner[4];
 } u;
 
 shared mat2 w[4];
+mat2 conv_mat2x2_f32(mat2x2_f32 val) {
+  return mat2(val.col0, val.col1);
+}
+
+mat2[4] conv_arr4_mat2x2_f32(mat2x2_f32 val[4]) {
+  mat2 arr[4] = mat2[4](mat2(0.0f, 0.0f, 0.0f, 0.0f), mat2(0.0f, 0.0f, 0.0f, 0.0f), mat2(0.0f, 0.0f, 0.0f, 0.0f), mat2(0.0f, 0.0f, 0.0f, 0.0f));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat2x2_f32(val[i]);
+    }
+  }
+  return arr;
+}
+
 void f(uint local_invocation_index) {
   {
     for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
@@ -19,10 +38,10 @@
     }
   }
   barrier();
-  w = u.inner;
-  w[1] = u.inner[2];
-  w[1][0] = u.inner[0][1].yx;
-  w[1][0].x = u.inner[0][1].x;
+  w = conv_arr4_mat2x2_f32(u.inner);
+  w[1] = conv_mat2x2_f32(u.inner[2u]);
+  w[1][0] = u.inner[0u].col1.yx;
+  w[1][0].x = u.inner[0u].col1[0u];
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat2x2/to_workgroup.wgsl.expected.spvasm
index 495667c..e70212f 100644
--- a/test/tint/buffer/uniform/std140/array/mat2x2/to_workgroup.wgsl.expected.spvasm
+++ b/test/tint/buffer/uniform/std140/array/mat2x2/to_workgroup.wgsl.expected.spvasm
@@ -1,115 +1,182 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 70
+; Bound: 111
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f" %local_invocation_index_1
                OpExecutionMode %f LocalSize 1 1 1
                OpName %local_invocation_index_1 "local_invocation_index_1"
-               OpName %u_block "u_block"
-               OpMemberName %u_block 0 "inner"
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %mat2x2_f32 "mat2x2_f32"
+               OpMemberName %mat2x2_f32 0 "col0"
+               OpMemberName %mat2x2_f32 1 "col1"
                OpName %u "u"
                OpName %w "w"
+               OpName %conv_mat2x2_f32 "conv_mat2x2_f32"
+               OpName %val "val"
+               OpName %conv_arr4_mat2x2_f32 "conv_arr4_mat2x2_f32"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
                OpName %f_inner "f_inner"
                OpName %local_invocation_index "local_invocation_index"
                OpName %idx "idx"
                OpName %f "f"
                OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
-               OpDecorate %u_block Block
-               OpMemberDecorate %u_block 0 Offset 0
-               OpMemberDecorate %u_block 0 ColMajor
-               OpMemberDecorate %u_block 0 MatrixStride 8
-               OpDecorate %_arr_mat2v2float_uint_4 ArrayStride 16
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %mat2x2_f32 0 Offset 0
+               OpMemberDecorate %mat2x2_f32 1 Offset 8
+               OpDecorate %_arr_mat2x2_f32_uint_4 ArrayStride 16
                OpDecorate %u NonWritable
                OpDecorate %u DescriptorSet 0
                OpDecorate %u Binding 0
+               OpDecorate %_arr_mat2v2float_uint_4 ArrayStride 16
        %uint = OpTypeInt 32 0
 %_ptr_Input_uint = OpTypePointer Input %uint
 %local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
       %float = OpTypeFloat 32
     %v2float = OpTypeVector %float 2
-%mat2v2float = OpTypeMatrix %v2float 2
+ %mat2x2_f32 = OpTypeStruct %v2float %v2float
      %uint_4 = OpConstant %uint 4
+%_arr_mat2x2_f32_uint_4 = OpTypeArray %mat2x2_f32 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_mat2x2_f32_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+%mat2v2float = OpTypeMatrix %v2float 2
 %_arr_mat2v2float_uint_4 = OpTypeArray %mat2v2float %uint_4
-    %u_block = OpTypeStruct %_arr_mat2v2float_uint_4
-%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
-          %u = OpVariable %_ptr_Uniform_u_block Uniform
 %_ptr_Workgroup__arr_mat2v2float_uint_4 = OpTypePointer Workgroup %_arr_mat2v2float_uint_4
           %w = OpVariable %_ptr_Workgroup__arr_mat2v2float_uint_4 Workgroup
-       %void = OpTypeVoid
-         %14 = OpTypeFunction %void %uint
+         %16 = OpTypeFunction %mat2v2float %mat2x2_f32
+         %23 = OpTypeFunction %_arr_mat2v2float_uint_4 %_arr_mat2x2_f32_uint_4
+%_ptr_Function__arr_mat2v2float_uint_4 = OpTypePointer Function %_arr_mat2v2float_uint_4
+         %29 = OpConstantNull %_arr_mat2v2float_uint_4
 %_ptr_Function_uint = OpTypePointer Function %uint
-         %21 = OpConstantNull %uint
+         %32 = OpConstantNull %uint
        %bool = OpTypeBool
-%_ptr_Workgroup_mat2v2float = OpTypePointer Workgroup %mat2v2float
-         %35 = OpConstantNull %mat2v2float
+%_ptr_Function__arr_mat2x2_f32_uint_4 = OpTypePointer Function %_arr_mat2x2_f32_uint_4
+         %45 = OpConstantNull %_arr_mat2x2_f32_uint_4
+%_ptr_Function_mat2v2float = OpTypePointer Function %mat2v2float
+%_ptr_Function_mat2x2_f32 = OpTypePointer Function %mat2x2_f32
      %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %58 = OpTypeFunction %void %uint
+%_ptr_Workgroup_mat2v2float = OpTypePointer Workgroup %mat2v2float
+         %76 = OpConstantNull %mat2v2float
      %uint_2 = OpConstant %uint 2
    %uint_264 = OpConstant %uint 264
      %uint_0 = OpConstant %uint 0
-%_ptr_Uniform__arr_mat2v2float_uint_4 = OpTypePointer Uniform %_arr_mat2v2float_uint_4
+%_ptr_Uniform__arr_mat2x2_f32_uint_4 = OpTypePointer Uniform %_arr_mat2x2_f32_uint_4
         %int = OpTypeInt 32 1
       %int_1 = OpConstant %int 1
-      %int_2 = OpConstant %int 2
-%_ptr_Uniform_mat2v2float = OpTypePointer Uniform %mat2v2float
-         %53 = OpConstantNull %int
+%_ptr_Uniform_mat2x2_f32 = OpTypePointer Uniform %mat2x2_f32
+         %94 = OpConstantNull %int
 %_ptr_Workgroup_v2float = OpTypePointer Workgroup %v2float
 %_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
 %_ptr_Workgroup_float = OpTypePointer Workgroup %float
 %_ptr_Uniform_float = OpTypePointer Uniform %float
-         %65 = OpTypeFunction %void
-    %f_inner = OpFunction %void None %14
+        %106 = OpTypeFunction %void
+%conv_mat2x2_f32 = OpFunction %mat2v2float None %16
+        %val = OpFunctionParameter %mat2x2_f32
+         %19 = OpLabel
+         %20 = OpCompositeExtract %v2float %val 0
+         %21 = OpCompositeExtract %v2float %val 1
+         %22 = OpCompositeConstruct %mat2v2float %20 %21
+               OpReturnValue %22
+               OpFunctionEnd
+%conv_arr4_mat2x2_f32 = OpFunction %_arr_mat2v2float_uint_4 None %23
+      %val_0 = OpFunctionParameter %_arr_mat2x2_f32_uint_4
+         %26 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_mat2v2float_uint_4 Function %29
+          %i = OpVariable %_ptr_Function_uint Function %32
+%var_for_index = OpVariable %_ptr_Function__arr_mat2x2_f32_uint_4 Function %45
+               OpBranch %33
+         %33 = OpLabel
+               OpLoopMerge %34 %35 None
+               OpBranch %36
+         %36 = OpLabel
+         %38 = OpLoad %uint %i
+         %39 = OpULessThan %bool %38 %uint_4
+         %37 = OpLogicalNot %bool %39
+               OpSelectionMerge %41 None
+               OpBranchConditional %37 %42 %41
+         %42 = OpLabel
+               OpBranch %34
+         %41 = OpLabel
+               OpStore %var_for_index %val_0
+         %46 = OpLoad %uint %i
+         %48 = OpAccessChain %_ptr_Function_mat2v2float %arr %46
+         %50 = OpLoad %uint %i
+         %52 = OpAccessChain %_ptr_Function_mat2x2_f32 %var_for_index %50
+         %53 = OpLoad %mat2x2_f32 %52
+         %49 = OpFunctionCall %mat2v2float %conv_mat2x2_f32 %53
+               OpStore %48 %49
+               OpBranch %35
+         %35 = OpLabel
+         %54 = OpLoad %uint %i
+         %56 = OpIAdd %uint %54 %uint_1
+               OpStore %i %56
+               OpBranch %33
+         %34 = OpLabel
+         %57 = OpLoad %_arr_mat2v2float_uint_4 %arr
+               OpReturnValue %57
+               OpFunctionEnd
+    %f_inner = OpFunction %void None %58
 %local_invocation_index = OpFunctionParameter %uint
-         %18 = OpLabel
-        %idx = OpVariable %_ptr_Function_uint Function %21
+         %62 = OpLabel
+        %idx = OpVariable %_ptr_Function_uint Function %32
                OpStore %idx %local_invocation_index
-               OpBranch %22
-         %22 = OpLabel
-               OpLoopMerge %23 %24 None
-               OpBranch %25
-         %25 = OpLabel
-         %27 = OpLoad %uint %idx
-         %28 = OpULessThan %bool %27 %uint_4
-         %26 = OpLogicalNot %bool %28
-               OpSelectionMerge %30 None
-               OpBranchConditional %26 %31 %30
-         %31 = OpLabel
-               OpBranch %23
-         %30 = OpLabel
-         %32 = OpLoad %uint %idx
-         %34 = OpAccessChain %_ptr_Workgroup_mat2v2float %w %32
-               OpStore %34 %35
-               OpBranch %24
-         %24 = OpLabel
-         %36 = OpLoad %uint %idx
-         %38 = OpIAdd %uint %36 %uint_1
-               OpStore %idx %38
-               OpBranch %22
-         %23 = OpLabel
+               OpBranch %64
+         %64 = OpLabel
+               OpLoopMerge %65 %66 None
+               OpBranch %67
+         %67 = OpLabel
+         %69 = OpLoad %uint %idx
+         %70 = OpULessThan %bool %69 %uint_4
+         %68 = OpLogicalNot %bool %70
+               OpSelectionMerge %71 None
+               OpBranchConditional %68 %72 %71
+         %72 = OpLabel
+               OpBranch %65
+         %71 = OpLabel
+         %73 = OpLoad %uint %idx
+         %75 = OpAccessChain %_ptr_Workgroup_mat2v2float %w %73
+               OpStore %75 %76
+               OpBranch %66
+         %66 = OpLabel
+         %77 = OpLoad %uint %idx
+         %78 = OpIAdd %uint %77 %uint_1
+               OpStore %idx %78
+               OpBranch %64
+         %65 = OpLabel
                OpControlBarrier %uint_2 %uint_2 %uint_264
-         %44 = OpAccessChain %_ptr_Uniform__arr_mat2v2float_uint_4 %u %uint_0
-         %45 = OpLoad %_arr_mat2v2float_uint_4 %44
-               OpStore %w %45
-         %48 = OpAccessChain %_ptr_Workgroup_mat2v2float %w %int_1
-         %51 = OpAccessChain %_ptr_Uniform_mat2v2float %u %uint_0 %int_2
-         %52 = OpLoad %mat2v2float %51
-               OpStore %48 %52
-         %55 = OpAccessChain %_ptr_Workgroup_v2float %w %int_1 %53
-         %57 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %53 %int_1
-         %58 = OpLoad %v2float %57
-         %59 = OpVectorShuffle %v2float %58 %58 1 0
-               OpStore %55 %59
-         %61 = OpAccessChain %_ptr_Workgroup_float %w %int_1 %53 %uint_0
-         %63 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %53 %int_1 %uint_0
-         %64 = OpLoad %float %63
-               OpStore %61 %64
+         %85 = OpAccessChain %_ptr_Uniform__arr_mat2x2_f32_uint_4 %u %uint_0
+         %86 = OpLoad %_arr_mat2x2_f32_uint_4 %85
+         %82 = OpFunctionCall %_arr_mat2v2float_uint_4 %conv_arr4_mat2x2_f32 %86
+               OpStore %w %82
+         %89 = OpAccessChain %_ptr_Workgroup_mat2v2float %w %int_1
+         %92 = OpAccessChain %_ptr_Uniform_mat2x2_f32 %u %uint_0 %uint_2
+         %93 = OpLoad %mat2x2_f32 %92
+         %90 = OpFunctionCall %mat2v2float %conv_mat2x2_f32 %93
+               OpStore %89 %90
+         %96 = OpAccessChain %_ptr_Workgroup_v2float %w %int_1 %94
+         %98 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %32 %uint_1
+         %99 = OpLoad %v2float %98
+        %100 = OpVectorShuffle %v2float %99 %99 1 0
+               OpStore %96 %100
+        %102 = OpAccessChain %_ptr_Workgroup_float %w %int_1 %94 %uint_0
+        %104 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %32 %uint_1 %32
+        %105 = OpLoad %float %104
+               OpStore %102 %105
                OpReturn
                OpFunctionEnd
-          %f = OpFunction %void None %65
-         %67 = OpLabel
-         %69 = OpLoad %uint %local_invocation_index_1
-         %68 = OpFunctionCall %void %f_inner %69
+          %f = OpFunction %void None %106
+        %108 = OpLabel
+        %110 = OpLoad %uint %local_invocation_index_1
+        %109 = OpFunctionCall %void %f_inner %110
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x2/dynamic_index_via_ptr.wgsl.expected.glsl
index a71a143..991d478 100644
--- a/test/tint/buffer/uniform/std140/array/mat4x2/dynamic_index_via_ptr.wgsl.expected.glsl
+++ b/test/tint/buffer/uniform/std140/array/mat4x2/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -1,7 +1,14 @@
 #version 310 es
 
-layout(binding = 0, std140) uniform a_block_ubo {
-  mat4x2 inner[4];
+struct mat4x2_f32 {
+  vec2 col0;
+  vec2 col1;
+  vec2 col2;
+  vec2 col3;
+};
+
+layout(binding = 0, std140) uniform a_block_std140_ubo {
+  mat4x2_f32 inner[4];
 } a;
 
 int counter = 0;
@@ -10,14 +17,54 @@
   return counter;
 }
 
+mat4x2 conv_mat4x2_f32(mat4x2_f32 val) {
+  return mat4x2(val.col0, val.col1, val.col2, val.col3);
+}
+
+mat4x2[4] conv_arr4_mat4x2_f32(mat4x2_f32 val[4]) {
+  mat4x2 arr[4] = mat4x2[4](mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat4x2_f32(val[i]);
+    }
+  }
+  return arr;
+}
+
+vec2 load_a_inner_p0_p1(uint p0, uint p1) {
+  switch(p1) {
+    case 0u: {
+      return a.inner[p0].col0;
+      break;
+    }
+    case 1u: {
+      return a.inner[p0].col1;
+      break;
+    }
+    case 2u: {
+      return a.inner[p0].col2;
+      break;
+    }
+    case 3u: {
+      return a.inner[p0].col3;
+      break;
+    }
+    default: {
+      return vec2(0.0f);
+      break;
+    }
+  }
+}
+
 void f() {
+  mat4x2 p_a[4] = conv_arr4_mat4x2_f32(a.inner);
   int tint_symbol = i();
-  int p_a_i_save = tint_symbol;
+  mat4x2 p_a_i = conv_mat4x2_f32(a.inner[tint_symbol]);
   int tint_symbol_1 = i();
-  int p_a_i_i_save = tint_symbol_1;
-  mat4x2 l_a[4] = a.inner;
-  mat4x2 l_a_i = a.inner[p_a_i_save];
-  vec2 l_a_i_i = a.inner[p_a_i_save][p_a_i_i_save];
+  vec2 p_a_i_i = load_a_inner_p0_p1(uint(tint_symbol), uint(tint_symbol_1));
+  mat4x2 l_a[4] = conv_arr4_mat4x2_f32(a.inner);
+  mat4x2 l_a_i = conv_mat4x2_f32(a.inner[tint_symbol]);
+  vec2 l_a_i_i = load_a_inner_p0_p1(uint(tint_symbol), uint(tint_symbol_1));
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x2/dynamic_index_via_ptr.wgsl.expected.spvasm
index 11457bd..40c95ac 100644
--- a/test/tint/buffer/uniform/std140/array/mat4x2/dynamic_index_via_ptr.wgsl.expected.spvasm
+++ b/test/tint/buffer/uniform/std140/array/mat4x2/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -1,47 +1,83 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 37
+; Bound: 108
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
-               OpName %a_block "a_block"
-               OpMemberName %a_block 0 "inner"
+               OpName %a_block_std140 "a_block_std140"
+               OpMemberName %a_block_std140 0 "inner"
+               OpName %mat4x2_f32 "mat4x2_f32"
+               OpMemberName %mat4x2_f32 0 "col0"
+               OpMemberName %mat4x2_f32 1 "col1"
+               OpMemberName %mat4x2_f32 2 "col2"
+               OpMemberName %mat4x2_f32 3 "col3"
                OpName %a "a"
                OpName %counter "counter"
                OpName %i "i"
+               OpName %conv_mat4x2_f32 "conv_mat4x2_f32"
+               OpName %val "val"
+               OpName %conv_arr4_mat4x2_f32 "conv_arr4_mat4x2_f32"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i_0 "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_a_inner_p0_p1 "load_a_inner_p0_p1"
+               OpName %p0 "p0"
+               OpName %p1 "p1"
                OpName %f "f"
-               OpDecorate %a_block Block
-               OpMemberDecorate %a_block 0 Offset 0
-               OpMemberDecorate %a_block 0 ColMajor
-               OpMemberDecorate %a_block 0 MatrixStride 8
-               OpDecorate %_arr_mat4v2float_uint_4 ArrayStride 32
+               OpDecorate %a_block_std140 Block
+               OpMemberDecorate %a_block_std140 0 Offset 0
+               OpMemberDecorate %mat4x2_f32 0 Offset 0
+               OpMemberDecorate %mat4x2_f32 1 Offset 8
+               OpMemberDecorate %mat4x2_f32 2 Offset 16
+               OpMemberDecorate %mat4x2_f32 3 Offset 24
+               OpDecorate %_arr_mat4x2_f32_uint_4 ArrayStride 32
                OpDecorate %a NonWritable
                OpDecorate %a DescriptorSet 0
                OpDecorate %a Binding 0
+               OpDecorate %_arr_mat4v2float_uint_4 ArrayStride 32
       %float = OpTypeFloat 32
     %v2float = OpTypeVector %float 2
-%mat4v2float = OpTypeMatrix %v2float 4
+ %mat4x2_f32 = OpTypeStruct %v2float %v2float %v2float %v2float
        %uint = OpTypeInt 32 0
      %uint_4 = OpConstant %uint 4
-%_arr_mat4v2float_uint_4 = OpTypeArray %mat4v2float %uint_4
-    %a_block = OpTypeStruct %_arr_mat4v2float_uint_4
-%_ptr_Uniform_a_block = OpTypePointer Uniform %a_block
-          %a = OpVariable %_ptr_Uniform_a_block Uniform
+%_arr_mat4x2_f32_uint_4 = OpTypeArray %mat4x2_f32 %uint_4
+%a_block_std140 = OpTypeStruct %_arr_mat4x2_f32_uint_4
+%_ptr_Uniform_a_block_std140 = OpTypePointer Uniform %a_block_std140
+          %a = OpVariable %_ptr_Uniform_a_block_std140 Uniform
         %int = OpTypeInt 32 1
          %11 = OpConstantNull %int
 %_ptr_Private_int = OpTypePointer Private %int
     %counter = OpVariable %_ptr_Private_int Private %11
          %14 = OpTypeFunction %int
       %int_1 = OpConstant %int 1
-       %void = OpTypeVoid
-         %21 = OpTypeFunction %void
+%mat4v2float = OpTypeMatrix %v2float 4
+         %21 = OpTypeFunction %mat4v2float %mat4x2_f32
+%_arr_mat4v2float_uint_4 = OpTypeArray %mat4v2float %uint_4
+         %31 = OpTypeFunction %_arr_mat4v2float_uint_4 %_arr_mat4x2_f32_uint_4
+%_ptr_Function__arr_mat4v2float_uint_4 = OpTypePointer Function %_arr_mat4v2float_uint_4
+         %38 = OpConstantNull %_arr_mat4v2float_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %41 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_mat4x2_f32_uint_4 = OpTypePointer Function %_arr_mat4x2_f32_uint_4
+         %54 = OpConstantNull %_arr_mat4x2_f32_uint_4
+%_ptr_Function_mat4v2float = OpTypePointer Function %mat4v2float
+%_ptr_Function_mat4x2_f32 = OpTypePointer Function %mat4x2_f32
+     %uint_1 = OpConstant %uint 1
+         %67 = OpTypeFunction %v2float %uint %uint
      %uint_0 = OpConstant %uint 0
-%_ptr_Uniform__arr_mat4v2float_uint_4 = OpTypePointer Uniform %_arr_mat4v2float_uint_4
-%_ptr_Uniform_mat4v2float = OpTypePointer Uniform %mat4v2float
 %_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+         %90 = OpConstantNull %v2float
+       %void = OpTypeVoid
+         %91 = OpTypeFunction %void
+%_ptr_Uniform__arr_mat4x2_f32_uint_4 = OpTypePointer Uniform %_arr_mat4x2_f32_uint_4
+%_ptr_Uniform_mat4x2_f32 = OpTypePointer Uniform %mat4x2_f32
           %i = OpFunction %int None %14
          %16 = OpLabel
          %17 = OpLoad %int %counter
@@ -50,15 +86,92 @@
          %20 = OpLoad %int %counter
                OpReturnValue %20
                OpFunctionEnd
-          %f = OpFunction %void None %21
-         %24 = OpLabel
-         %25 = OpFunctionCall %int %i
-         %26 = OpFunctionCall %int %i
-         %29 = OpAccessChain %_ptr_Uniform__arr_mat4v2float_uint_4 %a %uint_0
-         %30 = OpLoad %_arr_mat4v2float_uint_4 %29
-         %32 = OpAccessChain %_ptr_Uniform_mat4v2float %a %uint_0 %25
-         %33 = OpLoad %mat4v2float %32
-         %35 = OpAccessChain %_ptr_Uniform_v2float %a %uint_0 %25 %26
-         %36 = OpLoad %v2float %35
+%conv_mat4x2_f32 = OpFunction %mat4v2float None %21
+        %val = OpFunctionParameter %mat4x2_f32
+         %25 = OpLabel
+         %26 = OpCompositeExtract %v2float %val 0
+         %27 = OpCompositeExtract %v2float %val 1
+         %28 = OpCompositeExtract %v2float %val 2
+         %29 = OpCompositeExtract %v2float %val 3
+         %30 = OpCompositeConstruct %mat4v2float %26 %27 %28 %29
+               OpReturnValue %30
+               OpFunctionEnd
+%conv_arr4_mat4x2_f32 = OpFunction %_arr_mat4v2float_uint_4 None %31
+      %val_0 = OpFunctionParameter %_arr_mat4x2_f32_uint_4
+         %35 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_mat4v2float_uint_4 Function %38
+        %i_0 = OpVariable %_ptr_Function_uint Function %41
+%var_for_index = OpVariable %_ptr_Function__arr_mat4x2_f32_uint_4 Function %54
+               OpBranch %42
+         %42 = OpLabel
+               OpLoopMerge %43 %44 None
+               OpBranch %45
+         %45 = OpLabel
+         %47 = OpLoad %uint %i_0
+         %48 = OpULessThan %bool %47 %uint_4
+         %46 = OpLogicalNot %bool %48
+               OpSelectionMerge %50 None
+               OpBranchConditional %46 %51 %50
+         %51 = OpLabel
+               OpBranch %43
+         %50 = OpLabel
+               OpStore %var_for_index %val_0
+         %55 = OpLoad %uint %i_0
+         %57 = OpAccessChain %_ptr_Function_mat4v2float %arr %55
+         %59 = OpLoad %uint %i_0
+         %61 = OpAccessChain %_ptr_Function_mat4x2_f32 %var_for_index %59
+         %62 = OpLoad %mat4x2_f32 %61
+         %58 = OpFunctionCall %mat4v2float %conv_mat4x2_f32 %62
+               OpStore %57 %58
+               OpBranch %44
+         %44 = OpLabel
+         %63 = OpLoad %uint %i_0
+         %65 = OpIAdd %uint %63 %uint_1
+               OpStore %i_0 %65
+               OpBranch %42
+         %43 = OpLabel
+         %66 = OpLoad %_arr_mat4v2float_uint_4 %arr
+               OpReturnValue %66
+               OpFunctionEnd
+%load_a_inner_p0_p1 = OpFunction %v2float None %67
+         %p0 = OpFunctionParameter %uint
+         %p1 = OpFunctionParameter %uint
+         %71 = OpLabel
+               OpSelectionMerge %72 None
+               OpSwitch %p1 %73 0 %74 1 %75 2 %76 3 %77
+         %74 = OpLabel
+         %80 = OpAccessChain %_ptr_Uniform_v2float %a %uint_0 %p0 %uint_0
+         %81 = OpLoad %v2float %80
+               OpReturnValue %81
+         %75 = OpLabel
+         %82 = OpAccessChain %_ptr_Uniform_v2float %a %uint_0 %p0 %uint_1
+         %83 = OpLoad %v2float %82
+               OpReturnValue %83
+         %76 = OpLabel
+         %85 = OpAccessChain %_ptr_Uniform_v2float %a %uint_0 %p0 %uint_2
+         %86 = OpLoad %v2float %85
+               OpReturnValue %86
+         %77 = OpLabel
+         %88 = OpAccessChain %_ptr_Uniform_v2float %a %uint_0 %p0 %uint_3
+         %89 = OpLoad %v2float %88
+               OpReturnValue %89
+         %73 = OpLabel
+               OpReturnValue %90
+         %72 = OpLabel
+               OpReturnValue %90
+               OpFunctionEnd
+          %f = OpFunction %void None %91
+         %94 = OpLabel
+         %95 = OpFunctionCall %int %i
+         %96 = OpFunctionCall %int %i
+         %99 = OpAccessChain %_ptr_Uniform__arr_mat4x2_f32_uint_4 %a %uint_0
+        %100 = OpLoad %_arr_mat4x2_f32_uint_4 %99
+         %97 = OpFunctionCall %_arr_mat4v2float_uint_4 %conv_arr4_mat4x2_f32 %100
+        %103 = OpAccessChain %_ptr_Uniform_mat4x2_f32 %a %uint_0 %95
+        %104 = OpLoad %mat4x2_f32 %103
+        %101 = OpFunctionCall %mat4v2float %conv_mat4x2_f32 %104
+        %106 = OpBitcast %uint %95
+        %107 = OpBitcast %uint %96
+        %105 = OpFunctionCall %v2float %load_a_inner_p0_p1 %106 %107
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x2/static_index_via_ptr.wgsl.expected.glsl
index ef740a1..bd894de 100644
--- a/test/tint/buffer/uniform/std140/array/mat4x2/static_index_via_ptr.wgsl.expected.glsl
+++ b/test/tint/buffer/uniform/std140/array/mat4x2/static_index_via_ptr.wgsl.expected.glsl
@@ -1,13 +1,37 @@
 #version 310 es
 
-layout(binding = 0, std140) uniform a_block_ubo {
-  mat4x2 inner[4];
+struct mat4x2_f32 {
+  vec2 col0;
+  vec2 col1;
+  vec2 col2;
+  vec2 col3;
+};
+
+layout(binding = 0, std140) uniform a_block_std140_ubo {
+  mat4x2_f32 inner[4];
 } a;
 
+mat4x2 conv_mat4x2_f32(mat4x2_f32 val) {
+  return mat4x2(val.col0, val.col1, val.col2, val.col3);
+}
+
+mat4x2[4] conv_arr4_mat4x2_f32(mat4x2_f32 val[4]) {
+  mat4x2 arr[4] = mat4x2[4](mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat4x2_f32(val[i]);
+    }
+  }
+  return arr;
+}
+
 void f() {
-  mat4x2 l_a[4] = a.inner;
-  mat4x2 l_a_i = a.inner[2];
-  vec2 l_a_i_i = a.inner[2][1];
+  mat4x2 p_a[4] = conv_arr4_mat4x2_f32(a.inner);
+  mat4x2 p_a_2 = conv_mat4x2_f32(a.inner[2u]);
+  vec2 p_a_2_1 = a.inner[2u].col1;
+  mat4x2 l_a[4] = conv_arr4_mat4x2_f32(a.inner);
+  mat4x2 l_a_i = conv_mat4x2_f32(a.inner[2u]);
+  vec2 l_a_i_i = a.inner[2u].col1;
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x2/static_index_via_ptr.wgsl.expected.spvasm
index d69110b..844eddb 100644
--- a/test/tint/buffer/uniform/std140/array/mat4x2/static_index_via_ptr.wgsl.expected.spvasm
+++ b/test/tint/buffer/uniform/std140/array/mat4x2/static_index_via_ptr.wgsl.expected.spvasm
@@ -1,49 +1,125 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 27
+; Bound: 73
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
-               OpName %a_block "a_block"
-               OpMemberName %a_block 0 "inner"
+               OpName %a_block_std140 "a_block_std140"
+               OpMemberName %a_block_std140 0 "inner"
+               OpName %mat4x2_f32 "mat4x2_f32"
+               OpMemberName %mat4x2_f32 0 "col0"
+               OpMemberName %mat4x2_f32 1 "col1"
+               OpMemberName %mat4x2_f32 2 "col2"
+               OpMemberName %mat4x2_f32 3 "col3"
                OpName %a "a"
+               OpName %conv_mat4x2_f32 "conv_mat4x2_f32"
+               OpName %val "val"
+               OpName %conv_arr4_mat4x2_f32 "conv_arr4_mat4x2_f32"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
                OpName %f "f"
-               OpDecorate %a_block Block
-               OpMemberDecorate %a_block 0 Offset 0
-               OpMemberDecorate %a_block 0 ColMajor
-               OpMemberDecorate %a_block 0 MatrixStride 8
-               OpDecorate %_arr_mat4v2float_uint_4 ArrayStride 32
+               OpDecorate %a_block_std140 Block
+               OpMemberDecorate %a_block_std140 0 Offset 0
+               OpMemberDecorate %mat4x2_f32 0 Offset 0
+               OpMemberDecorate %mat4x2_f32 1 Offset 8
+               OpMemberDecorate %mat4x2_f32 2 Offset 16
+               OpMemberDecorate %mat4x2_f32 3 Offset 24
+               OpDecorate %_arr_mat4x2_f32_uint_4 ArrayStride 32
                OpDecorate %a NonWritable
                OpDecorate %a DescriptorSet 0
                OpDecorate %a Binding 0
+               OpDecorate %_arr_mat4v2float_uint_4 ArrayStride 32
       %float = OpTypeFloat 32
     %v2float = OpTypeVector %float 2
-%mat4v2float = OpTypeMatrix %v2float 4
+ %mat4x2_f32 = OpTypeStruct %v2float %v2float %v2float %v2float
        %uint = OpTypeInt 32 0
      %uint_4 = OpConstant %uint 4
+%_arr_mat4x2_f32_uint_4 = OpTypeArray %mat4x2_f32 %uint_4
+%a_block_std140 = OpTypeStruct %_arr_mat4x2_f32_uint_4
+%_ptr_Uniform_a_block_std140 = OpTypePointer Uniform %a_block_std140
+          %a = OpVariable %_ptr_Uniform_a_block_std140 Uniform
+%mat4v2float = OpTypeMatrix %v2float 4
+         %10 = OpTypeFunction %mat4v2float %mat4x2_f32
 %_arr_mat4v2float_uint_4 = OpTypeArray %mat4v2float %uint_4
-    %a_block = OpTypeStruct %_arr_mat4v2float_uint_4
-%_ptr_Uniform_a_block = OpTypePointer Uniform %a_block
-          %a = OpVariable %_ptr_Uniform_a_block Uniform
+         %20 = OpTypeFunction %_arr_mat4v2float_uint_4 %_arr_mat4x2_f32_uint_4
+%_ptr_Function__arr_mat4v2float_uint_4 = OpTypePointer Function %_arr_mat4v2float_uint_4
+         %27 = OpConstantNull %_arr_mat4v2float_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %30 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_mat4x2_f32_uint_4 = OpTypePointer Function %_arr_mat4x2_f32_uint_4
+         %43 = OpConstantNull %_arr_mat4x2_f32_uint_4
+%_ptr_Function_mat4v2float = OpTypePointer Function %mat4v2float
+%_ptr_Function_mat4x2_f32 = OpTypePointer Function %mat4x2_f32
+     %uint_1 = OpConstant %uint 1
        %void = OpTypeVoid
-         %10 = OpTypeFunction %void
+         %56 = OpTypeFunction %void
      %uint_0 = OpConstant %uint 0
-%_ptr_Uniform__arr_mat4v2float_uint_4 = OpTypePointer Uniform %_arr_mat4v2float_uint_4
-        %int = OpTypeInt 32 1
-      %int_2 = OpConstant %int 2
-%_ptr_Uniform_mat4v2float = OpTypePointer Uniform %mat4v2float
-      %int_1 = OpConstant %int 1
+%_ptr_Uniform__arr_mat4x2_f32_uint_4 = OpTypePointer Uniform %_arr_mat4x2_f32_uint_4
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_mat4x2_f32 = OpTypePointer Uniform %mat4x2_f32
 %_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
-          %f = OpFunction %void None %10
-         %13 = OpLabel
-         %16 = OpAccessChain %_ptr_Uniform__arr_mat4v2float_uint_4 %a %uint_0
-         %17 = OpLoad %_arr_mat4v2float_uint_4 %16
-         %21 = OpAccessChain %_ptr_Uniform_mat4v2float %a %uint_0 %int_2
-         %22 = OpLoad %mat4v2float %21
-         %25 = OpAccessChain %_ptr_Uniform_v2float %a %uint_0 %int_2 %int_1
-         %26 = OpLoad %v2float %25
+%conv_mat4x2_f32 = OpFunction %mat4v2float None %10
+        %val = OpFunctionParameter %mat4x2_f32
+         %14 = OpLabel
+         %15 = OpCompositeExtract %v2float %val 0
+         %16 = OpCompositeExtract %v2float %val 1
+         %17 = OpCompositeExtract %v2float %val 2
+         %18 = OpCompositeExtract %v2float %val 3
+         %19 = OpCompositeConstruct %mat4v2float %15 %16 %17 %18
+               OpReturnValue %19
+               OpFunctionEnd
+%conv_arr4_mat4x2_f32 = OpFunction %_arr_mat4v2float_uint_4 None %20
+      %val_0 = OpFunctionParameter %_arr_mat4x2_f32_uint_4
+         %24 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_mat4v2float_uint_4 Function %27
+          %i = OpVariable %_ptr_Function_uint Function %30
+%var_for_index = OpVariable %_ptr_Function__arr_mat4x2_f32_uint_4 Function %43
+               OpBranch %31
+         %31 = OpLabel
+               OpLoopMerge %32 %33 None
+               OpBranch %34
+         %34 = OpLabel
+         %36 = OpLoad %uint %i
+         %37 = OpULessThan %bool %36 %uint_4
+         %35 = OpLogicalNot %bool %37
+               OpSelectionMerge %39 None
+               OpBranchConditional %35 %40 %39
+         %40 = OpLabel
+               OpBranch %32
+         %39 = OpLabel
+               OpStore %var_for_index %val_0
+         %44 = OpLoad %uint %i
+         %46 = OpAccessChain %_ptr_Function_mat4v2float %arr %44
+         %48 = OpLoad %uint %i
+         %50 = OpAccessChain %_ptr_Function_mat4x2_f32 %var_for_index %48
+         %51 = OpLoad %mat4x2_f32 %50
+         %47 = OpFunctionCall %mat4v2float %conv_mat4x2_f32 %51
+               OpStore %46 %47
+               OpBranch %33
+         %33 = OpLabel
+         %52 = OpLoad %uint %i
+         %54 = OpIAdd %uint %52 %uint_1
+               OpStore %i %54
+               OpBranch %31
+         %32 = OpLabel
+         %55 = OpLoad %_arr_mat4v2float_uint_4 %arr
+               OpReturnValue %55
+               OpFunctionEnd
+          %f = OpFunction %void None %56
+         %59 = OpLabel
+         %63 = OpAccessChain %_ptr_Uniform__arr_mat4x2_f32_uint_4 %a %uint_0
+         %64 = OpLoad %_arr_mat4x2_f32_uint_4 %63
+         %60 = OpFunctionCall %_arr_mat4v2float_uint_4 %conv_arr4_mat4x2_f32 %64
+         %68 = OpAccessChain %_ptr_Uniform_mat4x2_f32 %a %uint_0 %uint_2
+         %69 = OpLoad %mat4x2_f32 %68
+         %65 = OpFunctionCall %mat4v2float %conv_mat4x2_f32 %69
+         %71 = OpAccessChain %_ptr_Uniform_v2float %a %uint_0 %uint_2 %uint_1
+         %72 = OpLoad %v2float %71
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x2/to_fn.wgsl.expected.glsl
index 850d586..7097f20 100644
--- a/test/tint/buffer/uniform/std140/array/mat4x2/to_fn.wgsl.expected.glsl
+++ b/test/tint/buffer/uniform/std140/array/mat4x2/to_fn.wgsl.expected.glsl
@@ -1,7 +1,14 @@
 #version 310 es
 
-layout(binding = 0, std140) uniform u_block_ubo {
-  mat4x2 inner[4];
+struct mat4x2_f32 {
+  vec2 col0;
+  vec2 col1;
+  vec2 col2;
+  vec2 col3;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  mat4x2_f32 inner[4];
 } u;
 
 void a(mat4x2 a_1[4]) {
@@ -16,11 +23,25 @@
 void d(float f_1) {
 }
 
+mat4x2 conv_mat4x2_f32(mat4x2_f32 val) {
+  return mat4x2(val.col0, val.col1, val.col2, val.col3);
+}
+
+mat4x2[4] conv_arr4_mat4x2_f32(mat4x2_f32 val[4]) {
+  mat4x2 arr[4] = mat4x2[4](mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat4x2_f32(val[i]);
+    }
+  }
+  return arr;
+}
+
 void f() {
-  a(u.inner);
-  b(u.inner[1]);
-  c(u.inner[1][0].yx);
-  d(u.inner[1][0].yx.x);
+  a(conv_arr4_mat4x2_f32(u.inner));
+  b(conv_mat4x2_f32(u.inner[1u]));
+  c(u.inner[1u].col0.yx);
+  d(u.inner[1u].col0.yx[0u]);
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x2/to_fn.wgsl.expected.spvasm
index 8ee216d..17a9c66 100644
--- a/test/tint/buffer/uniform/std140/array/mat4x2/to_fn.wgsl.expected.spvasm
+++ b/test/tint/buffer/uniform/std140/array/mat4x2/to_fn.wgsl.expected.spvasm
@@ -1,14 +1,19 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 52
+; Bound: 97
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
-               OpName %u_block "u_block"
-               OpMemberName %u_block 0 "inner"
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %mat4x2_f32 "mat4x2_f32"
+               OpMemberName %mat4x2_f32 0 "col0"
+               OpMemberName %mat4x2_f32 1 "col1"
+               OpMemberName %mat4x2_f32 2 "col2"
+               OpMemberName %mat4x2_f32 3 "col3"
                OpName %u "u"
                OpName %a "a"
                OpName %a_1 "a_1"
@@ -18,73 +23,143 @@
                OpName %v "v"
                OpName %d "d"
                OpName %f_1 "f_1"
+               OpName %conv_mat4x2_f32 "conv_mat4x2_f32"
+               OpName %val "val"
+               OpName %conv_arr4_mat4x2_f32 "conv_arr4_mat4x2_f32"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
                OpName %f "f"
-               OpDecorate %u_block Block
-               OpMemberDecorate %u_block 0 Offset 0
-               OpMemberDecorate %u_block 0 ColMajor
-               OpMemberDecorate %u_block 0 MatrixStride 8
-               OpDecorate %_arr_mat4v2float_uint_4 ArrayStride 32
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %mat4x2_f32 0 Offset 0
+               OpMemberDecorate %mat4x2_f32 1 Offset 8
+               OpMemberDecorate %mat4x2_f32 2 Offset 16
+               OpMemberDecorate %mat4x2_f32 3 Offset 24
+               OpDecorate %_arr_mat4x2_f32_uint_4 ArrayStride 32
                OpDecorate %u NonWritable
                OpDecorate %u DescriptorSet 0
                OpDecorate %u Binding 0
+               OpDecorate %_arr_mat4v2float_uint_4 ArrayStride 32
       %float = OpTypeFloat 32
     %v2float = OpTypeVector %float 2
-%mat4v2float = OpTypeMatrix %v2float 4
+ %mat4x2_f32 = OpTypeStruct %v2float %v2float %v2float %v2float
        %uint = OpTypeInt 32 0
      %uint_4 = OpConstant %uint 4
-%_arr_mat4v2float_uint_4 = OpTypeArray %mat4v2float %uint_4
-    %u_block = OpTypeStruct %_arr_mat4v2float_uint_4
-%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
-          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_arr_mat4x2_f32_uint_4 = OpTypeArray %mat4x2_f32 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_mat4x2_f32_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
        %void = OpTypeVoid
+%mat4v2float = OpTypeMatrix %v2float 4
+%_arr_mat4v2float_uint_4 = OpTypeArray %mat4v2float %uint_4
          %10 = OpTypeFunction %void %_arr_mat4v2float_uint_4
-         %15 = OpTypeFunction %void %mat4v2float
-         %19 = OpTypeFunction %void %v2float
-         %23 = OpTypeFunction %void %float
-         %27 = OpTypeFunction %void
+         %17 = OpTypeFunction %void %mat4v2float
+         %21 = OpTypeFunction %void %v2float
+         %25 = OpTypeFunction %void %float
+         %29 = OpTypeFunction %mat4v2float %mat4x2_f32
+         %38 = OpTypeFunction %_arr_mat4v2float_uint_4 %_arr_mat4x2_f32_uint_4
+%_ptr_Function__arr_mat4v2float_uint_4 = OpTypePointer Function %_arr_mat4v2float_uint_4
+         %44 = OpConstantNull %_arr_mat4v2float_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %47 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_mat4x2_f32_uint_4 = OpTypePointer Function %_arr_mat4x2_f32_uint_4
+         %60 = OpConstantNull %_arr_mat4x2_f32_uint_4
+%_ptr_Function_mat4v2float = OpTypePointer Function %mat4v2float
+%_ptr_Function_mat4x2_f32 = OpTypePointer Function %mat4x2_f32
+     %uint_1 = OpConstant %uint 1
+         %73 = OpTypeFunction %void
      %uint_0 = OpConstant %uint 0
-%_ptr_Uniform__arr_mat4v2float_uint_4 = OpTypePointer Uniform %_arr_mat4v2float_uint_4
-        %int = OpTypeInt 32 1
-      %int_1 = OpConstant %int 1
-%_ptr_Uniform_mat4v2float = OpTypePointer Uniform %mat4v2float
-         %42 = OpConstantNull %int
+%_ptr_Uniform__arr_mat4x2_f32_uint_4 = OpTypePointer Uniform %_arr_mat4x2_f32_uint_4
+%_ptr_Uniform_mat4x2_f32 = OpTypePointer Uniform %mat4x2_f32
 %_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
           %a = OpFunction %void None %10
         %a_1 = OpFunctionParameter %_arr_mat4v2float_uint_4
-         %14 = OpLabel
+         %16 = OpLabel
                OpReturn
                OpFunctionEnd
-          %b = OpFunction %void None %15
+          %b = OpFunction %void None %17
           %m = OpFunctionParameter %mat4v2float
-         %18 = OpLabel
+         %20 = OpLabel
                OpReturn
                OpFunctionEnd
-          %c = OpFunction %void None %19
+          %c = OpFunction %void None %21
           %v = OpFunctionParameter %v2float
-         %22 = OpLabel
+         %24 = OpLabel
                OpReturn
                OpFunctionEnd
-          %d = OpFunction %void None %23
+          %d = OpFunction %void None %25
         %f_1 = OpFunctionParameter %float
-         %26 = OpLabel
+         %28 = OpLabel
                OpReturn
                OpFunctionEnd
-          %f = OpFunction %void None %27
-         %29 = OpLabel
-         %33 = OpAccessChain %_ptr_Uniform__arr_mat4v2float_uint_4 %u %uint_0
-         %34 = OpLoad %_arr_mat4v2float_uint_4 %33
-         %30 = OpFunctionCall %void %a %34
-         %39 = OpAccessChain %_ptr_Uniform_mat4v2float %u %uint_0 %int_1
-         %40 = OpLoad %mat4v2float %39
-         %35 = OpFunctionCall %void %b %40
-         %44 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %int_1 %42
-         %45 = OpLoad %v2float %44
-         %46 = OpVectorShuffle %v2float %45 %45 1 0
-         %41 = OpFunctionCall %void %c %46
-         %48 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %int_1 %42
-         %49 = OpLoad %v2float %48
-         %50 = OpVectorShuffle %v2float %49 %49 1 0
-         %51 = OpCompositeExtract %float %50 0
-         %47 = OpFunctionCall %void %d %51
+%conv_mat4x2_f32 = OpFunction %mat4v2float None %29
+        %val = OpFunctionParameter %mat4x2_f32
+         %32 = OpLabel
+         %33 = OpCompositeExtract %v2float %val 0
+         %34 = OpCompositeExtract %v2float %val 1
+         %35 = OpCompositeExtract %v2float %val 2
+         %36 = OpCompositeExtract %v2float %val 3
+         %37 = OpCompositeConstruct %mat4v2float %33 %34 %35 %36
+               OpReturnValue %37
+               OpFunctionEnd
+%conv_arr4_mat4x2_f32 = OpFunction %_arr_mat4v2float_uint_4 None %38
+      %val_0 = OpFunctionParameter %_arr_mat4x2_f32_uint_4
+         %41 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_mat4v2float_uint_4 Function %44
+          %i = OpVariable %_ptr_Function_uint Function %47
+%var_for_index = OpVariable %_ptr_Function__arr_mat4x2_f32_uint_4 Function %60
+               OpBranch %48
+         %48 = OpLabel
+               OpLoopMerge %49 %50 None
+               OpBranch %51
+         %51 = OpLabel
+         %53 = OpLoad %uint %i
+         %54 = OpULessThan %bool %53 %uint_4
+         %52 = OpLogicalNot %bool %54
+               OpSelectionMerge %56 None
+               OpBranchConditional %52 %57 %56
+         %57 = OpLabel
+               OpBranch %49
+         %56 = OpLabel
+               OpStore %var_for_index %val_0
+         %61 = OpLoad %uint %i
+         %63 = OpAccessChain %_ptr_Function_mat4v2float %arr %61
+         %65 = OpLoad %uint %i
+         %67 = OpAccessChain %_ptr_Function_mat4x2_f32 %var_for_index %65
+         %68 = OpLoad %mat4x2_f32 %67
+         %64 = OpFunctionCall %mat4v2float %conv_mat4x2_f32 %68
+               OpStore %63 %64
+               OpBranch %50
+         %50 = OpLabel
+         %69 = OpLoad %uint %i
+         %71 = OpIAdd %uint %69 %uint_1
+               OpStore %i %71
+               OpBranch %48
+         %49 = OpLabel
+         %72 = OpLoad %_arr_mat4v2float_uint_4 %arr
+               OpReturnValue %72
+               OpFunctionEnd
+          %f = OpFunction %void None %73
+         %75 = OpLabel
+         %80 = OpAccessChain %_ptr_Uniform__arr_mat4x2_f32_uint_4 %u %uint_0
+         %81 = OpLoad %_arr_mat4x2_f32_uint_4 %80
+         %77 = OpFunctionCall %_arr_mat4v2float_uint_4 %conv_arr4_mat4x2_f32 %81
+         %76 = OpFunctionCall %void %a %77
+         %85 = OpAccessChain %_ptr_Uniform_mat4x2_f32 %u %uint_0 %uint_1
+         %86 = OpLoad %mat4x2_f32 %85
+         %83 = OpFunctionCall %mat4v2float %conv_mat4x2_f32 %86
+         %82 = OpFunctionCall %void %b %83
+         %89 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %uint_1 %uint_0
+         %90 = OpLoad %v2float %89
+         %91 = OpVectorShuffle %v2float %90 %90 1 0
+         %87 = OpFunctionCall %void %c %91
+         %93 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %uint_1 %uint_0
+         %94 = OpLoad %v2float %93
+         %95 = OpVectorShuffle %v2float %94 %94 1 0
+         %96 = OpCompositeExtract %float %95 0
+         %92 = OpFunctionCall %void %d %96
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x2/to_private.wgsl.expected.glsl
index 0b73e75..01b3ece 100644
--- a/test/tint/buffer/uniform/std140/array/mat4x2/to_private.wgsl.expected.glsl
+++ b/test/tint/buffer/uniform/std140/array/mat4x2/to_private.wgsl.expected.glsl
@@ -1,21 +1,42 @@
 #version 310 es
 
+struct mat4x2_f32 {
+  vec2 col0;
+  vec2 col1;
+  vec2 col2;
+  vec2 col3;
+};
+
 struct S {
   int before;
   mat4x2 m;
   int after;
 };
 
-layout(binding = 0, std140) uniform u_block_ubo {
-  mat4x2 inner[4];
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  mat4x2_f32 inner[4];
 } u;
 
 mat4x2 p[4] = mat4x2[4](mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
+mat4x2 conv_mat4x2_f32(mat4x2_f32 val) {
+  return mat4x2(val.col0, val.col1, val.col2, val.col3);
+}
+
+mat4x2[4] conv_arr4_mat4x2_f32(mat4x2_f32 val[4]) {
+  mat4x2 arr[4] = mat4x2[4](mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat4x2_f32(val[i]);
+    }
+  }
+  return arr;
+}
+
 void f() {
-  p = u.inner;
-  p[1] = u.inner[2];
-  p[1][0] = u.inner[0][1].yx;
-  p[1][0].x = u.inner[0][1].x;
+  p = conv_arr4_mat4x2_f32(u.inner);
+  p[1] = conv_mat4x2_f32(u.inner[2u]);
+  p[1][0] = u.inner[0u].col1.yx;
+  p[1][0].x = u.inner[0u].col1[0u];
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x2/to_private.wgsl.expected.spvasm
index 41ac892..f22ef5d 100644
--- a/test/tint/buffer/uniform/std140/array/mat4x2/to_private.wgsl.expected.spvasm
+++ b/test/tint/buffer/uniform/std140/array/mat4x2/to_private.wgsl.expected.spvasm
@@ -1,68 +1,145 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 41
+; Bound: 88
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
-               OpName %u_block "u_block"
-               OpMemberName %u_block 0 "inner"
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %mat4x2_f32 "mat4x2_f32"
+               OpMemberName %mat4x2_f32 0 "col0"
+               OpMemberName %mat4x2_f32 1 "col1"
+               OpMemberName %mat4x2_f32 2 "col2"
+               OpMemberName %mat4x2_f32 3 "col3"
                OpName %u "u"
                OpName %p "p"
+               OpName %conv_mat4x2_f32 "conv_mat4x2_f32"
+               OpName %val "val"
+               OpName %conv_arr4_mat4x2_f32 "conv_arr4_mat4x2_f32"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
                OpName %f "f"
-               OpDecorate %u_block Block
-               OpMemberDecorate %u_block 0 Offset 0
-               OpMemberDecorate %u_block 0 ColMajor
-               OpMemberDecorate %u_block 0 MatrixStride 8
-               OpDecorate %_arr_mat4v2float_uint_4 ArrayStride 32
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %mat4x2_f32 0 Offset 0
+               OpMemberDecorate %mat4x2_f32 1 Offset 8
+               OpMemberDecorate %mat4x2_f32 2 Offset 16
+               OpMemberDecorate %mat4x2_f32 3 Offset 24
+               OpDecorate %_arr_mat4x2_f32_uint_4 ArrayStride 32
                OpDecorate %u NonWritable
                OpDecorate %u DescriptorSet 0
                OpDecorate %u Binding 0
+               OpDecorate %_arr_mat4v2float_uint_4 ArrayStride 32
       %float = OpTypeFloat 32
     %v2float = OpTypeVector %float 2
-%mat4v2float = OpTypeMatrix %v2float 4
+ %mat4x2_f32 = OpTypeStruct %v2float %v2float %v2float %v2float
        %uint = OpTypeInt 32 0
      %uint_4 = OpConstant %uint 4
+%_arr_mat4x2_f32_uint_4 = OpTypeArray %mat4x2_f32 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_mat4x2_f32_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+%mat4v2float = OpTypeMatrix %v2float 4
 %_arr_mat4v2float_uint_4 = OpTypeArray %mat4v2float %uint_4
-    %u_block = OpTypeStruct %_arr_mat4v2float_uint_4
-%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
-          %u = OpVariable %_ptr_Uniform_u_block Uniform
 %_ptr_Private__arr_mat4v2float_uint_4 = OpTypePointer Private %_arr_mat4v2float_uint_4
-         %12 = OpConstantNull %_arr_mat4v2float_uint_4
-          %p = OpVariable %_ptr_Private__arr_mat4v2float_uint_4 Private %12
+         %14 = OpConstantNull %_arr_mat4v2float_uint_4
+          %p = OpVariable %_ptr_Private__arr_mat4v2float_uint_4 Private %14
+         %15 = OpTypeFunction %mat4v2float %mat4x2_f32
+         %24 = OpTypeFunction %_arr_mat4v2float_uint_4 %_arr_mat4x2_f32_uint_4
+%_ptr_Function__arr_mat4v2float_uint_4 = OpTypePointer Function %_arr_mat4v2float_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %32 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_mat4x2_f32_uint_4 = OpTypePointer Function %_arr_mat4x2_f32_uint_4
+         %45 = OpConstantNull %_arr_mat4x2_f32_uint_4
+%_ptr_Function_mat4v2float = OpTypePointer Function %mat4v2float
+%_ptr_Function_mat4x2_f32 = OpTypePointer Function %mat4x2_f32
+     %uint_1 = OpConstant %uint 1
        %void = OpTypeVoid
-         %13 = OpTypeFunction %void
+         %58 = OpTypeFunction %void
      %uint_0 = OpConstant %uint 0
-%_ptr_Uniform__arr_mat4v2float_uint_4 = OpTypePointer Uniform %_arr_mat4v2float_uint_4
+%_ptr_Uniform__arr_mat4x2_f32_uint_4 = OpTypePointer Uniform %_arr_mat4x2_f32_uint_4
         %int = OpTypeInt 32 1
       %int_1 = OpConstant %int 1
 %_ptr_Private_mat4v2float = OpTypePointer Private %mat4v2float
-      %int_2 = OpConstant %int 2
-%_ptr_Uniform_mat4v2float = OpTypePointer Uniform %mat4v2float
-         %29 = OpConstantNull %int
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_mat4x2_f32 = OpTypePointer Uniform %mat4x2_f32
+         %76 = OpConstantNull %int
 %_ptr_Private_v2float = OpTypePointer Private %v2float
 %_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
 %_ptr_Private_float = OpTypePointer Private %float
 %_ptr_Uniform_float = OpTypePointer Uniform %float
-          %f = OpFunction %void None %13
-         %16 = OpLabel
-         %19 = OpAccessChain %_ptr_Uniform__arr_mat4v2float_uint_4 %u %uint_0
-         %20 = OpLoad %_arr_mat4v2float_uint_4 %19
-               OpStore %p %20
-         %24 = OpAccessChain %_ptr_Private_mat4v2float %p %int_1
-         %27 = OpAccessChain %_ptr_Uniform_mat4v2float %u %uint_0 %int_2
-         %28 = OpLoad %mat4v2float %27
-               OpStore %24 %28
-         %31 = OpAccessChain %_ptr_Private_v2float %p %int_1 %29
-         %33 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %29 %int_1
-         %34 = OpLoad %v2float %33
-         %35 = OpVectorShuffle %v2float %34 %34 1 0
-               OpStore %31 %35
-         %37 = OpAccessChain %_ptr_Private_float %p %int_1 %29 %uint_0
-         %39 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %29 %int_1 %uint_0
-         %40 = OpLoad %float %39
-               OpStore %37 %40
+%conv_mat4x2_f32 = OpFunction %mat4v2float None %15
+        %val = OpFunctionParameter %mat4x2_f32
+         %18 = OpLabel
+         %19 = OpCompositeExtract %v2float %val 0
+         %20 = OpCompositeExtract %v2float %val 1
+         %21 = OpCompositeExtract %v2float %val 2
+         %22 = OpCompositeExtract %v2float %val 3
+         %23 = OpCompositeConstruct %mat4v2float %19 %20 %21 %22
+               OpReturnValue %23
+               OpFunctionEnd
+%conv_arr4_mat4x2_f32 = OpFunction %_arr_mat4v2float_uint_4 None %24
+      %val_0 = OpFunctionParameter %_arr_mat4x2_f32_uint_4
+         %27 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_mat4v2float_uint_4 Function %14
+          %i = OpVariable %_ptr_Function_uint Function %32
+%var_for_index = OpVariable %_ptr_Function__arr_mat4x2_f32_uint_4 Function %45
+               OpBranch %33
+         %33 = OpLabel
+               OpLoopMerge %34 %35 None
+               OpBranch %36
+         %36 = OpLabel
+         %38 = OpLoad %uint %i
+         %39 = OpULessThan %bool %38 %uint_4
+         %37 = OpLogicalNot %bool %39
+               OpSelectionMerge %41 None
+               OpBranchConditional %37 %42 %41
+         %42 = OpLabel
+               OpBranch %34
+         %41 = OpLabel
+               OpStore %var_for_index %val_0
+         %46 = OpLoad %uint %i
+         %48 = OpAccessChain %_ptr_Function_mat4v2float %arr %46
+         %50 = OpLoad %uint %i
+         %52 = OpAccessChain %_ptr_Function_mat4x2_f32 %var_for_index %50
+         %53 = OpLoad %mat4x2_f32 %52
+         %49 = OpFunctionCall %mat4v2float %conv_mat4x2_f32 %53
+               OpStore %48 %49
+               OpBranch %35
+         %35 = OpLabel
+         %54 = OpLoad %uint %i
+         %56 = OpIAdd %uint %54 %uint_1
+               OpStore %i %56
+               OpBranch %33
+         %34 = OpLabel
+         %57 = OpLoad %_arr_mat4v2float_uint_4 %arr
+               OpReturnValue %57
+               OpFunctionEnd
+          %f = OpFunction %void None %58
+         %61 = OpLabel
+         %65 = OpAccessChain %_ptr_Uniform__arr_mat4x2_f32_uint_4 %u %uint_0
+         %66 = OpLoad %_arr_mat4x2_f32_uint_4 %65
+         %62 = OpFunctionCall %_arr_mat4v2float_uint_4 %conv_arr4_mat4x2_f32 %66
+               OpStore %p %62
+         %70 = OpAccessChain %_ptr_Private_mat4v2float %p %int_1
+         %74 = OpAccessChain %_ptr_Uniform_mat4x2_f32 %u %uint_0 %uint_2
+         %75 = OpLoad %mat4x2_f32 %74
+         %71 = OpFunctionCall %mat4v2float %conv_mat4x2_f32 %75
+               OpStore %70 %71
+         %78 = OpAccessChain %_ptr_Private_v2float %p %int_1 %76
+         %80 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %32 %uint_1
+         %81 = OpLoad %v2float %80
+         %82 = OpVectorShuffle %v2float %81 %81 1 0
+               OpStore %78 %82
+         %84 = OpAccessChain %_ptr_Private_float %p %int_1 %76 %uint_0
+         %86 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %32 %uint_1 %32
+         %87 = OpLoad %float %86
+               OpStore %84 %87
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x2/to_storage.wgsl.expected.glsl
index 7eb1bf5..b7e9977 100644
--- a/test/tint/buffer/uniform/std140/array/mat4x2/to_storage.wgsl.expected.glsl
+++ b/test/tint/buffer/uniform/std140/array/mat4x2/to_storage.wgsl.expected.glsl
@@ -1,24 +1,45 @@
 #version 310 es
 
+struct mat4x2_f32 {
+  vec2 col0;
+  vec2 col1;
+  vec2 col2;
+  vec2 col3;
+};
+
 struct S {
   int before;
   mat4x2 m;
   int after;
 };
 
-layout(binding = 0, std140) uniform u_block_ubo {
-  mat4x2 inner[4];
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  mat4x2_f32 inner[4];
 } u;
 
 layout(binding = 1, std430) buffer u_block_ssbo {
   mat4x2 inner[4];
 } s;
 
+mat4x2 conv_mat4x2_f32(mat4x2_f32 val) {
+  return mat4x2(val.col0, val.col1, val.col2, val.col3);
+}
+
+mat4x2[4] conv_arr4_mat4x2_f32(mat4x2_f32 val[4]) {
+  mat4x2 arr[4] = mat4x2[4](mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat4x2_f32(val[i]);
+    }
+  }
+  return arr;
+}
+
 void f() {
-  s.inner = u.inner;
-  s.inner[1] = u.inner[2];
-  s.inner[1][0] = u.inner[0][1].yx;
-  s.inner[1][0].x = u.inner[0][1].x;
+  s.inner = conv_arr4_mat4x2_f32(u.inner);
+  s.inner[1] = conv_mat4x2_f32(u.inner[2u]);
+  s.inner[1][0] = u.inner[0u].col1.yx;
+  s.inner[1][0].x = u.inner[0u].col1[0u];
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x2/to_storage.wgsl.expected.spvasm
index f922154..ed2b150 100644
--- a/test/tint/buffer/uniform/std140/array/mat4x2/to_storage.wgsl.expected.spvasm
+++ b/test/tint/buffer/uniform/std140/array/mat4x2/to_storage.wgsl.expected.spvasm
@@ -1,71 +1,156 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 42
+; Bound: 91
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f"
                OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %mat4x2_f32 "mat4x2_f32"
+               OpMemberName %mat4x2_f32 0 "col0"
+               OpMemberName %mat4x2_f32 1 "col1"
+               OpMemberName %mat4x2_f32 2 "col2"
+               OpMemberName %mat4x2_f32 3 "col3"
+               OpName %u "u"
                OpName %u_block "u_block"
                OpMemberName %u_block 0 "inner"
-               OpName %u "u"
                OpName %s "s"
+               OpName %conv_mat4x2_f32 "conv_mat4x2_f32"
+               OpName %val "val"
+               OpName %conv_arr4_mat4x2_f32 "conv_arr4_mat4x2_f32"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
                OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %mat4x2_f32 0 Offset 0
+               OpMemberDecorate %mat4x2_f32 1 Offset 8
+               OpMemberDecorate %mat4x2_f32 2 Offset 16
+               OpMemberDecorate %mat4x2_f32 3 Offset 24
+               OpDecorate %_arr_mat4x2_f32_uint_4 ArrayStride 32
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
                OpDecorate %u_block Block
                OpMemberDecorate %u_block 0 Offset 0
                OpMemberDecorate %u_block 0 ColMajor
                OpMemberDecorate %u_block 0 MatrixStride 8
                OpDecorate %_arr_mat4v2float_uint_4 ArrayStride 32
-               OpDecorate %u NonWritable
-               OpDecorate %u DescriptorSet 0
-               OpDecorate %u Binding 0
                OpDecorate %s DescriptorSet 0
                OpDecorate %s Binding 1
       %float = OpTypeFloat 32
     %v2float = OpTypeVector %float 2
-%mat4v2float = OpTypeMatrix %v2float 4
+ %mat4x2_f32 = OpTypeStruct %v2float %v2float %v2float %v2float
        %uint = OpTypeInt 32 0
      %uint_4 = OpConstant %uint 4
+%_arr_mat4x2_f32_uint_4 = OpTypeArray %mat4x2_f32 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_mat4x2_f32_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+%mat4v2float = OpTypeMatrix %v2float 4
 %_arr_mat4v2float_uint_4 = OpTypeArray %mat4v2float %uint_4
     %u_block = OpTypeStruct %_arr_mat4v2float_uint_4
-%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
-          %u = OpVariable %_ptr_Uniform_u_block Uniform
 %_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
           %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+         %15 = OpTypeFunction %mat4v2float %mat4x2_f32
+         %24 = OpTypeFunction %_arr_mat4v2float_uint_4 %_arr_mat4x2_f32_uint_4
+%_ptr_Function__arr_mat4v2float_uint_4 = OpTypePointer Function %_arr_mat4v2float_uint_4
+         %30 = OpConstantNull %_arr_mat4v2float_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %33 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_mat4x2_f32_uint_4 = OpTypePointer Function %_arr_mat4x2_f32_uint_4
+         %46 = OpConstantNull %_arr_mat4x2_f32_uint_4
+%_ptr_Function_mat4v2float = OpTypePointer Function %mat4v2float
+%_ptr_Function_mat4x2_f32 = OpTypePointer Function %mat4x2_f32
+     %uint_1 = OpConstant %uint 1
        %void = OpTypeVoid
-         %12 = OpTypeFunction %void
+         %59 = OpTypeFunction %void
      %uint_0 = OpConstant %uint 0
 %_ptr_StorageBuffer__arr_mat4v2float_uint_4 = OpTypePointer StorageBuffer %_arr_mat4v2float_uint_4
-%_ptr_Uniform__arr_mat4v2float_uint_4 = OpTypePointer Uniform %_arr_mat4v2float_uint_4
+%_ptr_Uniform__arr_mat4x2_f32_uint_4 = OpTypePointer Uniform %_arr_mat4x2_f32_uint_4
         %int = OpTypeInt 32 1
       %int_1 = OpConstant %int 1
 %_ptr_StorageBuffer_mat4v2float = OpTypePointer StorageBuffer %mat4v2float
-      %int_2 = OpConstant %int 2
-%_ptr_Uniform_mat4v2float = OpTypePointer Uniform %mat4v2float
-         %30 = OpConstantNull %int
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_mat4x2_f32 = OpTypePointer Uniform %mat4x2_f32
+         %79 = OpConstantNull %int
 %_ptr_StorageBuffer_v2float = OpTypePointer StorageBuffer %v2float
 %_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
 %_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
 %_ptr_Uniform_float = OpTypePointer Uniform %float
-          %f = OpFunction %void None %12
-         %15 = OpLabel
-         %18 = OpAccessChain %_ptr_StorageBuffer__arr_mat4v2float_uint_4 %s %uint_0
-         %20 = OpAccessChain %_ptr_Uniform__arr_mat4v2float_uint_4 %u %uint_0
-         %21 = OpLoad %_arr_mat4v2float_uint_4 %20
-               OpStore %18 %21
-         %25 = OpAccessChain %_ptr_StorageBuffer_mat4v2float %s %uint_0 %int_1
-         %28 = OpAccessChain %_ptr_Uniform_mat4v2float %u %uint_0 %int_2
-         %29 = OpLoad %mat4v2float %28
-               OpStore %25 %29
-         %32 = OpAccessChain %_ptr_StorageBuffer_v2float %s %uint_0 %int_1 %30
-         %34 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %30 %int_1
-         %35 = OpLoad %v2float %34
-         %36 = OpVectorShuffle %v2float %35 %35 1 0
-               OpStore %32 %36
-         %38 = OpAccessChain %_ptr_StorageBuffer_float %s %uint_0 %int_1 %30 %uint_0
-         %40 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %30 %int_1 %uint_0
-         %41 = OpLoad %float %40
-               OpStore %38 %41
+%conv_mat4x2_f32 = OpFunction %mat4v2float None %15
+        %val = OpFunctionParameter %mat4x2_f32
+         %18 = OpLabel
+         %19 = OpCompositeExtract %v2float %val 0
+         %20 = OpCompositeExtract %v2float %val 1
+         %21 = OpCompositeExtract %v2float %val 2
+         %22 = OpCompositeExtract %v2float %val 3
+         %23 = OpCompositeConstruct %mat4v2float %19 %20 %21 %22
+               OpReturnValue %23
+               OpFunctionEnd
+%conv_arr4_mat4x2_f32 = OpFunction %_arr_mat4v2float_uint_4 None %24
+      %val_0 = OpFunctionParameter %_arr_mat4x2_f32_uint_4
+         %27 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_mat4v2float_uint_4 Function %30
+          %i = OpVariable %_ptr_Function_uint Function %33
+%var_for_index = OpVariable %_ptr_Function__arr_mat4x2_f32_uint_4 Function %46
+               OpBranch %34
+         %34 = OpLabel
+               OpLoopMerge %35 %36 None
+               OpBranch %37
+         %37 = OpLabel
+         %39 = OpLoad %uint %i
+         %40 = OpULessThan %bool %39 %uint_4
+         %38 = OpLogicalNot %bool %40
+               OpSelectionMerge %42 None
+               OpBranchConditional %38 %43 %42
+         %43 = OpLabel
+               OpBranch %35
+         %42 = OpLabel
+               OpStore %var_for_index %val_0
+         %47 = OpLoad %uint %i
+         %49 = OpAccessChain %_ptr_Function_mat4v2float %arr %47
+         %51 = OpLoad %uint %i
+         %53 = OpAccessChain %_ptr_Function_mat4x2_f32 %var_for_index %51
+         %54 = OpLoad %mat4x2_f32 %53
+         %50 = OpFunctionCall %mat4v2float %conv_mat4x2_f32 %54
+               OpStore %49 %50
+               OpBranch %36
+         %36 = OpLabel
+         %55 = OpLoad %uint %i
+         %57 = OpIAdd %uint %55 %uint_1
+               OpStore %i %57
+               OpBranch %34
+         %35 = OpLabel
+         %58 = OpLoad %_arr_mat4v2float_uint_4 %arr
+               OpReturnValue %58
+               OpFunctionEnd
+          %f = OpFunction %void None %59
+         %62 = OpLabel
+         %65 = OpAccessChain %_ptr_StorageBuffer__arr_mat4v2float_uint_4 %s %uint_0
+         %68 = OpAccessChain %_ptr_Uniform__arr_mat4x2_f32_uint_4 %u %uint_0
+         %69 = OpLoad %_arr_mat4x2_f32_uint_4 %68
+         %66 = OpFunctionCall %_arr_mat4v2float_uint_4 %conv_arr4_mat4x2_f32 %69
+               OpStore %65 %66
+         %73 = OpAccessChain %_ptr_StorageBuffer_mat4v2float %s %uint_0 %int_1
+         %77 = OpAccessChain %_ptr_Uniform_mat4x2_f32 %u %uint_0 %uint_2
+         %78 = OpLoad %mat4x2_f32 %77
+         %74 = OpFunctionCall %mat4v2float %conv_mat4x2_f32 %78
+               OpStore %73 %74
+         %81 = OpAccessChain %_ptr_StorageBuffer_v2float %s %uint_0 %int_1 %79
+         %83 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %33 %uint_1
+         %84 = OpLoad %v2float %83
+         %85 = OpVectorShuffle %v2float %84 %84 1 0
+               OpStore %81 %85
+         %87 = OpAccessChain %_ptr_StorageBuffer_float %s %uint_0 %int_1 %79 %uint_0
+         %89 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %33 %uint_1 %33
+         %90 = OpLoad %float %89
+               OpStore %87 %90
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x2/to_workgroup.wgsl.expected.glsl
index 6ca89c7..df52a3b 100644
--- a/test/tint/buffer/uniform/std140/array/mat4x2/to_workgroup.wgsl.expected.glsl
+++ b/test/tint/buffer/uniform/std140/array/mat4x2/to_workgroup.wgsl.expected.glsl
@@ -1,16 +1,37 @@
 #version 310 es
 
+struct mat4x2_f32 {
+  vec2 col0;
+  vec2 col1;
+  vec2 col2;
+  vec2 col3;
+};
+
 struct S {
   int before;
   mat4x2 m;
   int after;
 };
 
-layout(binding = 0, std140) uniform u_block_ubo {
-  mat4x2 inner[4];
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  mat4x2_f32 inner[4];
 } u;
 
 shared mat4x2 w[4];
+mat4x2 conv_mat4x2_f32(mat4x2_f32 val) {
+  return mat4x2(val.col0, val.col1, val.col2, val.col3);
+}
+
+mat4x2[4] conv_arr4_mat4x2_f32(mat4x2_f32 val[4]) {
+  mat4x2 arr[4] = mat4x2[4](mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat4x2_f32(val[i]);
+    }
+  }
+  return arr;
+}
+
 void f(uint local_invocation_index) {
   {
     for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
@@ -19,10 +40,10 @@
     }
   }
   barrier();
-  w = u.inner;
-  w[1] = u.inner[2];
-  w[1][0] = u.inner[0][1].yx;
-  w[1][0].x = u.inner[0][1].x;
+  w = conv_arr4_mat4x2_f32(u.inner);
+  w[1] = conv_mat4x2_f32(u.inner[2u]);
+  w[1][0] = u.inner[0u].col1.yx;
+  w[1][0].x = u.inner[0u].col1[0u];
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x2/to_workgroup.wgsl.expected.spvasm
index d38bf92..4b7fada 100644
--- a/test/tint/buffer/uniform/std140/array/mat4x2/to_workgroup.wgsl.expected.spvasm
+++ b/test/tint/buffer/uniform/std140/array/mat4x2/to_workgroup.wgsl.expected.spvasm
@@ -1,115 +1,188 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 70
+; Bound: 113
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %f "f" %local_invocation_index_1
                OpExecutionMode %f LocalSize 1 1 1
                OpName %local_invocation_index_1 "local_invocation_index_1"
-               OpName %u_block "u_block"
-               OpMemberName %u_block 0 "inner"
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %mat4x2_f32 "mat4x2_f32"
+               OpMemberName %mat4x2_f32 0 "col0"
+               OpMemberName %mat4x2_f32 1 "col1"
+               OpMemberName %mat4x2_f32 2 "col2"
+               OpMemberName %mat4x2_f32 3 "col3"
                OpName %u "u"
                OpName %w "w"
+               OpName %conv_mat4x2_f32 "conv_mat4x2_f32"
+               OpName %val "val"
+               OpName %conv_arr4_mat4x2_f32 "conv_arr4_mat4x2_f32"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
                OpName %f_inner "f_inner"
                OpName %local_invocation_index "local_invocation_index"
                OpName %idx "idx"
                OpName %f "f"
                OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
-               OpDecorate %u_block Block
-               OpMemberDecorate %u_block 0 Offset 0
-               OpMemberDecorate %u_block 0 ColMajor
-               OpMemberDecorate %u_block 0 MatrixStride 8
-               OpDecorate %_arr_mat4v2float_uint_4 ArrayStride 32
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %mat4x2_f32 0 Offset 0
+               OpMemberDecorate %mat4x2_f32 1 Offset 8
+               OpMemberDecorate %mat4x2_f32 2 Offset 16
+               OpMemberDecorate %mat4x2_f32 3 Offset 24
+               OpDecorate %_arr_mat4x2_f32_uint_4 ArrayStride 32
                OpDecorate %u NonWritable
                OpDecorate %u DescriptorSet 0
                OpDecorate %u Binding 0
+               OpDecorate %_arr_mat4v2float_uint_4 ArrayStride 32
        %uint = OpTypeInt 32 0
 %_ptr_Input_uint = OpTypePointer Input %uint
 %local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
       %float = OpTypeFloat 32
     %v2float = OpTypeVector %float 2
-%mat4v2float = OpTypeMatrix %v2float 4
+ %mat4x2_f32 = OpTypeStruct %v2float %v2float %v2float %v2float
      %uint_4 = OpConstant %uint 4
+%_arr_mat4x2_f32_uint_4 = OpTypeArray %mat4x2_f32 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_mat4x2_f32_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+%mat4v2float = OpTypeMatrix %v2float 4
 %_arr_mat4v2float_uint_4 = OpTypeArray %mat4v2float %uint_4
-    %u_block = OpTypeStruct %_arr_mat4v2float_uint_4
-%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
-          %u = OpVariable %_ptr_Uniform_u_block Uniform
 %_ptr_Workgroup__arr_mat4v2float_uint_4 = OpTypePointer Workgroup %_arr_mat4v2float_uint_4
           %w = OpVariable %_ptr_Workgroup__arr_mat4v2float_uint_4 Workgroup
-       %void = OpTypeVoid
-         %14 = OpTypeFunction %void %uint
+         %16 = OpTypeFunction %mat4v2float %mat4x2_f32
+         %25 = OpTypeFunction %_arr_mat4v2float_uint_4 %_arr_mat4x2_f32_uint_4
+%_ptr_Function__arr_mat4v2float_uint_4 = OpTypePointer Function %_arr_mat4v2float_uint_4
+         %31 = OpConstantNull %_arr_mat4v2float_uint_4
 %_ptr_Function_uint = OpTypePointer Function %uint
-         %21 = OpConstantNull %uint
+         %34 = OpConstantNull %uint
        %bool = OpTypeBool
-%_ptr_Workgroup_mat4v2float = OpTypePointer Workgroup %mat4v2float
-         %35 = OpConstantNull %mat4v2float
+%_ptr_Function__arr_mat4x2_f32_uint_4 = OpTypePointer Function %_arr_mat4x2_f32_uint_4
+         %47 = OpConstantNull %_arr_mat4x2_f32_uint_4
+%_ptr_Function_mat4v2float = OpTypePointer Function %mat4v2float
+%_ptr_Function_mat4x2_f32 = OpTypePointer Function %mat4x2_f32
      %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %60 = OpTypeFunction %void %uint
+%_ptr_Workgroup_mat4v2float = OpTypePointer Workgroup %mat4v2float
+         %78 = OpConstantNull %mat4v2float
      %uint_2 = OpConstant %uint 2
    %uint_264 = OpConstant %uint 264
      %uint_0 = OpConstant %uint 0
-%_ptr_Uniform__arr_mat4v2float_uint_4 = OpTypePointer Uniform %_arr_mat4v2float_uint_4
+%_ptr_Uniform__arr_mat4x2_f32_uint_4 = OpTypePointer Uniform %_arr_mat4x2_f32_uint_4
         %int = OpTypeInt 32 1
       %int_1 = OpConstant %int 1
-      %int_2 = OpConstant %int 2
-%_ptr_Uniform_mat4v2float = OpTypePointer Uniform %mat4v2float
-         %53 = OpConstantNull %int
+%_ptr_Uniform_mat4x2_f32 = OpTypePointer Uniform %mat4x2_f32
+         %96 = OpConstantNull %int
 %_ptr_Workgroup_v2float = OpTypePointer Workgroup %v2float
 %_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
 %_ptr_Workgroup_float = OpTypePointer Workgroup %float
 %_ptr_Uniform_float = OpTypePointer Uniform %float
-         %65 = OpTypeFunction %void
-    %f_inner = OpFunction %void None %14
+        %108 = OpTypeFunction %void
+%conv_mat4x2_f32 = OpFunction %mat4v2float None %16
+        %val = OpFunctionParameter %mat4x2_f32
+         %19 = OpLabel
+         %20 = OpCompositeExtract %v2float %val 0
+         %21 = OpCompositeExtract %v2float %val 1
+         %22 = OpCompositeExtract %v2float %val 2
+         %23 = OpCompositeExtract %v2float %val 3
+         %24 = OpCompositeConstruct %mat4v2float %20 %21 %22 %23
+               OpReturnValue %24
+               OpFunctionEnd
+%conv_arr4_mat4x2_f32 = OpFunction %_arr_mat4v2float_uint_4 None %25
+      %val_0 = OpFunctionParameter %_arr_mat4x2_f32_uint_4
+         %28 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_mat4v2float_uint_4 Function %31
+          %i = OpVariable %_ptr_Function_uint Function %34
+%var_for_index = OpVariable %_ptr_Function__arr_mat4x2_f32_uint_4 Function %47
+               OpBranch %35
+         %35 = OpLabel
+               OpLoopMerge %36 %37 None
+               OpBranch %38
+         %38 = OpLabel
+         %40 = OpLoad %uint %i
+         %41 = OpULessThan %bool %40 %uint_4
+         %39 = OpLogicalNot %bool %41
+               OpSelectionMerge %43 None
+               OpBranchConditional %39 %44 %43
+         %44 = OpLabel
+               OpBranch %36
+         %43 = OpLabel
+               OpStore %var_for_index %val_0
+         %48 = OpLoad %uint %i
+         %50 = OpAccessChain %_ptr_Function_mat4v2float %arr %48
+         %52 = OpLoad %uint %i
+         %54 = OpAccessChain %_ptr_Function_mat4x2_f32 %var_for_index %52
+         %55 = OpLoad %mat4x2_f32 %54
+         %51 = OpFunctionCall %mat4v2float %conv_mat4x2_f32 %55
+               OpStore %50 %51
+               OpBranch %37
+         %37 = OpLabel
+         %56 = OpLoad %uint %i
+         %58 = OpIAdd %uint %56 %uint_1
+               OpStore %i %58
+               OpBranch %35
+         %36 = OpLabel
+         %59 = OpLoad %_arr_mat4v2float_uint_4 %arr
+               OpReturnValue %59
+               OpFunctionEnd
+    %f_inner = OpFunction %void None %60
 %local_invocation_index = OpFunctionParameter %uint
-         %18 = OpLabel
-        %idx = OpVariable %_ptr_Function_uint Function %21
+         %64 = OpLabel
+        %idx = OpVariable %_ptr_Function_uint Function %34
                OpStore %idx %local_invocation_index
-               OpBranch %22
-         %22 = OpLabel
-               OpLoopMerge %23 %24 None
-               OpBranch %25
-         %25 = OpLabel
-         %27 = OpLoad %uint %idx
-         %28 = OpULessThan %bool %27 %uint_4
-         %26 = OpLogicalNot %bool %28
-               OpSelectionMerge %30 None
-               OpBranchConditional %26 %31 %30
-         %31 = OpLabel
-               OpBranch %23
-         %30 = OpLabel
-         %32 = OpLoad %uint %idx
-         %34 = OpAccessChain %_ptr_Workgroup_mat4v2float %w %32
-               OpStore %34 %35
-               OpBranch %24
-         %24 = OpLabel
-         %36 = OpLoad %uint %idx
-         %38 = OpIAdd %uint %36 %uint_1
-               OpStore %idx %38
-               OpBranch %22
-         %23 = OpLabel
+               OpBranch %66
+         %66 = OpLabel
+               OpLoopMerge %67 %68 None
+               OpBranch %69
+         %69 = OpLabel
+         %71 = OpLoad %uint %idx
+         %72 = OpULessThan %bool %71 %uint_4
+         %70 = OpLogicalNot %bool %72
+               OpSelectionMerge %73 None
+               OpBranchConditional %70 %74 %73
+         %74 = OpLabel
+               OpBranch %67
+         %73 = OpLabel
+         %75 = OpLoad %uint %idx
+         %77 = OpAccessChain %_ptr_Workgroup_mat4v2float %w %75
+               OpStore %77 %78
+               OpBranch %68
+         %68 = OpLabel
+         %79 = OpLoad %uint %idx
+         %80 = OpIAdd %uint %79 %uint_1
+               OpStore %idx %80
+               OpBranch %66
+         %67 = OpLabel
                OpControlBarrier %uint_2 %uint_2 %uint_264
-         %44 = OpAccessChain %_ptr_Uniform__arr_mat4v2float_uint_4 %u %uint_0
-         %45 = OpLoad %_arr_mat4v2float_uint_4 %44
-               OpStore %w %45
-         %48 = OpAccessChain %_ptr_Workgroup_mat4v2float %w %int_1
-         %51 = OpAccessChain %_ptr_Uniform_mat4v2float %u %uint_0 %int_2
-         %52 = OpLoad %mat4v2float %51
-               OpStore %48 %52
-         %55 = OpAccessChain %_ptr_Workgroup_v2float %w %int_1 %53
-         %57 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %53 %int_1
-         %58 = OpLoad %v2float %57
-         %59 = OpVectorShuffle %v2float %58 %58 1 0
-               OpStore %55 %59
-         %61 = OpAccessChain %_ptr_Workgroup_float %w %int_1 %53 %uint_0
-         %63 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %53 %int_1 %uint_0
-         %64 = OpLoad %float %63
-               OpStore %61 %64
+         %87 = OpAccessChain %_ptr_Uniform__arr_mat4x2_f32_uint_4 %u %uint_0
+         %88 = OpLoad %_arr_mat4x2_f32_uint_4 %87
+         %84 = OpFunctionCall %_arr_mat4v2float_uint_4 %conv_arr4_mat4x2_f32 %88
+               OpStore %w %84
+         %91 = OpAccessChain %_ptr_Workgroup_mat4v2float %w %int_1
+         %94 = OpAccessChain %_ptr_Uniform_mat4x2_f32 %u %uint_0 %uint_2
+         %95 = OpLoad %mat4x2_f32 %94
+         %92 = OpFunctionCall %mat4v2float %conv_mat4x2_f32 %95
+               OpStore %91 %92
+         %98 = OpAccessChain %_ptr_Workgroup_v2float %w %int_1 %96
+        %100 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %34 %uint_1
+        %101 = OpLoad %v2float %100
+        %102 = OpVectorShuffle %v2float %101 %101 1 0
+               OpStore %98 %102
+        %104 = OpAccessChain %_ptr_Workgroup_float %w %int_1 %96 %uint_0
+        %106 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %34 %uint_1 %34
+        %107 = OpLoad %float %106
+               OpStore %104 %107
                OpReturn
                OpFunctionEnd
-          %f = OpFunction %void None %65
-         %67 = OpLabel
-         %69 = OpLoad %uint %local_invocation_index_1
-         %68 = OpFunctionCall %void %f_inner %69
+          %f = OpFunction %void None %108
+        %110 = OpLabel
+        %112 = OpLoad %uint %local_invocation_index_1
+        %111 = OpFunctionCall %void %f_inner %112
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x2/dynamic_index_via_ptr.wgsl.expected.glsl
index e27a647..90e0cf3 100644
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/dynamic_index_via_ptr.wgsl.expected.glsl
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -31,7 +31,7 @@
   return Inner(mat2(val.m_0, val.m_1));
 }
 
-Inner[4] conv_arr_4_Inner(Inner_std140 val[4]) {
+Inner[4] conv_arr4_Inner(Inner_std140 val[4]) {
   Inner arr[4] = Inner[4](Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)));
   {
     for(uint i = 0u; (i < 4u); i = (i + 1u)) {
@@ -42,10 +42,10 @@
 }
 
 Outer conv_Outer(Outer_std140 val) {
-  return Outer(conv_arr_4_Inner(val.a));
+  return Outer(conv_arr4_Inner(val.a));
 }
 
-Outer[4] conv_arr_4_Outer(Outer_std140 val[4]) {
+Outer[4] conv_arr4_Outer(Outer_std140 val[4]) {
   Outer arr[4] = Outer[4](Outer(Inner[4](Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)))), Outer(Inner[4](Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)))), Outer(Inner[4](Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)))), Outer(Inner[4](Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)))));
   {
     for(uint i = 0u; (i < 4u); i = (i + 1u)) {
@@ -96,18 +96,18 @@
 }
 
 void f() {
-  Outer p_a[4] = conv_arr_4_Outer(a.inner);
+  Outer p_a[4] = conv_arr4_Outer(a.inner);
   int tint_symbol = i();
   Outer p_a_i = conv_Outer(a.inner[tint_symbol]);
-  Inner p_a_i_a[4] = conv_arr_4_Inner(a.inner[tint_symbol].a);
+  Inner p_a_i_a[4] = conv_arr4_Inner(a.inner[tint_symbol].a);
   int tint_symbol_1 = i();
   Inner p_a_i_a_i = conv_Inner(a.inner[tint_symbol].a[tint_symbol_1]);
   mat2 p_a_i_a_i_m = load_a_inner_p0_a_p1_m(uint(tint_symbol), uint(tint_symbol_1));
   int tint_symbol_2 = i();
   vec2 p_a_i_a_i_m_i = load_a_inner_p0_a_p1_m_p2(uint(tint_symbol), uint(tint_symbol_1), uint(tint_symbol_2));
-  Outer l_a[4] = conv_arr_4_Outer(a.inner);
+  Outer l_a[4] = conv_arr4_Outer(a.inner);
   Outer l_a_i = conv_Outer(a.inner[tint_symbol]);
-  Inner l_a_i_a[4] = conv_arr_4_Inner(a.inner[tint_symbol].a);
+  Inner l_a_i_a[4] = conv_arr4_Inner(a.inner[tint_symbol].a);
   Inner l_a_i_a_i = conv_Inner(a.inner[tint_symbol].a[tint_symbol_1]);
   mat2 l_a_i_a_i_m = load_a_inner_p0_a_p1_m(uint(tint_symbol), uint(tint_symbol_1));
   vec2 l_a_i_a_i_m_i = load_a_inner_p0_a_p1_m_p2(uint(tint_symbol), uint(tint_symbol_1), uint(tint_symbol_2));
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x2/dynamic_index_via_ptr.wgsl.expected.spvasm
index 7950eac..796a192 100644
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/dynamic_index_via_ptr.wgsl.expected.spvasm
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -21,7 +21,7 @@
                OpMemberName %Inner 0 "m"
                OpName %conv_Inner "conv_Inner"
                OpName %val "val"
-               OpName %conv_arr_4_Inner "conv_arr_4_Inner"
+               OpName %conv_arr4_Inner "conv_arr4_Inner"
                OpName %val_0 "val"
                OpName %arr "arr"
                OpName %i_0 "i"
@@ -30,7 +30,7 @@
                OpMemberName %Outer 0 "a"
                OpName %conv_Outer "conv_Outer"
                OpName %val_1 "val"
-               OpName %conv_arr_4_Outer "conv_arr_4_Outer"
+               OpName %conv_arr4_Outer "conv_arr4_Outer"
                OpName %val_2 "val"
                OpName %arr_0 "arr"
                OpName %i_1 "i"
@@ -137,7 +137,7 @@
          %32 = OpCompositeConstruct %Inner %31
                OpReturnValue %32
                OpFunctionEnd
-%conv_arr_4_Inner = OpFunction %_arr_Inner_uint_4 None %33
+%conv_arr4_Inner = OpFunction %_arr_Inner_uint_4 None %33
       %val_0 = OpFunctionParameter %_arr_Inner_std140_uint_4
          %37 = OpLabel
         %arr = OpVariable %_ptr_Function__arr_Inner_uint_4 Function %40
@@ -178,11 +178,11 @@
       %val_1 = OpFunctionParameter %Outer_std140
          %73 = OpLabel
          %75 = OpCompositeExtract %_arr_Inner_std140_uint_4 %val_1 0
-         %74 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr_4_Inner %75
+         %74 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %75
          %76 = OpCompositeConstruct %Outer %74
                OpReturnValue %76
                OpFunctionEnd
-%conv_arr_4_Outer = OpFunction %_arr_Outer_uint_4 None %77
+%conv_arr4_Outer = OpFunction %_arr_Outer_uint_4 None %77
       %val_2 = OpFunctionParameter %_arr_Outer_std140_uint_4
          %81 = OpLabel
       %arr_0 = OpVariable %_ptr_Function__arr_Outer_uint_4 Function %84
@@ -279,13 +279,13 @@
         %164 = OpFunctionCall %int %i
         %167 = OpAccessChain %_ptr_Uniform__arr_Outer_std140_uint_4 %a %uint_0
         %168 = OpLoad %_arr_Outer_std140_uint_4 %167
-        %165 = OpFunctionCall %_arr_Outer_uint_4 %conv_arr_4_Outer %168
+        %165 = OpFunctionCall %_arr_Outer_uint_4 %conv_arr4_Outer %168
         %171 = OpAccessChain %_ptr_Uniform_Outer_std140 %a %uint_0 %162
         %172 = OpLoad %Outer_std140 %171
         %169 = OpFunctionCall %Outer %conv_Outer %172
         %175 = OpAccessChain %_ptr_Uniform__arr_Inner_std140_uint_4 %a %uint_0 %162 %uint_0
         %176 = OpLoad %_arr_Inner_std140_uint_4 %175
-        %173 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr_4_Inner %176
+        %173 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %176
         %178 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %162 %uint_0 %163
         %179 = OpLoad %Inner_std140 %178
         %177 = OpFunctionCall %Inner %conv_Inner %179
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x2/static_index_via_ptr.wgsl.expected.glsl
index f00bbf5..3564979 100644
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/static_index_via_ptr.wgsl.expected.glsl
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2/static_index_via_ptr.wgsl.expected.glsl
@@ -25,7 +25,7 @@
   return Inner(mat2(val.m_0, val.m_1));
 }
 
-Inner[4] conv_arr_4_Inner(Inner_std140 val[4]) {
+Inner[4] conv_arr4_Inner(Inner_std140 val[4]) {
   Inner arr[4] = Inner[4](Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)));
   {
     for(uint i = 0u; (i < 4u); i = (i + 1u)) {
@@ -36,10 +36,10 @@
 }
 
 Outer conv_Outer(Outer_std140 val) {
-  return Outer(conv_arr_4_Inner(val.a));
+  return Outer(conv_arr4_Inner(val.a));
 }
 
-Outer[4] conv_arr_4_Outer(Outer_std140 val[4]) {
+Outer[4] conv_arr4_Outer(Outer_std140 val[4]) {
   Outer arr[4] = Outer[4](Outer(Inner[4](Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)))), Outer(Inner[4](Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)))), Outer(Inner[4](Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)))), Outer(Inner[4](Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)))));
   {
     for(uint i = 0u; (i < 4u); i = (i + 1u)) {
@@ -54,15 +54,15 @@
 }
 
 void f() {
-  Outer p_a[4] = conv_arr_4_Outer(a.inner);
+  Outer p_a[4] = conv_arr4_Outer(a.inner);
   Outer p_a_3 = conv_Outer(a.inner[3u]);
-  Inner p_a_3_a[4] = conv_arr_4_Inner(a.inner[3u].a);
+  Inner p_a_3_a[4] = conv_arr4_Inner(a.inner[3u].a);
   Inner p_a_3_a_2 = conv_Inner(a.inner[3u].a[2u]);
   mat2 p_a_3_a_2_m = load_a_inner_3_a_2_m();
   vec2 p_a_3_a_2_m_1 = a.inner[3u].a[2u].m_1;
-  Outer l_a[4] = conv_arr_4_Outer(a.inner);
+  Outer l_a[4] = conv_arr4_Outer(a.inner);
   Outer l_a_3 = conv_Outer(a.inner[3u]);
-  Inner l_a_3_a[4] = conv_arr_4_Inner(a.inner[3u].a);
+  Inner l_a_3_a[4] = conv_arr4_Inner(a.inner[3u].a);
   Inner l_a_3_a_2 = conv_Inner(a.inner[3u].a[2u]);
   mat2 l_a_3_a_2_m = load_a_inner_3_a_2_m();
   vec2 l_a_3_a_2_m_1 = a.inner[3u].a[2u].m_1;
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x2/static_index_via_ptr.wgsl.expected.spvasm
index 6a3a339..de1047e 100644
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/static_index_via_ptr.wgsl.expected.spvasm
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2/static_index_via_ptr.wgsl.expected.spvasm
@@ -19,7 +19,7 @@
                OpMemberName %Inner 0 "m"
                OpName %conv_Inner "conv_Inner"
                OpName %val "val"
-               OpName %conv_arr_4_Inner "conv_arr_4_Inner"
+               OpName %conv_arr4_Inner "conv_arr4_Inner"
                OpName %val_0 "val"
                OpName %arr "arr"
                OpName %i "i"
@@ -28,7 +28,7 @@
                OpMemberName %Outer 0 "a"
                OpName %conv_Outer "conv_Outer"
                OpName %val_1 "val"
-               OpName %conv_arr_4_Outer "conv_arr_4_Outer"
+               OpName %conv_arr4_Outer "conv_arr4_Outer"
                OpName %val_2 "val"
                OpName %arr_0 "arr"
                OpName %i_0 "i"
@@ -108,7 +108,7 @@
          %21 = OpCompositeConstruct %Inner %20
                OpReturnValue %21
                OpFunctionEnd
-%conv_arr_4_Inner = OpFunction %_arr_Inner_uint_4 None %22
+%conv_arr4_Inner = OpFunction %_arr_Inner_uint_4 None %22
       %val_0 = OpFunctionParameter %_arr_Inner_std140_uint_4
          %26 = OpLabel
         %arr = OpVariable %_ptr_Function__arr_Inner_uint_4 Function %29
@@ -149,11 +149,11 @@
       %val_1 = OpFunctionParameter %Outer_std140
          %62 = OpLabel
          %64 = OpCompositeExtract %_arr_Inner_std140_uint_4 %val_1 0
-         %63 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr_4_Inner %64
+         %63 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %64
          %65 = OpCompositeConstruct %Outer %63
                OpReturnValue %65
                OpFunctionEnd
-%conv_arr_4_Outer = OpFunction %_arr_Outer_uint_4 None %66
+%conv_arr4_Outer = OpFunction %_arr_Outer_uint_4 None %66
       %val_2 = OpFunctionParameter %_arr_Outer_std140_uint_4
          %70 = OpLabel
       %arr_0 = OpVariable %_ptr_Function__arr_Outer_uint_4 Function %73
@@ -204,13 +204,13 @@
         %118 = OpLabel
         %121 = OpAccessChain %_ptr_Uniform__arr_Outer_std140_uint_4 %a %uint_0
         %122 = OpLoad %_arr_Outer_std140_uint_4 %121
-        %119 = OpFunctionCall %_arr_Outer_uint_4 %conv_arr_4_Outer %122
+        %119 = OpFunctionCall %_arr_Outer_uint_4 %conv_arr4_Outer %122
         %125 = OpAccessChain %_ptr_Uniform_Outer_std140 %a %uint_0 %uint_3
         %126 = OpLoad %Outer_std140 %125
         %123 = OpFunctionCall %Outer %conv_Outer %126
         %129 = OpAccessChain %_ptr_Uniform__arr_Inner_std140_uint_4 %a %uint_0 %uint_3 %uint_0
         %130 = OpLoad %_arr_Inner_std140_uint_4 %129
-        %127 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr_4_Inner %130
+        %127 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %130
         %132 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %uint_3 %uint_0 %uint_2
         %133 = OpLoad %Inner_std140 %132
         %131 = OpFunctionCall %Inner %conv_Inner %133
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x2/to_fn.wgsl.expected.glsl
index 452c603..daaf731 100644
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/to_fn.wgsl.expected.glsl
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2/to_fn.wgsl.expected.glsl
@@ -40,7 +40,7 @@
   return S(val.before, val.pad, mat2(val.m_0, val.m_1), val.after, val.pad_1);
 }
 
-S[4] conv_arr_4_S(S_std140 val[4]) {
+S[4] conv_arr4_S(S_std140 val[4]) {
   S arr[4] = S[4](S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0, 0u));
   {
     for(uint i = 0u; (i < 4u); i = (i + 1u)) {
@@ -55,7 +55,7 @@
 }
 
 void f() {
-  a(conv_arr_4_S(u.inner));
+  a(conv_arr4_S(u.inner));
   b(conv_S(u.inner[2u]));
   c(load_u_inner_2_m());
   d(u.inner[0u].m_1.yx);
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x2/to_fn.wgsl.expected.spvasm
index 627852b..facd977 100644
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/to_fn.wgsl.expected.spvasm
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2/to_fn.wgsl.expected.spvasm
@@ -31,7 +31,7 @@
                OpName %f_1 "f_1"
                OpName %conv_S "conv_S"
                OpName %val "val"
-               OpName %conv_arr_4_S "conv_arr_4_S"
+               OpName %conv_arr4_S "conv_arr4_S"
                OpName %val_0 "val"
                OpName %arr "arr"
                OpName %i "i"
@@ -128,7 +128,7 @@
          %44 = OpCompositeConstruct %S %39 %42 %43
                OpReturnValue %44
                OpFunctionEnd
-%conv_arr_4_S = OpFunction %_arr_S_uint_4 None %45
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %45
       %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
          %48 = OpLabel
         %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %51
@@ -179,7 +179,7 @@
          %98 = OpLabel
         %102 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
         %103 = OpLoad %_arr_S_std140_uint_4 %102
-        %100 = OpFunctionCall %_arr_S_uint_4 %conv_arr_4_S %103
+        %100 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %103
          %99 = OpFunctionCall %void %a %100
         %106 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
         %107 = OpLoad %S_std140 %106
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x2/to_private.wgsl.expected.glsl
index ce7f2ce..9634531 100644
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/to_private.wgsl.expected.glsl
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2/to_private.wgsl.expected.glsl
@@ -26,7 +26,7 @@
   return S(val.before, val.pad, mat2(val.m_0, val.m_1), val.after, val.pad_1);
 }
 
-S[4] conv_arr_4_S(S_std140 val[4]) {
+S[4] conv_arr4_S(S_std140 val[4]) {
   S arr[4] = S[4](S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0, 0u));
   {
     for(uint i = 0u; (i < 4u); i = (i + 1u)) {
@@ -41,7 +41,7 @@
 }
 
 void f() {
-  p = conv_arr_4_S(u.inner);
+  p = conv_arr4_S(u.inner);
   p[1] = conv_S(u.inner[2u]);
   p[3].m = load_u_inner_2_m();
   p[1].m[0] = u.inner[0u].m_1.yx;
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x2/to_private.wgsl.expected.spvasm
index 118e476..57765b4 100644
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/to_private.wgsl.expected.spvasm
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2/to_private.wgsl.expected.spvasm
@@ -22,7 +22,7 @@
                OpName %p "p"
                OpName %conv_S "conv_S"
                OpName %val "val"
-               OpName %conv_arr_4_S "conv_arr_4_S"
+               OpName %conv_arr4_S "conv_arr4_S"
                OpName %val_0 "val"
                OpName %arr "arr"
                OpName %i "i"
@@ -97,7 +97,7 @@
          %26 = OpCompositeConstruct %S %21 %24 %25
                OpReturnValue %26
                OpFunctionEnd
-%conv_arr_4_S = OpFunction %_arr_S_uint_4 None %27
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %27
       %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
          %30 = OpLabel
         %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %16
@@ -148,7 +148,7 @@
          %80 = OpLabel
          %83 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
          %84 = OpLoad %_arr_S_std140_uint_4 %83
-         %81 = OpFunctionCall %_arr_S_uint_4 %conv_arr_4_S %84
+         %81 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %84
                OpStore %p %81
          %87 = OpAccessChain %_ptr_Private_S %p %int_1
          %89 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x2/to_storage.wgsl.expected.glsl
index 0fdf832..ec19f64 100644
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/to_storage.wgsl.expected.glsl
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2/to_storage.wgsl.expected.glsl
@@ -29,7 +29,7 @@
   return S(val.before, val.pad, mat2(val.m_0, val.m_1), val.after, val.pad_1);
 }
 
-S[4] conv_arr_4_S(S_std140 val[4]) {
+S[4] conv_arr4_S(S_std140 val[4]) {
   S arr[4] = S[4](S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0, 0u));
   {
     for(uint i = 0u; (i < 4u); i = (i + 1u)) {
@@ -44,7 +44,7 @@
 }
 
 void f() {
-  s.inner = conv_arr_4_S(u.inner);
+  s.inner = conv_arr4_S(u.inner);
   s.inner[1] = conv_S(u.inner[2u]);
   s.inner[3].m = load_u_inner_2_m();
   s.inner[1].m[0] = u.inner[0u].m_1.yx;
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x2/to_storage.wgsl.expected.spvasm
index 8769096..6f393c7 100644
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/to_storage.wgsl.expected.spvasm
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2/to_storage.wgsl.expected.spvasm
@@ -24,7 +24,7 @@
                OpName %s "s"
                OpName %conv_S "conv_S"
                OpName %val "val"
-               OpName %conv_arr_4_S "conv_arr_4_S"
+               OpName %conv_arr4_S "conv_arr4_S"
                OpName %val_0 "val"
                OpName %arr "arr"
                OpName %i "i"
@@ -105,7 +105,7 @@
          %26 = OpCompositeConstruct %S %21 %24 %25
                OpReturnValue %26
                OpFunctionEnd
-%conv_arr_4_S = OpFunction %_arr_S_uint_4 None %27
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %27
       %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
          %30 = OpLabel
         %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %33
@@ -157,7 +157,7 @@
          %83 = OpAccessChain %_ptr_StorageBuffer__arr_S_uint_4 %s %uint_0
          %86 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
          %87 = OpLoad %_arr_S_std140_uint_4 %86
-         %84 = OpFunctionCall %_arr_S_uint_4 %conv_arr_4_S %87
+         %84 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %87
                OpStore %83 %84
          %90 = OpAccessChain %_ptr_StorageBuffer_S %s %uint_0 %int_1
          %92 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x2/to_workgroup.wgsl.expected.glsl
index 9204f46..cdc0450 100644
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/to_workgroup.wgsl.expected.glsl
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2/to_workgroup.wgsl.expected.glsl
@@ -26,7 +26,7 @@
   return S(val.before, val.pad, mat2(val.m_0, val.m_1), val.after, val.pad_1);
 }
 
-S[4] conv_arr_4_S(S_std140 val[4]) {
+S[4] conv_arr4_S(S_std140 val[4]) {
   S arr[4] = S[4](S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0, 0u));
   {
     for(uint i = 0u; (i < 4u); i = (i + 1u)) {
@@ -49,7 +49,7 @@
     }
   }
   barrier();
-  w = conv_arr_4_S(u.inner);
+  w = conv_arr4_S(u.inner);
   w[1] = conv_S(u.inner[2u]);
   w[3].m = load_u_inner_2_m();
   w[1].m[0] = u.inner[0u].m_1.yx;
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x2/to_workgroup.wgsl.expected.spvasm
index 5e253f9..a6922dc 100644
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/to_workgroup.wgsl.expected.spvasm
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2/to_workgroup.wgsl.expected.spvasm
@@ -23,7 +23,7 @@
                OpName %w "w"
                OpName %conv_S "conv_S"
                OpName %val "val"
-               OpName %conv_arr_4_S "conv_arr_4_S"
+               OpName %conv_arr4_S "conv_arr4_S"
                OpName %val_0 "val"
                OpName %arr "arr"
                OpName %i "i"
@@ -107,7 +107,7 @@
          %27 = OpCompositeConstruct %S %22 %25 %26
                OpReturnValue %27
                OpFunctionEnd
-%conv_arr_4_S = OpFunction %_arr_S_uint_4 None %28
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %28
       %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
          %31 = OpLabel
         %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %34
@@ -185,7 +185,7 @@
                OpControlBarrier %uint_2 %uint_2 %uint_264
         %104 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
         %105 = OpLoad %_arr_S_std140_uint_4 %104
-        %102 = OpFunctionCall %_arr_S_uint_4 %conv_arr_4_S %105
+        %102 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %105
                OpStore %w %102
         %107 = OpAccessChain %_ptr_Workgroup_S %w %int_1
         %109 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x2/dynamic_index_via_ptr.wgsl.expected.glsl
index accf517..ea06cdd 100644
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/dynamic_index_via_ptr.wgsl.expected.glsl
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -52,7 +52,7 @@
   return Inner(mat3x2(val.m_0, val.m_1, val.m_2), val.pad, val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9);
 }
 
-Inner[4] conv_arr_4_Inner(Inner_std140 val[4]) {
+Inner[4] conv_arr4_Inner(Inner_std140 val[4]) {
   Inner arr[4] = Inner[4](Inner(mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
   {
     for(uint i = 0u; (i < 4u); i = (i + 1u)) {
@@ -63,10 +63,10 @@
 }
 
 Outer conv_Outer(Outer_std140 val) {
-  return Outer(conv_arr_4_Inner(val.a));
+  return Outer(conv_arr4_Inner(val.a));
 }
 
-Outer[4] conv_arr_4_Outer(Outer_std140 val[4]) {
+Outer[4] conv_arr4_Outer(Outer_std140 val[4]) {
   Outer arr[4] = Outer[4](Outer(Inner[4](Inner(mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))));
   {
     for(uint i = 0u; (i < 4u); i = (i + 1u)) {
@@ -125,18 +125,18 @@
 }
 
 void f() {
-  Outer p_a[4] = conv_arr_4_Outer(a.inner);
+  Outer p_a[4] = conv_arr4_Outer(a.inner);
   int tint_symbol = i();
   Outer p_a_i = conv_Outer(a.inner[tint_symbol]);
-  Inner p_a_i_a[4] = conv_arr_4_Inner(a.inner[tint_symbol].a);
+  Inner p_a_i_a[4] = conv_arr4_Inner(a.inner[tint_symbol].a);
   int tint_symbol_1 = i();
   Inner p_a_i_a_i = conv_Inner(a.inner[tint_symbol].a[tint_symbol_1]);
   mat3x2 p_a_i_a_i_m = load_a_inner_p0_a_p1_m(uint(tint_symbol), uint(tint_symbol_1));
   int tint_symbol_2 = i();
   vec2 p_a_i_a_i_m_i = load_a_inner_p0_a_p1_m_p2(uint(tint_symbol), uint(tint_symbol_1), uint(tint_symbol_2));
-  Outer l_a[4] = conv_arr_4_Outer(a.inner);
+  Outer l_a[4] = conv_arr4_Outer(a.inner);
   Outer l_a_i = conv_Outer(a.inner[tint_symbol]);
-  Inner l_a_i_a[4] = conv_arr_4_Inner(a.inner[tint_symbol].a);
+  Inner l_a_i_a[4] = conv_arr4_Inner(a.inner[tint_symbol].a);
   Inner l_a_i_a_i = conv_Inner(a.inner[tint_symbol].a[tint_symbol_1]);
   mat3x2 l_a_i_a_i_m = load_a_inner_p0_a_p1_m(uint(tint_symbol), uint(tint_symbol_1));
   vec2 l_a_i_a_i_m_i = load_a_inner_p0_a_p1_m_p2(uint(tint_symbol), uint(tint_symbol_1), uint(tint_symbol_2));
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x2/dynamic_index_via_ptr.wgsl.expected.spvasm
index bb1c350..eb9e73b 100644
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/dynamic_index_via_ptr.wgsl.expected.spvasm
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -22,7 +22,7 @@
                OpMemberName %Inner 0 "m"
                OpName %conv_Inner "conv_Inner"
                OpName %val "val"
-               OpName %conv_arr_4_Inner "conv_arr_4_Inner"
+               OpName %conv_arr4_Inner "conv_arr4_Inner"
                OpName %val_0 "val"
                OpName %arr "arr"
                OpName %i_0 "i"
@@ -31,7 +31,7 @@
                OpMemberName %Outer 0 "a"
                OpName %conv_Outer "conv_Outer"
                OpName %val_1 "val"
-               OpName %conv_arr_4_Outer "conv_arr_4_Outer"
+               OpName %conv_arr4_Outer "conv_arr4_Outer"
                OpName %val_2 "val"
                OpName %arr_0 "arr"
                OpName %i_1 "i"
@@ -141,7 +141,7 @@
          %33 = OpCompositeConstruct %Inner %32
                OpReturnValue %33
                OpFunctionEnd
-%conv_arr_4_Inner = OpFunction %_arr_Inner_uint_4 None %34
+%conv_arr4_Inner = OpFunction %_arr_Inner_uint_4 None %34
       %val_0 = OpFunctionParameter %_arr_Inner_std140_uint_4
          %38 = OpLabel
         %arr = OpVariable %_ptr_Function__arr_Inner_uint_4 Function %41
@@ -182,11 +182,11 @@
       %val_1 = OpFunctionParameter %Outer_std140
          %74 = OpLabel
          %76 = OpCompositeExtract %_arr_Inner_std140_uint_4 %val_1 0
-         %75 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr_4_Inner %76
+         %75 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %76
          %77 = OpCompositeConstruct %Outer %75
                OpReturnValue %77
                OpFunctionEnd
-%conv_arr_4_Outer = OpFunction %_arr_Outer_uint_4 None %78
+%conv_arr4_Outer = OpFunction %_arr_Outer_uint_4 None %78
       %val_2 = OpFunctionParameter %_arr_Outer_std140_uint_4
          %82 = OpLabel
       %arr_0 = OpVariable %_ptr_Function__arr_Outer_uint_4 Function %85
@@ -293,13 +293,13 @@
         %175 = OpFunctionCall %int %i
         %178 = OpAccessChain %_ptr_Uniform__arr_Outer_std140_uint_4 %a %uint_0
         %179 = OpLoad %_arr_Outer_std140_uint_4 %178
-        %176 = OpFunctionCall %_arr_Outer_uint_4 %conv_arr_4_Outer %179
+        %176 = OpFunctionCall %_arr_Outer_uint_4 %conv_arr4_Outer %179
         %182 = OpAccessChain %_ptr_Uniform_Outer_std140 %a %uint_0 %173
         %183 = OpLoad %Outer_std140 %182
         %180 = OpFunctionCall %Outer %conv_Outer %183
         %186 = OpAccessChain %_ptr_Uniform__arr_Inner_std140_uint_4 %a %uint_0 %173 %uint_0
         %187 = OpLoad %_arr_Inner_std140_uint_4 %186
-        %184 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr_4_Inner %187
+        %184 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %187
         %189 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %173 %uint_0 %174
         %190 = OpLoad %Inner_std140 %189
         %188 = OpFunctionCall %Inner %conv_Inner %190
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x2/static_index_via_ptr.wgsl.expected.glsl
index 2d72a86..21e940c 100644
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/static_index_via_ptr.wgsl.expected.glsl
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2/static_index_via_ptr.wgsl.expected.glsl
@@ -46,7 +46,7 @@
   return Inner(mat3x2(val.m_0, val.m_1, val.m_2), val.pad, val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9);
 }
 
-Inner[4] conv_arr_4_Inner(Inner_std140 val[4]) {
+Inner[4] conv_arr4_Inner(Inner_std140 val[4]) {
   Inner arr[4] = Inner[4](Inner(mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
   {
     for(uint i = 0u; (i < 4u); i = (i + 1u)) {
@@ -57,10 +57,10 @@
 }
 
 Outer conv_Outer(Outer_std140 val) {
-  return Outer(conv_arr_4_Inner(val.a));
+  return Outer(conv_arr4_Inner(val.a));
 }
 
-Outer[4] conv_arr_4_Outer(Outer_std140 val[4]) {
+Outer[4] conv_arr4_Outer(Outer_std140 val[4]) {
   Outer arr[4] = Outer[4](Outer(Inner[4](Inner(mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))));
   {
     for(uint i = 0u; (i < 4u); i = (i + 1u)) {
@@ -75,15 +75,15 @@
 }
 
 void f() {
-  Outer p_a[4] = conv_arr_4_Outer(a.inner);
+  Outer p_a[4] = conv_arr4_Outer(a.inner);
   Outer p_a_3 = conv_Outer(a.inner[3u]);
-  Inner p_a_3_a[4] = conv_arr_4_Inner(a.inner[3u].a);
+  Inner p_a_3_a[4] = conv_arr4_Inner(a.inner[3u].a);
   Inner p_a_3_a_2 = conv_Inner(a.inner[3u].a[2u]);
   mat3x2 p_a_3_a_2_m = load_a_inner_3_a_2_m();
   vec2 p_a_3_a_2_m_1 = a.inner[3u].a[2u].m_1;
-  Outer l_a[4] = conv_arr_4_Outer(a.inner);
+  Outer l_a[4] = conv_arr4_Outer(a.inner);
   Outer l_a_3 = conv_Outer(a.inner[3u]);
-  Inner l_a_3_a[4] = conv_arr_4_Inner(a.inner[3u].a);
+  Inner l_a_3_a[4] = conv_arr4_Inner(a.inner[3u].a);
   Inner l_a_3_a_2 = conv_Inner(a.inner[3u].a[2u]);
   mat3x2 l_a_3_a_2_m = load_a_inner_3_a_2_m();
   vec2 l_a_3_a_2_m_1 = a.inner[3u].a[2u].m_1;
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x2/static_index_via_ptr.wgsl.expected.spvasm
index cfe1926..6f790a8 100644
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/static_index_via_ptr.wgsl.expected.spvasm
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2/static_index_via_ptr.wgsl.expected.spvasm
@@ -20,7 +20,7 @@
                OpMemberName %Inner 0 "m"
                OpName %conv_Inner "conv_Inner"
                OpName %val "val"
-               OpName %conv_arr_4_Inner "conv_arr_4_Inner"
+               OpName %conv_arr4_Inner "conv_arr4_Inner"
                OpName %val_0 "val"
                OpName %arr "arr"
                OpName %i "i"
@@ -29,7 +29,7 @@
                OpMemberName %Outer 0 "a"
                OpName %conv_Outer "conv_Outer"
                OpName %val_1 "val"
-               OpName %conv_arr_4_Outer "conv_arr_4_Outer"
+               OpName %conv_arr4_Outer "conv_arr4_Outer"
                OpName %val_2 "val"
                OpName %arr_0 "arr"
                OpName %i_0 "i"
@@ -111,7 +111,7 @@
          %22 = OpCompositeConstruct %Inner %21
                OpReturnValue %22
                OpFunctionEnd
-%conv_arr_4_Inner = OpFunction %_arr_Inner_uint_4 None %23
+%conv_arr4_Inner = OpFunction %_arr_Inner_uint_4 None %23
       %val_0 = OpFunctionParameter %_arr_Inner_std140_uint_4
          %27 = OpLabel
         %arr = OpVariable %_ptr_Function__arr_Inner_uint_4 Function %30
@@ -152,11 +152,11 @@
       %val_1 = OpFunctionParameter %Outer_std140
          %63 = OpLabel
          %65 = OpCompositeExtract %_arr_Inner_std140_uint_4 %val_1 0
-         %64 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr_4_Inner %65
+         %64 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %65
          %66 = OpCompositeConstruct %Outer %64
                OpReturnValue %66
                OpFunctionEnd
-%conv_arr_4_Outer = OpFunction %_arr_Outer_uint_4 None %67
+%conv_arr4_Outer = OpFunction %_arr_Outer_uint_4 None %67
       %val_2 = OpFunctionParameter %_arr_Outer_std140_uint_4
          %71 = OpLabel
       %arr_0 = OpVariable %_ptr_Function__arr_Outer_uint_4 Function %74
@@ -209,13 +209,13 @@
         %122 = OpLabel
         %125 = OpAccessChain %_ptr_Uniform__arr_Outer_std140_uint_4 %a %uint_0
         %126 = OpLoad %_arr_Outer_std140_uint_4 %125
-        %123 = OpFunctionCall %_arr_Outer_uint_4 %conv_arr_4_Outer %126
+        %123 = OpFunctionCall %_arr_Outer_uint_4 %conv_arr4_Outer %126
         %129 = OpAccessChain %_ptr_Uniform_Outer_std140 %a %uint_0 %uint_3
         %130 = OpLoad %Outer_std140 %129
         %127 = OpFunctionCall %Outer %conv_Outer %130
         %133 = OpAccessChain %_ptr_Uniform__arr_Inner_std140_uint_4 %a %uint_0 %uint_3 %uint_0
         %134 = OpLoad %_arr_Inner_std140_uint_4 %133
-        %131 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr_4_Inner %134
+        %131 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %134
         %136 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %uint_3 %uint_0 %uint_2
         %137 = OpLoad %Inner_std140 %136
         %135 = OpFunctionCall %Inner %conv_Inner %137
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x2/to_fn.wgsl.expected.glsl
index 720e66b..41ff2a8 100644
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/to_fn.wgsl.expected.glsl
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2/to_fn.wgsl.expected.glsl
@@ -61,7 +61,7 @@
   return S(val.before, val.pad, mat3x2(val.m_0, val.m_1, val.m_2), val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.after, val.pad_11);
 }
 
-S[4] conv_arr_4_S(S_std140 val[4]) {
+S[4] conv_arr4_S(S_std140 val[4]) {
   S arr[4] = S[4](S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u), S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u), S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u), S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u));
   {
     for(uint i = 0u; (i < 4u); i = (i + 1u)) {
@@ -76,7 +76,7 @@
 }
 
 void f() {
-  a(conv_arr_4_S(u.inner));
+  a(conv_arr4_S(u.inner));
   b(conv_S(u.inner[2u]));
   c(load_u_inner_2_m());
   d(u.inner[0u].m_1.yx);
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x2/to_fn.wgsl.expected.spvasm
index 148b7b6..e7483d2 100644
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/to_fn.wgsl.expected.spvasm
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2/to_fn.wgsl.expected.spvasm
@@ -32,7 +32,7 @@
                OpName %f_1 "f_1"
                OpName %conv_S "conv_S"
                OpName %val "val"
-               OpName %conv_arr_4_S "conv_arr_4_S"
+               OpName %conv_arr4_S "conv_arr4_S"
                OpName %val_0 "val"
                OpName %arr "arr"
                OpName %i "i"
@@ -132,7 +132,7 @@
          %45 = OpCompositeConstruct %S %39 %43 %44
                OpReturnValue %45
                OpFunctionEnd
-%conv_arr_4_S = OpFunction %_arr_S_uint_4 None %46
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %46
       %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
          %49 = OpLabel
         %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %52
@@ -185,7 +185,7 @@
         %103 = OpLabel
         %107 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
         %108 = OpLoad %_arr_S_std140_uint_4 %107
-        %105 = OpFunctionCall %_arr_S_uint_4 %conv_arr_4_S %108
+        %105 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %108
         %104 = OpFunctionCall %void %a %105
         %111 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
         %112 = OpLoad %S_std140 %111
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x2/to_private.wgsl.expected.glsl
index 5fa11e4..7c90023 100644
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/to_private.wgsl.expected.glsl
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2/to_private.wgsl.expected.glsl
@@ -47,7 +47,7 @@
   return S(val.before, val.pad, mat3x2(val.m_0, val.m_1, val.m_2), val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.after, val.pad_11);
 }
 
-S[4] conv_arr_4_S(S_std140 val[4]) {
+S[4] conv_arr4_S(S_std140 val[4]) {
   S arr[4] = S[4](S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u), S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u), S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u), S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u));
   {
     for(uint i = 0u; (i < 4u); i = (i + 1u)) {
@@ -62,7 +62,7 @@
 }
 
 void f() {
-  p = conv_arr_4_S(u.inner);
+  p = conv_arr4_S(u.inner);
   p[1] = conv_S(u.inner[2u]);
   p[3].m = load_u_inner_2_m();
   p[1].m[0] = u.inner[0u].m_1.yx;
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x2/to_private.wgsl.expected.spvasm
index 0320931..4cadc2f 100644
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/to_private.wgsl.expected.spvasm
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2/to_private.wgsl.expected.spvasm
@@ -23,7 +23,7 @@
                OpName %p "p"
                OpName %conv_S "conv_S"
                OpName %val "val"
-               OpName %conv_arr_4_S "conv_arr_4_S"
+               OpName %conv_arr4_S "conv_arr4_S"
                OpName %val_0 "val"
                OpName %arr "arr"
                OpName %i "i"
@@ -101,7 +101,7 @@
          %27 = OpCompositeConstruct %S %21 %25 %26
                OpReturnValue %27
                OpFunctionEnd
-%conv_arr_4_S = OpFunction %_arr_S_uint_4 None %28
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %28
       %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
          %31 = OpLabel
         %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %16
@@ -154,7 +154,7 @@
          %85 = OpLabel
          %88 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
          %89 = OpLoad %_arr_S_std140_uint_4 %88
-         %86 = OpFunctionCall %_arr_S_uint_4 %conv_arr_4_S %89
+         %86 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %89
                OpStore %p %86
          %92 = OpAccessChain %_ptr_Private_S %p %int_1
          %94 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x2/to_storage.wgsl.expected.glsl
index ccd6e88..4013cf5 100644
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/to_storage.wgsl.expected.glsl
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2/to_storage.wgsl.expected.glsl
@@ -50,7 +50,7 @@
   return S(val.before, val.pad, mat3x2(val.m_0, val.m_1, val.m_2), val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.after, val.pad_11);
 }
 
-S[4] conv_arr_4_S(S_std140 val[4]) {
+S[4] conv_arr4_S(S_std140 val[4]) {
   S arr[4] = S[4](S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u), S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u), S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u), S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u));
   {
     for(uint i = 0u; (i < 4u); i = (i + 1u)) {
@@ -65,7 +65,7 @@
 }
 
 void f() {
-  s.inner = conv_arr_4_S(u.inner);
+  s.inner = conv_arr4_S(u.inner);
   s.inner[1] = conv_S(u.inner[2u]);
   s.inner[3].m = load_u_inner_2_m();
   s.inner[1].m[0] = u.inner[0u].m_1.yx;
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x2/to_storage.wgsl.expected.spvasm
index 3032953..93ef04f 100644
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/to_storage.wgsl.expected.spvasm
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2/to_storage.wgsl.expected.spvasm
@@ -25,7 +25,7 @@
                OpName %s "s"
                OpName %conv_S "conv_S"
                OpName %val "val"
-               OpName %conv_arr_4_S "conv_arr_4_S"
+               OpName %conv_arr4_S "conv_arr4_S"
                OpName %val_0 "val"
                OpName %arr "arr"
                OpName %i "i"
@@ -109,7 +109,7 @@
          %27 = OpCompositeConstruct %S %21 %25 %26
                OpReturnValue %27
                OpFunctionEnd
-%conv_arr_4_S = OpFunction %_arr_S_uint_4 None %28
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %28
       %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
          %31 = OpLabel
         %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %34
@@ -163,7 +163,7 @@
          %88 = OpAccessChain %_ptr_StorageBuffer__arr_S_uint_4 %s %uint_0
          %91 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
          %92 = OpLoad %_arr_S_std140_uint_4 %91
-         %89 = OpFunctionCall %_arr_S_uint_4 %conv_arr_4_S %92
+         %89 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %92
                OpStore %88 %89
          %95 = OpAccessChain %_ptr_StorageBuffer_S %s %uint_0 %int_1
          %97 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x2/to_workgroup.wgsl.expected.glsl
index fd14f19..9c72f93 100644
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/to_workgroup.wgsl.expected.glsl
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2/to_workgroup.wgsl.expected.glsl
@@ -47,7 +47,7 @@
   return S(val.before, val.pad, mat3x2(val.m_0, val.m_1, val.m_2), val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.after, val.pad_11);
 }
 
-S[4] conv_arr_4_S(S_std140 val[4]) {
+S[4] conv_arr4_S(S_std140 val[4]) {
   S arr[4] = S[4](S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u), S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u), S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u), S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u));
   {
     for(uint i = 0u; (i < 4u); i = (i + 1u)) {
@@ -70,7 +70,7 @@
     }
   }
   barrier();
-  w = conv_arr_4_S(u.inner);
+  w = conv_arr4_S(u.inner);
   w[1] = conv_S(u.inner[2u]);
   w[3].m = load_u_inner_2_m();
   w[1].m[0] = u.inner[0u].m_1.yx;
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x2/to_workgroup.wgsl.expected.spvasm
index 9db5af8..be09c71 100644
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/to_workgroup.wgsl.expected.spvasm
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2/to_workgroup.wgsl.expected.spvasm
@@ -24,7 +24,7 @@
                OpName %w "w"
                OpName %conv_S "conv_S"
                OpName %val "val"
-               OpName %conv_arr_4_S "conv_arr_4_S"
+               OpName %conv_arr4_S "conv_arr4_S"
                OpName %val_0 "val"
                OpName %arr "arr"
                OpName %i "i"
@@ -111,7 +111,7 @@
          %28 = OpCompositeConstruct %S %22 %26 %27
                OpReturnValue %28
                OpFunctionEnd
-%conv_arr_4_S = OpFunction %_arr_S_uint_4 None %29
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %29
       %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
          %32 = OpLabel
         %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %35
@@ -191,7 +191,7 @@
                OpControlBarrier %uint_2 %uint_2 %uint_264
         %109 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
         %110 = OpLoad %_arr_S_std140_uint_4 %109
-        %107 = OpFunctionCall %_arr_S_uint_4 %conv_arr_4_S %110
+        %107 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %110
                OpStore %w %107
         %112 = OpAccessChain %_ptr_Workgroup_S %w %int_1
         %114 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x2/dynamic_index_via_ptr.wgsl.expected.glsl
index 7e60332..4bffcae 100644
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/dynamic_index_via_ptr.wgsl.expected.glsl
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -33,7 +33,7 @@
   return Inner(mat4x2(val.m_0, val.m_1, val.m_2, val.m_3));
 }
 
-Inner[4] conv_arr_4_Inner(Inner_std140 val[4]) {
+Inner[4] conv_arr4_Inner(Inner_std140 val[4]) {
   Inner arr[4] = Inner[4](Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)));
   {
     for(uint i = 0u; (i < 4u); i = (i + 1u)) {
@@ -44,10 +44,10 @@
 }
 
 Outer conv_Outer(Outer_std140 val) {
-  return Outer(conv_arr_4_Inner(val.a));
+  return Outer(conv_arr4_Inner(val.a));
 }
 
-Outer[4] conv_arr_4_Outer(Outer_std140 val[4]) {
+Outer[4] conv_arr4_Outer(Outer_std140 val[4]) {
   Outer arr[4] = Outer[4](Outer(Inner[4](Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)))), Outer(Inner[4](Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)))), Outer(Inner[4](Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)))), Outer(Inner[4](Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)))));
   {
     for(uint i = 0u; (i < 4u); i = (i + 1u)) {
@@ -114,18 +114,18 @@
 }
 
 void f() {
-  Outer p_a[4] = conv_arr_4_Outer(a.inner);
+  Outer p_a[4] = conv_arr4_Outer(a.inner);
   int tint_symbol = i();
   Outer p_a_i = conv_Outer(a.inner[tint_symbol]);
-  Inner p_a_i_a[4] = conv_arr_4_Inner(a.inner[tint_symbol].a);
+  Inner p_a_i_a[4] = conv_arr4_Inner(a.inner[tint_symbol].a);
   int tint_symbol_1 = i();
   Inner p_a_i_a_i = conv_Inner(a.inner[tint_symbol].a[tint_symbol_1]);
   mat4x2 p_a_i_a_i_m = load_a_inner_p0_a_p1_m(uint(tint_symbol), uint(tint_symbol_1));
   int tint_symbol_2 = i();
   vec2 p_a_i_a_i_m_i = load_a_inner_p0_a_p1_m_p2(uint(tint_symbol), uint(tint_symbol_1), uint(tint_symbol_2));
-  Outer l_a[4] = conv_arr_4_Outer(a.inner);
+  Outer l_a[4] = conv_arr4_Outer(a.inner);
   Outer l_a_i = conv_Outer(a.inner[tint_symbol]);
-  Inner l_a_i_a[4] = conv_arr_4_Inner(a.inner[tint_symbol].a);
+  Inner l_a_i_a[4] = conv_arr4_Inner(a.inner[tint_symbol].a);
   Inner l_a_i_a_i = conv_Inner(a.inner[tint_symbol].a[tint_symbol_1]);
   mat4x2 l_a_i_a_i_m = load_a_inner_p0_a_p1_m(uint(tint_symbol), uint(tint_symbol_1));
   vec2 l_a_i_a_i_m_i = load_a_inner_p0_a_p1_m_p2(uint(tint_symbol), uint(tint_symbol_1), uint(tint_symbol_2));
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x2/dynamic_index_via_ptr.wgsl.expected.spvasm
index 2a4d2ca..9a4f081 100644
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/dynamic_index_via_ptr.wgsl.expected.spvasm
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -23,7 +23,7 @@
                OpMemberName %Inner 0 "m"
                OpName %conv_Inner "conv_Inner"
                OpName %val "val"
-               OpName %conv_arr_4_Inner "conv_arr_4_Inner"
+               OpName %conv_arr4_Inner "conv_arr4_Inner"
                OpName %val_0 "val"
                OpName %arr "arr"
                OpName %i_0 "i"
@@ -32,7 +32,7 @@
                OpMemberName %Outer 0 "a"
                OpName %conv_Outer "conv_Outer"
                OpName %val_1 "val"
-               OpName %conv_arr_4_Outer "conv_arr_4_Outer"
+               OpName %conv_arr4_Outer "conv_arr4_Outer"
                OpName %val_2 "val"
                OpName %arr_0 "arr"
                OpName %i_1 "i"
@@ -145,7 +145,7 @@
          %34 = OpCompositeConstruct %Inner %33
                OpReturnValue %34
                OpFunctionEnd
-%conv_arr_4_Inner = OpFunction %_arr_Inner_uint_4 None %35
+%conv_arr4_Inner = OpFunction %_arr_Inner_uint_4 None %35
       %val_0 = OpFunctionParameter %_arr_Inner_std140_uint_4
          %39 = OpLabel
         %arr = OpVariable %_ptr_Function__arr_Inner_uint_4 Function %42
@@ -186,11 +186,11 @@
       %val_1 = OpFunctionParameter %Outer_std140
          %75 = OpLabel
          %77 = OpCompositeExtract %_arr_Inner_std140_uint_4 %val_1 0
-         %76 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr_4_Inner %77
+         %76 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %77
          %78 = OpCompositeConstruct %Outer %76
                OpReturnValue %78
                OpFunctionEnd
-%conv_arr_4_Outer = OpFunction %_arr_Outer_uint_4 None %79
+%conv_arr4_Outer = OpFunction %_arr_Outer_uint_4 None %79
       %val_2 = OpFunctionParameter %_arr_Outer_std140_uint_4
          %83 = OpLabel
       %arr_0 = OpVariable %_ptr_Function__arr_Outer_uint_4 Function %86
@@ -307,13 +307,13 @@
         %186 = OpFunctionCall %int %i
         %189 = OpAccessChain %_ptr_Uniform__arr_Outer_std140_uint_4 %a %uint_0
         %190 = OpLoad %_arr_Outer_std140_uint_4 %189
-        %187 = OpFunctionCall %_arr_Outer_uint_4 %conv_arr_4_Outer %190
+        %187 = OpFunctionCall %_arr_Outer_uint_4 %conv_arr4_Outer %190
         %193 = OpAccessChain %_ptr_Uniform_Outer_std140 %a %uint_0 %184
         %194 = OpLoad %Outer_std140 %193
         %191 = OpFunctionCall %Outer %conv_Outer %194
         %197 = OpAccessChain %_ptr_Uniform__arr_Inner_std140_uint_4 %a %uint_0 %184 %uint_0
         %198 = OpLoad %_arr_Inner_std140_uint_4 %197
-        %195 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr_4_Inner %198
+        %195 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %198
         %200 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %184 %uint_0 %185
         %201 = OpLoad %Inner_std140 %200
         %199 = OpFunctionCall %Inner %conv_Inner %201
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x2/static_index_via_ptr.wgsl.expected.glsl
index c14425b..658fe9e 100644
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/static_index_via_ptr.wgsl.expected.glsl
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2/static_index_via_ptr.wgsl.expected.glsl
@@ -27,7 +27,7 @@
   return Inner(mat4x2(val.m_0, val.m_1, val.m_2, val.m_3));
 }
 
-Inner[4] conv_arr_4_Inner(Inner_std140 val[4]) {
+Inner[4] conv_arr4_Inner(Inner_std140 val[4]) {
   Inner arr[4] = Inner[4](Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)));
   {
     for(uint i = 0u; (i < 4u); i = (i + 1u)) {
@@ -38,10 +38,10 @@
 }
 
 Outer conv_Outer(Outer_std140 val) {
-  return Outer(conv_arr_4_Inner(val.a));
+  return Outer(conv_arr4_Inner(val.a));
 }
 
-Outer[4] conv_arr_4_Outer(Outer_std140 val[4]) {
+Outer[4] conv_arr4_Outer(Outer_std140 val[4]) {
   Outer arr[4] = Outer[4](Outer(Inner[4](Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)))), Outer(Inner[4](Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)))), Outer(Inner[4](Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)))), Outer(Inner[4](Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)))));
   {
     for(uint i = 0u; (i < 4u); i = (i + 1u)) {
@@ -56,15 +56,15 @@
 }
 
 void f() {
-  Outer p_a[4] = conv_arr_4_Outer(a.inner);
+  Outer p_a[4] = conv_arr4_Outer(a.inner);
   Outer p_a_3 = conv_Outer(a.inner[3u]);
-  Inner p_a_3_a[4] = conv_arr_4_Inner(a.inner[3u].a);
+  Inner p_a_3_a[4] = conv_arr4_Inner(a.inner[3u].a);
   Inner p_a_3_a_2 = conv_Inner(a.inner[3u].a[2u]);
   mat4x2 p_a_3_a_2_m = load_a_inner_3_a_2_m();
   vec2 p_a_3_a_2_m_1 = a.inner[3u].a[2u].m_1;
-  Outer l_a[4] = conv_arr_4_Outer(a.inner);
+  Outer l_a[4] = conv_arr4_Outer(a.inner);
   Outer l_a_3 = conv_Outer(a.inner[3u]);
-  Inner l_a_3_a[4] = conv_arr_4_Inner(a.inner[3u].a);
+  Inner l_a_3_a[4] = conv_arr4_Inner(a.inner[3u].a);
   Inner l_a_3_a_2 = conv_Inner(a.inner[3u].a[2u]);
   mat4x2 l_a_3_a_2_m = load_a_inner_3_a_2_m();
   vec2 l_a_3_a_2_m_1 = a.inner[3u].a[2u].m_1;
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x2/static_index_via_ptr.wgsl.expected.spvasm
index 3cd3ef3..730d12b 100644
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/static_index_via_ptr.wgsl.expected.spvasm
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2/static_index_via_ptr.wgsl.expected.spvasm
@@ -21,7 +21,7 @@
                OpMemberName %Inner 0 "m"
                OpName %conv_Inner "conv_Inner"
                OpName %val "val"
-               OpName %conv_arr_4_Inner "conv_arr_4_Inner"
+               OpName %conv_arr4_Inner "conv_arr4_Inner"
                OpName %val_0 "val"
                OpName %arr "arr"
                OpName %i "i"
@@ -30,7 +30,7 @@
                OpMemberName %Outer 0 "a"
                OpName %conv_Outer "conv_Outer"
                OpName %val_1 "val"
-               OpName %conv_arr_4_Outer "conv_arr_4_Outer"
+               OpName %conv_arr4_Outer "conv_arr4_Outer"
                OpName %val_2 "val"
                OpName %arr_0 "arr"
                OpName %i_0 "i"
@@ -114,7 +114,7 @@
          %23 = OpCompositeConstruct %Inner %22
                OpReturnValue %23
                OpFunctionEnd
-%conv_arr_4_Inner = OpFunction %_arr_Inner_uint_4 None %24
+%conv_arr4_Inner = OpFunction %_arr_Inner_uint_4 None %24
       %val_0 = OpFunctionParameter %_arr_Inner_std140_uint_4
          %28 = OpLabel
         %arr = OpVariable %_ptr_Function__arr_Inner_uint_4 Function %31
@@ -155,11 +155,11 @@
       %val_1 = OpFunctionParameter %Outer_std140
          %64 = OpLabel
          %66 = OpCompositeExtract %_arr_Inner_std140_uint_4 %val_1 0
-         %65 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr_4_Inner %66
+         %65 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %66
          %67 = OpCompositeConstruct %Outer %65
                OpReturnValue %67
                OpFunctionEnd
-%conv_arr_4_Outer = OpFunction %_arr_Outer_uint_4 None %68
+%conv_arr4_Outer = OpFunction %_arr_Outer_uint_4 None %68
       %val_2 = OpFunctionParameter %_arr_Outer_std140_uint_4
          %72 = OpLabel
       %arr_0 = OpVariable %_ptr_Function__arr_Outer_uint_4 Function %75
@@ -214,13 +214,13 @@
         %126 = OpLabel
         %129 = OpAccessChain %_ptr_Uniform__arr_Outer_std140_uint_4 %a %uint_0
         %130 = OpLoad %_arr_Outer_std140_uint_4 %129
-        %127 = OpFunctionCall %_arr_Outer_uint_4 %conv_arr_4_Outer %130
+        %127 = OpFunctionCall %_arr_Outer_uint_4 %conv_arr4_Outer %130
         %133 = OpAccessChain %_ptr_Uniform_Outer_std140 %a %uint_0 %uint_3
         %134 = OpLoad %Outer_std140 %133
         %131 = OpFunctionCall %Outer %conv_Outer %134
         %137 = OpAccessChain %_ptr_Uniform__arr_Inner_std140_uint_4 %a %uint_0 %uint_3 %uint_0
         %138 = OpLoad %_arr_Inner_std140_uint_4 %137
-        %135 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr_4_Inner %138
+        %135 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %138
         %140 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %uint_3 %uint_0 %uint_2
         %141 = OpLoad %Inner_std140 %140
         %139 = OpFunctionCall %Inner %conv_Inner %141
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x2/to_fn.wgsl.expected.glsl
index 42fa3a1..43a4f88 100644
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/to_fn.wgsl.expected.glsl
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2/to_fn.wgsl.expected.glsl
@@ -42,7 +42,7 @@
   return S(val.before, val.pad, mat4x2(val.m_0, val.m_1, val.m_2, val.m_3), val.after, val.pad_1);
 }
 
-S[4] conv_arr_4_S(S_std140 val[4]) {
+S[4] conv_arr4_S(S_std140 val[4]) {
   S arr[4] = S[4](S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0, 0u));
   {
     for(uint i = 0u; (i < 4u); i = (i + 1u)) {
@@ -57,7 +57,7 @@
 }
 
 void f() {
-  a(conv_arr_4_S(u.inner));
+  a(conv_arr4_S(u.inner));
   b(conv_S(u.inner[2u]));
   c(load_u_inner_2_m());
   d(u.inner[0u].m_1.yx);
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x2/to_fn.wgsl.expected.spvasm
index 06de1ef..63abbf3 100644
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/to_fn.wgsl.expected.spvasm
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2/to_fn.wgsl.expected.spvasm
@@ -33,7 +33,7 @@
                OpName %f_1 "f_1"
                OpName %conv_S "conv_S"
                OpName %val "val"
-               OpName %conv_arr_4_S "conv_arr_4_S"
+               OpName %conv_arr4_S "conv_arr4_S"
                OpName %val_0 "val"
                OpName %arr "arr"
                OpName %i "i"
@@ -135,7 +135,7 @@
          %46 = OpCompositeConstruct %S %39 %44 %45
                OpReturnValue %46
                OpFunctionEnd
-%conv_arr_4_S = OpFunction %_arr_S_uint_4 None %47
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %47
       %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
          %50 = OpLabel
         %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %53
@@ -190,7 +190,7 @@
         %107 = OpLabel
         %111 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
         %112 = OpLoad %_arr_S_std140_uint_4 %111
-        %109 = OpFunctionCall %_arr_S_uint_4 %conv_arr_4_S %112
+        %109 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %112
         %108 = OpFunctionCall %void %a %109
         %115 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
         %116 = OpLoad %S_std140 %115
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x2/to_private.wgsl.expected.glsl
index 658610e..1ff8aa4 100644
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/to_private.wgsl.expected.glsl
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2/to_private.wgsl.expected.glsl
@@ -28,7 +28,7 @@
   return S(val.before, val.pad, mat4x2(val.m_0, val.m_1, val.m_2, val.m_3), val.after, val.pad_1);
 }
 
-S[4] conv_arr_4_S(S_std140 val[4]) {
+S[4] conv_arr4_S(S_std140 val[4]) {
   S arr[4] = S[4](S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0, 0u));
   {
     for(uint i = 0u; (i < 4u); i = (i + 1u)) {
@@ -43,7 +43,7 @@
 }
 
 void f() {
-  p = conv_arr_4_S(u.inner);
+  p = conv_arr4_S(u.inner);
   p[1] = conv_S(u.inner[2u]);
   p[3].m = load_u_inner_2_m();
   p[1].m[0] = u.inner[0u].m_1.yx;
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x2/to_private.wgsl.expected.spvasm
index ea4bf22..e0ac972 100644
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/to_private.wgsl.expected.spvasm
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2/to_private.wgsl.expected.spvasm
@@ -24,7 +24,7 @@
                OpName %p "p"
                OpName %conv_S "conv_S"
                OpName %val "val"
-               OpName %conv_arr_4_S "conv_arr_4_S"
+               OpName %conv_arr4_S "conv_arr4_S"
                OpName %val_0 "val"
                OpName %arr "arr"
                OpName %i "i"
@@ -104,7 +104,7 @@
          %28 = OpCompositeConstruct %S %21 %26 %27
                OpReturnValue %28
                OpFunctionEnd
-%conv_arr_4_S = OpFunction %_arr_S_uint_4 None %29
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %29
       %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
          %32 = OpLabel
         %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %16
@@ -159,7 +159,7 @@
          %89 = OpLabel
          %92 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
          %93 = OpLoad %_arr_S_std140_uint_4 %92
-         %90 = OpFunctionCall %_arr_S_uint_4 %conv_arr_4_S %93
+         %90 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %93
                OpStore %p %90
          %96 = OpAccessChain %_ptr_Private_S %p %int_1
          %98 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x2/to_storage.wgsl.expected.glsl
index 90098bd..d9b6a9f 100644
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/to_storage.wgsl.expected.glsl
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2/to_storage.wgsl.expected.glsl
@@ -31,7 +31,7 @@
   return S(val.before, val.pad, mat4x2(val.m_0, val.m_1, val.m_2, val.m_3), val.after, val.pad_1);
 }
 
-S[4] conv_arr_4_S(S_std140 val[4]) {
+S[4] conv_arr4_S(S_std140 val[4]) {
   S arr[4] = S[4](S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0, 0u));
   {
     for(uint i = 0u; (i < 4u); i = (i + 1u)) {
@@ -46,7 +46,7 @@
 }
 
 void f() {
-  s.inner = conv_arr_4_S(u.inner);
+  s.inner = conv_arr4_S(u.inner);
   s.inner[1] = conv_S(u.inner[2u]);
   s.inner[3].m = load_u_inner_2_m();
   s.inner[1].m[0] = u.inner[0u].m_1.yx;
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x2/to_storage.wgsl.expected.spvasm
index 5d20562..bcbfadc5 100644
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/to_storage.wgsl.expected.spvasm
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2/to_storage.wgsl.expected.spvasm
@@ -26,7 +26,7 @@
                OpName %s "s"
                OpName %conv_S "conv_S"
                OpName %val "val"
-               OpName %conv_arr_4_S "conv_arr_4_S"
+               OpName %conv_arr4_S "conv_arr4_S"
                OpName %val_0 "val"
                OpName %arr "arr"
                OpName %i "i"
@@ -112,7 +112,7 @@
          %28 = OpCompositeConstruct %S %21 %26 %27
                OpReturnValue %28
                OpFunctionEnd
-%conv_arr_4_S = OpFunction %_arr_S_uint_4 None %29
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %29
       %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
          %32 = OpLabel
         %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %35
@@ -168,7 +168,7 @@
          %92 = OpAccessChain %_ptr_StorageBuffer__arr_S_uint_4 %s %uint_0
          %95 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
          %96 = OpLoad %_arr_S_std140_uint_4 %95
-         %93 = OpFunctionCall %_arr_S_uint_4 %conv_arr_4_S %96
+         %93 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %96
                OpStore %92 %93
          %99 = OpAccessChain %_ptr_StorageBuffer_S %s %uint_0 %int_1
         %101 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x2/to_workgroup.wgsl.expected.glsl
index 07cabf9..2e8a05f 100644
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/to_workgroup.wgsl.expected.glsl
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2/to_workgroup.wgsl.expected.glsl
@@ -28,7 +28,7 @@
   return S(val.before, val.pad, mat4x2(val.m_0, val.m_1, val.m_2, val.m_3), val.after, val.pad_1);
 }
 
-S[4] conv_arr_4_S(S_std140 val[4]) {
+S[4] conv_arr4_S(S_std140 val[4]) {
   S arr[4] = S[4](S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0, 0u));
   {
     for(uint i = 0u; (i < 4u); i = (i + 1u)) {
@@ -51,7 +51,7 @@
     }
   }
   barrier();
-  w = conv_arr_4_S(u.inner);
+  w = conv_arr4_S(u.inner);
   w[1] = conv_S(u.inner[2u]);
   w[3].m = load_u_inner_2_m();
   w[1].m[0] = u.inner[0u].m_1.yx;
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x2/to_workgroup.wgsl.expected.spvasm
index 80ec01c..a690ffc 100644
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/to_workgroup.wgsl.expected.spvasm
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2/to_workgroup.wgsl.expected.spvasm
@@ -25,7 +25,7 @@
                OpName %w "w"
                OpName %conv_S "conv_S"
                OpName %val "val"
-               OpName %conv_arr_4_S "conv_arr_4_S"
+               OpName %conv_arr4_S "conv_arr4_S"
                OpName %val_0 "val"
                OpName %arr "arr"
                OpName %i "i"
@@ -114,7 +114,7 @@
          %29 = OpCompositeConstruct %S %22 %27 %28
                OpReturnValue %29
                OpFunctionEnd
-%conv_arr_4_S = OpFunction %_arr_S_uint_4 None %30
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %30
       %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
          %33 = OpLabel
         %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %36
@@ -196,7 +196,7 @@
                OpControlBarrier %uint_2 %uint_2 %uint_264
         %113 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
         %114 = OpLoad %_arr_S_std140_uint_4 %113
-        %111 = OpFunctionCall %_arr_S_uint_4 %conv_arr_4_S %114
+        %111 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %114
                OpStore %w %111
         %116 = OpAccessChain %_ptr_Workgroup_S %w %int_1
         %118 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2