resolver: Enable support of out of order declarations

Allow module-scope declarations to be made in any order.

Bug: tint:1266
Change-Id: Ib2607b6c33fad7c83e2c36f85b0a965eac922ec5
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/79769
Reviewed-by: David Neto <dneto@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/src/resolver/call_test.cc b/src/resolver/call_test.cc
index 3448726..9a3cc85 100644
--- a/src/resolver/call_test.cc
+++ b/src/resolver/call_test.cc
@@ -101,6 +101,18 @@
   EXPECT_EQ(call->Target(), Sem().Get(func));
 }
 
+TEST_F(ResolverCallTest, OutOfOrder) {
+  auto* call_expr = Call("b");
+  Func("a", {}, ty.void_(), {CallStmt(call_expr)});
+  auto* b = Func("b", {}, ty.void_(), {});
+
+  EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+  auto* call = Sem().Get(call_expr);
+  EXPECT_NE(call, nullptr);
+  EXPECT_EQ(call->Target(), Sem().Get(b));
+}
+
 }  // namespace
 }  // namespace resolver
 }  // namespace tint
diff --git a/src/resolver/dependency_graph.cc b/src/resolver/dependency_graph.cc
index d520cd7..7aa5c52 100644
--- a/src/resolver/dependency_graph.cc
+++ b/src/resolver/dependency_graph.cc
@@ -474,7 +474,7 @@
   /// Performs global dependency analysis on the module, emitting any errors to
   /// #diagnostics.
   /// @returns true if analysis found no errors, otherwise false.
-  bool Run(const ast::Module& module, bool allow_out_of_order_decls) {
+  bool Run(const ast::Module& module) {
     // Collect all the named globals from the AST module
     GatherGlobals(module);
 
@@ -487,11 +487,6 @@
     // Dump the dependency graph if TINT_DUMP_DEPENDENCY_GRAPH is non-zero
     DumpDependencyGraph();
 
-    if (!allow_out_of_order_decls) {
-      // Prevent out-of-order declarations.
-      ErrorOnOutOfOrderDeclarations();
-    }
-
     graph_.ordered_globals = std::move(sorted_);
 
     return !diagnostics_.contains_errors();
@@ -668,36 +663,6 @@
     return {};
   }
 
-  // TODO(crbug.com/tint/1266): Errors if there are any uses of globals before
-  // their declaration. Out-of-order declarations was added to the WGSL
-  // specification with https://github.com/gpuweb/gpuweb/pull/2244, but Mozilla
-  // have objections to this change so this feature is currently disabled via
-  // this function.
-  void ErrorOnOutOfOrderDeclarations() {
-    if (diagnostics_.contains_errors()) {
-      // Might have already errored about cyclic dependencies. No need to report
-      // out-of-order errors as well.
-      return;
-    }
-    std::unordered_set<const Global*> seen;
-    for (auto* global : declaration_order_) {
-      for (auto* dep : global->deps) {
-        if (!seen.count(dep)) {
-          auto info = DepInfoFor(global, dep);
-          auto name = NameOf(dep->node);
-          AddError(diagnostics_,
-                   KindOf(dep->node) + " '" + name +
-                       "' used before it has been declared",
-                   info.source);
-          AddNote(diagnostics_,
-                  KindOf(dep->node) + " '" + name + "' declared here",
-                  dep->node->source);
-        }
-      }
-      seen.emplace(global);
-    }
-  }
-
   /// CyclicDependencyFound() emits an error diagnostic for a cyclic dependency.
   /// @param root is the global that starts the cyclic dependency, which must be
   /// found in `stack`.
@@ -789,10 +754,9 @@
 bool DependencyGraph::Build(const ast::Module& module,
                             const SymbolTable& symbols,
                             diag::List& diagnostics,
-                            DependencyGraph& output,
-                            bool allow_out_of_order_decls) {
+                            DependencyGraph& output) {
   DependencyAnalysis da{symbols, diagnostics, output};
-  return da.Run(module, allow_out_of_order_decls);
+  return da.Run(module);
 }
 
 }  // namespace resolver
diff --git a/src/resolver/dependency_graph.h b/src/resolver/dependency_graph.h
index 6235ad7..294786d 100644
--- a/src/resolver/dependency_graph.h
+++ b/src/resolver/dependency_graph.h
@@ -40,14 +40,11 @@
   /// @param symbols the symbol table
   /// @param diagnostics the diagnostic list to populate with errors / warnings
   /// @param output the resulting DependencyGraph
-  /// @param allow_out_of_order_decls if true, then out-of-order declarations
-  /// are not considered an error
   /// @returns true on success, false on error
   static bool Build(const ast::Module& module,
                     const SymbolTable& symbols,
                     diag::List& diagnostics,
-                    DependencyGraph& output,
-                    bool allow_out_of_order_decls);
+                    DependencyGraph& output);
 
   /// All globals in dependency-sorted order.
   std::vector<const ast::Node*> ordered_globals;
diff --git a/src/resolver/dependency_graph_test.cc b/src/resolver/dependency_graph_test.cc
index 0b9080c..2329d86 100644
--- a/src/resolver/dependency_graph_test.cc
+++ b/src/resolver/dependency_graph_test.cc
@@ -29,13 +29,10 @@
 template <typename T>
 class ResolverDependencyGraphTestWithParam : public ResolverTestWithParam<T> {
  public:
-  bool allow_out_of_order_decls = true;
-
   DependencyGraph Build(std::string expected_error = "") {
     DependencyGraph graph;
     auto result = DependencyGraph::Build(this->AST(), this->Symbols(),
-                                         this->Diagnostics(), graph,
-                                         allow_out_of_order_decls);
+                                         this->Diagnostics(), graph);
     if (expected_error.empty()) {
       EXPECT_TRUE(result) << this->Diagnostics().str();
     } else {
@@ -659,13 +656,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 namespace used_before_decl_tests {
 
-class ResolverDependencyGraphUsedBeforeDeclTest
-    : public ResolverDependencyGraphTest {
- public:
-  ResolverDependencyGraphUsedBeforeDeclTest() {
-    allow_out_of_order_decls = false;
-  }
-};
+using ResolverDependencyGraphUsedBeforeDeclTest = ResolverDependencyGraphTest;
 
 TEST_F(ResolverDependencyGraphUsedBeforeDeclTest, FuncCall) {
   // fn A() { B(); }
@@ -674,8 +665,7 @@
   Func("A", {}, ty.void_(), {CallStmt(Call(Expr(Source{{12, 34}}, "B")))});
   Func(Source{{56, 78}}, "B", {}, ty.void_(), {Return()});
 
-  Build(R"(12:34 error: function 'B' used before it has been declared
-56:78 note: function 'B' declared here)");
+  Build();
 }
 
 TEST_F(ResolverDependencyGraphUsedBeforeDeclTest, TypeConstructed) {
@@ -688,8 +678,7 @@
        {Block(Ignore(Construct(ty.type_name(Source{{12, 34}}, "T"))))});
   Alias(Source{{56, 78}}, "T", ty.i32());
 
-  Build(R"(12:34 error: alias 'T' used before it has been declared
-56:78 note: alias 'T' declared here)");
+  Build();
 }
 
 TEST_F(ResolverDependencyGraphUsedBeforeDeclTest, TypeUsedByLocal) {
@@ -702,8 +691,7 @@
        {Block(Decl(Var("v", ty.type_name(Source{{12, 34}}, "T"))))});
   Alias(Source{{56, 78}}, "T", ty.i32());
 
-  Build(R"(12:34 error: alias 'T' used before it has been declared
-56:78 note: alias 'T' declared here)");
+  Build();
 }
 
 TEST_F(ResolverDependencyGraphUsedBeforeDeclTest, TypeUsedByParam) {
@@ -713,8 +701,7 @@
   Func("F", {Param("p", ty.type_name(Source{{12, 34}}, "T"))}, ty.void_(), {});
   Alias(Source{{56, 78}}, "T", ty.i32());
 
-  Build(R"(12:34 error: alias 'T' used before it has been declared
-56:78 note: alias 'T' declared here)");
+  Build();
 }
 
 TEST_F(ResolverDependencyGraphUsedBeforeDeclTest, TypeUsedAsReturnType) {
@@ -724,8 +711,7 @@
   Func("F", {}, ty.type_name(Source{{12, 34}}, "T"), {});
   Alias(Source{{56, 78}}, "T", ty.i32());
 
-  Build(R"(12:34 error: alias 'T' used before it has been declared
-56:78 note: alias 'T' declared here)");
+  Build();
 }
 
 TEST_F(ResolverDependencyGraphUsedBeforeDeclTest, TypeByStructMember) {
@@ -735,8 +721,7 @@
   Structure("S", {Member("m", ty.type_name(Source{{12, 34}}, "T"))});
   Alias(Source{{56, 78}}, "T", ty.i32());
 
-  Build(R"(12:34 error: alias 'T' used before it has been declared
-56:78 note: alias 'T' declared here)");
+  Build();
 }
 
 TEST_F(ResolverDependencyGraphUsedBeforeDeclTest, VarUsed) {
@@ -751,10 +736,7 @@
   Global(Source{{56, 78}}, "G", ty.f32(), ast::StorageClass::kPrivate,
          Expr(2.1f));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            R"(12:34 error: var 'G' used before it has been declared
-56:78 note: var 'G' declared here)");
+  Build();
 }
 
 }  // namespace used_before_decl_tests
diff --git a/src/resolver/resolver.cc b/src/resolver/resolver.cc
index 2a77c96..623af60 100644
--- a/src/resolver/resolver.cc
+++ b/src/resolver/resolver.cc
@@ -95,8 +95,7 @@
   }
 
   if (!DependencyGraph::Build(builder_->AST(), builder_->Symbols(),
-                              builder_->Diagnostics(), dependencies_,
-                              /* allow_out_of_order_decls*/ false)) {
+                              builder_->Diagnostics(), dependencies_)) {
     return false;
   }
 
@@ -118,9 +117,8 @@
 bool Resolver::ResolveInternal() {
   Mark(&builder_->AST());
 
-  // Process everything else in the order they appear in the module. This is
-  // necessary for validation of use-before-declaration.
-  for (auto* decl : builder_->AST().GlobalDeclarations()) {
+  // Process all module-scope declarations in dependency order.
+  for (auto* decl : dependencies_.ordered_globals) {
     if (auto* td = decl->As<ast::TypeDecl>()) {
       Mark(td);
       if (!TypeDecl(td)) {
diff --git a/src/transform/add_spirv_block_attribute_test.cc b/src/transform/add_spirv_block_attribute_test.cc
index 21dbe19..256e8b7 100644
--- a/src/transform/add_spirv_block_attribute_test.cc
+++ b/src/transform/add_spirv_block_attribute_test.cc
@@ -548,6 +548,68 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(AddSpirvBlockAttributeTest,
+       Aliases_Nested_OuterBuffer_InnerBuffer_OutOfOrder) {
+  auto* src = R"(
+@stage(fragment)
+fn main() {
+  let f0 = u0.i.f;
+  let f1 = u1.f;
+}
+
+@group(0) @binding(1)
+var<uniform> u1 : MyInner;
+
+type MyInner = Inner;
+
+@group(0) @binding(0)
+var<uniform> u0 : MyOuter;
+
+type MyOuter = Outer;
+
+struct Outer {
+  i : MyInner;
+};
+
+struct Inner {
+  f : f32;
+};
+)";
+  auto* expect = R"(
+@stage(fragment)
+fn main() {
+  let f0 = u0.i.f;
+  let f1 = u1.inner.f;
+}
+
+@internal(spirv_block)
+struct u1_block {
+  inner : Inner;
+}
+
+@group(0) @binding(1) var<uniform> u1 : u1_block;
+
+type MyInner = Inner;
+
+@group(0) @binding(0) var<uniform> u0 : MyOuter;
+
+type MyOuter = Outer;
+
+@internal(spirv_block)
+struct Outer {
+  i : MyInner;
+}
+
+struct Inner {
+  f : f32;
+}
+)";
+
+  auto got = Run<AddSpirvBlockAttribute>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 }  // namespace
 }  // namespace transform
 }  // namespace tint
diff --git a/src/transform/array_length_from_uniform.cc b/src/transform/array_length_from_uniform.cc
index 9270fd9..9735317 100644
--- a/src/transform/array_length_from_uniform.cc
+++ b/src/transform/array_length_from_uniform.cc
@@ -154,10 +154,8 @@
       buffer_size_ubo = ctx.dst->Global(
           ctx.dst->Sym(), ctx.dst->ty.Of(buffer_size_struct),
           ast::StorageClass::kUniform,
-          ast::AttributeList{
-              ctx.dst->create<ast::GroupAttribute>(cfg->ubo_binding.group),
-              ctx.dst->create<ast::BindingAttribute>(
-                  cfg->ubo_binding.binding)});
+          ast::AttributeList{ctx.dst->GroupAndBinding(
+              cfg->ubo_binding.group, cfg->ubo_binding.binding)});
     }
     return buffer_size_ubo;
   };
diff --git a/src/transform/array_length_from_uniform_test.cc b/src/transform/array_length_from_uniform_test.cc
index a4f2fa9..1ae41ba 100644
--- a/src/transform/array_length_from_uniform_test.cc
+++ b/src/transform/array_length_from_uniform_test.cc
@@ -536,6 +536,54 @@
             got.data.Get<ArrayLengthFromUniform::Result>()->used_size_indices);
 }
 
+TEST_F(ArrayLengthFromUniformTest, OutOfOrder) {
+  auto* src = R"(
+@stage(compute) @workgroup_size(1)
+fn main() {
+  var len : u32 = arrayLength(&sb.arr);
+}
+
+@group(0) @binding(0) var<storage, read> sb : SB;
+
+struct SB {
+  x : i32;
+  arr : array<i32>;
+};
+)";
+
+  auto* expect = R"(
+struct tint_symbol {
+  buffer_size : array<vec4<u32>, 1u>;
+}
+
+@group(0) @binding(30) var<uniform> tint_symbol_1 : tint_symbol;
+
+@stage(compute) @workgroup_size(1)
+fn main() {
+  var len : u32 = ((tint_symbol_1.buffer_size[0u][0u] - 4u) / 4u);
+}
+
+@group(0) @binding(0) var<storage, read> sb : SB;
+
+struct SB {
+  x : i32;
+  arr : array<i32>;
+}
+)";
+
+  ArrayLengthFromUniform::Config cfg({0, 30u});
+  cfg.bindpoint_to_size_index.emplace(sem::BindingPoint{0, 0}, 0);
+
+  DataMap data;
+  data.Add<ArrayLengthFromUniform::Config>(std::move(cfg));
+
+  auto got = Run<Unshadow, SimplifyPointers, ArrayLengthFromUniform>(src, data);
+
+  EXPECT_EQ(expect, str(got));
+  EXPECT_EQ(std::unordered_set<uint32_t>({0}),
+            got.data.Get<ArrayLengthFromUniform::Result>()->used_size_indices);
+}
+
 }  // namespace
 }  // namespace transform
 }  // namespace tint
diff --git a/src/transform/calculate_array_length.cc b/src/transform/calculate_array_length.cc
index ac57650..b745bd2 100644
--- a/src/transform/calculate_array_length.cc
+++ b/src/transform/calculate_array_length.cc
@@ -101,7 +101,7 @@
       auto* type = CreateASTTypeFor(ctx, buffer_type);
       auto* disable_validation = ctx.dst->Disable(
           ast::DisabledValidation::kIgnoreConstructibleFunctionParameter);
-      auto* func = ctx.dst->create<ast::Function>(
+      ctx.dst->AST().AddFunction(ctx.dst->create<ast::Function>(
           name,
           ast::VariableList{
               // Note: The buffer parameter requires the kStorage StorageClass
@@ -118,20 +118,8 @@
           ast::AttributeList{
               ctx.dst->ASTNodes().Create<BufferSizeIntrinsic>(ctx.dst->ID()),
           },
-          ast::AttributeList{});
-      // Insert the intrinsic function after the structure or array structure
-      // element type. TODO(crbug.com/tint/1266): Once we allow out-of-order
-      // declarations, this can be simplified.
-      auto* insert_after = buffer_type;
-      while (auto* arr = insert_after->As<sem::Array>()) {
-        insert_after = arr->ElemType();
-      }
-      if (auto* str = insert_after->As<sem::Struct>()) {
-        ctx.InsertAfter(ctx.src->AST().GlobalDeclarations(), str->Declaration(),
-                        func);
-      } else {
-        ctx.InsertFront(ctx.src->AST().GlobalDeclarations(), func);
-      }
+          ast::AttributeList{}));
+
       return name;
     });
   };
diff --git a/src/transform/calculate_array_length_test.cc b/src/transform/calculate_array_length_test.cc
index fcf7001..fa1f274 100644
--- a/src/transform/calculate_array_length_test.cc
+++ b/src/transform/calculate_array_length_test.cc
@@ -111,14 +111,14 @@
 )";
 
   auto* expect = R"(
+@internal(intrinsic_buffer_size)
+fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, result : ptr<function, u32>)
+
 struct SB {
   x : i32;
   arr : array<i32>;
 }
 
-@internal(intrinsic_buffer_size)
-fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, result : ptr<function, u32>)
-
 @group(0) @binding(0) var<storage, read> sb : SB;
 
 @stage(compute) @workgroup_size(1)
@@ -149,13 +149,13 @@
 }
 )";
   auto* expect = R"(
+@internal(intrinsic_buffer_size)
+fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : array<S>, result : ptr<function, u32>)
+
 struct S {
   f : f32;
 }
 
-@internal(intrinsic_buffer_size)
-fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : array<S>, result : ptr<function, u32>)
-
 @group(0) @binding(0) var<storage, read> arr : array<S>;
 
 @stage(compute) @workgroup_size(1)
@@ -186,13 +186,13 @@
 }
 )";
   auto* expect = R"(
+@internal(intrinsic_buffer_size)
+fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : array<array<S, 4u>>, result : ptr<function, u32>)
+
 struct S {
   f : f32;
 }
 
-@internal(intrinsic_buffer_size)
-fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : array<array<S, 4u>>, result : ptr<function, u32>)
-
 @group(0) @binding(0) var<storage, read> arr : array<array<S, 4>>;
 
 @stage(compute) @workgroup_size(1)
@@ -261,14 +261,14 @@
 )";
 
   auto* expect = R"(
+@internal(intrinsic_buffer_size)
+fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, result : ptr<function, u32>)
+
 struct SB {
   x : i32;
   arr : array<i32>;
 }
 
-@internal(intrinsic_buffer_size)
-fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, result : ptr<function, u32>)
-
 @group(0) @binding(0) var<storage, read> sb : SB;
 
 @stage(compute) @workgroup_size(1)
@@ -334,15 +334,15 @@
 )";
 
   auto* expect = R"(
+@internal(intrinsic_buffer_size)
+fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, result : ptr<function, u32>)
+
 struct SB {
   x : i32;
   y : f32;
   arr : @stride(64) array<i32>;
 }
 
-@internal(intrinsic_buffer_size)
-fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, result : ptr<function, u32>)
-
 @group(0) @binding(0) var<storage, read> sb : SB;
 
 @stage(compute) @workgroup_size(1)
@@ -381,14 +381,14 @@
 )";
 
   auto* expect = R"(
+@internal(intrinsic_buffer_size)
+fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, result : ptr<function, u32>)
+
 struct SB {
   x : i32;
   arr : array<i32>;
 }
 
-@internal(intrinsic_buffer_size)
-fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, result : ptr<function, u32>)
-
 @group(0) @binding(0) var<storage, read> sb : SB;
 
 @stage(compute) @workgroup_size(1)
@@ -443,6 +443,12 @@
 
   auto* expect = R"(
 @internal(intrinsic_buffer_size)
+fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB1, result : ptr<function, u32>)
+
+@internal(intrinsic_buffer_size)
+fn tint_symbol_3(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB2, result : ptr<function, u32>)
+
+@internal(intrinsic_buffer_size)
 fn tint_symbol_6(@internal(disable_validation__ignore_constructible_function_parameter) buffer : array<i32>, result : ptr<function, u32>)
 
 struct SB1 {
@@ -450,17 +456,11 @@
   arr1 : array<i32>;
 }
 
-@internal(intrinsic_buffer_size)
-fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB1, result : ptr<function, u32>)
-
 struct SB2 {
   x : i32;
   arr2 : array<vec4<f32>>;
 }
 
-@internal(intrinsic_buffer_size)
-fn tint_symbol_3(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB2, result : ptr<function, u32>)
-
 @group(0) @binding(0) var<storage, read> sb1 : SB1;
 
 @group(0) @binding(1) var<storage, read> sb2 : SB2;
@@ -512,14 +512,14 @@
 
   auto* expect =
       R"(
+@internal(intrinsic_buffer_size)
+fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, result : ptr<function, u32>)
+
 struct SB {
   x : i32;
   arr : array<i32>;
 }
 
-@internal(intrinsic_buffer_size)
-fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, result : ptr<function, u32>)
-
 @group(0) @binding(0) var<storage, read> a : SB;
 
 @group(0) @binding(1) var<storage, read> b : SB;
@@ -544,6 +544,82 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(CalculateArrayLengthTest, OutOfOrder) {
+  auto* src = R"(
+@stage(compute) @workgroup_size(1)
+fn main() {
+  var len1 : u32 = arrayLength(&(sb1.arr1));
+  var len2 : u32 = arrayLength(&(sb2.arr2));
+  var len3 : u32 = arrayLength(&sb3);
+  var x : u32 = (len1 + len2 + len3);
+}
+
+@group(0) @binding(0) var<storage, read> sb1 : SB1;
+
+struct SB1 {
+  x : i32;
+  arr1 : array<i32>;
+};
+
+@group(0) @binding(1) var<storage, read> sb2 : SB2;
+
+struct SB2 {
+  x : i32;
+  arr2 : array<vec4<f32>>;
+};
+
+@group(0) @binding(2) var<storage, read> sb3 : array<i32>;
+)";
+
+  auto* expect = R"(
+@internal(intrinsic_buffer_size)
+fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB1, result : ptr<function, u32>)
+
+@internal(intrinsic_buffer_size)
+fn tint_symbol_3(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB2, result : ptr<function, u32>)
+
+@internal(intrinsic_buffer_size)
+fn tint_symbol_6(@internal(disable_validation__ignore_constructible_function_parameter) buffer : array<i32>, result : ptr<function, u32>)
+
+@stage(compute) @workgroup_size(1)
+fn main() {
+  var tint_symbol_1 : u32 = 0u;
+  tint_symbol(sb1, &(tint_symbol_1));
+  let tint_symbol_2 : u32 = ((tint_symbol_1 - 4u) / 4u);
+  var tint_symbol_4 : u32 = 0u;
+  tint_symbol_3(sb2, &(tint_symbol_4));
+  let tint_symbol_5 : u32 = ((tint_symbol_4 - 16u) / 16u);
+  var tint_symbol_7 : u32 = 0u;
+  tint_symbol_6(sb3, &(tint_symbol_7));
+  let tint_symbol_8 : u32 = (tint_symbol_7 / 4u);
+  var len1 : u32 = tint_symbol_2;
+  var len2 : u32 = tint_symbol_5;
+  var len3 : u32 = tint_symbol_8;
+  var x : u32 = ((len1 + len2) + len3);
+}
+
+@group(0) @binding(0) var<storage, read> sb1 : SB1;
+
+struct SB1 {
+  x : i32;
+  arr1 : array<i32>;
+}
+
+@group(0) @binding(1) var<storage, read> sb2 : SB2;
+
+struct SB2 {
+  x : i32;
+  arr2 : array<vec4<f32>>;
+}
+
+@group(0) @binding(2) var<storage, read> sb3 : array<i32>;
+)";
+
+  auto got = Run<Unshadow, SimplifyPointers, CalculateArrayLength>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 }  // namespace
 }  // namespace transform
 }  // namespace tint
diff --git a/src/transform/canonicalize_entry_point_io_test.cc b/src/transform/canonicalize_entry_point_io_test.cc
index 23030cb..990a0c5 100644
--- a/src/transform/canonicalize_entry_point_io_test.cc
+++ b/src/transform/canonicalize_entry_point_io_test.cc
@@ -203,6 +203,42 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(CanonicalizeEntryPointIOTest, Parameter_TypeAlias_OutOfOrder) {
+  auto* src = R"(
+@stage(fragment)
+fn frag_main(@location(1) loc1 : myf32) {
+  var x : myf32 = loc1;
+}
+
+type myf32 = f32;
+)";
+
+  auto* expect = R"(
+struct tint_symbol_1 {
+  @location(1)
+  loc1 : f32;
+}
+
+fn frag_main_inner(loc1 : myf32) {
+  var x : myf32 = loc1;
+}
+
+@stage(fragment)
+fn frag_main(tint_symbol : tint_symbol_1) {
+  frag_main_inner(tint_symbol.loc1);
+}
+
+type myf32 = f32;
+)";
+
+  DataMap data;
+  data.Add<CanonicalizeEntryPointIO::Config>(
+      CanonicalizeEntryPointIO::ShaderStyle::kMsl);
+  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(CanonicalizeEntryPointIOTest, StructParameters_Spirv) {
   auto* src = R"(
 struct FragBuiltins {
@@ -257,6 +293,60 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(CanonicalizeEntryPointIOTest, StructParameters_Spirv_OutOfOrder) {
+  auto* src = R"(
+@stage(fragment)
+fn frag_main(@location(0) loc0 : f32,
+             locations : FragLocations,
+             builtins : FragBuiltins) {
+  var col : f32 = ((builtins.coord.x * locations.loc1) + loc0);
+}
+
+struct FragBuiltins {
+  @builtin(position) coord : vec4<f32>;
+};
+struct FragLocations {
+  @location(1) loc1 : f32;
+  @location(2) @interpolate(flat) loc2 : vec4<u32>;
+};
+)";
+
+  auto* expect = R"(
+@location(0) @internal(disable_validation__ignore_storage_class) var<in> loc0_1 : f32;
+
+@location(1) @internal(disable_validation__ignore_storage_class) var<in> loc1_1 : f32;
+
+@location(2) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var<in> loc2_1 : vec4<u32>;
+
+@builtin(position) @internal(disable_validation__ignore_storage_class) var<in> coord_1 : vec4<f32>;
+
+fn frag_main_inner(loc0 : f32, locations : FragLocations, builtins : FragBuiltins) {
+  var col : f32 = ((builtins.coord.x * locations.loc1) + loc0);
+}
+
+@stage(fragment)
+fn frag_main() {
+  frag_main_inner(loc0_1, FragLocations(loc1_1, loc2_1), FragBuiltins(coord_1));
+}
+
+struct FragBuiltins {
+  coord : vec4<f32>;
+}
+
+struct FragLocations {
+  loc1 : f32;
+  loc2 : vec4<u32>;
+}
+)";
+
+  DataMap data;
+  data.Add<CanonicalizeEntryPointIO::Config>(
+      CanonicalizeEntryPointIO::ShaderStyle::kSpirv);
+  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(CanonicalizeEntryPointIOTest, StructParameters_kMsl) {
   auto* src = R"(
 struct FragBuiltins {
@@ -312,6 +402,61 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(CanonicalizeEntryPointIOTest, StructParameters_kMsl_OutOfOrder) {
+  auto* src = R"(
+@stage(fragment)
+fn frag_main(@location(0) loc0 : f32,
+             locations : FragLocations,
+             builtins : FragBuiltins) {
+  var col : f32 = ((builtins.coord.x * locations.loc1) + loc0);
+}
+
+struct FragBuiltins {
+  @builtin(position) coord : vec4<f32>;
+};
+struct FragLocations {
+  @location(1) loc1 : f32;
+  @location(2) @interpolate(flat) loc2 : vec4<u32>;
+};
+)";
+
+  auto* expect = R"(
+struct tint_symbol_1 {
+  @location(0)
+  loc0 : f32;
+  @location(1)
+  loc1 : f32;
+  @location(2) @interpolate(flat)
+  loc2 : vec4<u32>;
+}
+
+fn frag_main_inner(loc0 : f32, locations : FragLocations, builtins : FragBuiltins) {
+  var col : f32 = ((builtins.coord.x * locations.loc1) + loc0);
+}
+
+@stage(fragment)
+fn frag_main(@builtin(position) coord : vec4<f32>, tint_symbol : tint_symbol_1) {
+  frag_main_inner(tint_symbol.loc0, FragLocations(tint_symbol.loc1, tint_symbol.loc2), FragBuiltins(coord));
+}
+
+struct FragBuiltins {
+  coord : vec4<f32>;
+}
+
+struct FragLocations {
+  loc1 : f32;
+  loc2 : vec4<u32>;
+}
+)";
+
+  DataMap data;
+  data.Add<CanonicalizeEntryPointIO::Config>(
+      CanonicalizeEntryPointIO::ShaderStyle::kMsl);
+  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(CanonicalizeEntryPointIOTest, StructParameters_Hlsl) {
   auto* src = R"(
 struct FragBuiltins {
@@ -369,6 +514,63 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(CanonicalizeEntryPointIOTest, StructParameters_Hlsl_OutOfOrder) {
+  auto* src = R"(
+@stage(fragment)
+fn frag_main(@location(0) loc0 : f32,
+             locations : FragLocations,
+             builtins : FragBuiltins) {
+  var col : f32 = ((builtins.coord.x * locations.loc1) + loc0);
+}
+
+struct FragBuiltins {
+  @builtin(position) coord : vec4<f32>;
+};
+struct FragLocations {
+  @location(1) loc1 : f32;
+  @location(2) @interpolate(flat) loc2 : vec4<u32>;
+};
+)";
+
+  auto* expect = R"(
+struct tint_symbol_1 {
+  @location(0)
+  loc0 : f32;
+  @location(1)
+  loc1 : f32;
+  @location(2) @interpolate(flat)
+  loc2 : vec4<u32>;
+  @builtin(position)
+  coord : vec4<f32>;
+}
+
+fn frag_main_inner(loc0 : f32, locations : FragLocations, builtins : FragBuiltins) {
+  var col : f32 = ((builtins.coord.x * locations.loc1) + loc0);
+}
+
+@stage(fragment)
+fn frag_main(tint_symbol : tint_symbol_1) {
+  frag_main_inner(tint_symbol.loc0, FragLocations(tint_symbol.loc1, tint_symbol.loc2), FragBuiltins(tint_symbol.coord));
+}
+
+struct FragBuiltins {
+  coord : vec4<f32>;
+}
+
+struct FragLocations {
+  loc1 : f32;
+  loc2 : vec4<u32>;
+}
+)";
+
+  DataMap data;
+  data.Add<CanonicalizeEntryPointIO::Config>(
+      CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
+  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(CanonicalizeEntryPointIOTest, Return_NonStruct_Spirv) {
   auto* src = R"(
 @stage(fragment)
@@ -525,6 +727,62 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(CanonicalizeEntryPointIOTest, Return_Struct_Spirv_OutOfOrder) {
+  auto* src = R"(
+@stage(fragment)
+fn frag_main() -> FragOutput {
+  var output : FragOutput;
+  output.depth = 1.0;
+  output.mask = 7u;
+  output.color = vec4<f32>(0.5, 0.5, 0.5, 1.0);
+  return output;
+}
+
+struct FragOutput {
+  @location(0) color : vec4<f32>;
+  @builtin(frag_depth) depth : f32;
+  @builtin(sample_mask) mask : u32;
+};
+)";
+
+  auto* expect = R"(
+@location(0) @internal(disable_validation__ignore_storage_class) var<out> color_1 : vec4<f32>;
+
+@builtin(frag_depth) @internal(disable_validation__ignore_storage_class) var<out> depth_1 : f32;
+
+@builtin(sample_mask) @internal(disable_validation__ignore_storage_class) var<out> mask_1 : array<u32, 1>;
+
+fn frag_main_inner() -> FragOutput {
+  var output : FragOutput;
+  output.depth = 1.0;
+  output.mask = 7u;
+  output.color = vec4<f32>(0.5, 0.5, 0.5, 1.0);
+  return output;
+}
+
+@stage(fragment)
+fn frag_main() {
+  let inner_result = frag_main_inner();
+  color_1 = inner_result.color;
+  depth_1 = inner_result.depth;
+  mask_1[0] = inner_result.mask;
+}
+
+struct FragOutput {
+  color : vec4<f32>;
+  depth : f32;
+  mask : u32;
+}
+)";
+
+  DataMap data;
+  data.Add<CanonicalizeEntryPointIO::Config>(
+      CanonicalizeEntryPointIO::ShaderStyle::kSpirv);
+  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(CanonicalizeEntryPointIOTest, Return_Struct_Msl) {
   auto* src = R"(
 struct FragOutput {
@@ -586,6 +844,67 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(CanonicalizeEntryPointIOTest, Return_Struct_Msl_OutOfOrder) {
+  auto* src = R"(
+@stage(fragment)
+fn frag_main() -> FragOutput {
+  var output : FragOutput;
+  output.depth = 1.0;
+  output.mask = 7u;
+  output.color = vec4<f32>(0.5, 0.5, 0.5, 1.0);
+  return output;
+}
+
+struct FragOutput {
+  @location(0) color : vec4<f32>;
+  @builtin(frag_depth) depth : f32;
+  @builtin(sample_mask) mask : u32;
+};
+)";
+
+  auto* expect = R"(
+struct tint_symbol {
+  @location(0)
+  color : vec4<f32>;
+  @builtin(frag_depth)
+  depth : f32;
+  @builtin(sample_mask)
+  mask : u32;
+}
+
+fn frag_main_inner() -> FragOutput {
+  var output : FragOutput;
+  output.depth = 1.0;
+  output.mask = 7u;
+  output.color = vec4<f32>(0.5, 0.5, 0.5, 1.0);
+  return output;
+}
+
+@stage(fragment)
+fn frag_main() -> tint_symbol {
+  let inner_result = frag_main_inner();
+  var wrapper_result : tint_symbol;
+  wrapper_result.color = inner_result.color;
+  wrapper_result.depth = inner_result.depth;
+  wrapper_result.mask = inner_result.mask;
+  return wrapper_result;
+}
+
+struct FragOutput {
+  color : vec4<f32>;
+  depth : f32;
+  mask : u32;
+}
+)";
+
+  DataMap data;
+  data.Add<CanonicalizeEntryPointIO::Config>(
+      CanonicalizeEntryPointIO::ShaderStyle::kMsl);
+  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(CanonicalizeEntryPointIOTest, Return_Struct_Hlsl) {
   auto* src = R"(
 struct FragOutput {
@@ -647,6 +966,67 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(CanonicalizeEntryPointIOTest, Return_Struct_Hlsl_OutOfOrder) {
+  auto* src = R"(
+@stage(fragment)
+fn frag_main() -> FragOutput {
+  var output : FragOutput;
+  output.depth = 1.0;
+  output.mask = 7u;
+  output.color = vec4<f32>(0.5, 0.5, 0.5, 1.0);
+  return output;
+}
+
+struct FragOutput {
+  @location(0) color : vec4<f32>;
+  @builtin(frag_depth) depth : f32;
+  @builtin(sample_mask) mask : u32;
+};
+)";
+
+  auto* expect = R"(
+struct tint_symbol {
+  @location(0)
+  color : vec4<f32>;
+  @builtin(frag_depth)
+  depth : f32;
+  @builtin(sample_mask)
+  mask : u32;
+}
+
+fn frag_main_inner() -> FragOutput {
+  var output : FragOutput;
+  output.depth = 1.0;
+  output.mask = 7u;
+  output.color = vec4<f32>(0.5, 0.5, 0.5, 1.0);
+  return output;
+}
+
+@stage(fragment)
+fn frag_main() -> tint_symbol {
+  let inner_result = frag_main_inner();
+  var wrapper_result : tint_symbol;
+  wrapper_result.color = inner_result.color;
+  wrapper_result.depth = inner_result.depth;
+  wrapper_result.mask = inner_result.mask;
+  return wrapper_result;
+}
+
+struct FragOutput {
+  color : vec4<f32>;
+  depth : f32;
+  mask : u32;
+}
+)";
+
+  DataMap data;
+  data.Add<CanonicalizeEntryPointIO::Config>(
+      CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
+  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(CanonicalizeEntryPointIOTest,
        StructParameters_SharedDeviceFunction_Spirv) {
   auto* src = R"(
@@ -716,6 +1096,74 @@
 }
 
 TEST_F(CanonicalizeEntryPointIOTest,
+       StructParameters_SharedDeviceFunction_Spirv_OutOfOrder) {
+  auto* src = R"(
+@stage(fragment)
+fn frag_main1(inputs : FragmentInput) {
+  var x : f32 = foo(inputs);
+}
+
+@stage(fragment)
+fn frag_main2(inputs : FragmentInput) {
+  var x : f32 = foo(inputs);
+}
+
+fn foo(x : FragmentInput) -> f32 {
+  return x.value * x.mul;
+}
+
+struct FragmentInput {
+  @location(0) value : f32;
+  @location(1) mul : f32;
+};
+)";
+
+  auto* expect = R"(
+@location(0) @internal(disable_validation__ignore_storage_class) var<in> value_1 : f32;
+
+@location(1) @internal(disable_validation__ignore_storage_class) var<in> mul_1 : f32;
+
+@location(0) @internal(disable_validation__ignore_storage_class) var<in> value_2 : f32;
+
+@location(1) @internal(disable_validation__ignore_storage_class) var<in> mul_2 : f32;
+
+fn frag_main1_inner(inputs : FragmentInput) {
+  var x : f32 = foo(inputs);
+}
+
+@stage(fragment)
+fn frag_main1() {
+  frag_main1_inner(FragmentInput(value_1, mul_1));
+}
+
+fn frag_main2_inner(inputs : FragmentInput) {
+  var x : f32 = foo(inputs);
+}
+
+@stage(fragment)
+fn frag_main2() {
+  frag_main2_inner(FragmentInput(value_2, mul_2));
+}
+
+fn foo(x : FragmentInput) -> f32 {
+  return (x.value * x.mul);
+}
+
+struct FragmentInput {
+  value : f32;
+  mul : f32;
+}
+)";
+
+  DataMap data;
+  data.Add<CanonicalizeEntryPointIO::Config>(
+      CanonicalizeEntryPointIO::ShaderStyle::kSpirv);
+  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+
+  EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(CanonicalizeEntryPointIOTest,
        StructParameters_SharedDeviceFunction_Msl) {
   auto* src = R"(
 struct FragmentInput {
@@ -790,6 +1238,80 @@
 }
 
 TEST_F(CanonicalizeEntryPointIOTest,
+       StructParameters_SharedDeviceFunction_Msl_OutOfOrder) {
+  auto* src = R"(
+@stage(fragment)
+fn frag_main1(inputs : FragmentInput) {
+  var x : f32 = foo(inputs);
+}
+
+@stage(fragment)
+fn frag_main2(inputs : FragmentInput) {
+  var x : f32 = foo(inputs);
+}
+
+fn foo(x : FragmentInput) -> f32 {
+  return x.value * x.mul;
+}
+
+struct FragmentInput {
+  @location(0) value : f32;
+  @location(1) mul : f32;
+};
+)";
+
+  auto* expect = R"(
+struct tint_symbol_1 {
+  @location(0)
+  value : f32;
+  @location(1)
+  mul : f32;
+}
+
+fn frag_main1_inner(inputs : FragmentInput) {
+  var x : f32 = foo(inputs);
+}
+
+@stage(fragment)
+fn frag_main1(tint_symbol : tint_symbol_1) {
+  frag_main1_inner(FragmentInput(tint_symbol.value, tint_symbol.mul));
+}
+
+struct tint_symbol_3 {
+  @location(0)
+  value : f32;
+  @location(1)
+  mul : f32;
+}
+
+fn frag_main2_inner(inputs : FragmentInput) {
+  var x : f32 = foo(inputs);
+}
+
+@stage(fragment)
+fn frag_main2(tint_symbol_2 : tint_symbol_3) {
+  frag_main2_inner(FragmentInput(tint_symbol_2.value, tint_symbol_2.mul));
+}
+
+fn foo(x : FragmentInput) -> f32 {
+  return (x.value * x.mul);
+}
+
+struct FragmentInput {
+  value : f32;
+  mul : f32;
+}
+)";
+
+  DataMap data;
+  data.Add<CanonicalizeEntryPointIO::Config>(
+      CanonicalizeEntryPointIO::ShaderStyle::kMsl);
+  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+
+  EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(CanonicalizeEntryPointIOTest,
        StructParameters_SharedDeviceFunction_Hlsl) {
   auto* src = R"(
 struct FragmentInput {
@@ -863,6 +1385,80 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(CanonicalizeEntryPointIOTest,
+       StructParameters_SharedDeviceFunction_Hlsl_OutOfOrder) {
+  auto* src = R"(
+@stage(fragment)
+fn frag_main1(inputs : FragmentInput) {
+  var x : f32 = foo(inputs);
+}
+
+@stage(fragment)
+fn frag_main2(inputs : FragmentInput) {
+  var x : f32 = foo(inputs);
+}
+
+fn foo(x : FragmentInput) -> f32 {
+  return x.value * x.mul;
+}
+
+struct FragmentInput {
+  @location(0) value : f32;
+  @location(1) mul : f32;
+};
+)";
+
+  auto* expect = R"(
+struct tint_symbol_1 {
+  @location(0)
+  value : f32;
+  @location(1)
+  mul : f32;
+}
+
+fn frag_main1_inner(inputs : FragmentInput) {
+  var x : f32 = foo(inputs);
+}
+
+@stage(fragment)
+fn frag_main1(tint_symbol : tint_symbol_1) {
+  frag_main1_inner(FragmentInput(tint_symbol.value, tint_symbol.mul));
+}
+
+struct tint_symbol_3 {
+  @location(0)
+  value : f32;
+  @location(1)
+  mul : f32;
+}
+
+fn frag_main2_inner(inputs : FragmentInput) {
+  var x : f32 = foo(inputs);
+}
+
+@stage(fragment)
+fn frag_main2(tint_symbol_2 : tint_symbol_3) {
+  frag_main2_inner(FragmentInput(tint_symbol_2.value, tint_symbol_2.mul));
+}
+
+fn foo(x : FragmentInput) -> f32 {
+  return (x.value * x.mul);
+}
+
+struct FragmentInput {
+  value : f32;
+  mul : f32;
+}
+)";
+
+  DataMap data;
+  data.Add<CanonicalizeEntryPointIO::Config>(
+      CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
+  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(CanonicalizeEntryPointIOTest, Struct_ModuleScopeVariable) {
   auto* src = R"(
 struct FragmentInput {
@@ -931,6 +1527,74 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(CanonicalizeEntryPointIOTest, Struct_ModuleScopeVariable_OutOfOrder) {
+  auto* src = R"(
+@stage(fragment)
+fn frag_main1(inputs : FragmentInput) {
+ global_inputs = inputs;
+ var r : f32 = foo();
+ var g : f32 = bar();
+}
+
+fn foo() -> f32 {
+  return global_inputs.col1 * 0.5;
+}
+
+fn bar() -> f32 {
+  return global_inputs.col2 * 2.0;
+}
+
+var<private> global_inputs : FragmentInput;
+
+struct FragmentInput {
+  @location(0) col1 : f32;
+  @location(1) col2 : f32;
+};
+)";
+
+  auto* expect = R"(
+struct tint_symbol_1 {
+  @location(0)
+  col1 : f32;
+  @location(1)
+  col2 : f32;
+}
+
+fn frag_main1_inner(inputs : FragmentInput) {
+  global_inputs = inputs;
+  var r : f32 = foo();
+  var g : f32 = bar();
+}
+
+@stage(fragment)
+fn frag_main1(tint_symbol : tint_symbol_1) {
+  frag_main1_inner(FragmentInput(tint_symbol.col1, tint_symbol.col2));
+}
+
+fn foo() -> f32 {
+  return (global_inputs.col1 * 0.5);
+}
+
+fn bar() -> f32 {
+  return (global_inputs.col2 * 2.0);
+}
+
+var<private> global_inputs : FragmentInput;
+
+struct FragmentInput {
+  col1 : f32;
+  col2 : f32;
+}
+)";
+
+  DataMap data;
+  data.Add<CanonicalizeEntryPointIO::Config>(
+      CanonicalizeEntryPointIO::ShaderStyle::kMsl);
+  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(CanonicalizeEntryPointIOTest, Struct_TypeAliases) {
   auto* src = R"(
 type myf32 = f32;
@@ -1018,6 +1682,93 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(CanonicalizeEntryPointIOTest, Struct_TypeAliases_OutOfOrder) {
+  auto* src = R"(
+@stage(fragment)
+fn frag_main(inputs : MyFragmentInput) -> MyFragmentOutput {
+  var x : myf32 = foo(inputs);
+  return MyFragmentOutput(x, inputs.col2);
+}
+
+type MyFragmentInput = FragmentInput;
+
+type MyFragmentOutput = FragmentOutput;
+
+fn foo(x : MyFragmentInput) -> myf32 {
+  return x.col1;
+}
+
+struct FragmentInput {
+  @location(0) col1 : myf32;
+  @location(1) col2 : myf32;
+};
+
+struct FragmentOutput {
+  @location(0) col1 : myf32;
+  @location(1) col2 : myf32;
+};
+
+type myf32 = f32;
+)";
+
+  auto* expect = R"(
+struct tint_symbol_1 {
+  @location(0)
+  col1 : f32;
+  @location(1)
+  col2 : f32;
+}
+
+struct tint_symbol_2 {
+  @location(0)
+  col1 : f32;
+  @location(1)
+  col2 : f32;
+}
+
+fn frag_main_inner(inputs : MyFragmentInput) -> MyFragmentOutput {
+  var x : myf32 = foo(inputs);
+  return MyFragmentOutput(x, inputs.col2);
+}
+
+@stage(fragment)
+fn frag_main(tint_symbol : tint_symbol_1) -> tint_symbol_2 {
+  let inner_result = frag_main_inner(MyFragmentInput(tint_symbol.col1, tint_symbol.col2));
+  var wrapper_result : tint_symbol_2;
+  wrapper_result.col1 = inner_result.col1;
+  wrapper_result.col2 = inner_result.col2;
+  return wrapper_result;
+}
+
+type MyFragmentInput = FragmentInput;
+
+type MyFragmentOutput = FragmentOutput;
+
+fn foo(x : MyFragmentInput) -> myf32 {
+  return x.col1;
+}
+
+struct FragmentInput {
+  col1 : myf32;
+  col2 : myf32;
+}
+
+struct FragmentOutput {
+  col1 : myf32;
+  col2 : myf32;
+}
+
+type myf32 = f32;
+)";
+
+  DataMap data;
+  data.Add<CanonicalizeEntryPointIO::Config>(
+      CanonicalizeEntryPointIO::ShaderStyle::kMsl);
+  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(CanonicalizeEntryPointIOTest, InterpolateAttributes) {
   auto* src = R"(
 struct VertexOut {
@@ -1110,6 +1861,98 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(CanonicalizeEntryPointIOTest, InterpolateAttributes_OutOfOrder) {
+  auto* src = R"(
+@stage(fragment)
+fn frag_main(inputs : FragmentIn,
+             @location(3) @interpolate(perspective, centroid) loc3 : f32) {
+  let x = inputs.loc1 + inputs.loc2 + loc3;
+}
+
+@stage(vertex)
+fn vert_main() -> VertexOut {
+  return VertexOut();
+}
+
+struct VertexOut {
+  @builtin(position) pos : vec4<f32>;
+  @location(1) @interpolate(flat) loc1: f32;
+  @location(2) @interpolate(linear, sample) loc2 : f32;
+  @location(3) @interpolate(perspective, centroid) loc3 : f32;
+};
+
+struct FragmentIn {
+  @location(1) @interpolate(flat) loc1: f32;
+  @location(2) @interpolate(linear, sample) loc2 : f32;
+};
+)";
+
+  auto* expect = R"(
+struct tint_symbol_1 {
+  @location(1) @interpolate(flat)
+  loc1 : f32;
+  @location(2) @interpolate(linear, sample)
+  loc2 : f32;
+  @location(3) @interpolate(perspective, centroid)
+  loc3 : f32;
+}
+
+fn frag_main_inner(inputs : FragmentIn, loc3 : f32) {
+  let x = ((inputs.loc1 + inputs.loc2) + loc3);
+}
+
+@stage(fragment)
+fn frag_main(tint_symbol : tint_symbol_1) {
+  frag_main_inner(FragmentIn(tint_symbol.loc1, tint_symbol.loc2), tint_symbol.loc3);
+}
+
+struct tint_symbol_2 {
+  @location(1) @interpolate(flat)
+  loc1 : f32;
+  @location(2) @interpolate(linear, sample)
+  loc2 : f32;
+  @location(3) @interpolate(perspective, centroid)
+  loc3 : f32;
+  @builtin(position)
+  pos : vec4<f32>;
+}
+
+fn vert_main_inner() -> VertexOut {
+  return VertexOut();
+}
+
+@stage(vertex)
+fn vert_main() -> tint_symbol_2 {
+  let inner_result = vert_main_inner();
+  var wrapper_result : tint_symbol_2;
+  wrapper_result.pos = inner_result.pos;
+  wrapper_result.loc1 = inner_result.loc1;
+  wrapper_result.loc2 = inner_result.loc2;
+  wrapper_result.loc3 = inner_result.loc3;
+  return wrapper_result;
+}
+
+struct VertexOut {
+  pos : vec4<f32>;
+  loc1 : f32;
+  loc2 : f32;
+  loc3 : f32;
+}
+
+struct FragmentIn {
+  loc1 : f32;
+  loc2 : f32;
+}
+)";
+
+  DataMap data;
+  data.Add<CanonicalizeEntryPointIO::Config>(
+      CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
+  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(CanonicalizeEntryPointIOTest, InterpolateAttributes_Integers_Spirv) {
   // Test that we add a Flat attribute to integers that are vertex outputs and
   // fragment inputs, but not vertex inputs or fragment outputs.
@@ -1241,6 +2084,138 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(CanonicalizeEntryPointIOTest,
+       InterpolateAttributes_Integers_Spirv_OutOfOrder) {
+  // Test that we add a Flat attribute to integers that are vertex outputs and
+  // fragment inputs, but not vertex inputs or fragment outputs.
+  auto* src = R"(
+@stage(vertex)
+fn vert_main(in : VertexIn) -> VertexOut {
+  return VertexOut(in.i, in.u, in.vi, in.vu, vec4<f32>());
+}
+
+@stage(fragment)
+fn frag_main(inputs : FragmentInterface) -> FragmentInterface {
+  return inputs;
+}
+
+struct VertexIn {
+  @location(0) i : i32;
+  @location(1) u : u32;
+  @location(2) vi : vec4<i32>;
+  @location(3) vu : vec4<u32>;
+};
+
+struct VertexOut {
+  @location(0) @interpolate(flat) i : i32;
+  @location(1) @interpolate(flat) u : u32;
+  @location(2) @interpolate(flat) vi : vec4<i32>;
+  @location(3) @interpolate(flat) vu : vec4<u32>;
+  @builtin(position) pos : vec4<f32>;
+};
+
+struct FragmentInterface {
+  @location(0) @interpolate(flat) i : i32;
+  @location(1) @interpolate(flat) u : u32;
+  @location(2) @interpolate(flat) vi : vec4<i32>;
+  @location(3) @interpolate(flat) vu : vec4<u32>;
+};
+)";
+
+  auto* expect =
+      R"(
+@location(0) @internal(disable_validation__ignore_storage_class) var<in> i_1 : i32;
+
+@location(1) @internal(disable_validation__ignore_storage_class) var<in> u_1 : u32;
+
+@location(2) @internal(disable_validation__ignore_storage_class) var<in> vi_1 : vec4<i32>;
+
+@location(3) @internal(disable_validation__ignore_storage_class) var<in> vu_1 : vec4<u32>;
+
+@location(0) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var<out> i_2 : i32;
+
+@location(1) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var<out> u_2 : u32;
+
+@location(2) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var<out> vi_2 : vec4<i32>;
+
+@location(3) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var<out> vu_2 : vec4<u32>;
+
+@builtin(position) @internal(disable_validation__ignore_storage_class) var<out> pos_1 : vec4<f32>;
+
+@location(0) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var<in> i_3 : i32;
+
+@location(1) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var<in> u_3 : u32;
+
+@location(2) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var<in> vi_3 : vec4<i32>;
+
+@location(3) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var<in> vu_3 : vec4<u32>;
+
+@location(0) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var<out> i_4 : i32;
+
+@location(1) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var<out> u_4 : u32;
+
+@location(2) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var<out> vi_4 : vec4<i32>;
+
+@location(3) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var<out> vu_4 : vec4<u32>;
+
+fn vert_main_inner(in : VertexIn) -> VertexOut {
+  return VertexOut(in.i, in.u, in.vi, in.vu, vec4<f32>());
+}
+
+@stage(vertex)
+fn vert_main() {
+  let inner_result = vert_main_inner(VertexIn(i_1, u_1, vi_1, vu_1));
+  i_2 = inner_result.i;
+  u_2 = inner_result.u;
+  vi_2 = inner_result.vi;
+  vu_2 = inner_result.vu;
+  pos_1 = inner_result.pos;
+}
+
+fn frag_main_inner(inputs : FragmentInterface) -> FragmentInterface {
+  return inputs;
+}
+
+@stage(fragment)
+fn frag_main() {
+  let inner_result_1 = frag_main_inner(FragmentInterface(i_3, u_3, vi_3, vu_3));
+  i_4 = inner_result_1.i;
+  u_4 = inner_result_1.u;
+  vi_4 = inner_result_1.vi;
+  vu_4 = inner_result_1.vu;
+}
+
+struct VertexIn {
+  i : i32;
+  u : u32;
+  vi : vec4<i32>;
+  vu : vec4<u32>;
+}
+
+struct VertexOut {
+  i : i32;
+  u : u32;
+  vi : vec4<i32>;
+  vu : vec4<u32>;
+  pos : vec4<f32>;
+}
+
+struct FragmentInterface {
+  i : i32;
+  u : u32;
+  vi : vec4<i32>;
+  vu : vec4<u32>;
+}
+)";
+
+  DataMap data;
+  data.Add<CanonicalizeEntryPointIO::Config>(
+      CanonicalizeEntryPointIO::ShaderStyle::kSpirv);
+  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(CanonicalizeEntryPointIOTest, InvariantAttributes) {
   auto* src = R"(
 struct VertexOut {
@@ -1306,6 +2281,71 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(CanonicalizeEntryPointIOTest, InvariantAttributes_OutOfOrder) {
+  auto* src = R"(
+@stage(vertex)
+fn main1() -> VertexOut {
+  return VertexOut();
+}
+
+@stage(vertex)
+fn main2() -> [[builtin(position), invariant]] vec4<f32> {
+  return vec4<f32>();
+}
+
+struct VertexOut {
+  [[builtin(position), invariant]] pos : vec4<f32>;
+};
+)";
+
+  auto* expect = R"(
+struct tint_symbol {
+  @builtin(position) @invariant
+  pos : vec4<f32>;
+}
+
+fn main1_inner() -> VertexOut {
+  return VertexOut();
+}
+
+@stage(vertex)
+fn main1() -> tint_symbol {
+  let inner_result = main1_inner();
+  var wrapper_result : tint_symbol;
+  wrapper_result.pos = inner_result.pos;
+  return wrapper_result;
+}
+
+struct tint_symbol_1 {
+  @builtin(position) @invariant
+  value : vec4<f32>;
+}
+
+fn main2_inner() -> vec4<f32> {
+  return vec4<f32>();
+}
+
+@stage(vertex)
+fn main2() -> tint_symbol_1 {
+  let inner_result_1 = main2_inner();
+  var wrapper_result_1 : tint_symbol_1;
+  wrapper_result_1.value = inner_result_1;
+  return wrapper_result_1;
+}
+
+struct VertexOut {
+  pos : vec4<f32>;
+}
+)";
+
+  DataMap data;
+  data.Add<CanonicalizeEntryPointIO::Config>(
+      CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
+  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(CanonicalizeEntryPointIOTest, Struct_LayoutAttributes) {
   auto* src = R"(
 struct FragmentInput {
@@ -1374,6 +2414,74 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(CanonicalizeEntryPointIOTest, Struct_LayoutAttributes_OutOfOrder) {
+  auto* src = R"(
+@stage(fragment)
+fn frag_main(inputs : FragmentInput) -> FragmentOutput {
+  return FragmentOutput(inputs.coord.x * inputs.value + inputs.loc0);
+}
+
+struct FragmentInput {
+  @size(16) @location(1) value : f32;
+  @builtin(position) @align(32) coord : vec4<f32>;
+  @location(0) @interpolate(linear, sample) @align(128) loc0 : f32;
+};
+
+struct FragmentOutput {
+  @size(16) @location(1) @interpolate(flat) value : f32;
+};
+)";
+
+  auto* expect = R"(
+struct tint_symbol_1 {
+  @location(0) @interpolate(linear, sample)
+  loc0 : f32;
+  @location(1)
+  value : f32;
+  @builtin(position)
+  coord : vec4<f32>;
+}
+
+struct tint_symbol_2 {
+  @location(1) @interpolate(flat)
+  value : f32;
+}
+
+fn frag_main_inner(inputs : FragmentInput) -> FragmentOutput {
+  return FragmentOutput(((inputs.coord.x * inputs.value) + inputs.loc0));
+}
+
+@stage(fragment)
+fn frag_main(tint_symbol : tint_symbol_1) -> tint_symbol_2 {
+  let inner_result = frag_main_inner(FragmentInput(tint_symbol.value, tint_symbol.coord, tint_symbol.loc0));
+  var wrapper_result : tint_symbol_2;
+  wrapper_result.value = inner_result.value;
+  return wrapper_result;
+}
+
+struct FragmentInput {
+  @size(16)
+  value : f32;
+  @align(32)
+  coord : vec4<f32>;
+  @align(128)
+  loc0 : f32;
+}
+
+struct FragmentOutput {
+  @size(16)
+  value : f32;
+}
+)";
+
+  DataMap data;
+  data.Add<CanonicalizeEntryPointIO::Config>(
+      CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
+  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(CanonicalizeEntryPointIOTest, SortedMembers) {
   auto* src = R"(
 struct VertexOutput {
@@ -1479,6 +2587,111 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(CanonicalizeEntryPointIOTest, SortedMembers_OutOfOrder) {
+  auto* src = R"(
+@stage(vertex)
+fn vert_main() -> VertexOutput {
+  return VertexOutput();
+}
+
+@stage(fragment)
+fn frag_main(@builtin(front_facing) ff : bool,
+             @location(2) @interpolate(flat) c : i32,
+             inputs : FragmentInputExtra,
+             @location(1) @interpolate(flat) b : u32) {
+}
+
+struct VertexOutput {
+  @location(1) @interpolate(flat) b : u32;
+  @builtin(position) pos : vec4<f32>;
+  @location(3) @interpolate(flat) d : u32;
+  @location(0) a : f32;
+  @location(2) @interpolate(flat) c : i32;
+};
+
+struct FragmentInputExtra {
+  @location(3) @interpolate(flat) d : u32;
+  @builtin(position) pos : vec4<f32>;
+  @location(0) a : f32;
+};
+)";
+
+  auto* expect = R"(
+struct tint_symbol {
+  @location(0)
+  a : f32;
+  @location(1) @interpolate(flat)
+  b : u32;
+  @location(2) @interpolate(flat)
+  c : i32;
+  @location(3) @interpolate(flat)
+  d : u32;
+  @builtin(position)
+  pos : vec4<f32>;
+}
+
+fn vert_main_inner() -> VertexOutput {
+  return VertexOutput();
+}
+
+@stage(vertex)
+fn vert_main() -> tint_symbol {
+  let inner_result = vert_main_inner();
+  var wrapper_result : tint_symbol;
+  wrapper_result.b = inner_result.b;
+  wrapper_result.pos = inner_result.pos;
+  wrapper_result.d = inner_result.d;
+  wrapper_result.a = inner_result.a;
+  wrapper_result.c = inner_result.c;
+  return wrapper_result;
+}
+
+struct tint_symbol_2 {
+  @location(0)
+  a : f32;
+  @location(1) @interpolate(flat)
+  b : u32;
+  @location(2) @interpolate(flat)
+  c : i32;
+  @location(3) @interpolate(flat)
+  d : u32;
+  @builtin(position)
+  pos : vec4<f32>;
+  @builtin(front_facing)
+  ff : bool;
+}
+
+fn frag_main_inner(ff : bool, c : i32, inputs : FragmentInputExtra, b : u32) {
+}
+
+@stage(fragment)
+fn frag_main(tint_symbol_1 : tint_symbol_2) {
+  frag_main_inner(tint_symbol_1.ff, tint_symbol_1.c, FragmentInputExtra(tint_symbol_1.d, tint_symbol_1.pos, tint_symbol_1.a), tint_symbol_1.b);
+}
+
+struct VertexOutput {
+  b : u32;
+  pos : vec4<f32>;
+  d : u32;
+  a : f32;
+  c : i32;
+}
+
+struct FragmentInputExtra {
+  d : u32;
+  pos : vec4<f32>;
+  a : f32;
+}
+)";
+
+  DataMap data;
+  data.Add<CanonicalizeEntryPointIO::Config>(
+      CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
+  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(CanonicalizeEntryPointIOTest, DontRenameSymbols) {
   auto* src = R"(
 @stage(fragment)
@@ -1704,6 +2917,60 @@
 }
 
 TEST_F(CanonicalizeEntryPointIOTest,
+       FixedSampleMask_StructWithAuthoredMask_OutOfOrder) {
+  auto* src = R"(
+@stage(fragment)
+fn frag_main() -> Output {
+  return Output(0.5, 7u, 1.0);
+}
+
+struct Output {
+  @builtin(frag_depth) depth : f32;
+  @builtin(sample_mask) mask : u32;
+  @location(0) value : f32;
+};
+)";
+
+  auto* expect = R"(
+struct tint_symbol {
+  @location(0)
+  value : f32;
+  @builtin(frag_depth)
+  depth : f32;
+  @builtin(sample_mask)
+  mask : u32;
+}
+
+fn frag_main_inner() -> Output {
+  return Output(0.5, 7u, 1.0);
+}
+
+@stage(fragment)
+fn frag_main() -> tint_symbol {
+  let inner_result = frag_main_inner();
+  var wrapper_result : tint_symbol;
+  wrapper_result.depth = inner_result.depth;
+  wrapper_result.mask = (inner_result.mask & 3u);
+  wrapper_result.value = inner_result.value;
+  return wrapper_result;
+}
+
+struct Output {
+  depth : f32;
+  mask : u32;
+  value : f32;
+}
+)";
+
+  DataMap data;
+  data.Add<CanonicalizeEntryPointIO::Config>(
+      CanonicalizeEntryPointIO::ShaderStyle::kMsl, 0x03u);
+  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+
+  EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(CanonicalizeEntryPointIOTest,
        FixedSampleMask_StructWithoutAuthoredMask) {
   auto* src = R"(
 struct Output {
@@ -1755,6 +3022,58 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(CanonicalizeEntryPointIOTest,
+       FixedSampleMask_StructWithoutAuthoredMask_OutOfOrder) {
+  auto* src = R"(
+@stage(fragment)
+fn frag_main() -> Output {
+  return Output(0.5, 1.0);
+}
+
+struct Output {
+  @builtin(frag_depth) depth : f32;
+  @location(0) value : f32;
+};
+)";
+
+  auto* expect = R"(
+struct tint_symbol {
+  @location(0)
+  value : f32;
+  @builtin(frag_depth)
+  depth : f32;
+  @builtin(sample_mask)
+  fixed_sample_mask : u32;
+}
+
+fn frag_main_inner() -> Output {
+  return Output(0.5, 1.0);
+}
+
+@stage(fragment)
+fn frag_main() -> tint_symbol {
+  let inner_result = frag_main_inner();
+  var wrapper_result : tint_symbol;
+  wrapper_result.depth = inner_result.depth;
+  wrapper_result.value = inner_result.value;
+  wrapper_result.fixed_sample_mask = 3u;
+  return wrapper_result;
+}
+
+struct Output {
+  depth : f32;
+  value : f32;
+}
+)";
+
+  DataMap data;
+  data.Add<CanonicalizeEntryPointIO::Config>(
+      CanonicalizeEntryPointIO::ShaderStyle::kMsl, 0x03u);
+  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(CanonicalizeEntryPointIOTest, FixedSampleMask_MultipleShaders) {
   auto* src = R"(
 @stage(fragment)
@@ -2009,6 +3328,48 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(CanonicalizeEntryPointIOTest,
+       EmitVertexPointSize_ReturnStruct_Spirv_OutOfOrder) {
+  auto* src = R"(
+@stage(vertex)
+fn vert_main() -> VertOut {
+  return VertOut();
+}
+
+struct VertOut {
+  @builtin(position) pos : vec4<f32>;
+};
+)";
+
+  auto* expect = R"(
+@builtin(position) @internal(disable_validation__ignore_storage_class) var<out> pos_1 : vec4<f32>;
+
+@builtin(pointsize) @internal(disable_validation__ignore_storage_class) var<out> vertex_point_size : f32;
+
+fn vert_main_inner() -> VertOut {
+  return VertOut();
+}
+
+@stage(vertex)
+fn vert_main() {
+  let inner_result = vert_main_inner();
+  pos_1 = inner_result.pos;
+  vertex_point_size = 1.0;
+}
+
+struct VertOut {
+  pos : vec4<f32>;
+}
+)";
+
+  DataMap data;
+  data.Add<CanonicalizeEntryPointIO::Config>(
+      CanonicalizeEntryPointIO::ShaderStyle::kSpirv, 0xFFFFFFFF, true);
+  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(CanonicalizeEntryPointIOTest, EmitVertexPointSize_ReturnStruct_Msl) {
   auto* src = R"(
 struct VertOut {
@@ -2055,6 +3416,53 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(CanonicalizeEntryPointIOTest,
+       EmitVertexPointSize_ReturnStruct_Msl_OutOfOrder) {
+  auto* src = R"(
+@stage(vertex)
+fn vert_main() -> VertOut {
+  return VertOut();
+}
+
+struct VertOut {
+  @builtin(position) pos : vec4<f32>;
+};
+)";
+
+  auto* expect = R"(
+struct tint_symbol {
+  @builtin(position)
+  pos : vec4<f32>;
+  @builtin(pointsize)
+  vertex_point_size : f32;
+}
+
+fn vert_main_inner() -> VertOut {
+  return VertOut();
+}
+
+@stage(vertex)
+fn vert_main() -> tint_symbol {
+  let inner_result = vert_main_inner();
+  var wrapper_result : tint_symbol;
+  wrapper_result.pos = inner_result.pos;
+  wrapper_result.vertex_point_size = 1.0;
+  return wrapper_result;
+}
+
+struct VertOut {
+  pos : vec4<f32>;
+}
+)";
+
+  DataMap data;
+  data.Add<CanonicalizeEntryPointIO::Config>(
+      CanonicalizeEntryPointIO::ShaderStyle::kMsl, 0xFFFFFFFF, true);
+  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(CanonicalizeEntryPointIOTest, EmitVertexPointSize_AvoidNameClash_Spirv) {
   auto* src = R"(
 var<private> vertex_point_size : f32;
@@ -2133,6 +3541,85 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(CanonicalizeEntryPointIOTest,
+       EmitVertexPointSize_AvoidNameClash_Spirv_OutOfOrder) {
+  auto* src = R"(
+@stage(vertex)
+fn vert_main(collide : VertIn1, collide_1 : VertIn2) -> VertOut {
+  let x = collide.collide + collide_1.collide;
+  return VertOut();
+}
+
+struct VertIn1 {
+  @location(0) collide : f32;
+};
+
+struct VertIn2 {
+  @location(1) collide : f32;
+};
+
+var<private> vertex_point_size : f32;
+var<private> vertex_point_size_1 : f32;
+var<private> vertex_point_size_2 : f32;
+
+struct VertOut {
+  @location(0) vertex_point_size : f32;
+  @builtin(position) vertex_point_size_1 : vec4<f32>;
+};
+)";
+
+  auto* expect = R"(
+@location(0) @internal(disable_validation__ignore_storage_class) var<in> collide_2 : f32;
+
+@location(1) @internal(disable_validation__ignore_storage_class) var<in> collide_3 : f32;
+
+@location(0) @internal(disable_validation__ignore_storage_class) var<out> vertex_point_size_3 : f32;
+
+@builtin(position) @internal(disable_validation__ignore_storage_class) var<out> vertex_point_size_1_1 : vec4<f32>;
+
+@builtin(pointsize) @internal(disable_validation__ignore_storage_class) var<out> vertex_point_size_4 : f32;
+
+fn vert_main_inner(collide : VertIn1, collide_1 : VertIn2) -> VertOut {
+  let x = (collide.collide + collide_1.collide);
+  return VertOut();
+}
+
+@stage(vertex)
+fn vert_main() {
+  let inner_result = vert_main_inner(VertIn1(collide_2), VertIn2(collide_3));
+  vertex_point_size_3 = inner_result.vertex_point_size;
+  vertex_point_size_1_1 = inner_result.vertex_point_size_1;
+  vertex_point_size_4 = 1.0;
+}
+
+struct VertIn1 {
+  collide : f32;
+}
+
+struct VertIn2 {
+  collide : f32;
+}
+
+var<private> vertex_point_size : f32;
+
+var<private> vertex_point_size_1 : f32;
+
+var<private> vertex_point_size_2 : f32;
+
+struct VertOut {
+  vertex_point_size : f32;
+  vertex_point_size_1 : vec4<f32>;
+}
+)";
+
+  DataMap data;
+  data.Add<CanonicalizeEntryPointIO::Config>(
+      CanonicalizeEntryPointIO::ShaderStyle::kSpirv, 0xFFFFFFFF, true);
+  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(CanonicalizeEntryPointIOTest, EmitVertexPointSize_AvoidNameClash_Msl) {
   auto* src = R"(
 struct VertIn1 {
@@ -2209,6 +3696,83 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(CanonicalizeEntryPointIOTest,
+       EmitVertexPointSize_AvoidNameClash_Msl_OutOfOrder) {
+  auto* src = R"(
+@stage(vertex)
+fn vert_main(collide : VertIn1, collide_1 : VertIn2) -> VertOut {
+  let x = collide.collide + collide_1.collide;
+  return VertOut();
+}
+
+struct VertIn1 {
+  @location(0) collide : f32;
+};
+
+struct VertIn2 {
+  @location(1) collide : f32;
+};
+
+struct VertOut {
+  @location(0) vertex_point_size : vec4<f32>;
+  @builtin(position) vertex_point_size_1 : vec4<f32>;
+};
+)";
+
+  auto* expect = R"(
+struct tint_symbol_1 {
+  @location(0)
+  collide : f32;
+  @location(1)
+  collide_2 : f32;
+}
+
+struct tint_symbol_2 {
+  @location(0)
+  vertex_point_size : vec4<f32>;
+  @builtin(position)
+  vertex_point_size_1 : vec4<f32>;
+  @builtin(pointsize)
+  vertex_point_size_2 : f32;
+}
+
+fn vert_main_inner(collide : VertIn1, collide_1 : VertIn2) -> VertOut {
+  let x = (collide.collide + collide_1.collide);
+  return VertOut();
+}
+
+@stage(vertex)
+fn vert_main(tint_symbol : tint_symbol_1) -> tint_symbol_2 {
+  let inner_result = vert_main_inner(VertIn1(tint_symbol.collide), VertIn2(tint_symbol.collide_2));
+  var wrapper_result : tint_symbol_2;
+  wrapper_result.vertex_point_size = inner_result.vertex_point_size;
+  wrapper_result.vertex_point_size_1 = inner_result.vertex_point_size_1;
+  wrapper_result.vertex_point_size_2 = 1.0;
+  return wrapper_result;
+}
+
+struct VertIn1 {
+  collide : f32;
+}
+
+struct VertIn2 {
+  collide : f32;
+}
+
+struct VertOut {
+  vertex_point_size : vec4<f32>;
+  vertex_point_size_1 : vec4<f32>;
+}
+)";
+
+  DataMap data;
+  data.Add<CanonicalizeEntryPointIO::Config>(
+      CanonicalizeEntryPointIO::ShaderStyle::kMsl, 0xFFFFFFFF, true);
+  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(CanonicalizeEntryPointIOTest, EmitVertexPointSize_AvoidNameClash_Hlsl) {
   auto* src = R"(
 struct VertIn1 {
@@ -2285,6 +3849,83 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(CanonicalizeEntryPointIOTest,
+       EmitVertexPointSize_AvoidNameClash_Hlsl_OutOfOrder) {
+  auto* src = R"(
+@stage(vertex)
+fn vert_main(collide : VertIn1, collide_1 : VertIn2) -> VertOut {
+  let x = collide.collide + collide_1.collide;
+  return VertOut();
+}
+
+struct VertIn1 {
+  @location(0) collide : f32;
+};
+
+struct VertIn2 {
+  @location(1) collide : f32;
+};
+
+struct VertOut {
+  @location(0) vertex_point_size : vec4<f32>;
+  @builtin(position) vertex_point_size_1 : vec4<f32>;
+};
+)";
+
+  auto* expect = R"(
+struct tint_symbol_1 {
+  @location(0)
+  collide : f32;
+  @location(1)
+  collide_2 : f32;
+}
+
+struct tint_symbol_2 {
+  @location(0)
+  vertex_point_size : vec4<f32>;
+  @builtin(position)
+  vertex_point_size_1 : vec4<f32>;
+  @builtin(pointsize)
+  vertex_point_size_2 : f32;
+}
+
+fn vert_main_inner(collide : VertIn1, collide_1 : VertIn2) -> VertOut {
+  let x = (collide.collide + collide_1.collide);
+  return VertOut();
+}
+
+@stage(vertex)
+fn vert_main(tint_symbol : tint_symbol_1) -> tint_symbol_2 {
+  let inner_result = vert_main_inner(VertIn1(tint_symbol.collide), VertIn2(tint_symbol.collide_2));
+  var wrapper_result : tint_symbol_2;
+  wrapper_result.vertex_point_size = inner_result.vertex_point_size;
+  wrapper_result.vertex_point_size_1 = inner_result.vertex_point_size_1;
+  wrapper_result.vertex_point_size_2 = 1.0;
+  return wrapper_result;
+}
+
+struct VertIn1 {
+  collide : f32;
+}
+
+struct VertIn2 {
+  collide : f32;
+}
+
+struct VertOut {
+  vertex_point_size : vec4<f32>;
+  vertex_point_size_1 : vec4<f32>;
+}
+)";
+
+  DataMap data;
+  data.Add<CanonicalizeEntryPointIO::Config>(
+      CanonicalizeEntryPointIO::ShaderStyle::kHlsl, 0xFFFFFFFF, true);
+  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(CanonicalizeEntryPointIOTest, SpirvSampleMaskBuiltins) {
   auto* src = R"(
 @stage(fragment)
diff --git a/src/transform/combine_samplers_test.cc b/src/transform/combine_samplers_test.cc
index f0c3a33..481ef3d 100644
--- a/src/transform/combine_samplers_test.cc
+++ b/src/transform/combine_samplers_test.cc
@@ -65,6 +65,34 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(CombineSamplersTest, SimplePair_OutOfOrder) {
+  auto* src = R"(
+fn main() -> vec4<f32> {
+  return textureSample(t, s, vec2<f32>(1.0, 2.0));
+}
+
+@group(0) @binding(0) var t : texture_2d<f32>;
+
+@group(0) @binding(1) var s : sampler;
+)";
+  auto* expect = R"(
+@group(0) @binding(0) @internal(disable_validation__binding_point_collision) var t_s : texture_2d<f32>;
+
+@group(0) @binding(0) @internal(disable_validation__binding_point_collision) var placeholder_sampler : sampler;
+
+fn main() -> vec4<f32> {
+  return textureSample(t_s, placeholder_sampler, vec2<f32>(1.0, 2.0));
+}
+)";
+
+  DataMap data;
+  data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(),
+                                         sem::BindingPoint());
+  auto got = Run<CombineSamplers>(src, data);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(CombineSamplersTest, SimplePairInAFunction) {
   auto* src = R"(
 @group(0) @binding(0) var t : texture_2d<f32>;
@@ -101,6 +129,42 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(CombineSamplersTest, SimplePairInAFunction_OutOfOrder) {
+  auto* src = R"(
+fn main() -> vec4<f32> {
+  return sample(t, s, vec2<f32>(1.0, 2.0));
+}
+
+fn sample(t : texture_2d<f32>, s : sampler, coords : vec2<f32>) -> vec4<f32> {
+  return textureSample(t, s, coords);
+}
+
+@group(0) @binding(1) var s : sampler;
+
+@group(0) @binding(0) var t : texture_2d<f32>;
+)";
+  auto* expect = R"(
+@group(0) @binding(0) @internal(disable_validation__binding_point_collision) var t_s : texture_2d<f32>;
+
+fn main() -> vec4<f32> {
+  return sample(t_s, vec2<f32>(1.0, 2.0));
+}
+
+@group(0) @binding(0) @internal(disable_validation__binding_point_collision) var placeholder_sampler : sampler;
+
+fn sample(t_s_1 : texture_2d<f32>, coords : vec2<f32>) -> vec4<f32> {
+  return textureSample(t_s_1, placeholder_sampler, coords);
+}
+)";
+
+  DataMap data;
+  data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(),
+                                         sem::BindingPoint());
+  auto got = Run<CombineSamplers>(src, data);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(CombineSamplersTest, SimplePairRename) {
   auto* src = R"(
 @group(0) @binding(1) var t : texture_2d<f32>;
@@ -212,6 +276,45 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(CombineSamplersTest, AliasedTypes_OutOfOrder) {
+  auto* src = R"(
+fn main() -> vec4<f32> {
+  return sample(t, s, vec2<f32>(1.0, 2.0));
+}
+
+fn sample(t : Tex2d, s : sampler, coords : vec2<f32>) -> vec4<f32> {
+  return textureSample(t, s, coords);
+}
+
+@group(0) @binding(0) var t : Tex2d;
+@group(0) @binding(1) var s : sampler;
+
+type Tex2d = texture_2d<f32>;
+)";
+  auto* expect = R"(
+@group(0) @binding(0) @internal(disable_validation__binding_point_collision) var t_s : texture_2d<f32>;
+
+fn main() -> vec4<f32> {
+  return sample(t_s, vec2<f32>(1.0, 2.0));
+}
+
+@group(0) @binding(0) @internal(disable_validation__binding_point_collision) var placeholder_sampler : sampler;
+
+fn sample(t_s_1 : texture_2d<f32>, coords : vec2<f32>) -> vec4<f32> {
+  return textureSample(t_s_1, placeholder_sampler, coords);
+}
+
+type Tex2d = texture_2d<f32>;
+)";
+
+  DataMap data;
+  data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(),
+                                         sem::BindingPoint());
+  auto got = Run<CombineSamplers>(src, data);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(CombineSamplersTest, SimplePairInTwoFunctions) {
   auto* src = R"(
 @group(0) @binding(0) var t : texture_2d<f32>;
@@ -256,6 +359,49 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(CombineSamplersTest, SimplePairInTwoFunctions_OutOfOrder) {
+  auto* src = R"(
+fn main() -> vec4<f32> {
+  return f(t, s, vec2<f32>(1.0, 2.0));
+}
+
+fn f(t : texture_2d<f32>, s : sampler, coords : vec2<f32>) -> vec4<f32> {
+  return g(t, s, coords);
+}
+
+fn g(t : texture_2d<f32>, s : sampler, coords : vec2<f32>) -> vec4<f32> {
+  return textureSample(t, s, coords);
+}
+
+@group(0) @binding(1) var s : sampler;
+@group(0) @binding(0) var t : texture_2d<f32>;
+)";
+  auto* expect = R"(
+@group(0) @binding(0) @internal(disable_validation__binding_point_collision) var t_s : texture_2d<f32>;
+
+fn main() -> vec4<f32> {
+  return f(t_s, vec2<f32>(1.0, 2.0));
+}
+
+fn f(t_s_1 : texture_2d<f32>, coords : vec2<f32>) -> vec4<f32> {
+  return g(t_s_1, coords);
+}
+
+@group(0) @binding(0) @internal(disable_validation__binding_point_collision) var placeholder_sampler : sampler;
+
+fn g(t_s_2 : texture_2d<f32>, coords : vec2<f32>) -> vec4<f32> {
+  return textureSample(t_s_2, placeholder_sampler, coords);
+}
+)";
+
+  DataMap data;
+  data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(),
+                                         sem::BindingPoint());
+  auto got = Run<CombineSamplers>(src, data);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(CombineSamplersTest, TwoFunctionsGenerateSamePair) {
   auto* src = R"(
 @group(1) @binding(0) var tex : texture_2d<f32>;
@@ -500,6 +646,44 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(CombineSamplersTest, GlobalTextureLocalSampler_OutOfOrder) {
+  auto* src = R"(
+fn main() -> vec4<f32> {
+  return f(samp1, samp2, vec2<f32>(1.0, 2.0));
+}
+
+fn f(s1 : sampler, s2 : sampler, coords : vec2<f32>) -> vec4<f32> {
+  return textureSample(tex, s1, coords) + textureSample(tex, s2, coords);
+}
+
+@group(0) @binding(1) var samp1 : sampler;
+@group(0) @binding(2) var samp2 : sampler;
+@group(0) @binding(0) var tex : texture_2d<f32>;
+)";
+  auto* expect = R"(
+@group(0) @binding(0) @internal(disable_validation__binding_point_collision) var tex_samp1 : texture_2d<f32>;
+
+@group(0) @binding(0) @internal(disable_validation__binding_point_collision) var tex_samp2 : texture_2d<f32>;
+
+fn main() -> vec4<f32> {
+  return f(tex_samp1, tex_samp2, vec2<f32>(1.0, 2.0));
+}
+
+@group(0) @binding(0) @internal(disable_validation__binding_point_collision) var placeholder_sampler : sampler;
+
+fn f(tex_s1 : texture_2d<f32>, tex_s2 : texture_2d<f32>, coords : vec2<f32>) -> vec4<f32> {
+  return (textureSample(tex_s1, placeholder_sampler, coords) + textureSample(tex_s2, placeholder_sampler, coords));
+}
+)";
+
+  DataMap data;
+  data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(),
+                                         sem::BindingPoint());
+  auto got = Run<CombineSamplers>(src, data);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(CombineSamplersTest, LocalTextureGlobalSampler) {
   auto* src = R"(
 @group(0) @binding(0) var tex1 : texture_2d<f32>;
@@ -540,6 +724,44 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(CombineSamplersTest, LocalTextureGlobalSampler_OutOfOrder) {
+  auto* src = R"(
+fn main() -> vec4<f32> {
+  return f(tex1, tex2, vec2<f32>(1.0, 2.0));
+}
+
+fn f(t1 : texture_2d<f32>, t2 : texture_2d<f32>, coords : vec2<f32>) -> vec4<f32> {
+  return textureSample(t1, samp, coords) + textureSample(t2, samp, coords);
+}
+
+@group(0) @binding(2) var samp : sampler;
+@group(0) @binding(0) var tex1 : texture_2d<f32>;
+@group(0) @binding(1) var tex2 : texture_2d<f32>;
+)";
+  auto* expect = R"(
+@group(0) @binding(0) @internal(disable_validation__binding_point_collision) var tex1_samp : texture_2d<f32>;
+
+@group(0) @binding(0) @internal(disable_validation__binding_point_collision) var tex2_samp : texture_2d<f32>;
+
+fn main() -> vec4<f32> {
+  return f(tex1_samp, tex2_samp, vec2<f32>(1.0, 2.0));
+}
+
+@group(0) @binding(0) @internal(disable_validation__binding_point_collision) var placeholder_sampler : sampler;
+
+fn f(t1_samp : texture_2d<f32>, t2_samp : texture_2d<f32>, coords : vec2<f32>) -> vec4<f32> {
+  return (textureSample(t1_samp, placeholder_sampler, coords) + textureSample(t2_samp, placeholder_sampler, coords));
+}
+)";
+
+  DataMap data;
+  data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(),
+                                         sem::BindingPoint());
+  auto got = Run<CombineSamplers>(src, data);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(CombineSamplersTest, TextureLoadNoSampler) {
   auto* src = R"(
 @group(0) @binding(0) var tex : texture_2d<f32>;
@@ -687,6 +909,41 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(CombineSamplersTest, TextureSampleCompareInAFunction_OutOfOrder) {
+  auto* src = R"(
+fn main() -> vec4<f32> {
+  return vec4<f32>(f(tex, samp, vec2<f32>(1.0, 2.0)));
+}
+
+fn f(t : texture_depth_2d, s : sampler_comparison, coords : vec2<f32>) -> f32 {
+  return textureSampleCompare(t, s, coords, 5.0f);
+}
+
+@group(0) @binding(0) var tex : texture_depth_2d;
+@group(0) @binding(1) var samp : sampler_comparison;
+)";
+  auto* expect = R"(
+@group(0) @binding(0) @internal(disable_validation__binding_point_collision) var tex_samp : texture_depth_2d;
+
+fn main() -> vec4<f32> {
+  return vec4<f32>(f(tex_samp, vec2<f32>(1.0, 2.0)));
+}
+
+@group(0) @binding(0) @internal(disable_validation__binding_point_collision) var placeholder_comparison_sampler : sampler_comparison;
+
+fn f(t_s : texture_depth_2d, coords : vec2<f32>) -> f32 {
+  return textureSampleCompare(t_s, placeholder_comparison_sampler, coords, 5.0);
+}
+)";
+
+  DataMap data;
+  data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(),
+                                         sem::BindingPoint());
+  auto got = Run<CombineSamplers>(src, data);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(CombineSamplersTest, BindingPointCollision) {
   auto* src = R"(
 @group(1) @binding(0) var tex : texture_2d<f32>;
@@ -719,6 +976,37 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(CombineSamplersTest, BindingPointCollision_OutOfOrder) {
+  auto* src = R"(
+fn main() -> vec4<f32> {
+  return textureSample(tex, samp, gcoords);
+}
+
+@group(1) @binding(1) var samp : sampler;
+@group(0) @binding(0) var<uniform> gcoords : vec2<f32>;
+@group(1) @binding(0) var tex : texture_2d<f32>;
+
+)";
+  auto* expect = R"(
+@group(0) @binding(0) @internal(disable_validation__binding_point_collision) var tex_samp : texture_2d<f32>;
+
+@group(0) @binding(0) @internal(disable_validation__binding_point_collision) var placeholder_sampler : sampler;
+
+fn main() -> vec4<f32> {
+  return textureSample(tex_samp, placeholder_sampler, gcoords);
+}
+
+@internal(disable_validation__binding_point_collision) @group(0) @binding(0) var<uniform> gcoords : vec2<f32>;
+)";
+
+  DataMap data;
+  data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(),
+                                         sem::BindingPoint());
+  auto got = Run<CombineSamplers>(src, data);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 }  // namespace
 }  // namespace transform
 }  // namespace tint
diff --git a/src/transform/decompose_memory_access_test.cc b/src/transform/decompose_memory_access_test.cc
index dffb3f2..2f8ed59 100644
--- a/src/transform/decompose_memory_access_test.cc
+++ b/src/transform/decompose_memory_access_test.cc
@@ -246,6 +246,202 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(DecomposeMemoryAccessTest, SB_BasicLoad_OutOfOrder) {
+  auto* src = R"(
+@stage(compute) @workgroup_size(1)
+fn main() {
+  var a : i32 = sb.a;
+  var b : u32 = sb.b;
+  var c : f32 = sb.c;
+  var d : vec2<i32> = sb.d;
+  var e : vec2<u32> = sb.e;
+  var f : vec2<f32> = sb.f;
+  var g : vec3<i32> = sb.g;
+  var h : vec3<u32> = sb.h;
+  var i : vec3<f32> = sb.i;
+  var j : vec4<i32> = sb.j;
+  var k : vec4<u32> = sb.k;
+  var l : vec4<f32> = sb.l;
+  var m : mat2x2<f32> = sb.m;
+  var n : mat2x3<f32> = sb.n;
+  var o : mat2x4<f32> = sb.o;
+  var p : mat3x2<f32> = sb.p;
+  var q : mat3x3<f32> = sb.q;
+  var r : mat3x4<f32> = sb.r;
+  var s : mat4x2<f32> = sb.s;
+  var t : mat4x3<f32> = sb.t;
+  var u : mat4x4<f32> = sb.u;
+  var v : array<vec3<f32>, 2> = sb.v;
+}
+
+@group(0) @binding(0) var<storage, read_write> sb : SB;
+
+struct SB {
+  a : i32;
+  b : u32;
+  c : f32;
+  d : vec2<i32>;
+  e : vec2<u32>;
+  f : vec2<f32>;
+  g : vec3<i32>;
+  h : vec3<u32>;
+  i : vec3<f32>;
+  j : vec4<i32>;
+  k : vec4<u32>;
+  l : vec4<f32>;
+  m : mat2x2<f32>;
+  n : mat2x3<f32>;
+  o : mat2x4<f32>;
+  p : mat3x2<f32>;
+  q : mat3x3<f32>;
+  r : mat3x4<f32>;
+  s : mat4x2<f32>;
+  t : mat4x3<f32>;
+  u : mat4x4<f32>;
+  v : array<vec3<f32>, 2>;
+};
+)";
+
+  auto* expect = R"(
+@internal(intrinsic_load_storage_i32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> i32
+
+@internal(intrinsic_load_storage_u32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_1(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> u32
+
+@internal(intrinsic_load_storage_f32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_2(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> f32
+
+@internal(intrinsic_load_storage_vec2_i32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_3(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec2<i32>
+
+@internal(intrinsic_load_storage_vec2_u32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_4(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec2<u32>
+
+@internal(intrinsic_load_storage_vec2_f32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_5(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec2<f32>
+
+@internal(intrinsic_load_storage_vec3_i32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_6(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec3<i32>
+
+@internal(intrinsic_load_storage_vec3_u32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_7(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec3<u32>
+
+@internal(intrinsic_load_storage_vec3_f32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_8(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec3<f32>
+
+@internal(intrinsic_load_storage_vec4_i32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_9(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec4<i32>
+
+@internal(intrinsic_load_storage_vec4_u32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_10(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec4<u32>
+
+@internal(intrinsic_load_storage_vec4_f32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_11(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec4<f32>
+
+fn tint_symbol_12(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat2x2<f32> {
+  return mat2x2<f32>(tint_symbol_5(buffer, (offset + 0u)), tint_symbol_5(buffer, (offset + 8u)));
+}
+
+fn tint_symbol_13(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat2x3<f32> {
+  return mat2x3<f32>(tint_symbol_8(buffer, (offset + 0u)), tint_symbol_8(buffer, (offset + 16u)));
+}
+
+fn tint_symbol_14(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat2x4<f32> {
+  return mat2x4<f32>(tint_symbol_11(buffer, (offset + 0u)), tint_symbol_11(buffer, (offset + 16u)));
+}
+
+fn tint_symbol_15(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat3x2<f32> {
+  return mat3x2<f32>(tint_symbol_5(buffer, (offset + 0u)), tint_symbol_5(buffer, (offset + 8u)), tint_symbol_5(buffer, (offset + 16u)));
+}
+
+fn tint_symbol_16(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat3x3<f32> {
+  return mat3x3<f32>(tint_symbol_8(buffer, (offset + 0u)), tint_symbol_8(buffer, (offset + 16u)), tint_symbol_8(buffer, (offset + 32u)));
+}
+
+fn tint_symbol_17(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat3x4<f32> {
+  return mat3x4<f32>(tint_symbol_11(buffer, (offset + 0u)), tint_symbol_11(buffer, (offset + 16u)), tint_symbol_11(buffer, (offset + 32u)));
+}
+
+fn tint_symbol_18(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat4x2<f32> {
+  return mat4x2<f32>(tint_symbol_5(buffer, (offset + 0u)), tint_symbol_5(buffer, (offset + 8u)), tint_symbol_5(buffer, (offset + 16u)), tint_symbol_5(buffer, (offset + 24u)));
+}
+
+fn tint_symbol_19(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat4x3<f32> {
+  return mat4x3<f32>(tint_symbol_8(buffer, (offset + 0u)), tint_symbol_8(buffer, (offset + 16u)), tint_symbol_8(buffer, (offset + 32u)), tint_symbol_8(buffer, (offset + 48u)));
+}
+
+fn tint_symbol_20(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat4x4<f32> {
+  return mat4x4<f32>(tint_symbol_11(buffer, (offset + 0u)), tint_symbol_11(buffer, (offset + 16u)), tint_symbol_11(buffer, (offset + 32u)), tint_symbol_11(buffer, (offset + 48u)));
+}
+
+fn tint_symbol_21(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> array<vec3<f32>, 2u> {
+  var arr : array<vec3<f32>, 2u>;
+  for(var i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
+    arr[i_1] = tint_symbol_8(buffer, (offset + (i_1 * 16u)));
+  }
+  return arr;
+}
+
+@stage(compute) @workgroup_size(1)
+fn main() {
+  var a : i32 = tint_symbol(sb, 0u);
+  var b : u32 = tint_symbol_1(sb, 4u);
+  var c : f32 = tint_symbol_2(sb, 8u);
+  var d : vec2<i32> = tint_symbol_3(sb, 16u);
+  var e : vec2<u32> = tint_symbol_4(sb, 24u);
+  var f : vec2<f32> = tint_symbol_5(sb, 32u);
+  var g : vec3<i32> = tint_symbol_6(sb, 48u);
+  var h : vec3<u32> = tint_symbol_7(sb, 64u);
+  var i : vec3<f32> = tint_symbol_8(sb, 80u);
+  var j : vec4<i32> = tint_symbol_9(sb, 96u);
+  var k : vec4<u32> = tint_symbol_10(sb, 112u);
+  var l : vec4<f32> = tint_symbol_11(sb, 128u);
+  var m : mat2x2<f32> = tint_symbol_12(sb, 144u);
+  var n : mat2x3<f32> = tint_symbol_13(sb, 160u);
+  var o : mat2x4<f32> = tint_symbol_14(sb, 192u);
+  var p : mat3x2<f32> = tint_symbol_15(sb, 224u);
+  var q : mat3x3<f32> = tint_symbol_16(sb, 256u);
+  var r : mat3x4<f32> = tint_symbol_17(sb, 304u);
+  var s : mat4x2<f32> = tint_symbol_18(sb, 352u);
+  var t : mat4x3<f32> = tint_symbol_19(sb, 384u);
+  var u : mat4x4<f32> = tint_symbol_20(sb, 448u);
+  var v : array<vec3<f32>, 2> = tint_symbol_21(sb, 512u);
+}
+
+@group(0) @binding(0) var<storage, read_write> sb : SB;
+
+struct SB {
+  a : i32;
+  b : u32;
+  c : f32;
+  d : vec2<i32>;
+  e : vec2<u32>;
+  f : vec2<f32>;
+  g : vec3<i32>;
+  h : vec3<u32>;
+  i : vec3<f32>;
+  j : vec4<i32>;
+  k : vec4<u32>;
+  l : vec4<f32>;
+  m : mat2x2<f32>;
+  n : mat2x3<f32>;
+  o : mat2x4<f32>;
+  p : mat3x2<f32>;
+  q : mat3x3<f32>;
+  r : mat3x4<f32>;
+  s : mat4x2<f32>;
+  t : mat4x3<f32>;
+  u : mat4x4<f32>;
+  v : array<vec3<f32>, 2>;
+}
+)";
+
+  auto got = Run<DecomposeMemoryAccess>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(DecomposeMemoryAccessTest, UB_BasicLoad) {
   auto* src = R"(
 struct UB {
@@ -442,6 +638,202 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(DecomposeMemoryAccessTest, UB_BasicLoad_OutOfOrder) {
+  auto* src = R"(
+@stage(compute) @workgroup_size(1)
+fn main() {
+  var a : i32 = ub.a;
+  var b : u32 = ub.b;
+  var c : f32 = ub.c;
+  var d : vec2<i32> = ub.d;
+  var e : vec2<u32> = ub.e;
+  var f : vec2<f32> = ub.f;
+  var g : vec3<i32> = ub.g;
+  var h : vec3<u32> = ub.h;
+  var i : vec3<f32> = ub.i;
+  var j : vec4<i32> = ub.j;
+  var k : vec4<u32> = ub.k;
+  var l : vec4<f32> = ub.l;
+  var m : mat2x2<f32> = ub.m;
+  var n : mat2x3<f32> = ub.n;
+  var o : mat2x4<f32> = ub.o;
+  var p : mat3x2<f32> = ub.p;
+  var q : mat3x3<f32> = ub.q;
+  var r : mat3x4<f32> = ub.r;
+  var s : mat4x2<f32> = ub.s;
+  var t : mat4x3<f32> = ub.t;
+  var u : mat4x4<f32> = ub.u;
+  var v : array<vec3<f32>, 2> = ub.v;
+}
+
+@group(0) @binding(0) var<uniform> ub : UB;
+
+struct UB {
+  a : i32;
+  b : u32;
+  c : f32;
+  d : vec2<i32>;
+  e : vec2<u32>;
+  f : vec2<f32>;
+  g : vec3<i32>;
+  h : vec3<u32>;
+  i : vec3<f32>;
+  j : vec4<i32>;
+  k : vec4<u32>;
+  l : vec4<f32>;
+  m : mat2x2<f32>;
+  n : mat2x3<f32>;
+  o : mat2x4<f32>;
+  p : mat3x2<f32>;
+  q : mat3x3<f32>;
+  r : mat3x4<f32>;
+  s : mat4x2<f32>;
+  t : mat4x3<f32>;
+  u : mat4x4<f32>;
+  v : array<vec3<f32>, 2>;
+};
+)";
+
+  auto* expect = R"(
+@internal(intrinsic_load_uniform_i32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> i32
+
+@internal(intrinsic_load_uniform_u32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_1(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> u32
+
+@internal(intrinsic_load_uniform_f32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_2(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> f32
+
+@internal(intrinsic_load_uniform_vec2_i32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_3(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> vec2<i32>
+
+@internal(intrinsic_load_uniform_vec2_u32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_4(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> vec2<u32>
+
+@internal(intrinsic_load_uniform_vec2_f32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_5(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> vec2<f32>
+
+@internal(intrinsic_load_uniform_vec3_i32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_6(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> vec3<i32>
+
+@internal(intrinsic_load_uniform_vec3_u32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_7(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> vec3<u32>
+
+@internal(intrinsic_load_uniform_vec3_f32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_8(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> vec3<f32>
+
+@internal(intrinsic_load_uniform_vec4_i32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_9(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> vec4<i32>
+
+@internal(intrinsic_load_uniform_vec4_u32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_10(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> vec4<u32>
+
+@internal(intrinsic_load_uniform_vec4_f32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_11(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> vec4<f32>
+
+fn tint_symbol_12(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> mat2x2<f32> {
+  return mat2x2<f32>(tint_symbol_5(buffer, (offset + 0u)), tint_symbol_5(buffer, (offset + 8u)));
+}
+
+fn tint_symbol_13(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> mat2x3<f32> {
+  return mat2x3<f32>(tint_symbol_8(buffer, (offset + 0u)), tint_symbol_8(buffer, (offset + 16u)));
+}
+
+fn tint_symbol_14(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> mat2x4<f32> {
+  return mat2x4<f32>(tint_symbol_11(buffer, (offset + 0u)), tint_symbol_11(buffer, (offset + 16u)));
+}
+
+fn tint_symbol_15(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> mat3x2<f32> {
+  return mat3x2<f32>(tint_symbol_5(buffer, (offset + 0u)), tint_symbol_5(buffer, (offset + 8u)), tint_symbol_5(buffer, (offset + 16u)));
+}
+
+fn tint_symbol_16(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> mat3x3<f32> {
+  return mat3x3<f32>(tint_symbol_8(buffer, (offset + 0u)), tint_symbol_8(buffer, (offset + 16u)), tint_symbol_8(buffer, (offset + 32u)));
+}
+
+fn tint_symbol_17(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> mat3x4<f32> {
+  return mat3x4<f32>(tint_symbol_11(buffer, (offset + 0u)), tint_symbol_11(buffer, (offset + 16u)), tint_symbol_11(buffer, (offset + 32u)));
+}
+
+fn tint_symbol_18(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> mat4x2<f32> {
+  return mat4x2<f32>(tint_symbol_5(buffer, (offset + 0u)), tint_symbol_5(buffer, (offset + 8u)), tint_symbol_5(buffer, (offset + 16u)), tint_symbol_5(buffer, (offset + 24u)));
+}
+
+fn tint_symbol_19(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> mat4x3<f32> {
+  return mat4x3<f32>(tint_symbol_8(buffer, (offset + 0u)), tint_symbol_8(buffer, (offset + 16u)), tint_symbol_8(buffer, (offset + 32u)), tint_symbol_8(buffer, (offset + 48u)));
+}
+
+fn tint_symbol_20(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> mat4x4<f32> {
+  return mat4x4<f32>(tint_symbol_11(buffer, (offset + 0u)), tint_symbol_11(buffer, (offset + 16u)), tint_symbol_11(buffer, (offset + 32u)), tint_symbol_11(buffer, (offset + 48u)));
+}
+
+fn tint_symbol_21(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> array<vec3<f32>, 2u> {
+  var arr : array<vec3<f32>, 2u>;
+  for(var i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
+    arr[i_1] = tint_symbol_8(buffer, (offset + (i_1 * 16u)));
+  }
+  return arr;
+}
+
+@stage(compute) @workgroup_size(1)
+fn main() {
+  var a : i32 = tint_symbol(ub, 0u);
+  var b : u32 = tint_symbol_1(ub, 4u);
+  var c : f32 = tint_symbol_2(ub, 8u);
+  var d : vec2<i32> = tint_symbol_3(ub, 16u);
+  var e : vec2<u32> = tint_symbol_4(ub, 24u);
+  var f : vec2<f32> = tint_symbol_5(ub, 32u);
+  var g : vec3<i32> = tint_symbol_6(ub, 48u);
+  var h : vec3<u32> = tint_symbol_7(ub, 64u);
+  var i : vec3<f32> = tint_symbol_8(ub, 80u);
+  var j : vec4<i32> = tint_symbol_9(ub, 96u);
+  var k : vec4<u32> = tint_symbol_10(ub, 112u);
+  var l : vec4<f32> = tint_symbol_11(ub, 128u);
+  var m : mat2x2<f32> = tint_symbol_12(ub, 144u);
+  var n : mat2x3<f32> = tint_symbol_13(ub, 160u);
+  var o : mat2x4<f32> = tint_symbol_14(ub, 192u);
+  var p : mat3x2<f32> = tint_symbol_15(ub, 224u);
+  var q : mat3x3<f32> = tint_symbol_16(ub, 256u);
+  var r : mat3x4<f32> = tint_symbol_17(ub, 304u);
+  var s : mat4x2<f32> = tint_symbol_18(ub, 352u);
+  var t : mat4x3<f32> = tint_symbol_19(ub, 384u);
+  var u : mat4x4<f32> = tint_symbol_20(ub, 448u);
+  var v : array<vec3<f32>, 2> = tint_symbol_21(ub, 512u);
+}
+
+@group(0) @binding(0) var<uniform> ub : UB;
+
+struct UB {
+  a : i32;
+  b : u32;
+  c : f32;
+  d : vec2<i32>;
+  e : vec2<u32>;
+  f : vec2<f32>;
+  g : vec3<i32>;
+  h : vec3<u32>;
+  i : vec3<f32>;
+  j : vec4<i32>;
+  k : vec4<u32>;
+  l : vec4<f32>;
+  m : mat2x2<f32>;
+  n : mat2x3<f32>;
+  o : mat2x4<f32>;
+  p : mat3x2<f32>;
+  q : mat3x3<f32>;
+  r : mat3x4<f32>;
+  s : mat4x2<f32>;
+  t : mat4x3<f32>;
+  u : mat4x4<f32>;
+  v : array<vec3<f32>, 2>;
+}
+)";
+
+  auto got = Run<DecomposeMemoryAccess>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(DecomposeMemoryAccessTest, SB_BasicStore) {
   auto* src = R"(
 struct SB {
@@ -655,6 +1047,219 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(DecomposeMemoryAccessTest, SB_BasicStore_OutOfOrder) {
+  auto* src = R"(
+@stage(compute) @workgroup_size(1)
+fn main() {
+  sb.a = i32();
+  sb.b = u32();
+  sb.c = f32();
+  sb.d = vec2<i32>();
+  sb.e = vec2<u32>();
+  sb.f = vec2<f32>();
+  sb.g = vec3<i32>();
+  sb.h = vec3<u32>();
+  sb.i = vec3<f32>();
+  sb.j = vec4<i32>();
+  sb.k = vec4<u32>();
+  sb.l = vec4<f32>();
+  sb.m = mat2x2<f32>();
+  sb.n = mat2x3<f32>();
+  sb.o = mat2x4<f32>();
+  sb.p = mat3x2<f32>();
+  sb.q = mat3x3<f32>();
+  sb.r = mat3x4<f32>();
+  sb.s = mat4x2<f32>();
+  sb.t = mat4x3<f32>();
+  sb.u = mat4x4<f32>();
+  sb.v = array<vec3<f32>, 2>();
+}
+
+@group(0) @binding(0) var<storage, read_write> sb : SB;
+
+struct SB {
+  a : i32;
+  b : u32;
+  c : f32;
+  d : vec2<i32>;
+  e : vec2<u32>;
+  f : vec2<f32>;
+  g : vec3<i32>;
+  h : vec3<u32>;
+  i : vec3<f32>;
+  j : vec4<i32>;
+  k : vec4<u32>;
+  l : vec4<f32>;
+  m : mat2x2<f32>;
+  n : mat2x3<f32>;
+  o : mat2x4<f32>;
+  p : mat3x2<f32>;
+  q : mat3x3<f32>;
+  r : mat3x4<f32>;
+  s : mat4x2<f32>;
+  t : mat4x3<f32>;
+  u : mat4x4<f32>;
+  v : array<vec3<f32>, 2>;
+};
+)";
+
+  auto* expect = R"(
+@internal(intrinsic_store_storage_i32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : i32)
+
+@internal(intrinsic_store_storage_u32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_1(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : u32)
+
+@internal(intrinsic_store_storage_f32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_2(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : f32)
+
+@internal(intrinsic_store_storage_vec2_i32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_3(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec2<i32>)
+
+@internal(intrinsic_store_storage_vec2_u32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_4(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec2<u32>)
+
+@internal(intrinsic_store_storage_vec2_f32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_5(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec2<f32>)
+
+@internal(intrinsic_store_storage_vec3_i32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_6(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec3<i32>)
+
+@internal(intrinsic_store_storage_vec3_u32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_7(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec3<u32>)
+
+@internal(intrinsic_store_storage_vec3_f32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_8(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec3<f32>)
+
+@internal(intrinsic_store_storage_vec4_i32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_9(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec4<i32>)
+
+@internal(intrinsic_store_storage_vec4_u32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_10(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec4<u32>)
+
+@internal(intrinsic_store_storage_vec4_f32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_11(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec4<f32>)
+
+fn tint_symbol_12(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat2x2<f32>) {
+  tint_symbol_5(buffer, (offset + 0u), value[0u]);
+  tint_symbol_5(buffer, (offset + 8u), value[1u]);
+}
+
+fn tint_symbol_13(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat2x3<f32>) {
+  tint_symbol_8(buffer, (offset + 0u), value[0u]);
+  tint_symbol_8(buffer, (offset + 16u), value[1u]);
+}
+
+fn tint_symbol_14(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat2x4<f32>) {
+  tint_symbol_11(buffer, (offset + 0u), value[0u]);
+  tint_symbol_11(buffer, (offset + 16u), value[1u]);
+}
+
+fn tint_symbol_15(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat3x2<f32>) {
+  tint_symbol_5(buffer, (offset + 0u), value[0u]);
+  tint_symbol_5(buffer, (offset + 8u), value[1u]);
+  tint_symbol_5(buffer, (offset + 16u), value[2u]);
+}
+
+fn tint_symbol_16(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat3x3<f32>) {
+  tint_symbol_8(buffer, (offset + 0u), value[0u]);
+  tint_symbol_8(buffer, (offset + 16u), value[1u]);
+  tint_symbol_8(buffer, (offset + 32u), value[2u]);
+}
+
+fn tint_symbol_17(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat3x4<f32>) {
+  tint_symbol_11(buffer, (offset + 0u), value[0u]);
+  tint_symbol_11(buffer, (offset + 16u), value[1u]);
+  tint_symbol_11(buffer, (offset + 32u), value[2u]);
+}
+
+fn tint_symbol_18(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat4x2<f32>) {
+  tint_symbol_5(buffer, (offset + 0u), value[0u]);
+  tint_symbol_5(buffer, (offset + 8u), value[1u]);
+  tint_symbol_5(buffer, (offset + 16u), value[2u]);
+  tint_symbol_5(buffer, (offset + 24u), value[3u]);
+}
+
+fn tint_symbol_19(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat4x3<f32>) {
+  tint_symbol_8(buffer, (offset + 0u), value[0u]);
+  tint_symbol_8(buffer, (offset + 16u), value[1u]);
+  tint_symbol_8(buffer, (offset + 32u), value[2u]);
+  tint_symbol_8(buffer, (offset + 48u), value[3u]);
+}
+
+fn tint_symbol_20(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat4x4<f32>) {
+  tint_symbol_11(buffer, (offset + 0u), value[0u]);
+  tint_symbol_11(buffer, (offset + 16u), value[1u]);
+  tint_symbol_11(buffer, (offset + 32u), value[2u]);
+  tint_symbol_11(buffer, (offset + 48u), value[3u]);
+}
+
+fn tint_symbol_21(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : array<vec3<f32>, 2u>) {
+  var array = value;
+  for(var i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
+    tint_symbol_8(buffer, (offset + (i_1 * 16u)), array[i_1]);
+  }
+}
+
+@stage(compute) @workgroup_size(1)
+fn main() {
+  tint_symbol(sb, 0u, i32());
+  tint_symbol_1(sb, 4u, u32());
+  tint_symbol_2(sb, 8u, f32());
+  tint_symbol_3(sb, 16u, vec2<i32>());
+  tint_symbol_4(sb, 24u, vec2<u32>());
+  tint_symbol_5(sb, 32u, vec2<f32>());
+  tint_symbol_6(sb, 48u, vec3<i32>());
+  tint_symbol_7(sb, 64u, vec3<u32>());
+  tint_symbol_8(sb, 80u, vec3<f32>());
+  tint_symbol_9(sb, 96u, vec4<i32>());
+  tint_symbol_10(sb, 112u, vec4<u32>());
+  tint_symbol_11(sb, 128u, vec4<f32>());
+  tint_symbol_12(sb, 144u, mat2x2<f32>());
+  tint_symbol_13(sb, 160u, mat2x3<f32>());
+  tint_symbol_14(sb, 192u, mat2x4<f32>());
+  tint_symbol_15(sb, 224u, mat3x2<f32>());
+  tint_symbol_16(sb, 256u, mat3x3<f32>());
+  tint_symbol_17(sb, 304u, mat3x4<f32>());
+  tint_symbol_18(sb, 352u, mat4x2<f32>());
+  tint_symbol_19(sb, 384u, mat4x3<f32>());
+  tint_symbol_20(sb, 448u, mat4x4<f32>());
+  tint_symbol_21(sb, 512u, array<vec3<f32>, 2>());
+}
+
+@group(0) @binding(0) var<storage, read_write> sb : SB;
+
+struct SB {
+  a : i32;
+  b : u32;
+  c : f32;
+  d : vec2<i32>;
+  e : vec2<u32>;
+  f : vec2<f32>;
+  g : vec3<i32>;
+  h : vec3<u32>;
+  i : vec3<f32>;
+  j : vec4<i32>;
+  k : vec4<u32>;
+  l : vec4<f32>;
+  m : mat2x2<f32>;
+  n : mat2x3<f32>;
+  o : mat2x4<f32>;
+  p : mat3x2<f32>;
+  q : mat3x3<f32>;
+  r : mat3x4<f32>;
+  s : mat4x2<f32>;
+  t : mat4x3<f32>;
+  u : mat4x4<f32>;
+  v : array<vec3<f32>, 2>;
+}
+)";
+
+  auto got = Run<DecomposeMemoryAccess>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(DecomposeMemoryAccessTest, LoadStructure) {
   auto* src = R"(
 struct SB {
@@ -813,6 +1418,164 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(DecomposeMemoryAccessTest, LoadStructure_OutOfOrder) {
+  auto* src = R"(
+@stage(compute) @workgroup_size(1)
+fn main() {
+  var x : SB = sb;
+}
+
+@group(0) @binding(0) var<storage, read_write> sb : SB;
+
+struct SB {
+  a : i32;
+  b : u32;
+  c : f32;
+  d : vec2<i32>;
+  e : vec2<u32>;
+  f : vec2<f32>;
+  g : vec3<i32>;
+  h : vec3<u32>;
+  i : vec3<f32>;
+  j : vec4<i32>;
+  k : vec4<u32>;
+  l : vec4<f32>;
+  m : mat2x2<f32>;
+  n : mat2x3<f32>;
+  o : mat2x4<f32>;
+  p : mat3x2<f32>;
+  q : mat3x3<f32>;
+  r : mat3x4<f32>;
+  s : mat4x2<f32>;
+  t : mat4x3<f32>;
+  u : mat4x4<f32>;
+  v : array<vec3<f32>, 2>;
+};
+)";
+
+  auto* expect = R"(
+@internal(intrinsic_load_storage_i32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_1(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> i32
+
+@internal(intrinsic_load_storage_u32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_2(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> u32
+
+@internal(intrinsic_load_storage_f32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_3(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> f32
+
+@internal(intrinsic_load_storage_vec2_i32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_4(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec2<i32>
+
+@internal(intrinsic_load_storage_vec2_u32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_5(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec2<u32>
+
+@internal(intrinsic_load_storage_vec2_f32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_6(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec2<f32>
+
+@internal(intrinsic_load_storage_vec3_i32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_7(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec3<i32>
+
+@internal(intrinsic_load_storage_vec3_u32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_8(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec3<u32>
+
+@internal(intrinsic_load_storage_vec3_f32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_9(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec3<f32>
+
+@internal(intrinsic_load_storage_vec4_i32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_10(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec4<i32>
+
+@internal(intrinsic_load_storage_vec4_u32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_11(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec4<u32>
+
+@internal(intrinsic_load_storage_vec4_f32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_12(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> vec4<f32>
+
+fn tint_symbol_13(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat2x2<f32> {
+  return mat2x2<f32>(tint_symbol_6(buffer, (offset + 0u)), tint_symbol_6(buffer, (offset + 8u)));
+}
+
+fn tint_symbol_14(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat2x3<f32> {
+  return mat2x3<f32>(tint_symbol_9(buffer, (offset + 0u)), tint_symbol_9(buffer, (offset + 16u)));
+}
+
+fn tint_symbol_15(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat2x4<f32> {
+  return mat2x4<f32>(tint_symbol_12(buffer, (offset + 0u)), tint_symbol_12(buffer, (offset + 16u)));
+}
+
+fn tint_symbol_16(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat3x2<f32> {
+  return mat3x2<f32>(tint_symbol_6(buffer, (offset + 0u)), tint_symbol_6(buffer, (offset + 8u)), tint_symbol_6(buffer, (offset + 16u)));
+}
+
+fn tint_symbol_17(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat3x3<f32> {
+  return mat3x3<f32>(tint_symbol_9(buffer, (offset + 0u)), tint_symbol_9(buffer, (offset + 16u)), tint_symbol_9(buffer, (offset + 32u)));
+}
+
+fn tint_symbol_18(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat3x4<f32> {
+  return mat3x4<f32>(tint_symbol_12(buffer, (offset + 0u)), tint_symbol_12(buffer, (offset + 16u)), tint_symbol_12(buffer, (offset + 32u)));
+}
+
+fn tint_symbol_19(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat4x2<f32> {
+  return mat4x2<f32>(tint_symbol_6(buffer, (offset + 0u)), tint_symbol_6(buffer, (offset + 8u)), tint_symbol_6(buffer, (offset + 16u)), tint_symbol_6(buffer, (offset + 24u)));
+}
+
+fn tint_symbol_20(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat4x3<f32> {
+  return mat4x3<f32>(tint_symbol_9(buffer, (offset + 0u)), tint_symbol_9(buffer, (offset + 16u)), tint_symbol_9(buffer, (offset + 32u)), tint_symbol_9(buffer, (offset + 48u)));
+}
+
+fn tint_symbol_21(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> mat4x4<f32> {
+  return mat4x4<f32>(tint_symbol_12(buffer, (offset + 0u)), tint_symbol_12(buffer, (offset + 16u)), tint_symbol_12(buffer, (offset + 32u)), tint_symbol_12(buffer, (offset + 48u)));
+}
+
+fn tint_symbol_22(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> array<vec3<f32>, 2u> {
+  var arr : array<vec3<f32>, 2u>;
+  for(var i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
+    arr[i_1] = tint_symbol_9(buffer, (offset + (i_1 * 16u)));
+  }
+  return arr;
+}
+
+fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> SB {
+  return SB(tint_symbol_1(buffer, (offset + 0u)), tint_symbol_2(buffer, (offset + 4u)), tint_symbol_3(buffer, (offset + 8u)), tint_symbol_4(buffer, (offset + 16u)), tint_symbol_5(buffer, (offset + 24u)), tint_symbol_6(buffer, (offset + 32u)), tint_symbol_7(buffer, (offset + 48u)), tint_symbol_8(buffer, (offset + 64u)), tint_symbol_9(buffer, (offset + 80u)), tint_symbol_10(buffer, (offset + 96u)), tint_symbol_11(buffer, (offset + 112u)), tint_symbol_12(buffer, (offset + 128u)), tint_symbol_13(buffer, (offset + 144u)), tint_symbol_14(buffer, (offset + 160u)), tint_symbol_15(buffer, (offset + 192u)), tint_symbol_16(buffer, (offset + 224u)), tint_symbol_17(buffer, (offset + 256u)), tint_symbol_18(buffer, (offset + 304u)), tint_symbol_19(buffer, (offset + 352u)), tint_symbol_20(buffer, (offset + 384u)), tint_symbol_21(buffer, (offset + 448u)), tint_symbol_22(buffer, (offset + 512u)));
+}
+
+@stage(compute) @workgroup_size(1)
+fn main() {
+  var x : SB = tint_symbol(sb, 0u);
+}
+
+@group(0) @binding(0) var<storage, read_write> sb : SB;
+
+struct SB {
+  a : i32;
+  b : u32;
+  c : f32;
+  d : vec2<i32>;
+  e : vec2<u32>;
+  f : vec2<f32>;
+  g : vec3<i32>;
+  h : vec3<u32>;
+  i : vec3<f32>;
+  j : vec4<i32>;
+  k : vec4<u32>;
+  l : vec4<f32>;
+  m : mat2x2<f32>;
+  n : mat2x3<f32>;
+  o : mat2x4<f32>;
+  p : mat3x2<f32>;
+  q : mat3x3<f32>;
+  r : mat3x4<f32>;
+  s : mat4x2<f32>;
+  t : mat4x3<f32>;
+  u : mat4x4<f32>;
+  v : array<vec3<f32>, 2>;
+}
+)";
+
+  auto got = Run<DecomposeMemoryAccess>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(DecomposeMemoryAccessTest, StoreStructure) {
   auto* src = R"(
 struct SB {
@@ -1009,6 +1772,202 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(DecomposeMemoryAccessTest, StoreStructure_OutOfOrder) {
+  auto* src = R"(
+@stage(compute) @workgroup_size(1)
+fn main() {
+  sb = SB();
+}
+
+@group(0) @binding(0) var<storage, read_write> sb : SB;
+
+struct SB {
+  a : i32;
+  b : u32;
+  c : f32;
+  d : vec2<i32>;
+  e : vec2<u32>;
+  f : vec2<f32>;
+  g : vec3<i32>;
+  h : vec3<u32>;
+  i : vec3<f32>;
+  j : vec4<i32>;
+  k : vec4<u32>;
+  l : vec4<f32>;
+  m : mat2x2<f32>;
+  n : mat2x3<f32>;
+  o : mat2x4<f32>;
+  p : mat3x2<f32>;
+  q : mat3x3<f32>;
+  r : mat3x4<f32>;
+  s : mat4x2<f32>;
+  t : mat4x3<f32>;
+  u : mat4x4<f32>;
+  v : array<vec3<f32>, 2>;
+};
+)";
+
+  auto* expect = R"(
+@internal(intrinsic_store_storage_i32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_1(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : i32)
+
+@internal(intrinsic_store_storage_u32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_2(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : u32)
+
+@internal(intrinsic_store_storage_f32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_3(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : f32)
+
+@internal(intrinsic_store_storage_vec2_i32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_4(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec2<i32>)
+
+@internal(intrinsic_store_storage_vec2_u32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_5(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec2<u32>)
+
+@internal(intrinsic_store_storage_vec2_f32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_6(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec2<f32>)
+
+@internal(intrinsic_store_storage_vec3_i32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_7(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec3<i32>)
+
+@internal(intrinsic_store_storage_vec3_u32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_8(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec3<u32>)
+
+@internal(intrinsic_store_storage_vec3_f32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_9(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec3<f32>)
+
+@internal(intrinsic_store_storage_vec4_i32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_10(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec4<i32>)
+
+@internal(intrinsic_store_storage_vec4_u32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_11(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec4<u32>)
+
+@internal(intrinsic_store_storage_vec4_f32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_12(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : vec4<f32>)
+
+fn tint_symbol_13(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat2x2<f32>) {
+  tint_symbol_6(buffer, (offset + 0u), value[0u]);
+  tint_symbol_6(buffer, (offset + 8u), value[1u]);
+}
+
+fn tint_symbol_14(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat2x3<f32>) {
+  tint_symbol_9(buffer, (offset + 0u), value[0u]);
+  tint_symbol_9(buffer, (offset + 16u), value[1u]);
+}
+
+fn tint_symbol_15(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat2x4<f32>) {
+  tint_symbol_12(buffer, (offset + 0u), value[0u]);
+  tint_symbol_12(buffer, (offset + 16u), value[1u]);
+}
+
+fn tint_symbol_16(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat3x2<f32>) {
+  tint_symbol_6(buffer, (offset + 0u), value[0u]);
+  tint_symbol_6(buffer, (offset + 8u), value[1u]);
+  tint_symbol_6(buffer, (offset + 16u), value[2u]);
+}
+
+fn tint_symbol_17(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat3x3<f32>) {
+  tint_symbol_9(buffer, (offset + 0u), value[0u]);
+  tint_symbol_9(buffer, (offset + 16u), value[1u]);
+  tint_symbol_9(buffer, (offset + 32u), value[2u]);
+}
+
+fn tint_symbol_18(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat3x4<f32>) {
+  tint_symbol_12(buffer, (offset + 0u), value[0u]);
+  tint_symbol_12(buffer, (offset + 16u), value[1u]);
+  tint_symbol_12(buffer, (offset + 32u), value[2u]);
+}
+
+fn tint_symbol_19(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat4x2<f32>) {
+  tint_symbol_6(buffer, (offset + 0u), value[0u]);
+  tint_symbol_6(buffer, (offset + 8u), value[1u]);
+  tint_symbol_6(buffer, (offset + 16u), value[2u]);
+  tint_symbol_6(buffer, (offset + 24u), value[3u]);
+}
+
+fn tint_symbol_20(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat4x3<f32>) {
+  tint_symbol_9(buffer, (offset + 0u), value[0u]);
+  tint_symbol_9(buffer, (offset + 16u), value[1u]);
+  tint_symbol_9(buffer, (offset + 32u), value[2u]);
+  tint_symbol_9(buffer, (offset + 48u), value[3u]);
+}
+
+fn tint_symbol_21(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : mat4x4<f32>) {
+  tint_symbol_12(buffer, (offset + 0u), value[0u]);
+  tint_symbol_12(buffer, (offset + 16u), value[1u]);
+  tint_symbol_12(buffer, (offset + 32u), value[2u]);
+  tint_symbol_12(buffer, (offset + 48u), value[3u]);
+}
+
+fn tint_symbol_22(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : array<vec3<f32>, 2u>) {
+  var array = value;
+  for(var i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
+    tint_symbol_9(buffer, (offset + (i_1 * 16u)), array[i_1]);
+  }
+}
+
+fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : SB) {
+  tint_symbol_1(buffer, (offset + 0u), value.a);
+  tint_symbol_2(buffer, (offset + 4u), value.b);
+  tint_symbol_3(buffer, (offset + 8u), value.c);
+  tint_symbol_4(buffer, (offset + 16u), value.d);
+  tint_symbol_5(buffer, (offset + 24u), value.e);
+  tint_symbol_6(buffer, (offset + 32u), value.f);
+  tint_symbol_7(buffer, (offset + 48u), value.g);
+  tint_symbol_8(buffer, (offset + 64u), value.h);
+  tint_symbol_9(buffer, (offset + 80u), value.i);
+  tint_symbol_10(buffer, (offset + 96u), value.j);
+  tint_symbol_11(buffer, (offset + 112u), value.k);
+  tint_symbol_12(buffer, (offset + 128u), value.l);
+  tint_symbol_13(buffer, (offset + 144u), value.m);
+  tint_symbol_14(buffer, (offset + 160u), value.n);
+  tint_symbol_15(buffer, (offset + 192u), value.o);
+  tint_symbol_16(buffer, (offset + 224u), value.p);
+  tint_symbol_17(buffer, (offset + 256u), value.q);
+  tint_symbol_18(buffer, (offset + 304u), value.r);
+  tint_symbol_19(buffer, (offset + 352u), value.s);
+  tint_symbol_20(buffer, (offset + 384u), value.t);
+  tint_symbol_21(buffer, (offset + 448u), value.u);
+  tint_symbol_22(buffer, (offset + 512u), value.v);
+}
+
+@stage(compute) @workgroup_size(1)
+fn main() {
+  tint_symbol(sb, 0u, SB());
+}
+
+@group(0) @binding(0) var<storage, read_write> sb : SB;
+
+struct SB {
+  a : i32;
+  b : u32;
+  c : f32;
+  d : vec2<i32>;
+  e : vec2<u32>;
+  f : vec2<f32>;
+  g : vec3<i32>;
+  h : vec3<u32>;
+  i : vec3<f32>;
+  j : vec4<i32>;
+  k : vec4<u32>;
+  l : vec4<f32>;
+  m : mat2x2<f32>;
+  n : mat2x3<f32>;
+  o : mat2x4<f32>;
+  p : mat3x2<f32>;
+  q : mat3x3<f32>;
+  r : mat3x4<f32>;
+  s : mat4x2<f32>;
+  t : mat4x3<f32>;
+  u : mat4x4<f32>;
+  v : array<vec3<f32>, 2>;
+}
+)";
+
+  auto got = Run<DecomposeMemoryAccess>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(DecomposeMemoryAccessTest, ComplexStaticAccessChain) {
   auto* src = R"(
 struct S1 {
@@ -1079,6 +2038,76 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(DecomposeMemoryAccessTest, ComplexStaticAccessChain_OutOfOrder) {
+  auto* src = R"(
+@stage(compute) @workgroup_size(1)
+fn main() {
+  var x : f32 = sb.b[4].b[1].b.z;
+}
+
+@group(0) @binding(0) var<storage, read_write> sb : SB;
+
+struct SB {
+  @size(128)
+  a : i32;
+  b : @stride(256) array<S2>;
+};
+
+struct S2 {
+  a : i32;
+  b : @stride(32) array<S1, 3>;
+  c : i32;
+};
+
+struct S1 {
+  a : i32;
+  b : vec3<f32>;
+  c : i32;
+};
+)";
+
+  // sb.b[4].b[1].b.z
+  //    ^  ^ ^  ^ ^ ^
+  //    |  | |  | | |
+  //  128  | |1200| 1224
+  //       | |    |
+  //    1152 1168 1216
+
+  auto* expect = R"(
+@internal(intrinsic_load_storage_f32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> f32
+
+@stage(compute) @workgroup_size(1)
+fn main() {
+  var x : f32 = tint_symbol(sb, 1224u);
+}
+
+@group(0) @binding(0) var<storage, read_write> sb : SB;
+
+struct SB {
+  @size(128)
+  a : i32;
+  b : @stride(256) array<S2>;
+}
+
+struct S2 {
+  a : i32;
+  b : @stride(32) array<S1, 3>;
+  c : i32;
+}
+
+struct S1 {
+  a : i32;
+  b : vec3<f32>;
+  c : i32;
+}
+)";
+
+  auto got = Run<DecomposeMemoryAccess>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(DecomposeMemoryAccessTest, ComplexDynamicAccessChain) {
   auto* src = R"(
 struct S1 {
@@ -1148,6 +2177,75 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(DecomposeMemoryAccessTest, ComplexDynamicAccessChain_OutOfOrder) {
+  auto* src = R"(
+@stage(compute) @workgroup_size(1)
+fn main() {
+  var i : i32 = 4;
+  var j : u32 = 1u;
+  var k : i32 = 2;
+  var x : f32 = sb.b[i].b[j].b[k];
+}
+
+@group(0) @binding(0) var<storage, read_write> sb : SB;
+
+struct SB {
+  @size(128)
+  a : i32;
+  b : @stride(256) array<S2>;
+};
+
+struct S2 {
+  a : i32;
+  b : @stride(32) array<S1, 3>;
+  c : i32;
+};
+
+struct S1 {
+  a : i32;
+  b : vec3<f32>;
+  c : i32;
+};
+)";
+
+  auto* expect = R"(
+@internal(intrinsic_load_storage_f32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> f32
+
+@stage(compute) @workgroup_size(1)
+fn main() {
+  var i : i32 = 4;
+  var j : u32 = 1u;
+  var k : i32 = 2;
+  var x : f32 = tint_symbol(sb, (((((128u + (256u * u32(i))) + 16u) + (32u * j)) + 16u) + (4u * u32(k))));
+}
+
+@group(0) @binding(0) var<storage, read_write> sb : SB;
+
+struct SB {
+  @size(128)
+  a : i32;
+  b : @stride(256) array<S2>;
+}
+
+struct S2 {
+  a : i32;
+  b : @stride(32) array<S1, 3>;
+  c : i32;
+}
+
+struct S1 {
+  a : i32;
+  b : vec3<f32>;
+  c : i32;
+}
+)";
+
+  auto got = Run<DecomposeMemoryAccess>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(DecomposeMemoryAccessTest, ComplexDynamicAccessChainWithAliases) {
   auto* src = R"(
 struct S1 {
@@ -1233,6 +2331,92 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(DecomposeMemoryAccessTest,
+       ComplexDynamicAccessChainWithAliases_OutOfOrder) {
+  auto* src = R"(
+@stage(compute) @workgroup_size(1)
+fn main() {
+  var i : i32 = 4;
+  var j : u32 = 1u;
+  var k : i32 = 2;
+  var x : f32 = sb.b[i].b[j].b[k];
+}
+
+@group(0) @binding(0) var<storage, read_write> sb : SB;
+
+struct SB {
+  @size(128)
+  a : i32;
+  b : A2_Array;
+};
+
+type A2_Array = @stride(256) array<S2>;
+
+type A2 = S2;
+
+struct S2 {
+  a : i32;
+  b : A1_Array;
+  c : i32;
+};
+
+type A1 = S1;
+
+type A1_Array = @stride(32) array<S1, 3>;
+
+struct S1 {
+  a : i32;
+  b : vec3<f32>;
+  c : i32;
+};
+)";
+
+  auto* expect = R"(
+@internal(intrinsic_load_storage_f32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> f32
+
+@stage(compute) @workgroup_size(1)
+fn main() {
+  var i : i32 = 4;
+  var j : u32 = 1u;
+  var k : i32 = 2;
+  var x : f32 = tint_symbol(sb, (((((128u + (256u * u32(i))) + 16u) + (32u * j)) + 16u) + (4u * u32(k))));
+}
+
+@group(0) @binding(0) var<storage, read_write> sb : SB;
+
+struct SB {
+  @size(128)
+  a : i32;
+  b : A2_Array;
+}
+
+type A2_Array = @stride(256) array<S2>;
+
+type A2 = S2;
+
+struct S2 {
+  a : i32;
+  b : A1_Array;
+  c : i32;
+}
+
+type A1 = S1;
+
+type A1_Array = @stride(32) array<S1, 3>;
+
+struct S1 {
+  a : i32;
+  b : vec3<f32>;
+  c : i32;
+}
+)";
+
+  auto got = Run<DecomposeMemoryAccess>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(DecomposeMemoryAccessTest, StorageBufferAtomics) {
   auto* src = R"(
 struct SB {
@@ -1378,6 +2562,151 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(DecomposeMemoryAccessTest, StorageBufferAtomics_OutOfOrder) {
+  auto* src = R"(
+@stage(compute) @workgroup_size(1)
+fn main() {
+  atomicStore(&sb.a, 123);
+  atomicLoad(&sb.a);
+  atomicAdd(&sb.a, 123);
+  atomicSub(&sb.a, 123);
+  atomicMax(&sb.a, 123);
+  atomicMin(&sb.a, 123);
+  atomicAnd(&sb.a, 123);
+  atomicOr(&sb.a, 123);
+  atomicXor(&sb.a, 123);
+  atomicExchange(&sb.a, 123);
+  atomicCompareExchangeWeak(&sb.a, 123, 345);
+
+  atomicStore(&sb.b, 123u);
+  atomicLoad(&sb.b);
+  atomicAdd(&sb.b, 123u);
+  atomicSub(&sb.b, 123u);
+  atomicMax(&sb.b, 123u);
+  atomicMin(&sb.b, 123u);
+  atomicAnd(&sb.b, 123u);
+  atomicOr(&sb.b, 123u);
+  atomicXor(&sb.b, 123u);
+  atomicExchange(&sb.b, 123u);
+  atomicCompareExchangeWeak(&sb.b, 123u, 345u);
+}
+
+@group(0) @binding(0) var<storage, read_write> sb : SB;
+
+struct SB {
+  padding : vec4<f32>;
+  a : atomic<i32>;
+  b : atomic<u32>;
+};
+)";
+
+  auto* expect = R"(
+@internal(intrinsic_atomic_store_storage_i32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : i32)
+
+@internal(intrinsic_atomic_load_storage_i32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_1(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> i32
+
+@internal(intrinsic_atomic_add_storage_i32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_2(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : i32) -> i32
+
+@internal(intrinsic_atomic_sub_storage_i32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_3(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : i32) -> i32
+
+@internal(intrinsic_atomic_max_storage_i32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_4(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : i32) -> i32
+
+@internal(intrinsic_atomic_min_storage_i32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_5(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : i32) -> i32
+
+@internal(intrinsic_atomic_and_storage_i32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_6(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : i32) -> i32
+
+@internal(intrinsic_atomic_or_storage_i32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_7(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : i32) -> i32
+
+@internal(intrinsic_atomic_xor_storage_i32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_8(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : i32) -> i32
+
+@internal(intrinsic_atomic_exchange_storage_i32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_9(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : i32) -> i32
+
+@internal(intrinsic_atomic_compare_exchange_weak_storage_i32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_10(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : i32, param_2 : i32) -> vec2<i32>
+
+@internal(intrinsic_atomic_store_storage_u32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_11(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : u32)
+
+@internal(intrinsic_atomic_load_storage_u32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_12(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> u32
+
+@internal(intrinsic_atomic_add_storage_u32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_13(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : u32) -> u32
+
+@internal(intrinsic_atomic_sub_storage_u32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_14(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : u32) -> u32
+
+@internal(intrinsic_atomic_max_storage_u32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_15(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : u32) -> u32
+
+@internal(intrinsic_atomic_min_storage_u32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_16(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : u32) -> u32
+
+@internal(intrinsic_atomic_and_storage_u32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_17(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : u32) -> u32
+
+@internal(intrinsic_atomic_or_storage_u32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_18(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : u32) -> u32
+
+@internal(intrinsic_atomic_xor_storage_u32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_19(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : u32) -> u32
+
+@internal(intrinsic_atomic_exchange_storage_u32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_20(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : u32) -> u32
+
+@internal(intrinsic_atomic_compare_exchange_weak_storage_u32) @internal(disable_validation__function_has_no_body)
+fn tint_symbol_21(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : u32, param_2 : u32) -> vec2<u32>
+
+@stage(compute) @workgroup_size(1)
+fn main() {
+  tint_symbol(sb, 16u, 123);
+  tint_symbol_1(sb, 16u);
+  tint_symbol_2(sb, 16u, 123);
+  tint_symbol_3(sb, 16u, 123);
+  tint_symbol_4(sb, 16u, 123);
+  tint_symbol_5(sb, 16u, 123);
+  tint_symbol_6(sb, 16u, 123);
+  tint_symbol_7(sb, 16u, 123);
+  tint_symbol_8(sb, 16u, 123);
+  tint_symbol_9(sb, 16u, 123);
+  tint_symbol_10(sb, 16u, 123, 345);
+  tint_symbol_11(sb, 20u, 123u);
+  tint_symbol_12(sb, 20u);
+  tint_symbol_13(sb, 20u, 123u);
+  tint_symbol_14(sb, 20u, 123u);
+  tint_symbol_15(sb, 20u, 123u);
+  tint_symbol_16(sb, 20u, 123u);
+  tint_symbol_17(sb, 20u, 123u);
+  tint_symbol_18(sb, 20u, 123u);
+  tint_symbol_19(sb, 20u, 123u);
+  tint_symbol_20(sb, 20u, 123u);
+  tint_symbol_21(sb, 20u, 123u, 345u);
+}
+
+@group(0) @binding(0) var<storage, read_write> sb : SB;
+
+struct SB {
+  padding : vec4<f32>;
+  a : atomic<i32>;
+  b : atomic<u32>;
+}
+)";
+
+  auto got = Run<DecomposeMemoryAccess>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(DecomposeMemoryAccessTest, WorkgroupBufferAtomics) {
   auto* src = R"(
 struct S {
@@ -1422,6 +2751,50 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(DecomposeMemoryAccessTest, WorkgroupBufferAtomics_OutOfOrder) {
+  auto* src = R"(
+@stage(compute) @workgroup_size(1)
+fn main() {
+  atomicStore(&(w.a), 123);
+  atomicLoad(&(w.a));
+  atomicAdd(&(w.a), 123);
+  atomicSub(&(w.a), 123);
+  atomicMax(&(w.a), 123);
+  atomicMin(&(w.a), 123);
+  atomicAnd(&(w.a), 123);
+  atomicOr(&(w.a), 123);
+  atomicXor(&(w.a), 123);
+  atomicExchange(&(w.a), 123);
+  atomicCompareExchangeWeak(&(w.a), 123, 345);
+  atomicStore(&(w.b), 123u);
+  atomicLoad(&(w.b));
+  atomicAdd(&(w.b), 123u);
+  atomicSub(&(w.b), 123u);
+  atomicMax(&(w.b), 123u);
+  atomicMin(&(w.b), 123u);
+  atomicAnd(&(w.b), 123u);
+  atomicOr(&(w.b), 123u);
+  atomicXor(&(w.b), 123u);
+  atomicExchange(&(w.b), 123u);
+  atomicCompareExchangeWeak(&(w.b), 123u, 345u);
+}
+
+var<workgroup> w : S;
+
+struct S {
+  padding : vec4<f32>;
+  a : atomic<i32>;
+  b : atomic<u32>;
+}
+)";
+
+  auto* expect = src;
+
+  auto got = Run<DecomposeMemoryAccess>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 }  // namespace
 }  // namespace transform
 }  // namespace tint
diff --git a/src/transform/external_texture_transform_test.cc b/src/transform/external_texture_transform_test.cc
index 28baadf..0c41717 100644
--- a/src/transform/external_texture_transform_test.cc
+++ b/src/transform/external_texture_transform_test.cc
@@ -50,6 +50,34 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(ExternalTextureTransformTest, SampleLevelSinglePlane_OutOfOrder) {
+  auto* src = R"(
+@stage(fragment)
+fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
+  return textureSampleLevel(t, s, (coord.xy / vec2<f32>(4.0, 4.0)));
+}
+
+@group(0) @binding(1) var t : texture_external;
+
+@group(0) @binding(0) var s : sampler;
+)";
+
+  auto* expect = R"(
+@stage(fragment)
+fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
+  return textureSampleLevel(t, s, (coord.xy / vec2<f32>(4.0, 4.0)), 0.0);
+}
+
+@group(0) @binding(1) var t : texture_2d<f32>;
+
+@group(0) @binding(0) var s : sampler;
+)";
+
+  auto got = Run<ExternalTextureTransform>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(ExternalTextureTransformTest, LoadSinglePlane) {
   auto* src = R"(
 @group(0) @binding(0) var t : texture_external;
@@ -74,6 +102,30 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(ExternalTextureTransformTest, LoadSinglePlane_OutOfOrder) {
+  auto* src = R"(
+@stage(fragment)
+fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
+  return textureLoad(t, vec2<i32>(1, 1));
+}
+
+@group(0) @binding(0) var t : texture_external;
+)";
+
+  auto* expect = R"(
+@stage(fragment)
+fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
+  return textureLoad(t, vec2<i32>(1, 1), 0);
+}
+
+@group(0) @binding(0) var t : texture_2d<f32>;
+)";
+
+  auto got = Run<ExternalTextureTransform>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(ExternalTextureTransformTest, DimensionsSinglePlane) {
   auto* src = R"(
 @group(0) @binding(0) var t : texture_external;
@@ -102,6 +154,34 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(ExternalTextureTransformTest, DimensionsSinglePlane_OutOfOrder) {
+  auto* src = R"(
+@stage(fragment)
+fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
+  var dim : vec2<i32>;
+  dim = textureDimensions(t);
+  return vec4<f32>(0.0, 0.0, 0.0, 0.0);
+}
+
+@group(0) @binding(0) var t : texture_external;
+)";
+
+  auto* expect = R"(
+@stage(fragment)
+fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
+  var dim : vec2<i32>;
+  dim = textureDimensions(t);
+  return vec4<f32>(0.0, 0.0, 0.0, 0.0);
+}
+
+@group(0) @binding(0) var t : texture_2d<f32>;
+)";
+
+  auto got = Run<ExternalTextureTransform>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 }  // namespace
 }  // namespace transform
 }  // namespace tint
diff --git a/src/transform/first_index_offset_test.cc b/src/transform/first_index_offset_test.cc
index 05fefa8..61075a6 100644
--- a/src/transform/first_index_offset_test.cc
+++ b/src/transform/first_index_offset_test.cc
@@ -139,6 +139,52 @@
   EXPECT_EQ(data->first_instance_offset, 0u);
 }
 
+TEST_F(FirstIndexOffsetTest, BasicModuleVertexIndex_OutOfOrder) {
+  auto* src = R"(
+@stage(vertex)
+fn entry(@builtin(vertex_index) vert_idx : u32) -> @builtin(position) vec4<f32> {
+  test(vert_idx);
+  return vec4<f32>();
+}
+
+fn test(vert_idx : u32) -> u32 {
+  return vert_idx;
+}
+)";
+
+  auto* expect = R"(
+struct tint_symbol {
+  first_vertex_index : u32;
+}
+
+@binding(1) @group(2) var<uniform> tint_symbol_1 : tint_symbol;
+
+@stage(vertex)
+fn entry(@builtin(vertex_index) vert_idx : u32) -> @builtin(position) vec4<f32> {
+  test((vert_idx + tint_symbol_1.first_vertex_index));
+  return vec4<f32>();
+}
+
+fn test(vert_idx : u32) -> u32 {
+  return vert_idx;
+}
+)";
+
+  DataMap config;
+  config.Add<FirstIndexOffset::BindingPoint>(1, 2);
+  auto got = Run<FirstIndexOffset>(src, std::move(config));
+
+  EXPECT_EQ(expect, str(got));
+
+  auto* data = got.data.Get<FirstIndexOffset::Data>();
+
+  ASSERT_NE(data, nullptr);
+  EXPECT_EQ(data->has_vertex_index, true);
+  EXPECT_EQ(data->has_instance_index, false);
+  EXPECT_EQ(data->first_vertex_offset, 0u);
+  EXPECT_EQ(data->first_instance_offset, 0u);
+}
+
 TEST_F(FirstIndexOffsetTest, BasicModuleInstanceIndex) {
   auto* src = R"(
 fn test(inst_idx : u32) -> u32 {
@@ -185,6 +231,52 @@
   EXPECT_EQ(data->first_instance_offset, 0u);
 }
 
+TEST_F(FirstIndexOffsetTest, BasicModuleInstanceIndex_OutOfOrder) {
+  auto* src = R"(
+@stage(vertex)
+fn entry(@builtin(instance_index) inst_idx : u32) -> @builtin(position) vec4<f32> {
+  test(inst_idx);
+  return vec4<f32>();
+}
+
+fn test(inst_idx : u32) -> u32 {
+  return inst_idx;
+}
+)";
+
+  auto* expect = R"(
+struct tint_symbol {
+  first_instance_index : u32;
+}
+
+@binding(1) @group(7) var<uniform> tint_symbol_1 : tint_symbol;
+
+@stage(vertex)
+fn entry(@builtin(instance_index) inst_idx : u32) -> @builtin(position) vec4<f32> {
+  test((inst_idx + tint_symbol_1.first_instance_index));
+  return vec4<f32>();
+}
+
+fn test(inst_idx : u32) -> u32 {
+  return inst_idx;
+}
+)";
+
+  DataMap config;
+  config.Add<FirstIndexOffset::BindingPoint>(1, 7);
+  auto got = Run<FirstIndexOffset>(src, std::move(config));
+
+  EXPECT_EQ(expect, str(got));
+
+  auto* data = got.data.Get<FirstIndexOffset::Data>();
+
+  ASSERT_NE(data, nullptr);
+  EXPECT_EQ(data->has_vertex_index, false);
+  EXPECT_EQ(data->has_instance_index, true);
+  EXPECT_EQ(data->first_vertex_offset, 0u);
+  EXPECT_EQ(data->first_instance_offset, 0u);
+}
+
 TEST_F(FirstIndexOffsetTest, BasicModuleBothIndex) {
   auto* src = R"(
 fn test(instance_idx : u32, vert_idx : u32) -> u32 {
@@ -244,6 +336,65 @@
   EXPECT_EQ(data->first_instance_offset, 4u);
 }
 
+TEST_F(FirstIndexOffsetTest, BasicModuleBothIndex_OutOfOrder) {
+  auto* src = R"(
+@stage(vertex)
+fn entry(inputs : Inputs) -> @builtin(position) vec4<f32> {
+  test(inputs.instance_idx, inputs.vert_idx);
+  return vec4<f32>();
+}
+
+struct Inputs {
+  @builtin(instance_index) instance_idx : u32;
+  @builtin(vertex_index) vert_idx : u32;
+};
+
+fn test(instance_idx : u32, vert_idx : u32) -> u32 {
+  return instance_idx + vert_idx;
+}
+)";
+
+  auto* expect = R"(
+struct tint_symbol {
+  first_vertex_index : u32;
+  first_instance_index : u32;
+}
+
+@binding(1) @group(2) var<uniform> tint_symbol_1 : tint_symbol;
+
+@stage(vertex)
+fn entry(inputs : Inputs) -> @builtin(position) vec4<f32> {
+  test((inputs.instance_idx + tint_symbol_1.first_instance_index), (inputs.vert_idx + tint_symbol_1.first_vertex_index));
+  return vec4<f32>();
+}
+
+struct Inputs {
+  @builtin(instance_index)
+  instance_idx : u32;
+  @builtin(vertex_index)
+  vert_idx : u32;
+}
+
+fn test(instance_idx : u32, vert_idx : u32) -> u32 {
+  return (instance_idx + vert_idx);
+}
+)";
+
+  DataMap config;
+  config.Add<FirstIndexOffset::BindingPoint>(1, 2);
+  auto got = Run<FirstIndexOffset>(src, std::move(config));
+
+  EXPECT_EQ(expect, str(got));
+
+  auto* data = got.data.Get<FirstIndexOffset::Data>();
+
+  ASSERT_NE(data, nullptr);
+  EXPECT_EQ(data->has_vertex_index, true);
+  EXPECT_EQ(data->has_instance_index, true);
+  EXPECT_EQ(data->first_vertex_offset, 0u);
+  EXPECT_EQ(data->first_instance_offset, 4u);
+}
+
 TEST_F(FirstIndexOffsetTest, NestedCalls) {
   auto* src = R"(
 fn func1(vert_idx : u32) -> u32 {
@@ -298,6 +449,60 @@
   EXPECT_EQ(data->first_instance_offset, 0u);
 }
 
+TEST_F(FirstIndexOffsetTest, NestedCalls_OutOfOrder) {
+  auto* src = R"(
+@stage(vertex)
+fn entry(@builtin(vertex_index) vert_idx : u32) -> @builtin(position) vec4<f32> {
+  func2(vert_idx);
+  return vec4<f32>();
+}
+
+fn func2(vert_idx : u32) -> u32 {
+  return func1(vert_idx);
+}
+
+fn func1(vert_idx : u32) -> u32 {
+  return vert_idx;
+}
+)";
+
+  auto* expect = R"(
+struct tint_symbol {
+  first_vertex_index : u32;
+}
+
+@binding(1) @group(2) var<uniform> tint_symbol_1 : tint_symbol;
+
+@stage(vertex)
+fn entry(@builtin(vertex_index) vert_idx : u32) -> @builtin(position) vec4<f32> {
+  func2((vert_idx + tint_symbol_1.first_vertex_index));
+  return vec4<f32>();
+}
+
+fn func2(vert_idx : u32) -> u32 {
+  return func1(vert_idx);
+}
+
+fn func1(vert_idx : u32) -> u32 {
+  return vert_idx;
+}
+)";
+
+  DataMap config;
+  config.Add<FirstIndexOffset::BindingPoint>(1, 2);
+  auto got = Run<FirstIndexOffset>(src, std::move(config));
+
+  EXPECT_EQ(expect, str(got));
+
+  auto* data = got.data.Get<FirstIndexOffset::Data>();
+
+  ASSERT_NE(data, nullptr);
+  EXPECT_EQ(data->has_vertex_index, true);
+  EXPECT_EQ(data->has_instance_index, false);
+  EXPECT_EQ(data->first_vertex_offset, 0u);
+  EXPECT_EQ(data->first_instance_offset, 0u);
+}
+
 TEST_F(FirstIndexOffsetTest, MultipleEntryPoints) {
   auto* src = R"(
 fn func(i : u32) -> u32 {
@@ -369,6 +574,77 @@
   EXPECT_EQ(data->first_instance_offset, 4u);
 }
 
+TEST_F(FirstIndexOffsetTest, MultipleEntryPoints_OutOfOrder) {
+  auto* src = R"(
+@stage(vertex)
+fn entry_a(@builtin(vertex_index) vert_idx : u32) -> @builtin(position) vec4<f32> {
+  func(vert_idx);
+  return vec4<f32>();
+}
+
+@stage(vertex)
+fn entry_b(@builtin(vertex_index) vert_idx : u32, @builtin(instance_index) inst_idx : u32) -> @builtin(position) vec4<f32> {
+  func(vert_idx + inst_idx);
+  return vec4<f32>();
+}
+
+@stage(vertex)
+fn entry_c(@builtin(instance_index) inst_idx : u32) -> @builtin(position) vec4<f32> {
+  func(inst_idx);
+  return vec4<f32>();
+}
+
+fn func(i : u32) -> u32 {
+  return i;
+}
+)";
+
+  auto* expect = R"(
+struct tint_symbol {
+  first_vertex_index : u32;
+  first_instance_index : u32;
+}
+
+@binding(1) @group(2) var<uniform> tint_symbol_1 : tint_symbol;
+
+@stage(vertex)
+fn entry_a(@builtin(vertex_index) vert_idx : u32) -> @builtin(position) vec4<f32> {
+  func((vert_idx + tint_symbol_1.first_vertex_index));
+  return vec4<f32>();
+}
+
+@stage(vertex)
+fn entry_b(@builtin(vertex_index) vert_idx : u32, @builtin(instance_index) inst_idx : u32) -> @builtin(position) vec4<f32> {
+  func(((vert_idx + tint_symbol_1.first_vertex_index) + (inst_idx + tint_symbol_1.first_instance_index)));
+  return vec4<f32>();
+}
+
+@stage(vertex)
+fn entry_c(@builtin(instance_index) inst_idx : u32) -> @builtin(position) vec4<f32> {
+  func((inst_idx + tint_symbol_1.first_instance_index));
+  return vec4<f32>();
+}
+
+fn func(i : u32) -> u32 {
+  return i;
+}
+)";
+
+  DataMap config;
+  config.Add<FirstIndexOffset::BindingPoint>(1, 2);
+  auto got = Run<FirstIndexOffset>(src, std::move(config));
+
+  EXPECT_EQ(expect, str(got));
+
+  auto* data = got.data.Get<FirstIndexOffset::Data>();
+
+  ASSERT_NE(data, nullptr);
+  EXPECT_EQ(data->has_vertex_index, true);
+  EXPECT_EQ(data->has_instance_index, true);
+  EXPECT_EQ(data->first_vertex_offset, 0u);
+  EXPECT_EQ(data->first_instance_offset, 4u);
+}
+
 }  // namespace
 }  // namespace transform
 }  // namespace tint
diff --git a/src/transform/fold_trivial_single_use_lets_test.cc b/src/transform/fold_trivial_single_use_lets_test.cc
index 42aae29..32109c6 100644
--- a/src/transform/fold_trivial_single_use_lets_test.cc
+++ b/src/transform/fold_trivial_single_use_lets_test.cc
@@ -112,6 +112,26 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(FoldTrivialSingleUseLetsTest, NoFold_NonTrivialLet_OutOfOrder) {
+  auto* src = R"(
+fn f() {
+  let x = 1;
+  let y = function_with_posssible_side_effect();
+  _ = (x + y);
+}
+
+fn function_with_posssible_side_effect() -> i32 {
+  return 1;
+}
+)";
+
+  auto* expect = src;
+
+  auto got = Run<FoldTrivialSingleUseLets>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(FoldTrivialSingleUseLetsTest, NoFold_UseInSubBlock) {
   auto* src = R"(
 fn f() {
diff --git a/src/transform/localize_struct_array_assignment_test.cc b/src/transform/localize_struct_array_assignment_test.cc
index 0147d8e..7d92ba6 100644
--- a/src/transform/localize_struct_array_assignment_test.cc
+++ b/src/transform/localize_struct_array_assignment_test.cc
@@ -90,6 +90,64 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(LocalizeStructArrayAssignmentTest, StructArray_OutOfOrder) {
+  auto* src = R"(
+@stage(compute) @workgroup_size(1)
+fn main() {
+  var v : InnerS;
+  var s1 : OuterS;
+  s1.a1[uniforms.i] = v;
+}
+
+@group(1) @binding(4) var<uniform> uniforms : Uniforms;
+
+struct OuterS {
+  a1 : array<InnerS, 8>;
+};
+
+struct InnerS {
+  v : i32;
+};
+
+@block struct Uniforms {
+  i : u32;
+};
+)";
+
+  auto* expect = R"(
+@stage(compute) @workgroup_size(1)
+fn main() {
+  var v : InnerS;
+  var s1 : OuterS;
+  {
+    let tint_symbol = &(s1.a1);
+    var tint_symbol_1 = *(tint_symbol);
+    tint_symbol_1[uniforms.i] = v;
+    *(tint_symbol) = tint_symbol_1;
+  }
+}
+
+@group(1) @binding(4) var<uniform> uniforms : Uniforms;
+
+struct OuterS {
+  a1 : array<InnerS, 8>;
+}
+
+struct InnerS {
+  v : i32;
+}
+
+@block
+struct Uniforms {
+  i : u32;
+}
+)";
+
+  auto got =
+      Run<Unshadow, SimplifyPointers, LocalizeStructArrayAssignment>(src);
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(LocalizeStructArrayAssignmentTest, StructStructArray) {
   auto* src = R"(
 @block struct Uniforms {
@@ -156,6 +214,72 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(LocalizeStructArrayAssignmentTest, StructStructArray_OutOfOrder) {
+  auto* src = R"(
+@stage(compute) @workgroup_size(1)
+fn main() {
+  var v : InnerS;
+  var s1 : OuterS;
+  s1.s2.a[uniforms.i] = v;
+}
+
+@group(1) @binding(4) var<uniform> uniforms : Uniforms;
+
+struct OuterS {
+  s2 : S1;
+};
+
+struct S1 {
+  a : array<InnerS, 8>;
+};
+
+struct InnerS {
+  v : i32;
+};
+
+@block struct Uniforms {
+  i : u32;
+};
+)";
+
+  auto* expect = R"(
+@stage(compute) @workgroup_size(1)
+fn main() {
+  var v : InnerS;
+  var s1 : OuterS;
+  {
+    let tint_symbol = &(s1.s2.a);
+    var tint_symbol_1 = *(tint_symbol);
+    tint_symbol_1[uniforms.i] = v;
+    *(tint_symbol) = tint_symbol_1;
+  }
+}
+
+@group(1) @binding(4) var<uniform> uniforms : Uniforms;
+
+struct OuterS {
+  s2 : S1;
+}
+
+struct S1 {
+  a : array<InnerS, 8>;
+}
+
+struct InnerS {
+  v : i32;
+}
+
+@block
+struct Uniforms {
+  i : u32;
+}
+)";
+
+  auto got =
+      Run<Unshadow, SimplifyPointers, LocalizeStructArrayAssignment>(src);
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(LocalizeStructArrayAssignmentTest, StructArrayArray) {
   auto* src = R"(
 @block struct Uniforms {
@@ -437,6 +561,91 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(LocalizeStructArrayAssignmentTest,
+       IndexingWithSideEffectFunc_OutOfOrder) {
+  auto* src = R"(
+@stage(compute) @workgroup_size(1)
+fn main() {
+  var v : InnerS;
+  var s : OuterS;
+  s.a1[getNextIndex()].a2[uniforms.j] = v;
+}
+
+@group(1) @binding(4) var<uniform> uniforms : Uniforms;
+
+@block struct Uniforms {
+  i : u32;
+  j : u32;
+};
+
+var<private> nextIndex : u32;
+fn getNextIndex() -> u32 {
+  nextIndex = nextIndex + 1u;
+  return nextIndex;
+}
+
+struct OuterS {
+  a1 : array<S1, 8>;
+};
+
+struct S1 {
+  a2 : array<InnerS, 8>;
+};
+
+struct InnerS {
+  v : i32;
+};
+)";
+
+  auto* expect = R"(
+@stage(compute) @workgroup_size(1)
+fn main() {
+  var v : InnerS;
+  var s : OuterS;
+  {
+    let tint_symbol = &(s.a1);
+    var tint_symbol_1 = *(tint_symbol);
+    let tint_symbol_2 = &(tint_symbol_1[getNextIndex()].a2);
+    var tint_symbol_3 = *(tint_symbol_2);
+    tint_symbol_3[uniforms.j] = v;
+    *(tint_symbol_2) = tint_symbol_3;
+    *(tint_symbol) = tint_symbol_1;
+  }
+}
+
+@group(1) @binding(4) var<uniform> uniforms : Uniforms;
+
+@block
+struct Uniforms {
+  i : u32;
+  j : u32;
+}
+
+var<private> nextIndex : u32;
+
+fn getNextIndex() -> u32 {
+  nextIndex = (nextIndex + 1u);
+  return nextIndex;
+}
+
+struct OuterS {
+  a1 : array<S1, 8>;
+}
+
+struct S1 {
+  a2 : array<InnerS, 8>;
+}
+
+struct InnerS {
+  v : i32;
+}
+)";
+
+  auto got =
+      Run<Unshadow, SimplifyPointers, LocalizeStructArrayAssignment>(src);
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(LocalizeStructArrayAssignmentTest, ViaPointerArg) {
   auto* src = R"(
 @block struct Uniforms {
@@ -500,6 +709,71 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(LocalizeStructArrayAssignmentTest, ViaPointerArg_OutOfOrder) {
+  auto* src = R"(
+@stage(compute) @workgroup_size(1)
+fn main() {
+  var s1 : OuterS;
+  f(&s1);
+}
+
+fn f(p : ptr<function, OuterS>) {
+  var v : InnerS;
+  (*p).a1[uniforms.i] = v;
+}
+
+struct InnerS {
+  v : i32;
+};
+struct OuterS {
+  a1 : array<InnerS, 8>;
+};
+
+@group(1) @binding(4) var<uniform> uniforms : Uniforms;
+
+@block struct Uniforms {
+  i : u32;
+};
+)";
+
+  auto* expect = R"(
+@stage(compute) @workgroup_size(1)
+fn main() {
+  var s1 : OuterS;
+  f(&(s1));
+}
+
+fn f(p : ptr<function, OuterS>) {
+  var v : InnerS;
+  {
+    let tint_symbol = &((*(p)).a1);
+    var tint_symbol_1 = *(tint_symbol);
+    tint_symbol_1[uniforms.i] = v;
+    *(tint_symbol) = tint_symbol_1;
+  }
+}
+
+struct InnerS {
+  v : i32;
+}
+
+struct OuterS {
+  a1 : array<InnerS, 8>;
+}
+
+@group(1) @binding(4) var<uniform> uniforms : Uniforms;
+
+@block
+struct Uniforms {
+  i : u32;
+}
+)";
+
+  auto got =
+      Run<Unshadow, SimplifyPointers, LocalizeStructArrayAssignment>(src);
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(LocalizeStructArrayAssignmentTest, ViaPointerVar) {
   auto* src = R"(
 @block
diff --git a/src/transform/module_scope_var_to_entry_point_param_test.cc b/src/transform/module_scope_var_to_entry_point_param_test.cc
index 52967a7..0a0d761 100644
--- a/src/transform/module_scope_var_to_entry_point_param_test.cc
+++ b/src/transform/module_scope_var_to_entry_point_param_test.cc
@@ -63,6 +63,31 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(ModuleScopeVarToEntryPointParamTest, Basic_OutOfOrder) {
+  auto* src = R"(
+@stage(compute) @workgroup_size(1)
+fn main() {
+  w = p;
+}
+
+var<workgroup> w : f32;
+var<private> p : f32;
+)";
+
+  auto* expect = R"(
+@stage(compute) @workgroup_size(1)
+fn main() {
+  @internal(disable_validation__ignore_storage_class) var<workgroup> tint_symbol : f32;
+  @internal(disable_validation__ignore_storage_class) var<private> tint_symbol_1 : f32;
+  tint_symbol = tint_symbol_1;
+}
+)";
+
+  auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(ModuleScopeVarToEntryPointParamTest, FunctionCalls) {
   auto* src = R"(
 var<private> p : f32;
@@ -116,6 +141,59 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(ModuleScopeVarToEntryPointParamTest, FunctionCalls_OutOfOrder) {
+  auto* src = R"(
+@stage(compute) @workgroup_size(1)
+fn main() {
+  foo(1.0);
+}
+
+fn foo(a : f32) {
+  let b : f32 = 2.0;
+  bar(a, b);
+  no_uses();
+}
+
+fn no_uses() {
+}
+
+fn bar(a : f32, b : f32) {
+  p = a;
+  w = b;
+}
+
+var<private> p : f32;
+var<workgroup> w : f32;
+)";
+
+  auto* expect = R"(
+@stage(compute) @workgroup_size(1)
+fn main() {
+  @internal(disable_validation__ignore_storage_class) var<private> tint_symbol : f32;
+  @internal(disable_validation__ignore_storage_class) var<workgroup> tint_symbol_1 : f32;
+  foo(1.0, &(tint_symbol), &(tint_symbol_1));
+}
+
+fn foo(a : f32, @internal(disable_validation__ignore_storage_class) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol_2 : ptr<private, f32>, @internal(disable_validation__ignore_storage_class) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol_3 : ptr<workgroup, f32>) {
+  let b : f32 = 2.0;
+  bar(a, b, tint_symbol_2, tint_symbol_3);
+  no_uses();
+}
+
+fn no_uses() {
+}
+
+fn bar(a : f32, b : f32, @internal(disable_validation__ignore_storage_class) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol_4 : ptr<private, f32>, @internal(disable_validation__ignore_storage_class) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol_5 : ptr<workgroup, f32>) {
+  *(tint_symbol_4) = a;
+  *(tint_symbol_5) = b;
+}
+)";
+
+  auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(ModuleScopeVarToEntryPointParamTest, Constructors) {
   auto* src = R"(
 var<private> a : f32 = 1.0;
@@ -141,6 +219,31 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(ModuleScopeVarToEntryPointParamTest, Constructors_OutOfOrder) {
+  auto* src = R"(
+@stage(compute) @workgroup_size(1)
+fn main() {
+  let x : f32 = a + b;
+}
+
+var<private> b : f32 = f32();
+var<private> a : f32 = 1.0;
+)";
+
+  auto* expect = R"(
+@stage(compute) @workgroup_size(1)
+fn main() {
+  @internal(disable_validation__ignore_storage_class) var<private> tint_symbol : f32 = 1.0;
+  @internal(disable_validation__ignore_storage_class) var<private> tint_symbol_1 : f32 = f32();
+  let x : f32 = (tint_symbol + tint_symbol_1);
+}
+)";
+
+  auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(ModuleScopeVarToEntryPointParamTest, Pointers) {
   auto* src = R"(
 var<private> p : f32;
@@ -172,6 +275,37 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(ModuleScopeVarToEntryPointParamTest, Pointers_OutOfOrder) {
+  auto* src = R"(
+@stage(compute) @workgroup_size(1)
+fn main() {
+  let p_ptr : ptr<private, f32> = &p;
+  let w_ptr : ptr<workgroup, f32> = &w;
+  let x : f32 = *p_ptr + *w_ptr;
+  *p_ptr = x;
+}
+
+var<workgroup> w : f32;
+var<private> p : f32;
+)";
+
+  auto* expect = R"(
+@stage(compute) @workgroup_size(1)
+fn main() {
+  @internal(disable_validation__ignore_storage_class) var<private> tint_symbol : f32;
+  @internal(disable_validation__ignore_storage_class) var<workgroup> tint_symbol_1 : f32;
+  let p_ptr : ptr<private, f32> = &(tint_symbol);
+  let w_ptr : ptr<workgroup, f32> = &(tint_symbol_1);
+  let x : f32 = (*(p_ptr) + *(w_ptr));
+  *(p_ptr) = x;
+}
+)";
+
+  auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(ModuleScopeVarToEntryPointParamTest, FoldAddressOfDeref) {
   auto* src = R"(
 var<private> v : f32;
@@ -211,6 +345,45 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(ModuleScopeVarToEntryPointParamTest, FoldAddressOfDeref_OutOfOrder) {
+  auto* src = R"(
+@stage(compute) @workgroup_size(1)
+fn main() {
+  foo();
+}
+
+fn foo() {
+  bar(&v);
+}
+
+fn bar(p : ptr<private, f32>) {
+  (*p) = 0.0;
+}
+
+var<private> v : f32;
+)";
+
+  auto* expect = R"(
+@stage(compute) @workgroup_size(1)
+fn main() {
+  @internal(disable_validation__ignore_storage_class) var<private> tint_symbol : f32;
+  foo(&(tint_symbol));
+}
+
+fn foo(@internal(disable_validation__ignore_storage_class) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol_1 : ptr<private, f32>) {
+  bar(tint_symbol_1);
+}
+
+fn bar(p : ptr<private, f32>) {
+  *(p) = 0.0;
+}
+)";
+
+  auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(ModuleScopeVarToEntryPointParamTest, Buffers_Basic) {
   auto* src = R"(
 struct S {
@@ -246,6 +419,40 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(ModuleScopeVarToEntryPointParamTest, Buffers_Basic_OutOfOrder) {
+  auto* src = R"(
+@stage(compute) @workgroup_size(1)
+fn main() {
+  _ = u;
+  _ = s;
+}
+
+@group(0) @binding(0) var<uniform> u : S;
+@group(0) @binding(1) var<storage> s : S;
+
+struct S {
+  a : f32;
+};
+
+)";
+
+  auto* expect = R"(
+@stage(compute) @workgroup_size(1)
+fn main(@group(0) @binding(0) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_storage_class) tint_symbol : ptr<uniform, S>, @group(0) @binding(1) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_storage_class) tint_symbol_1 : ptr<storage, S>) {
+  _ = *(tint_symbol);
+  _ = *(tint_symbol_1);
+}
+
+struct S {
+  a : f32;
+}
+)";
+
+  auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(ModuleScopeVarToEntryPointParamTest, Buffer_RuntimeArray) {
   auto* src = R"(
 @group(0) @binding(0)
@@ -273,6 +480,33 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(ModuleScopeVarToEntryPointParamTest, Buffer_RuntimeArray_OutOfOrder) {
+  auto* src = R"(
+@stage(compute) @workgroup_size(1)
+fn main() {
+  _ = buffer[0];
+}
+
+@group(0) @binding(0)
+var<storage> buffer : array<f32>;
+)";
+
+  auto* expect = R"(
+struct tint_symbol_1 {
+  arr : array<f32>;
+}
+
+@stage(compute) @workgroup_size(1)
+fn main(@group(0) @binding(0) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_storage_class) tint_symbol : ptr<storage, tint_symbol_1>) {
+  _ = (*(tint_symbol)).arr[0];
+}
+)";
+
+  auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(ModuleScopeVarToEntryPointParamTest, Buffer_RuntimeArrayInsideFunction) {
   auto* src = R"(
 @group(0) @binding(0)
@@ -308,6 +542,41 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(ModuleScopeVarToEntryPointParamTest,
+       Buffer_RuntimeArrayInsideFunction_OutOfOrder) {
+  auto* src = R"(
+@stage(compute) @workgroup_size(1)
+fn main() {
+  foo();
+}
+
+fn foo() {
+  _ = buffer[0];
+}
+
+@group(0) @binding(0) var<storage> buffer : array<f32>;
+)";
+
+  auto* expect = R"(
+struct tint_symbol_1 {
+  arr : array<f32>;
+}
+
+@stage(compute) @workgroup_size(1)
+fn main(@group(0) @binding(0) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_storage_class) tint_symbol : ptr<storage, tint_symbol_1>) {
+  foo(&((*(tint_symbol)).arr));
+}
+
+fn foo(@internal(disable_validation__ignore_storage_class) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol_2 : ptr<storage, array<f32>>) {
+  _ = (*(tint_symbol_2))[0];
+}
+)";
+
+  auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(ModuleScopeVarToEntryPointParamTest, Buffer_RuntimeArray_Alias) {
   auto* src = R"(
 type myarray = array<f32>;
@@ -339,6 +608,37 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(ModuleScopeVarToEntryPointParamTest,
+       Buffer_RuntimeArray_Alias_OutOfOrder) {
+  auto* src = R"(
+@stage(compute) @workgroup_size(1)
+fn main() {
+  _ = buffer[0];
+}
+
+@group(0) @binding(0) var<storage> buffer : myarray;
+
+type myarray = array<f32>;
+)";
+
+  auto* expect = R"(
+struct tint_symbol_1 {
+  arr : array<f32>;
+}
+
+@stage(compute) @workgroup_size(1)
+fn main(@group(0) @binding(0) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_storage_class) tint_symbol : ptr<storage, tint_symbol_1>) {
+  _ = (*(tint_symbol)).arr[0];
+}
+
+type myarray = array<f32>;
+)";
+
+  auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(ModuleScopeVarToEntryPointParamTest, Buffer_ArrayOfStruct) {
   auto* src = R"(
 struct S {
@@ -374,6 +674,40 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(ModuleScopeVarToEntryPointParamTest, Buffer_ArrayOfStruct_OutOfOrder) {
+  auto* src = R"(
+@stage(compute) @workgroup_size(1)
+fn main() {
+  _ = buffer[0];
+}
+
+@group(0) @binding(0) var<storage> buffer : array<S>;
+
+struct S {
+  f : f32;
+};
+)";
+
+  auto* expect = R"(
+struct S {
+  f : f32;
+}
+
+struct tint_symbol_1 {
+  arr : array<S>;
+}
+
+@stage(compute) @workgroup_size(1)
+fn main(@group(0) @binding(0) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_storage_class) tint_symbol : ptr<storage, tint_symbol_1>) {
+  _ = (*(tint_symbol)).arr[0];
+}
+)";
+
+  auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(ModuleScopeVarToEntryPointParamTest, Buffers_FunctionCalls) {
   auto* src = R"(
 struct S {
@@ -437,6 +771,69 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(ModuleScopeVarToEntryPointParamTest, Buffers_FunctionCalls_OutOfOrder) {
+  auto* src = R"(
+@stage(compute) @workgroup_size(1)
+fn main() {
+  foo(1.0);
+}
+
+fn foo(a : f32) {
+  let b : f32 = 2.0;
+  _ = u;
+  bar(a, b);
+  no_uses();
+}
+
+fn no_uses() {
+}
+
+fn bar(a : f32, b : f32) {
+  _ = u;
+  _ = s;
+}
+
+struct S {
+  a : f32;
+};
+
+@group(0) @binding(0)
+var<uniform> u : S;
+@group(0) @binding(1)
+var<storage> s : S;
+)";
+
+  auto* expect = R"(
+@stage(compute) @workgroup_size(1)
+fn main(@group(0) @binding(0) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_storage_class) tint_symbol : ptr<uniform, S>, @group(0) @binding(1) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_storage_class) tint_symbol_1 : ptr<storage, S>) {
+  foo(1.0, tint_symbol, tint_symbol_1);
+}
+
+fn foo(a : f32, @internal(disable_validation__ignore_storage_class) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol_2 : ptr<uniform, S>, @internal(disable_validation__ignore_storage_class) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol_3 : ptr<storage, S>) {
+  let b : f32 = 2.0;
+  _ = *(tint_symbol_2);
+  bar(a, b, tint_symbol_2, tint_symbol_3);
+  no_uses();
+}
+
+fn no_uses() {
+}
+
+fn bar(a : f32, b : f32, @internal(disable_validation__ignore_storage_class) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol_4 : ptr<uniform, S>, @internal(disable_validation__ignore_storage_class) @internal(disable_validation__ignore_invalid_pointer_argument) tint_symbol_5 : ptr<storage, S>) {
+  _ = *(tint_symbol_4);
+  _ = *(tint_symbol_5);
+}
+
+struct S {
+  a : f32;
+}
+)";
+
+  auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(ModuleScopeVarToEntryPointParamTest, HandleTypes_Basic) {
   auto* src = R"(
 @group(0) @binding(0) var t : texture_2d<f32>;
@@ -515,6 +912,60 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(ModuleScopeVarToEntryPointParamTest,
+       HandleTypes_FunctionCalls_OutOfOrder) {
+  auto* src = R"(
+@stage(compute) @workgroup_size(1)
+fn main() {
+  foo(1.0);
+}
+
+fn foo(a : f32) {
+  let b : f32 = 2.0;
+  _ = t;
+  bar(a, b);
+  no_uses();
+}
+
+fn no_uses() {
+}
+
+fn bar(a : f32, b : f32) {
+  _ = t;
+  _ = s;
+}
+
+@group(0) @binding(0) var t : texture_2d<f32>;
+@group(0) @binding(1) var s : sampler;
+)";
+
+  auto* expect = R"(
+@stage(compute) @workgroup_size(1)
+fn main(@group(0) @binding(0) @internal(disable_validation__entry_point_parameter) tint_symbol : texture_2d<f32>, @group(0) @binding(1) @internal(disable_validation__entry_point_parameter) tint_symbol_1 : sampler) {
+  foo(1.0, tint_symbol, tint_symbol_1);
+}
+
+fn foo(a : f32, tint_symbol_2 : texture_2d<f32>, tint_symbol_3 : sampler) {
+  let b : f32 = 2.0;
+  _ = tint_symbol_2;
+  bar(a, b, tint_symbol_2, tint_symbol_3);
+  no_uses();
+}
+
+fn no_uses() {
+}
+
+fn bar(a : f32, b : f32, tint_symbol_4 : texture_2d<f32>, tint_symbol_5 : sampler) {
+  _ = tint_symbol_4;
+  _ = tint_symbol_5;
+}
+)";
+
+  auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(ModuleScopeVarToEntryPointParamTest, Matrix) {
   auto* src = R"(
 var<workgroup> m : mat2x2<f32>;
@@ -626,6 +1077,49 @@
   EXPECT_EQ(expect, str(got));
 }
 
+// Test that we do not duplicate a struct type used by multiple workgroup
+// variables that are promoted to threadgroup memory arguments.
+TEST_F(ModuleScopeVarToEntryPointParamTest,
+       DuplicateThreadgroupArgumentTypes_OutOfOrder) {
+  auto* src = R"(
+@stage(compute) @workgroup_size(1)
+fn main() {
+  let x = a;
+  let y = b;
+}
+
+var<workgroup> a : S;
+var<workgroup> b : S;
+
+struct S {
+  m : mat2x2<f32>;
+};
+)";
+
+  auto* expect = R"(
+struct S {
+  m : mat2x2<f32>;
+}
+
+struct tint_symbol_3 {
+  a : S;
+  b : S;
+}
+
+@stage(compute) @workgroup_size(1)
+fn main(@internal(disable_validation__entry_point_parameter) tint_symbol_1 : ptr<workgroup, tint_symbol_3>) {
+  let tint_symbol : ptr<workgroup, S> = &((*(tint_symbol_1)).a);
+  let tint_symbol_2 : ptr<workgroup, S> = &((*(tint_symbol_1)).b);
+  let x = *(tint_symbol);
+  let y = *(tint_symbol_2);
+}
+)";
+
+  auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(ModuleScopeVarToEntryPointParamTest, UnusedVariables) {
   auto* src = R"(
 struct S {
diff --git a/src/transform/multiplanar_external_texture_test.cc b/src/transform/multiplanar_external_texture_test.cc
index a0a42b8..8a43308 100644
--- a/src/transform/multiplanar_external_texture_test.cc
+++ b/src/transform/multiplanar_external_texture_test.cc
@@ -136,6 +136,49 @@
   EXPECT_EQ(expect, str(got));
 }
 
+// Tests that the transform works with a textureDimensions call.
+TEST_F(MultiplanarExternalTextureTest, Dimensions_OutOfOrder) {
+  auto* src = R"(
+@stage(fragment)
+fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
+  var dim : vec2<i32>;
+  dim = textureDimensions(ext_tex);
+  return vec4<f32>(0.0, 0.0, 0.0, 0.0);
+}
+
+@group(0) @binding(0) var ext_tex : texture_external;
+)";
+
+  auto* expect = R"(
+struct ExternalTextureParams {
+  numPlanes : u32;
+  vr : f32;
+  ug : f32;
+  vg : f32;
+  ub : f32;
+}
+
+@group(0) @binding(1) var ext_tex_plane_1 : texture_2d<f32>;
+
+@group(0) @binding(2) var<uniform> ext_tex_params : ExternalTextureParams;
+
+@stage(fragment)
+fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
+  var dim : vec2<i32>;
+  dim = textureDimensions(ext_tex);
+  return vec4<f32>(0.0, 0.0, 0.0, 0.0);
+}
+
+@group(0) @binding(0) var ext_tex : texture_2d<f32>;
+)";
+
+  DataMap data;
+  data.Add<MultiplanarExternalTexture::NewBindingPoints>(
+      MultiplanarExternalTexture::BindingsMap{{{0, 0}, {{0, 1}, {0, 2}}}});
+  auto got = Run<MultiplanarExternalTexture>(src, data);
+  EXPECT_EQ(expect, str(got));
+}
+
 // Test that the transform works with a textureSampleLevel call.
 TEST_F(MultiplanarExternalTextureTest, BasicTextureSampleLevel) {
   auto* src = R"(
@@ -192,6 +235,62 @@
   EXPECT_EQ(expect, str(got));
 }
 
+// Test that the transform works with a textureSampleLevel call.
+TEST_F(MultiplanarExternalTextureTest, BasicTextureSampleLevel_OutOfOrder) {
+  auto* src = R"(
+@stage(fragment)
+fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
+  return textureSampleLevel(ext_tex, s, coord.xy);
+}
+
+@group(0) @binding(1) var ext_tex : texture_external;
+@group(0) @binding(0) var s : sampler;
+)";
+
+  auto* expect = R"(
+struct ExternalTextureParams {
+  numPlanes : u32;
+  vr : f32;
+  ug : f32;
+  vg : f32;
+  ub : f32;
+}
+
+@group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
+
+@group(0) @binding(3) var<uniform> ext_tex_params : ExternalTextureParams;
+
+fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
+  if ((params.numPlanes == 1u)) {
+    return textureSampleLevel(plane0, smp, coord, 0.0);
+  }
+  let y = (textureSampleLevel(plane0, smp, coord, 0.0).r - 0.0625);
+  let uv = (textureSampleLevel(plane1, smp, coord, 0.0).rg - 0.5);
+  let u = uv.x;
+  let v = uv.y;
+  let r = ((1.164000034 * y) + (params.vr * v));
+  let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
+  let b = ((1.164000034 * y) + (params.ub * u));
+  return vec4<f32>(r, g, b, 1.0);
+}
+
+@stage(fragment)
+fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
+  return textureSampleExternal(ext_tex, ext_tex_plane_1, s, coord.xy, ext_tex_params);
+}
+
+@group(0) @binding(1) var ext_tex : texture_2d<f32>;
+
+@group(0) @binding(0) var s : sampler;
+)";
+
+  DataMap data;
+  data.Add<MultiplanarExternalTexture::NewBindingPoints>(
+      MultiplanarExternalTexture::BindingsMap{{{0, 1}, {{0, 2}, {0, 3}}}});
+  auto got = Run<MultiplanarExternalTexture>(src, data);
+  EXPECT_EQ(expect, str(got));
+}
+
 // Tests that the transform works with a textureLoad call.
 TEST_F(MultiplanarExternalTextureTest, BasicTextureLoad) {
   auto* src = R"(
@@ -245,6 +344,59 @@
   EXPECT_EQ(expect, str(got));
 }
 
+// Tests that the transform works with a textureLoad call.
+TEST_F(MultiplanarExternalTextureTest, BasicTextureLoad_OutOfOrder) {
+  auto* src = R"(
+@stage(fragment)
+fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
+  return textureLoad(ext_tex, vec2<i32>(1, 1));
+}
+
+@group(0) @binding(0) var ext_tex : texture_external;
+)";
+
+  auto* expect = R"(
+struct ExternalTextureParams {
+  numPlanes : u32;
+  vr : f32;
+  ug : f32;
+  vg : f32;
+  ub : f32;
+}
+
+@group(0) @binding(1) var ext_tex_plane_1 : texture_2d<f32>;
+
+@group(0) @binding(2) var<uniform> ext_tex_params : ExternalTextureParams;
+
+fn textureLoadExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, coord : vec2<i32>, params : ExternalTextureParams) -> vec4<f32> {
+  if ((params.numPlanes == 1u)) {
+    return textureLoad(plane0, coord, 0);
+  }
+  let y = (textureLoad(plane0, coord, 0).r - 0.0625);
+  let uv = (textureLoad(plane1, coord, 0).rg - 0.5);
+  let u = uv.x;
+  let v = uv.y;
+  let r = ((1.164000034 * y) + (params.vr * v));
+  let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
+  let b = ((1.164000034 * y) + (params.ub * u));
+  return vec4<f32>(r, g, b, 1.0);
+}
+
+@stage(fragment)
+fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
+  return textureLoadExternal(ext_tex, ext_tex_plane_1, vec2<i32>(1, 1), ext_tex_params);
+}
+
+@group(0) @binding(0) var ext_tex : texture_2d<f32>;
+)";
+
+  DataMap data;
+  data.Add<MultiplanarExternalTexture::NewBindingPoints>(
+      MultiplanarExternalTexture::BindingsMap{{{0, 0}, {{0, 1}, {0, 2}}}});
+  auto got = Run<MultiplanarExternalTexture>(src, data);
+  EXPECT_EQ(expect, str(got));
+}
+
 // Tests that the transform works with both a textureSampleLevel and textureLoad
 // call.
 TEST_F(MultiplanarExternalTextureTest, TextureSampleAndTextureLoad) {
@@ -316,6 +468,77 @@
   EXPECT_EQ(expect, str(got));
 }
 
+// Tests that the transform works with both a textureSampleLevel and textureLoad
+// call.
+TEST_F(MultiplanarExternalTextureTest, TextureSampleAndTextureLoad_OutOfOrder) {
+  auto* src = R"(
+@stage(fragment)
+fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
+  return textureSampleLevel(ext_tex, s, coord.xy) + textureLoad(ext_tex, vec2<i32>(1, 1));
+}
+
+@group(0) @binding(0) var s : sampler;
+@group(0) @binding(1) var ext_tex : texture_external;
+)";
+
+  auto* expect = R"(
+struct ExternalTextureParams {
+  numPlanes : u32;
+  vr : f32;
+  ug : f32;
+  vg : f32;
+  ub : f32;
+}
+
+@group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
+
+@group(0) @binding(3) var<uniform> ext_tex_params : ExternalTextureParams;
+
+fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
+  if ((params.numPlanes == 1u)) {
+    return textureSampleLevel(plane0, smp, coord, 0.0);
+  }
+  let y = (textureSampleLevel(plane0, smp, coord, 0.0).r - 0.0625);
+  let uv = (textureSampleLevel(plane1, smp, coord, 0.0).rg - 0.5);
+  let u = uv.x;
+  let v = uv.y;
+  let r = ((1.164000034 * y) + (params.vr * v));
+  let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
+  let b = ((1.164000034 * y) + (params.ub * u));
+  return vec4<f32>(r, g, b, 1.0);
+}
+
+fn textureLoadExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, coord : vec2<i32>, params : ExternalTextureParams) -> vec4<f32> {
+  if ((params.numPlanes == 1u)) {
+    return textureLoad(plane0, coord, 0);
+  }
+  let y = (textureLoad(plane0, coord, 0).r - 0.0625);
+  let uv = (textureLoad(plane1, coord, 0).rg - 0.5);
+  let u = uv.x;
+  let v = uv.y;
+  let r = ((1.164000034 * y) + (params.vr * v));
+  let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
+  let b = ((1.164000034 * y) + (params.ub * u));
+  return vec4<f32>(r, g, b, 1.0);
+}
+
+@stage(fragment)
+fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
+  return (textureSampleExternal(ext_tex, ext_tex_plane_1, s, coord.xy, ext_tex_params) + textureLoadExternal(ext_tex, ext_tex_plane_1, vec2<i32>(1, 1), ext_tex_params));
+}
+
+@group(0) @binding(0) var s : sampler;
+
+@group(0) @binding(1) var ext_tex : texture_2d<f32>;
+)";
+
+  DataMap data;
+  data.Add<MultiplanarExternalTexture::NewBindingPoints>(
+      MultiplanarExternalTexture::BindingsMap{{{0, 1}, {{0, 2}, {0, 3}}}});
+  auto got = Run<MultiplanarExternalTexture>(src, data);
+  EXPECT_EQ(expect, str(got));
+}
+
 // Tests that the transform works with many instances of texture_external.
 TEST_F(MultiplanarExternalTextureTest, ManyTextureSampleLevel) {
   auto* src = R"(
@@ -464,6 +687,73 @@
   EXPECT_EQ(expect, str(got));
 }
 
+// Tests that the texture_external passed as a function parameter produces the
+// correct output.
+TEST_F(MultiplanarExternalTextureTest,
+       ExternalTexturePassedAsParam_OutOfOrder) {
+  auto* src = R"(
+@stage(fragment)
+fn main() {
+  f(ext_tex, smp);
+}
+
+fn f(t : texture_external, s : sampler) {
+  textureSampleLevel(t, s, vec2<f32>(1.0, 2.0));
+}
+
+@group(0) @binding(0) var ext_tex : texture_external;
+@group(0) @binding(1) var smp : sampler;
+)";
+
+  auto* expect = R"(
+struct ExternalTextureParams {
+  numPlanes : u32;
+  vr : f32;
+  ug : f32;
+  vg : f32;
+  ub : f32;
+}
+
+@group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
+
+@group(0) @binding(3) var<uniform> ext_tex_params : ExternalTextureParams;
+
+@stage(fragment)
+fn main() {
+  f(ext_tex, ext_tex_plane_1, ext_tex_params, smp);
+}
+
+fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
+  if ((params.numPlanes == 1u)) {
+    return textureSampleLevel(plane0, smp, coord, 0.0);
+  }
+  let y = (textureSampleLevel(plane0, smp, coord, 0.0).r - 0.0625);
+  let uv = (textureSampleLevel(plane1, smp, coord, 0.0).rg - 0.5);
+  let u = uv.x;
+  let v = uv.y;
+  let r = ((1.164000034 * y) + (params.vr * v));
+  let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
+  let b = ((1.164000034 * y) + (params.ub * u));
+  return vec4<f32>(r, g, b, 1.0);
+}
+
+fn f(t : texture_2d<f32>, ext_tex_plane_1_1 : texture_2d<f32>, ext_tex_params_1 : ExternalTextureParams, s : sampler) {
+  textureSampleExternal(t, ext_tex_plane_1_1, s, vec2<f32>(1.0, 2.0), ext_tex_params_1);
+}
+
+@group(0) @binding(0) var ext_tex : texture_2d<f32>;
+
+@group(0) @binding(1) var smp : sampler;
+)";
+  DataMap data;
+  data.Add<MultiplanarExternalTexture::NewBindingPoints>(
+      MultiplanarExternalTexture::BindingsMap{
+          {{0, 0}, {{0, 2}, {0, 3}}},
+      });
+  auto got = Run<MultiplanarExternalTexture>(src, data);
+  EXPECT_EQ(expect, str(got));
+}
+
 // Tests that the texture_external passed as a parameter not in the first
 // position produces the correct output.
 TEST_F(MultiplanarExternalTextureTest, ExternalTexturePassedAsSecondParam) {
@@ -606,6 +896,84 @@
   EXPECT_EQ(expect, str(got));
 }
 
+// Tests that multiple texture_external params passed to a function produces the
+// correct output.
+TEST_F(MultiplanarExternalTextureTest,
+       ExternalTexturePassedAsParamMultiple_OutOfOrder) {
+  auto* src = R"(
+@stage(fragment)
+fn main() {
+  f(ext_tex, smp, ext_tex2);
+}
+
+fn f(t : texture_external, s : sampler, t2 : texture_external) {
+  textureSampleLevel(t, s, vec2<f32>(1.0, 2.0));
+  textureSampleLevel(t2, s, vec2<f32>(1.0, 2.0));
+}
+
+@group(0) @binding(0) var ext_tex : texture_external;
+@group(0) @binding(1) var smp : sampler;
+@group(0) @binding(2) var ext_tex2 : texture_external;
+
+)";
+
+  auto* expect = R"(
+struct ExternalTextureParams {
+  numPlanes : u32;
+  vr : f32;
+  ug : f32;
+  vg : f32;
+  ub : f32;
+}
+
+@group(0) @binding(3) var ext_tex_plane_1 : texture_2d<f32>;
+
+@group(0) @binding(4) var<uniform> ext_tex_params : ExternalTextureParams;
+
+@group(0) @binding(5) var ext_tex_plane_1_1 : texture_2d<f32>;
+
+@group(0) @binding(6) var<uniform> ext_tex_params_1 : ExternalTextureParams;
+
+@stage(fragment)
+fn main() {
+  f(ext_tex, ext_tex_plane_1, ext_tex_params, smp, ext_tex2, ext_tex_plane_1_1, ext_tex_params_1);
+}
+
+fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
+  if ((params.numPlanes == 1u)) {
+    return textureSampleLevel(plane0, smp, coord, 0.0);
+  }
+  let y = (textureSampleLevel(plane0, smp, coord, 0.0).r - 0.0625);
+  let uv = (textureSampleLevel(plane1, smp, coord, 0.0).rg - 0.5);
+  let u = uv.x;
+  let v = uv.y;
+  let r = ((1.164000034 * y) + (params.vr * v));
+  let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
+  let b = ((1.164000034 * y) + (params.ub * u));
+  return vec4<f32>(r, g, b, 1.0);
+}
+
+fn f(t : texture_2d<f32>, ext_tex_plane_1_2 : texture_2d<f32>, ext_tex_params_2 : ExternalTextureParams, s : sampler, t2 : texture_2d<f32>, ext_tex_plane_1_3 : texture_2d<f32>, ext_tex_params_3 : ExternalTextureParams) {
+  textureSampleExternal(t, ext_tex_plane_1_2, s, vec2<f32>(1.0, 2.0), ext_tex_params_2);
+  textureSampleExternal(t2, ext_tex_plane_1_3, s, vec2<f32>(1.0, 2.0), ext_tex_params_3);
+}
+
+@group(0) @binding(0) var ext_tex : texture_2d<f32>;
+
+@group(0) @binding(1) var smp : sampler;
+
+@group(0) @binding(2) var ext_tex2 : texture_2d<f32>;
+)";
+  DataMap data;
+  data.Add<MultiplanarExternalTexture::NewBindingPoints>(
+      MultiplanarExternalTexture::BindingsMap{
+          {{0, 0}, {{0, 3}, {0, 4}}},
+          {{0, 2}, {{0, 5}, {0, 6}}},
+      });
+  auto got = Run<MultiplanarExternalTexture>(src, data);
+  EXPECT_EQ(expect, str(got));
+}
+
 // Tests that the texture_external passed to as a parameter to multiple
 // functions produces the correct output.
 TEST_F(MultiplanarExternalTextureTest, ExternalTexturePassedAsParamNested) {
@@ -680,6 +1048,81 @@
   EXPECT_EQ(expect, str(got));
 }
 
+// Tests that the texture_external passed to as a parameter to multiple
+// functions produces the correct output.
+TEST_F(MultiplanarExternalTextureTest,
+       ExternalTexturePassedAsParamNested_OutOfOrder) {
+  auto* src = R"(
+fn nested(t : texture_external, s : sampler) {
+  textureSampleLevel(t, s, vec2<f32>(1.0, 2.0));
+}
+
+fn f(t : texture_external, s : sampler) {
+  nested(t, s);
+}
+
+@group(0) @binding(0) var ext_tex : texture_external;
+@group(0) @binding(1) var smp : sampler;
+
+@stage(fragment)
+fn main() {
+  f(ext_tex, smp);
+}
+)";
+
+  auto* expect = R"(
+struct ExternalTextureParams {
+  numPlanes : u32;
+  vr : f32;
+  ug : f32;
+  vg : f32;
+  ub : f32;
+}
+
+@group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
+
+@group(0) @binding(3) var<uniform> ext_tex_params : ExternalTextureParams;
+
+fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
+  if ((params.numPlanes == 1u)) {
+    return textureSampleLevel(plane0, smp, coord, 0.0);
+  }
+  let y = (textureSampleLevel(plane0, smp, coord, 0.0).r - 0.0625);
+  let uv = (textureSampleLevel(plane1, smp, coord, 0.0).rg - 0.5);
+  let u = uv.x;
+  let v = uv.y;
+  let r = ((1.164000034 * y) + (params.vr * v));
+  let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
+  let b = ((1.164000034 * y) + (params.ub * u));
+  return vec4<f32>(r, g, b, 1.0);
+}
+
+fn nested(t : texture_2d<f32>, ext_tex_plane_1_1 : texture_2d<f32>, ext_tex_params_1 : ExternalTextureParams, s : sampler) {
+  textureSampleExternal(t, ext_tex_plane_1_1, s, vec2<f32>(1.0, 2.0), ext_tex_params_1);
+}
+
+fn f(t : texture_2d<f32>, ext_tex_plane_1_2 : texture_2d<f32>, ext_tex_params_2 : ExternalTextureParams, s : sampler) {
+  nested(t, ext_tex_plane_1_2, ext_tex_params_2, s);
+}
+
+@group(0) @binding(0) var ext_tex : texture_2d<f32>;
+
+@group(0) @binding(1) var smp : sampler;
+
+@stage(fragment)
+fn main() {
+  f(ext_tex, ext_tex_plane_1, ext_tex_params, smp);
+}
+)";
+  DataMap data;
+  data.Add<MultiplanarExternalTexture::NewBindingPoints>(
+      MultiplanarExternalTexture::BindingsMap{
+          {{0, 0}, {{0, 2}, {0, 3}}},
+      });
+  auto got = Run<MultiplanarExternalTexture>(src, data);
+  EXPECT_EQ(expect, str(got));
+}
+
 // Tests that the transform works with a function using an external texture,
 // even if there's no external texture declared at module scope.
 TEST_F(MultiplanarExternalTextureTest,
@@ -780,6 +1223,75 @@
   EXPECT_EQ(expect, str(got));
 }
 
+// Tests that the the transform handles aliases to external textures
+TEST_F(MultiplanarExternalTextureTest, ExternalTextureAlias_OutOfOrder) {
+  auto* src = R"(
+[[stage(fragment)]]
+fn main() {
+  f(ext_tex, smp);
+}
+
+fn f(t : ET, s : sampler) {
+  textureSampleLevel(t, s, vec2<f32>(1.0, 2.0));
+}
+
+[[group(0), binding(0)]] var ext_tex : ET;
+[[group(0), binding(1)]] var smp : sampler;
+
+type ET = texture_external;
+)";
+
+  auto* expect = R"(
+struct ExternalTextureParams {
+  numPlanes : u32;
+  vr : f32;
+  ug : f32;
+  vg : f32;
+  ub : f32;
+}
+
+@group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
+
+@group(0) @binding(3) var<uniform> ext_tex_params : ExternalTextureParams;
+
+@stage(fragment)
+fn main() {
+  f(ext_tex, ext_tex_plane_1, ext_tex_params, smp);
+}
+
+fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
+  if ((params.numPlanes == 1u)) {
+    return textureSampleLevel(plane0, smp, coord, 0.0);
+  }
+  let y = (textureSampleLevel(plane0, smp, coord, 0.0).r - 0.0625);
+  let uv = (textureSampleLevel(plane1, smp, coord, 0.0).rg - 0.5);
+  let u = uv.x;
+  let v = uv.y;
+  let r = ((1.164000034 * y) + (params.vr * v));
+  let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
+  let b = ((1.164000034 * y) + (params.ub * u));
+  return vec4<f32>(r, g, b, 1.0);
+}
+
+fn f(t : texture_2d<f32>, ext_tex_plane_1_1 : texture_2d<f32>, ext_tex_params_1 : ExternalTextureParams, s : sampler) {
+  textureSampleExternal(t, ext_tex_plane_1_1, s, vec2<f32>(1.0, 2.0), ext_tex_params_1);
+}
+
+@group(0) @binding(0) var ext_tex : texture_2d<f32>;
+
+@group(0) @binding(1) var smp : sampler;
+
+type ET = texture_external;
+)";
+  DataMap data;
+  data.Add<MultiplanarExternalTexture::NewBindingPoints>(
+      MultiplanarExternalTexture::BindingsMap{
+          {{0, 0}, {{0, 2}, {0, 3}}},
+      });
+  auto got = Run<MultiplanarExternalTexture>(src, data);
+  EXPECT_EQ(expect, str(got));
+}
+
 }  // namespace
 }  // namespace transform
 }  // namespace tint
diff --git a/src/transform/num_workgroups_from_uniform_test.cc b/src/transform/num_workgroups_from_uniform_test.cc
index dedee54..8471b03 100644
--- a/src/transform/num_workgroups_from_uniform_test.cc
+++ b/src/transform/num_workgroups_from_uniform_test.cc
@@ -146,6 +146,52 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(NumWorkgroupsFromUniformTest, StructOnlyMember_OutOfOrder) {
+  auto* src = R"(
+@stage(compute) @workgroup_size(1)
+fn main(in : Builtins) {
+  let groups_x = in.num_wgs.x;
+  let groups_y = in.num_wgs.y;
+  let groups_z = in.num_wgs.z;
+}
+
+struct Builtins {
+  @builtin(num_workgroups) num_wgs : vec3<u32>;
+};
+)";
+
+  auto* expect = R"(
+struct tint_symbol_2 {
+  num_workgroups : vec3<u32>;
+}
+
+@group(0) @binding(30) var<uniform> tint_symbol_3 : tint_symbol_2;
+
+fn main_inner(in : Builtins) {
+  let groups_x = in.num_wgs.x;
+  let groups_y = in.num_wgs.y;
+  let groups_z = in.num_wgs.z;
+}
+
+@stage(compute) @workgroup_size(1)
+fn main() {
+  main_inner(Builtins(tint_symbol_3.num_workgroups));
+}
+
+struct Builtins {
+  num_wgs : vec3<u32>;
+}
+)";
+
+  DataMap data;
+  data.Add<CanonicalizeEntryPointIO::Config>(
+      CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
+  data.Add<NumWorkgroupsFromUniform::Config>(sem::BindingPoint{0, 30u});
+  auto got = Run<Unshadow, CanonicalizeEntryPointIO, NumWorkgroupsFromUniform>(
+      src, data);
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(NumWorkgroupsFromUniformTest, StructMultipleMembers) {
   auto* src = R"(
 struct Builtins {
@@ -203,6 +249,64 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(NumWorkgroupsFromUniformTest, StructMultipleMembers_OutOfOrder) {
+  auto* src = R"(
+@stage(compute) @workgroup_size(1)
+fn main(in : Builtins) {
+  let groups_x = in.num_wgs.x;
+  let groups_y = in.num_wgs.y;
+  let groups_z = in.num_wgs.z;
+}
+
+struct Builtins {
+  @builtin(global_invocation_id) gid : vec3<u32>;
+  @builtin(num_workgroups) num_wgs : vec3<u32>;
+  @builtin(workgroup_id) wgid : vec3<u32>;
+};
+
+)";
+
+  auto* expect = R"(
+struct tint_symbol_2 {
+  num_workgroups : vec3<u32>;
+}
+
+@group(0) @binding(30) var<uniform> tint_symbol_3 : tint_symbol_2;
+
+struct tint_symbol_1 {
+  @builtin(global_invocation_id)
+  gid : vec3<u32>;
+  @builtin(workgroup_id)
+  wgid : vec3<u32>;
+}
+
+fn main_inner(in : Builtins) {
+  let groups_x = in.num_wgs.x;
+  let groups_y = in.num_wgs.y;
+  let groups_z = in.num_wgs.z;
+}
+
+@stage(compute) @workgroup_size(1)
+fn main(tint_symbol : tint_symbol_1) {
+  main_inner(Builtins(tint_symbol.gid, tint_symbol_3.num_workgroups, tint_symbol.wgid));
+}
+
+struct Builtins {
+  gid : vec3<u32>;
+  num_wgs : vec3<u32>;
+  wgid : vec3<u32>;
+}
+)";
+
+  DataMap data;
+  data.Add<CanonicalizeEntryPointIO::Config>(
+      CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
+  data.Add<NumWorkgroupsFromUniform::Config>(sem::BindingPoint{0, 30u});
+  auto got = Run<Unshadow, CanonicalizeEntryPointIO, NumWorkgroupsFromUniform>(
+      src, data);
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(NumWorkgroupsFromUniformTest, MultipleEntryPoints) {
   auto* src = R"(
 struct Builtins1 {
diff --git a/src/transform/pad_array_elements_test.cc b/src/transform/pad_array_elements_test.cc
index 5139edc..f3da053 100644
--- a/src/transform/pad_array_elements_test.cc
+++ b/src/transform/pad_array_elements_test.cc
@@ -216,6 +216,42 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(PadArrayElementsTest, ArrayAlias_OutOfOrder) {
+  auto* src = R"(
+fn f() {
+  var arr : Array;
+  arr = Array();
+  arr = Array(1, 2, 3, 4);
+  let vals : Array = Array(1, 2, 3, 4);
+  arr = vals;
+  let x = arr[3];
+}
+
+type Array = @stride(16) array<i32, 4>;
+)";
+  auto* expect = R"(
+struct tint_padded_array_element {
+  @size(16)
+  el : i32;
+}
+
+fn f() {
+  var arr : array<tint_padded_array_element, 4u>;
+  arr = array<tint_padded_array_element, 4u>();
+  arr = array<tint_padded_array_element, 4u>(tint_padded_array_element(1), tint_padded_array_element(2), tint_padded_array_element(3), tint_padded_array_element(4));
+  let vals : array<tint_padded_array_element, 4u> = array<tint_padded_array_element, 4u>(tint_padded_array_element(1), tint_padded_array_element(2), tint_padded_array_element(3), tint_padded_array_element(4));
+  arr = vals;
+  let x = arr[3].el;
+}
+
+type Array = array<tint_padded_array_element, 4u>;
+)";
+
+  auto got = Run<PadArrayElements>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(PadArrayElementsTest, ArraysInStruct) {
   auto* src = R"(
 struct S {
@@ -364,6 +400,65 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(PadArrayElementsTest, AccessArraysOfArraysInStruct_OutOfOrder) {
+  auto* src = R"(
+fn f(s : S) -> i32 {
+  return s.a[2] + s.b[1][2] + s.c[3][1][2];
+}
+
+struct S {
+  a : @stride(512) array<i32, 4>;
+  b : @stride(512) array<@stride(32) array<i32, 4>, 4>;
+  c : @stride(512) array<@stride(64) array<@stride(8) array<i32, 4>, 4>, 4>;
+};
+)";
+  auto* expect = R"(
+struct tint_padded_array_element {
+  @size(512)
+  el : i32;
+}
+
+struct tint_padded_array_element_1 {
+  @size(32)
+  el : i32;
+}
+
+struct tint_padded_array_element_2 {
+  @size(512)
+  el : array<tint_padded_array_element_1, 4u>;
+}
+
+struct tint_padded_array_element_3 {
+  @size(8)
+  el : i32;
+}
+
+struct tint_padded_array_element_4 {
+  @size(64)
+  el : array<tint_padded_array_element_3, 4u>;
+}
+
+struct tint_padded_array_element_5 {
+  @size(512)
+  el : array<tint_padded_array_element_4, 4u>;
+}
+
+fn f(s : S) -> i32 {
+  return ((s.a[2].el + s.b[1].el[2].el) + s.c[3].el[1].el[2].el);
+}
+
+struct S {
+  a : array<tint_padded_array_element, 4u>;
+  b : array<tint_padded_array_element_2, 4u>;
+  c : array<tint_padded_array_element_5, 4u>;
+}
+)";
+
+  auto got = Run<PadArrayElements>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(PadArrayElementsTest, DeclarationOrder) {
   auto* src = R"(
 type T0 = i32;
diff --git a/src/transform/promote_initializers_to_const_var_test.cc b/src/transform/promote_initializers_to_const_var_test.cc
index c9210dd..109615b 100644
--- a/src/transform/promote_initializers_to_const_var_test.cc
+++ b/src/transform/promote_initializers_to_const_var_test.cc
@@ -91,6 +91,38 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(PromoteInitializersToConstVarTest, BasicStruct_OutOfOrder) {
+  auto* src = R"(
+fn f() {
+  var x = S(1, 2.0, vec3<f32>()).b;
+}
+
+struct S {
+  a : i32;
+  b : f32;
+  c : vec3<f32>;
+};
+)";
+
+  auto* expect = R"(
+fn f() {
+  let tint_symbol = S(1, 2.0, vec3<f32>());
+  var x = tint_symbol.b;
+}
+
+struct S {
+  a : i32;
+  b : f32;
+  c : vec3<f32>;
+}
+)";
+
+  DataMap data;
+  auto got = Run<PromoteInitializersToConstVar>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(PromoteInitializersToConstVarTest, ArrayInForLoopInit) {
   auto* src = R"(
 fn f() {
@@ -155,6 +187,44 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(PromoteInitializersToConstVarTest, StructInForLoopInit_OutOfOrder) {
+  auto* src = R"(
+fn f() {
+  var insert_after = 1;
+  for(var x = S(1, 2.0, vec3<f32>()).b; ; ) {
+    break;
+  }
+}
+
+struct S {
+  a : i32;
+  b : f32;
+  c : vec3<f32>;
+};
+)";
+
+  auto* expect = R"(
+fn f() {
+  var insert_after = 1;
+  let tint_symbol = S(1, 2.0, vec3<f32>());
+  for(var x = tint_symbol.b; ; ) {
+    break;
+  }
+}
+
+struct S {
+  a : i32;
+  b : f32;
+  c : vec3<f32>;
+}
+)";
+
+  DataMap data;
+  auto got = Run<PromoteInitializersToConstVar>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(PromoteInitializersToConstVarTest, ArrayInForLoopCond) {
   auto* src = R"(
 fn f() {
@@ -460,6 +530,46 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(PromoteInitializersToConstVarTest, Mixed_OutOfOrder) {
+  auto* src = R"(
+fn f() {
+  var x = S2(array<S1, 3u>(S1(1), S1(2), S1(3))).a[1].a;
+}
+
+struct S2 {
+  a : array<S1, 3u>;
+};
+
+struct S1 {
+  a : i32;
+};
+)";
+
+  auto* expect = R"(
+fn f() {
+  let tint_symbol = S1(1);
+  let tint_symbol_1 = S1(2);
+  let tint_symbol_2 = S1(3);
+  let tint_symbol_3 = array<S1, 3u>(tint_symbol, tint_symbol_1, tint_symbol_2);
+  let tint_symbol_4 = S2(tint_symbol_3);
+  var x = tint_symbol_4.a[1].a;
+}
+
+struct S2 {
+  a : array<S1, 3u>;
+}
+
+struct S1 {
+  a : i32;
+}
+)";
+
+  DataMap data;
+  auto got = Run<PromoteInitializersToConstVar>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(PromoteInitializersToConstVarTest, NoChangeOnVarDecl) {
   auto* src = R"(
 struct S {
@@ -486,6 +596,32 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(PromoteInitializersToConstVarTest, NoChangeOnVarDecl_OutOfOrder) {
+  auto* src = R"(
+fn f() {
+  var local_arr = array<f32, 4u>(0.0, 1.0, 2.0, 3.0);
+  var local_str = S(1, 2.0, 3);
+}
+
+let module_str : S = S(1, 2.0, 3);
+
+struct S {
+  a : i32;
+  b : f32;
+  c : i32;
+}
+
+let module_arr : array<f32, 4u> = array<f32, 4u>(0.0, 1.0, 2.0, 3.0);
+)";
+
+  auto* expect = src;
+
+  DataMap data;
+  auto got = Run<PromoteInitializersToConstVar>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 }  // namespace
 }  // namespace transform
 }  // namespace tint
diff --git a/src/transform/remove_phonies_test.cc b/src/transform/remove_phonies_test.cc
index d073d35..a8fd5ea 100644
--- a/src/transform/remove_phonies_test.cc
+++ b/src/transform/remove_phonies_test.cc
@@ -130,6 +130,54 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(RemovePhoniesTest, SingleSideEffects_OutOfOrder) {
+  auto* src = R"(
+fn f() {
+  _ = neg(1);
+  _ = add(2, 3);
+  _ = add(neg(4), neg(5));
+  _ = u32(neg(6));
+  _ = f32(add(7, 8));
+  _ = vec2<f32>(f32(neg(9)));
+  _ = vec3<i32>(1, neg(10), 3);
+  _ = mat2x2<f32>(1.0, f32(add(11, 12)), 3.0, 4.0);
+}
+
+fn add(a : i32, b : i32) -> i32 {
+  return (a + b);
+}
+
+fn neg(a : i32) -> i32 {
+  return -(a);
+}
+)";
+
+  auto* expect = R"(
+fn f() {
+  neg(1);
+  add(2, 3);
+  add(neg(4), neg(5));
+  neg(6);
+  add(7, 8);
+  neg(9);
+  neg(10);
+  add(11, 12);
+}
+
+fn add(a : i32, b : i32) -> i32 {
+  return (a + b);
+}
+
+fn neg(a : i32) -> i32 {
+  return -(a);
+}
+)";
+
+  auto got = Run<RemovePhonies>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(RemovePhoniesTest, MultipleSideEffects) {
   auto* src = R"(
 fn neg(a : i32) -> i32 {
@@ -187,6 +235,63 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(RemovePhoniesTest, MultipleSideEffects_OutOfOrder) {
+  auto* src = R"(
+fn f() {
+  _ = (1 + add(2 + add(3, 4), 5)) * add(6, 7) * neg(8);
+  _ = add(9, neg(10)) + neg(11);
+  _ = xor(12u, 13u) + xor(14u, 15u);
+  _ = neg(16) / neg(17) + add(18, 19);
+}
+
+fn neg(a : i32) -> i32 {
+  return -(a);
+}
+
+fn add(a : i32, b : i32) -> i32 {
+  return (a + b);
+}
+
+fn xor(a : u32, b : u32) -> u32 {
+  return (a ^ b);
+}
+)";
+
+  auto* expect = R"(
+fn phony_sink(p0 : i32, p1 : i32, p2 : i32) {
+}
+
+fn phony_sink_1(p0 : i32, p1 : i32) {
+}
+
+fn phony_sink_2(p0 : u32, p1 : u32) {
+}
+
+fn f() {
+  phony_sink(add((2 + add(3, 4)), 5), add(6, 7), neg(8));
+  phony_sink_1(add(9, neg(10)), neg(11));
+  phony_sink_2(xor(12u, 13u), xor(14u, 15u));
+  phony_sink(neg(16), neg(17), add(18, 19));
+}
+
+fn neg(a : i32) -> i32 {
+  return -(a);
+}
+
+fn add(a : i32, b : i32) -> i32 {
+  return (a + b);
+}
+
+fn xor(a : u32, b : u32) -> u32 {
+  return (a ^ b);
+}
+)";
+
+  auto got = Run<RemovePhonies>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(RemovePhoniesTest, ForLoop) {
   auto* src = R"(
 struct S {
@@ -254,6 +359,73 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(RemovePhoniesTest, ForLoop_OutOfOrder) {
+  auto* src = R"(
+fn f() {
+  for (_ = &s.arr; ;_ = &s.arr) {
+    break;
+  }
+  for (_ = x(); ;_ = y() + z()) {
+    break;
+  }
+}
+
+fn x() -> i32 {
+  return 0;
+}
+
+fn y() -> i32 {
+  return 0;
+}
+
+fn z() -> i32 {
+  return 0;
+}
+
+struct S {
+  arr : array<i32>;
+};
+
+@group(0) @binding(0) var<storage, read_write> s : S;
+)";
+
+  auto* expect = R"(
+fn phony_sink(p0 : i32, p1 : i32) {
+}
+
+fn f() {
+  for(; ; ) {
+    break;
+  }
+  for(x(); ; phony_sink(y(), z())) {
+    break;
+  }
+}
+
+fn x() -> i32 {
+  return 0;
+}
+
+fn y() -> i32 {
+  return 0;
+}
+
+fn z() -> i32 {
+  return 0;
+}
+
+struct S {
+  arr : array<i32>;
+}
+
+@group(0) @binding(0) var<storage, read_write> s : S;
+)";
+
+  auto got = Run<RemovePhonies>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 }  // namespace
 }  // namespace transform
 }  // namespace tint
diff --git a/src/transform/robustness_test.cc b/src/transform/robustness_test.cc
index 8af6cce..ac422c0 100644
--- a/src/transform/robustness_test.cc
+++ b/src/transform/robustness_test.cc
@@ -48,6 +48,32 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(RobustnessTest, Array_Idx_Clamp_OutOfOrder) {
+  auto* src = R"(
+fn f() {
+  let b : f32 = a[c];
+}
+
+let c : u32 = 1u;
+
+var<private> a : array<f32, 3>;
+)";
+
+  auto* expect = R"(
+fn f() {
+  let b : f32 = a[1u];
+}
+
+let c : u32 = 1u;
+
+var<private> a : array<f32, 3>;
+)";
+
+  auto got = Run<Robustness>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(RobustnessTest, Array_Idx_Nested_Scalar) {
   auto* src = R"(
 var<private> a : array<f32, 3>;
@@ -78,6 +104,36 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(RobustnessTest, Array_Idx_Nested_Scalar_OutOfOrder) {
+  auto* src = R"(
+fn f() {
+  var c : f32 = a[ b[i] ];
+}
+
+var<private> i : u32;
+
+var<private> b : array<i32, 5>;
+
+var<private> a : array<f32, 3>;
+)";
+
+  auto* expect = R"(
+fn f() {
+  var c : f32 = a[min(u32(b[min(i, 4u)]), 2u)];
+}
+
+var<private> i : u32;
+
+var<private> b : array<i32, 5>;
+
+var<private> a : array<f32, 3>;
+)";
+
+  auto got = Run<Robustness>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(RobustnessTest, Array_Idx_Scalar) {
   auto* src = R"(
 var<private> a : array<f32, 3>;
@@ -100,6 +156,28 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(RobustnessTest, Array_Idx_Scalar_OutOfOrder) {
+  auto* src = R"(
+fn f() {
+  var b : f32 = a[1];
+}
+
+var<private> a : array<f32, 3>;
+)";
+
+  auto* expect = R"(
+fn f() {
+  var b : f32 = a[1];
+}
+
+var<private> a : array<f32, 3>;
+)";
+
+  auto got = Run<Robustness>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(RobustnessTest, Array_Idx_Expr) {
   auto* src = R"(
 var<private> a : array<f32, 3>;
@@ -126,6 +204,32 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(RobustnessTest, Array_Idx_Expr_OutOfOrder) {
+  auto* src = R"(
+fn f() {
+  var b : f32 = a[c + 2 - 3];
+}
+
+var<private> c : i32;
+
+var<private> a : array<f32, 3>;
+)";
+
+  auto* expect = R"(
+fn f() {
+  var b : f32 = a[min(u32(((c + 2) - 3)), 2u)];
+}
+
+var<private> c : i32;
+
+var<private> a : array<f32, 3>;
+)";
+
+  auto got = Run<Robustness>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(RobustnessTest, Array_Idx_Negative) {
   auto* src = R"(
 var<private> a : array<f32, 3>;
@@ -148,6 +252,28 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(RobustnessTest, Array_Idx_Negative_OutOfOrder) {
+  auto* src = R"(
+fn f() {
+  var b : f32 = a[-1];
+}
+
+var<private> a : array<f32, 3>;
+)";
+
+  auto* expect = R"(
+fn f() {
+  var b : f32 = a[0];
+}
+
+var<private> a : array<f32, 3>;
+)";
+
+  auto got = Run<Robustness>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(RobustnessTest, Array_Idx_OutOfBounds) {
   auto* src = R"(
 var<private> a : array<f32, 3>;
@@ -170,6 +296,28 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(RobustnessTest, Array_Idx_OutOfBounds_OutOfOrder) {
+  auto* src = R"(
+fn f() {
+  var b : f32 = a[3];
+}
+
+var<private> a : array<f32, 3>;
+)";
+
+  auto* expect = R"(
+fn f() {
+  var b : f32 = a[2];
+}
+
+var<private> a : array<f32, 3>;
+)";
+
+  auto got = Run<Robustness>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 // TODO(crbug.com/tint/1177) - Validation currently forbids arrays larger than
 // 0xffffffff. If WGSL supports 64-bit indexing, re-enable this test.
 TEST_F(RobustnessTest, DISABLED_LargeArrays_Idx) {
@@ -272,6 +420,28 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(RobustnessTest, Vector_Idx_Scalar_OutOfOrder) {
+  auto* src = R"(
+fn f() {
+  var b : f32 = a[1];
+}
+
+var<private> a : vec3<f32>;
+)";
+
+  auto* expect = R"(
+fn f() {
+  var b : f32 = a[1];
+}
+
+var<private> a : vec3<f32>;
+)";
+
+  auto got = Run<Robustness>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(RobustnessTest, Vector_Idx_Expr) {
   auto* src = R"(
 var<private> a : vec3<f32>;
@@ -298,6 +468,32 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(RobustnessTest, Vector_Idx_Expr_OutOfOrder) {
+  auto* src = R"(
+fn f() {
+  var b : f32 = a[c + 2 - 3];
+}
+
+var<private> c : i32;
+
+var<private> a : vec3<f32>;
+)";
+
+  auto* expect = R"(
+fn f() {
+  var b : f32 = a[min(u32(((c + 2) - 3)), 2u)];
+}
+
+var<private> c : i32;
+
+var<private> a : vec3<f32>;
+)";
+
+  auto got = Run<Robustness>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(RobustnessTest, Vector_Swizzle_Idx_Scalar) {
   auto* src = R"(
 var<private> a : vec3<f32>;
@@ -320,6 +516,28 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(RobustnessTest, Vector_Swizzle_Idx_Scalar_OutOfOrder) {
+  auto* src = R"(
+fn f() {
+  var b : f32 = a.xy[2];
+}
+
+var<private> a : vec3<f32>;
+)";
+
+  auto* expect = R"(
+fn f() {
+  var b : f32 = a.xy[1];
+}
+
+var<private> a : vec3<f32>;
+)";
+
+  auto got = Run<Robustness>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(RobustnessTest, Vector_Swizzle_Idx_Var) {
   auto* src = R"(
 var<private> a : vec3<f32>;
@@ -345,6 +563,33 @@
 
   EXPECT_EQ(expect, str(got));
 }
+
+TEST_F(RobustnessTest, Vector_Swizzle_Idx_Var_OutOfOrder) {
+  auto* src = R"(
+fn f() {
+  var b : f32 = a.xy[c];
+}
+
+var<private> c : i32;
+
+var<private> a : vec3<f32>;
+)";
+
+  auto* expect = R"(
+fn f() {
+  var b : f32 = a.xy[min(u32(c), 1u)];
+}
+
+var<private> c : i32;
+
+var<private> a : vec3<f32>;
+)";
+
+  auto got = Run<Robustness>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(RobustnessTest, Vector_Swizzle_Idx_Expr) {
   auto* src = R"(
 var<private> a : vec3<f32>;
@@ -371,6 +616,32 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(RobustnessTest, Vector_Swizzle_Idx_Expr_OutOfOrder) {
+  auto* src = R"(
+fn f() {
+  var b : f32 = a.xy[c + 2 - 3];
+}
+
+var<private> c : i32;
+
+var<private> a : vec3<f32>;
+)";
+
+  auto* expect = R"(
+fn f() {
+  var b : f32 = a.xy[min(u32(((c + 2) - 3)), 1u)];
+}
+
+var<private> c : i32;
+
+var<private> a : vec3<f32>;
+)";
+
+  auto got = Run<Robustness>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(RobustnessTest, Vector_Idx_Negative) {
   auto* src = R"(
 var<private> a : vec3<f32>;
@@ -393,6 +664,28 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(RobustnessTest, Vector_Idx_Negative_OutOfOrder) {
+  auto* src = R"(
+fn f() {
+  var b : f32 = a[-1];
+}
+
+var<private> a : vec3<f32>;
+)";
+
+  auto* expect = R"(
+fn f() {
+  var b : f32 = a[0];
+}
+
+var<private> a : vec3<f32>;
+)";
+
+  auto got = Run<Robustness>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(RobustnessTest, Vector_Idx_OutOfBounds) {
   auto* src = R"(
 var<private> a : vec3<f32>;
@@ -415,6 +708,28 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(RobustnessTest, Vector_Idx_OutOfBounds_OutOfOrder) {
+  auto* src = R"(
+fn f() {
+  var b : f32 = a[3];
+}
+
+var<private> a : vec3<f32>;
+)";
+
+  auto* expect = R"(
+fn f() {
+  var b : f32 = a[2];
+}
+
+var<private> a : vec3<f32>;
+)";
+
+  auto got = Run<Robustness>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(RobustnessTest, Matrix_Idx_Scalar) {
   auto* src = R"(
 var<private> a : mat3x2<f32>;
@@ -437,6 +752,28 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(RobustnessTest, Matrix_Idx_Scalar_OutOfOrder) {
+  auto* src = R"(
+fn f() {
+  var b : f32 = a[2][1];
+}
+
+var<private> a : mat3x2<f32>;
+)";
+
+  auto* expect = R"(
+fn f() {
+  var b : f32 = a[2][1];
+}
+
+var<private> a : mat3x2<f32>;
+)";
+
+  auto got = Run<Robustness>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(RobustnessTest, Matrix_Idx_Expr_Column) {
   auto* src = R"(
 var<private> a : mat3x2<f32>;
@@ -463,6 +800,32 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(RobustnessTest, Matrix_Idx_Expr_Column_OutOfOrder) {
+  auto* src = R"(
+fn f() {
+  var b : f32 = a[c + 2 - 3][1];
+}
+
+var<private> c : i32;
+
+var<private> a : mat3x2<f32>;
+)";
+
+  auto* expect = R"(
+fn f() {
+  var b : f32 = a[min(u32(((c + 2) - 3)), 2u)][1];
+}
+
+var<private> c : i32;
+
+var<private> a : mat3x2<f32>;
+)";
+
+  auto got = Run<Robustness>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(RobustnessTest, Matrix_Idx_Expr_Row) {
   auto* src = R"(
 var<private> a : mat3x2<f32>;
@@ -489,6 +852,32 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(RobustnessTest, Matrix_Idx_Expr_Row_OutOfOrder) {
+  auto* src = R"(
+fn f() {
+  var b : f32 = a[1][c + 2 - 3];
+}
+
+var<private> c : i32;
+
+var<private> a : mat3x2<f32>;
+)";
+
+  auto* expect = R"(
+fn f() {
+  var b : f32 = a[1][min(u32(((c + 2) - 3)), 1u)];
+}
+
+var<private> c : i32;
+
+var<private> a : mat3x2<f32>;
+)";
+
+  auto got = Run<Robustness>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(RobustnessTest, Matrix_Idx_Negative_Column) {
   auto* src = R"(
 var<private> a : mat3x2<f32>;
@@ -511,6 +900,28 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(RobustnessTest, Matrix_Idx_Negative_Column_OutOfOrder) {
+  auto* src = R"(
+fn f() {
+  var b : f32 = a[-1][1];
+}
+
+var<private> a : mat3x2<f32>;
+)";
+
+  auto* expect = R"(
+fn f() {
+  var b : f32 = a[0][1];
+}
+
+var<private> a : mat3x2<f32>;
+)";
+
+  auto got = Run<Robustness>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(RobustnessTest, Matrix_Idx_Negative_Row) {
   auto* src = R"(
 var<private> a : mat3x2<f32>;
@@ -533,6 +944,28 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(RobustnessTest, Matrix_Idx_Negative_Row_OutOfOrder) {
+  auto* src = R"(
+fn f() {
+  var b : f32 = a[2][-1];
+}
+
+var<private> a : mat3x2<f32>;
+)";
+
+  auto* expect = R"(
+fn f() {
+  var b : f32 = a[2][0];
+}
+
+var<private> a : mat3x2<f32>;
+)";
+
+  auto got = Run<Robustness>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(RobustnessTest, Matrix_Idx_OutOfBounds_Column) {
   auto* src = R"(
 var<private> a : mat3x2<f32>;
@@ -555,6 +988,28 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(RobustnessTest, Matrix_Idx_OutOfBounds_Column_OutOfOrder) {
+  auto* src = R"(
+fn f() {
+  var b : f32 = a[5][1];
+}
+
+var<private> a : mat3x2<f32>;
+)";
+
+  auto* expect = R"(
+fn f() {
+  var b : f32 = a[2][1];
+}
+
+var<private> a : mat3x2<f32>;
+)";
+
+  auto got = Run<Robustness>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(RobustnessTest, Matrix_Idx_OutOfBounds_Row) {
   auto* src = R"(
 var<private> a : mat3x2<f32>;
@@ -577,6 +1032,28 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(RobustnessTest, Matrix_Idx_OutOfBounds_Row_OutOfOrder) {
+  auto* src = R"(
+fn f() {
+  var b : f32 = a[2][5];
+}
+
+var<private> a : mat3x2<f32>;
+)";
+
+  auto* expect = R"(
+fn f() {
+  var b : f32 = a[2][1];
+}
+
+var<private> a : mat3x2<f32>;
+)";
+
+  auto got = Run<Robustness>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 // TODO(dsinclair): Implement when constant_id exists
 TEST_F(RobustnessTest, DISABLED_Vector_Constant_Id_Clamps) {
   // @override(1300) let idx : i32;
@@ -644,9 +1121,36 @@
   EXPECT_EQ(expect, str(got));
 }
 
-// TODO(dsinclair): Clamp atomics when available.
-TEST_F(RobustnessTest, DISABLED_Atomics_Clamp) {
-  FAIL();
+TEST_F(RobustnessTest, RuntimeArray_Clamps_OutOfOrder) {
+  auto* src = R"(
+fn f() {
+  var d : f32 = s.b[25];
+}
+
+@group(0) @binding(0) var<storage, read> s : S;
+
+struct S {
+  a : f32;
+  b : array<f32>;
+};
+)";
+
+  auto* expect = R"(
+fn f() {
+  var d : f32 = s.b[min(25u, (arrayLength(&(s.b)) - 1u))];
+}
+
+@group(0) @binding(0) var<storage, read> s : S;
+
+struct S {
+  a : f32;
+  b : array<f32>;
+}
+)";
+
+  auto got = Run<Robustness>(src);
+
+  EXPECT_EQ(expect, str(got));
 }
 
 // Clamp textureLoad() coord, array_index and level values
@@ -715,6 +1219,72 @@
   EXPECT_EQ(expect, str(got));
 }
 
+// Clamp textureLoad() coord, array_index and level values
+TEST_F(RobustnessTest, TextureLoad_Clamp_OutOfOrder) {
+  auto* src = R"(
+fn f() {
+  var array_idx : i32;
+  var level_idx : i32;
+  var sample_idx : i32;
+
+  textureLoad(tex_1d, 1, level_idx);
+  textureLoad(tex_2d, vec2<i32>(1, 2), level_idx);
+  textureLoad(tex_2d_arr, vec2<i32>(1, 2), array_idx, level_idx);
+  textureLoad(tex_3d, vec3<i32>(1, 2, 3), level_idx);
+  textureLoad(tex_ms_2d, vec2<i32>(1, 2), sample_idx);
+  textureLoad(tex_depth_2d, vec2<i32>(1, 2), level_idx);
+  textureLoad(tex_depth_2d_arr, vec2<i32>(1, 2), array_idx, level_idx);
+  textureLoad(tex_external, vec2<i32>(1, 2));
+}
+
+@group(0) @binding(0) var tex_1d : texture_1d<f32>;
+@group(0) @binding(0) var tex_2d : texture_2d<f32>;
+@group(0) @binding(0) var tex_2d_arr : texture_2d_array<f32>;
+@group(0) @binding(0) var tex_3d : texture_3d<f32>;
+@group(0) @binding(0) var tex_ms_2d : texture_multisampled_2d<f32>;
+@group(0) @binding(0) var tex_depth_2d : texture_depth_2d;
+@group(0) @binding(0) var tex_depth_2d_arr : texture_depth_2d_array;
+@group(0) @binding(0) var tex_external : texture_external;
+)";
+
+  auto* expect =
+      R"(
+fn f() {
+  var array_idx : i32;
+  var level_idx : i32;
+  var sample_idx : i32;
+  textureLoad(tex_1d, clamp(1, i32(), (textureDimensions(tex_1d, clamp(level_idx, 0, (textureNumLevels(tex_1d) - 1))) - i32(1))), clamp(level_idx, 0, (textureNumLevels(tex_1d) - 1)));
+  textureLoad(tex_2d, clamp(vec2<i32>(1, 2), vec2<i32>(), (textureDimensions(tex_2d, clamp(level_idx, 0, (textureNumLevels(tex_2d) - 1))) - vec2<i32>(1))), clamp(level_idx, 0, (textureNumLevels(tex_2d) - 1)));
+  textureLoad(tex_2d_arr, clamp(vec2<i32>(1, 2), vec2<i32>(), (textureDimensions(tex_2d_arr, clamp(level_idx, 0, (textureNumLevels(tex_2d_arr) - 1))) - vec2<i32>(1))), clamp(array_idx, 0, (textureNumLayers(tex_2d_arr) - 1)), clamp(level_idx, 0, (textureNumLevels(tex_2d_arr) - 1)));
+  textureLoad(tex_3d, clamp(vec3<i32>(1, 2, 3), vec3<i32>(), (textureDimensions(tex_3d, clamp(level_idx, 0, (textureNumLevels(tex_3d) - 1))) - vec3<i32>(1))), clamp(level_idx, 0, (textureNumLevels(tex_3d) - 1)));
+  textureLoad(tex_ms_2d, clamp(vec2<i32>(1, 2), vec2<i32>(), (textureDimensions(tex_ms_2d) - vec2<i32>(1))), sample_idx);
+  textureLoad(tex_depth_2d, clamp(vec2<i32>(1, 2), vec2<i32>(), (textureDimensions(tex_depth_2d, clamp(level_idx, 0, (textureNumLevels(tex_depth_2d) - 1))) - vec2<i32>(1))), clamp(level_idx, 0, (textureNumLevels(tex_depth_2d) - 1)));
+  textureLoad(tex_depth_2d_arr, clamp(vec2<i32>(1, 2), vec2<i32>(), (textureDimensions(tex_depth_2d_arr, clamp(level_idx, 0, (textureNumLevels(tex_depth_2d_arr) - 1))) - vec2<i32>(1))), clamp(array_idx, 0, (textureNumLayers(tex_depth_2d_arr) - 1)), clamp(level_idx, 0, (textureNumLevels(tex_depth_2d_arr) - 1)));
+  textureLoad(tex_external, clamp(vec2<i32>(1, 2), vec2<i32>(), (textureDimensions(tex_external) - vec2<i32>(1))));
+}
+
+@group(0) @binding(0) var tex_1d : texture_1d<f32>;
+
+@group(0) @binding(0) var tex_2d : texture_2d<f32>;
+
+@group(0) @binding(0) var tex_2d_arr : texture_2d_array<f32>;
+
+@group(0) @binding(0) var tex_3d : texture_3d<f32>;
+
+@group(0) @binding(0) var tex_ms_2d : texture_multisampled_2d<f32>;
+
+@group(0) @binding(0) var tex_depth_2d : texture_depth_2d;
+
+@group(0) @binding(0) var tex_depth_2d_arr : texture_depth_2d_array;
+
+@group(0) @binding(0) var tex_external : texture_external;
+)";
+
+  auto got = Run<Robustness>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 // Clamp textureStore() coord, array_index and level values
 TEST_F(RobustnessTest, TextureStore_Clamp) {
   auto* src = R"(
@@ -756,6 +1326,48 @@
   EXPECT_EQ(expect, str(got));
 }
 
+// Clamp textureStore() coord, array_index and level values
+TEST_F(RobustnessTest, TextureStore_Clamp_OutOfOrder) {
+  auto* src = R"(
+fn f() {
+  textureStore(tex1d, 10, vec4<i32>());
+  textureStore(tex2d, vec2<i32>(10, 20), vec4<i32>());
+  textureStore(tex2d_arr, vec2<i32>(10, 20), 50, vec4<i32>());
+  textureStore(tex3d, vec3<i32>(10, 20, 30), vec4<i32>());
+}
+
+@group(0) @binding(0) var tex1d : texture_storage_1d<rgba8sint, write>;
+
+@group(0) @binding(1) var tex2d : texture_storage_2d<rgba8sint, write>;
+
+@group(0) @binding(2) var tex2d_arr : texture_storage_2d_array<rgba8sint, write>;
+
+@group(0) @binding(3) var tex3d : texture_storage_3d<rgba8sint, write>;
+
+)";
+
+  auto* expect = R"(
+fn f() {
+  textureStore(tex1d, clamp(10, i32(), (textureDimensions(tex1d) - i32(1))), vec4<i32>());
+  textureStore(tex2d, clamp(vec2<i32>(10, 20), vec2<i32>(), (textureDimensions(tex2d) - vec2<i32>(1))), vec4<i32>());
+  textureStore(tex2d_arr, clamp(vec2<i32>(10, 20), vec2<i32>(), (textureDimensions(tex2d_arr) - vec2<i32>(1))), clamp(50, 0, (textureNumLayers(tex2d_arr) - 1)), vec4<i32>());
+  textureStore(tex3d, clamp(vec3<i32>(10, 20, 30), vec3<i32>(), (textureDimensions(tex3d) - vec3<i32>(1))), vec4<i32>());
+}
+
+@group(0) @binding(0) var tex1d : texture_storage_1d<rgba8sint, write>;
+
+@group(0) @binding(1) var tex2d : texture_storage_2d<rgba8sint, write>;
+
+@group(0) @binding(2) var tex2d_arr : texture_storage_2d_array<rgba8sint, write>;
+
+@group(0) @binding(3) var tex3d : texture_storage_3d<rgba8sint, write>;
+)";
+
+  auto got = Run<Robustness>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 // TODO(dsinclair): Test for scoped variables when shadowing is implemented
 TEST_F(RobustnessTest, DISABLED_Shadowed_Variable) {
   // var a : array<f32, 3>;
diff --git a/src/transform/unshadow_test.cc b/src/transform/unshadow_test.cc
index ddba826..f6383ef 100644
--- a/src/transform/unshadow_test.cc
+++ b/src/transform/unshadow_test.cc
@@ -84,6 +84,36 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(UnshadowTest, LocalShadowsAlias_OutOfOrder) {
+  auto* src = R"(
+fn X() {
+  var a = false;
+}
+
+fn Y() {
+  let a = true;
+}
+
+type a = i32;
+)";
+
+  auto* expect = R"(
+fn X() {
+  var a_1 = false;
+}
+
+fn Y() {
+  let a_2 = true;
+}
+
+type a = i32;
+)";
+
+  auto got = Run<Unshadow>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(UnshadowTest, LocalShadowsStruct) {
   auto* src = R"(
 struct a {
@@ -118,13 +148,50 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(UnshadowTest, LocalShadowsStruct_OutOfOrder) {
+  auto* src = R"(
+fn X() {
+  var a = true;
+}
+
+fn Y() {
+  let a = false;
+}
+
+struct a {
+  m : i32;
+};
+
+)";
+
+  auto* expect = R"(
+fn X() {
+  var a_1 = true;
+}
+
+fn Y() {
+  let a_2 = false;
+}
+
+struct a {
+  m : i32;
+}
+)";
+
+  auto got = Run<Unshadow>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(UnshadowTest, LocalShadowsFunction) {
   auto* src = R"(
 fn a() {
   var a = true;
+  var b = false;
 }
 
 fn b() {
+  let a = true;
   let b = false;
 }
 )";
@@ -132,11 +199,44 @@
   auto* expect = R"(
 fn a() {
   var a_1 = true;
+  var b_1 = false;
 }
 
 fn b() {
+  let a_2 = true;
+  let b_2 = false;
+}
+)";
+
+  auto got = Run<Unshadow>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(UnshadowTest, LocalShadowsFunction_OutOfOrder) {
+  auto* src = R"(
+fn b() {
+  let a = true;
+  let b = false;
+}
+
+fn a() {
+  var a = true;
+  var b = false;
+}
+
+)";
+
+  auto* expect = R"(
+fn b() {
+  let a_1 = true;
   let b_1 = false;
 }
+
+fn a() {
+  var a_2 = true;
+  var b_2 = false;
+}
 )";
 
   auto got = Run<Unshadow>(src);
@@ -174,6 +274,36 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(UnshadowTest, LocalShadowsGlobalVar_OutOfOrder) {
+  auto* src = R"(
+fn X() {
+  var a = (a == 123);
+}
+
+fn Y() {
+  let a = (a == 321);
+}
+
+var<private> a : i32;
+)";
+
+  auto* expect = R"(
+fn X() {
+  var a_1 = (a == 123);
+}
+
+fn Y() {
+  let a_2 = (a == 321);
+}
+
+var<private> a : i32;
+)";
+
+  auto got = Run<Unshadow>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(UnshadowTest, LocalShadowsGlobalLet) {
   auto* src = R"(
 let a : i32 = 1;
@@ -204,6 +334,36 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(UnshadowTest, LocalShadowsGlobalLet_OutOfOrder) {
+  auto* src = R"(
+fn X() {
+  var a = (a == 123);
+}
+
+fn Y() {
+  let a = (a == 321);
+}
+
+let a : i32 = 1;
+)";
+
+  auto* expect = R"(
+fn X() {
+  var a_1 = (a == 123);
+}
+
+fn Y() {
+  let a_2 = (a == 321);
+}
+
+let a : i32 = 1;
+)";
+
+  auto got = Run<Unshadow>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(UnshadowTest, LocalShadowsLocalVar) {
   auto* src = R"(
 fn X() {
@@ -360,6 +520,26 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(UnshadowTest, ParamShadowsGlobalLet_OutOfOrder) {
+  auto* src = R"(
+fn F(a : bool) {
+}
+
+let a : i32 = 1;
+)";
+
+  auto* expect = R"(
+fn F(a_1 : bool) {
+}
+
+let a : i32 = 1;
+)";
+
+  auto got = Run<Unshadow>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(UnshadowTest, ParamShadowsAlias) {
   auto* src = R"(
 type a = i32;
@@ -392,6 +572,38 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(UnshadowTest, ParamShadowsAlias_OutOfOrder) {
+  auto* src = R"(
+fn F(a : a) {
+  {
+    var a = (a == 123);
+  }
+  {
+    let a = (a == 321);
+  }
+}
+
+type a = i32;
+)";
+
+  auto* expect = R"(
+fn F(a_1 : a) {
+  {
+    var a_2 = (a_1 == 123);
+  }
+  {
+    let a_3 = (a_1 == 321);
+  }
+}
+
+type a = i32;
+)";
+
+  auto got = Run<Unshadow>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 }  // namespace
 }  // namespace transform
 }  // namespace tint
diff --git a/src/transform/vertex_pulling_test.cc b/src/transform/vertex_pulling_test.cc
index b2482af..8c551ec 100644
--- a/src/transform/vertex_pulling_test.cc
+++ b/src/transform/vertex_pulling_test.cc
@@ -426,6 +426,86 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(VertexPullingTest,
+       ExistingVertexIndexAndInstanceIndex_Struct_OutOfOrder) {
+  auto* src = R"(
+@stage(vertex)
+fn main(inputs : Inputs) -> @builtin(position) vec4<f32> {
+  return vec4<f32>(inputs.var_a, inputs.var_b, 0.0, 1.0);
+}
+
+struct Inputs {
+  @location(0) var_a : f32;
+  @location(1) var_b : f32;
+  @builtin(vertex_index) custom_vertex_index : u32;
+  @builtin(instance_index) custom_instance_index : u32;
+};
+)";
+
+  auto* expect = R"(
+struct TintVertexData {
+  tint_vertex_data : @stride(4) array<u32>;
+}
+
+@binding(0) @group(4) var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData;
+
+@binding(1) @group(4) var<storage, read> tint_pulling_vertex_buffer_1 : TintVertexData;
+
+struct tint_symbol {
+  @builtin(vertex_index)
+  custom_vertex_index : u32;
+  @builtin(instance_index)
+  custom_instance_index : u32;
+}
+
+@stage(vertex)
+fn main(tint_symbol_1 : tint_symbol) -> @builtin(position) vec4<f32> {
+  var inputs : Inputs;
+  inputs.custom_vertex_index = tint_symbol_1.custom_vertex_index;
+  inputs.custom_instance_index = tint_symbol_1.custom_instance_index;
+  {
+    let buffer_array_base_0 = inputs.custom_vertex_index;
+    inputs.var_a = bitcast<f32>(tint_pulling_vertex_buffer_0.tint_vertex_data[buffer_array_base_0]);
+    let buffer_array_base_1 = inputs.custom_instance_index;
+    inputs.var_b = bitcast<f32>(tint_pulling_vertex_buffer_1.tint_vertex_data[buffer_array_base_1]);
+  }
+  return vec4<f32>(inputs.var_a, inputs.var_b, 0.0, 1.0);
+}
+
+struct Inputs {
+  @location(0)
+  var_a : f32;
+  @location(1)
+  var_b : f32;
+  @builtin(vertex_index)
+  custom_vertex_index : u32;
+  @builtin(instance_index)
+  custom_instance_index : u32;
+}
+)";
+
+  VertexPulling::Config cfg;
+  cfg.vertex_state = {{
+      {
+          4,
+          VertexStepMode::kVertex,
+          {{VertexFormat::kFloat32, 0, 0}},
+      },
+      {
+          4,
+          VertexStepMode::kInstance,
+          {{VertexFormat::kFloat32, 0, 1}},
+      },
+  }};
+  cfg.entry_point_name = "main";
+
+  DataMap data;
+  data.Add<VertexPulling::Config>(cfg);
+  auto got = Run<VertexPulling>(src, data);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(VertexPullingTest, ExistingVertexIndexAndInstanceIndex_SeparateStruct) {
   auto* src = R"(
 struct Inputs {
@@ -502,6 +582,83 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(VertexPullingTest,
+       ExistingVertexIndexAndInstanceIndex_SeparateStruct_OutOfOrder) {
+  auto* src = R"(
+@stage(vertex)
+fn main(inputs : Inputs, indices : Indices) -> @builtin(position) vec4<f32> {
+  return vec4<f32>(inputs.var_a, inputs.var_b, 0.0, 1.0);
+}
+
+struct Inputs {
+  @location(0) var_a : f32;
+  @location(1) var_b : f32;
+};
+
+struct Indices {
+  @builtin(vertex_index) custom_vertex_index : u32;
+  @builtin(instance_index) custom_instance_index : u32;
+};
+)";
+
+  auto* expect = R"(
+struct TintVertexData {
+  tint_vertex_data : @stride(4) array<u32>;
+}
+
+@binding(0) @group(4) var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData;
+
+@binding(1) @group(4) var<storage, read> tint_pulling_vertex_buffer_1 : TintVertexData;
+
+@stage(vertex)
+fn main(indices : Indices) -> @builtin(position) vec4<f32> {
+  var inputs : Inputs;
+  {
+    let buffer_array_base_0 = indices.custom_vertex_index;
+    inputs.var_a = bitcast<f32>(tint_pulling_vertex_buffer_0.tint_vertex_data[buffer_array_base_0]);
+    let buffer_array_base_1 = indices.custom_instance_index;
+    inputs.var_b = bitcast<f32>(tint_pulling_vertex_buffer_1.tint_vertex_data[buffer_array_base_1]);
+  }
+  return vec4<f32>(inputs.var_a, inputs.var_b, 0.0, 1.0);
+}
+
+struct Inputs {
+  @location(0)
+  var_a : f32;
+  @location(1)
+  var_b : f32;
+}
+
+struct Indices {
+  @builtin(vertex_index)
+  custom_vertex_index : u32;
+  @builtin(instance_index)
+  custom_instance_index : u32;
+}
+)";
+
+  VertexPulling::Config cfg;
+  cfg.vertex_state = {{
+      {
+          4,
+          VertexStepMode::kVertex,
+          {{VertexFormat::kFloat32, 0, 0}},
+      },
+      {
+          4,
+          VertexStepMode::kInstance,
+          {{VertexFormat::kFloat32, 0, 1}},
+      },
+  }};
+  cfg.entry_point_name = "main";
+
+  DataMap data;
+  data.Add<VertexPulling::Config>(cfg);
+  auto got = Run<VertexPulling>(src, data);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(VertexPullingTest, TwoAttributesSameBuffer) {
   auto* src = R"(
 @stage(vertex)
diff --git a/src/transform/wrap_arrays_in_structs_test.cc b/src/transform/wrap_arrays_in_structs_test.cc
index 4f3b5d4..c9daaf8 100644
--- a/src/transform/wrap_arrays_in_structs_test.cc
+++ b/src/transform/wrap_arrays_in_structs_test.cc
@@ -172,6 +172,48 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(WrapArraysInStructsTest, ArrayAlias_OutOfOrder) {
+  auto* src = R"(
+fn f() {
+  var arr : Array;
+  arr = Array();
+  arr = Array(Inner(1, 2), Inner(3, 4));
+  let vals : Array = Array(Inner(1, 2), Inner(3, 4));
+  arr = vals;
+  let x = arr[3];
+}
+
+type Array = array<Inner, 2>;
+type Inner = array<i32, 2>;
+)";
+  auto* expect = R"(
+struct tint_array_wrapper_1 {
+  arr : array<i32, 2u>;
+}
+
+struct tint_array_wrapper {
+  arr : array<tint_array_wrapper_1, 2u>;
+}
+
+fn f() {
+  var arr : tint_array_wrapper;
+  arr = tint_array_wrapper(array<tint_array_wrapper_1, 2u>());
+  arr = tint_array_wrapper(array<tint_array_wrapper_1, 2u>(tint_array_wrapper_1(array<i32, 2u>(1, 2)), tint_array_wrapper_1(array<i32, 2u>(3, 4))));
+  let vals : tint_array_wrapper = tint_array_wrapper(array<tint_array_wrapper_1, 2u>(tint_array_wrapper_1(array<i32, 2u>(1, 2)), tint_array_wrapper_1(array<i32, 2u>(3, 4))));
+  arr = vals;
+  let x = arr.arr[3];
+}
+
+type Array = tint_array_wrapper;
+
+type Inner = tint_array_wrapper_1;
+)";
+
+  auto got = Run<WrapArraysInStructs>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(WrapArraysInStructsTest, ArraysInStruct) {
   auto* src = R"(
 struct S {
@@ -326,6 +368,57 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(WrapArraysInStructsTest, DeclarationOrder_OutOfOrder) {
+  auto* src = R"(
+fn f2() {
+  var v : array<i32, 3>;
+}
+
+type T3 = i32;
+
+fn f1(a : array<i32, 2>) {
+}
+
+type T2 = i32;
+
+type T1 = array<i32, 1>;
+
+type T0 = i32;
+)";
+  auto* expect = R"(
+struct tint_array_wrapper {
+  arr : array<i32, 3u>;
+}
+
+fn f2() {
+  var v : tint_array_wrapper;
+}
+
+type T3 = i32;
+
+struct tint_array_wrapper_1 {
+  arr : array<i32, 2u>;
+}
+
+fn f1(a : tint_array_wrapper_1) {
+}
+
+type T2 = i32;
+
+struct tint_array_wrapper_2 {
+  arr : array<i32, 1u>;
+}
+
+type T1 = tint_array_wrapper_2;
+
+type T0 = i32;
+)";
+
+  auto got = Run<WrapArraysInStructs>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 }  // namespace
 }  // namespace transform
 }  // namespace tint
diff --git a/src/transform/zero_init_workgroup_memory_test.cc b/src/transform/zero_init_workgroup_memory_test.cc
index 6cceb20..54e1aa2 100644
--- a/src/transform/zero_init_workgroup_memory_test.cc
+++ b/src/transform/zero_init_workgroup_memory_test.cc
@@ -93,6 +93,29 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(ZeroInitWorkgroupMemoryTest, UnreferencedWorkgroupVars_OutOfOrder) {
+  auto* src = R"(
+@stage(compute) @workgroup_size(1)
+fn f() {
+}
+
+fn unreferenced() {
+  b = c;
+}
+
+var<workgroup> a : i32;
+
+var<workgroup> b : i32;
+
+var<workgroup> c : i32;
+)";
+  auto* expect = src;
+
+  auto got = Run<ZeroInitWorkgroupMemory>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(ZeroInitWorkgroupMemoryTest, SingleWorkgroupVar_ExistingLocalIndex) {
   auto* src = R"(
 var<workgroup> v : i32;
@@ -121,6 +144,34 @@
 }
 
 TEST_F(ZeroInitWorkgroupMemoryTest,
+       SingleWorkgroupVar_ExistingLocalIndex_OutOfOrder) {
+  auto* src = R"(
+@stage(compute) @workgroup_size(1)
+fn f(@builtin(local_invocation_index) local_idx : u32) {
+  _ = v; // Initialization should be inserted above this statement
+}
+
+var<workgroup> v : i32;
+)";
+  auto* expect = R"(
+@stage(compute) @workgroup_size(1)
+fn f(@builtin(local_invocation_index) local_idx : u32) {
+  {
+    v = i32();
+  }
+  workgroupBarrier();
+  _ = v;
+}
+
+var<workgroup> v : i32;
+)";
+
+  auto got = Run<ZeroInitWorkgroupMemory>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(ZeroInitWorkgroupMemoryTest,
        SingleWorkgroupVar_ExistingLocalIndexInStruct) {
   auto* src = R"(
 var<workgroup> v : i32;
@@ -157,6 +208,43 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(ZeroInitWorkgroupMemoryTest,
+       SingleWorkgroupVar_ExistingLocalIndexInStruct_OutOfOrder) {
+  auto* src = R"(
+@stage(compute) @workgroup_size(1)
+fn f(params : Params) {
+  _ = v; // Initialization should be inserted above this statement
+}
+
+struct Params {
+  @builtin(local_invocation_index) local_idx : u32;
+};
+
+var<workgroup> v : i32;
+)";
+  auto* expect = R"(
+@stage(compute) @workgroup_size(1)
+fn f(params : Params) {
+  {
+    v = i32();
+  }
+  workgroupBarrier();
+  _ = v;
+}
+
+struct Params {
+  @builtin(local_invocation_index)
+  local_idx : u32;
+}
+
+var<workgroup> v : i32;
+)";
+
+  auto got = Run<ZeroInitWorkgroupMemory>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(ZeroInitWorkgroupMemoryTest, SingleWorkgroupVar_InjectedLocalIndex) {
   auto* src = R"(
 var<workgroup> v : i32;
@@ -185,6 +273,34 @@
 }
 
 TEST_F(ZeroInitWorkgroupMemoryTest,
+       SingleWorkgroupVar_InjectedLocalIndex_OutOfOrder) {
+  auto* src = R"(
+@stage(compute) @workgroup_size(1)
+fn f() {
+  _ = v; // Initialization should be inserted above this statement
+}
+
+var<workgroup> v : i32;
+)";
+  auto* expect = R"(
+@stage(compute) @workgroup_size(1)
+fn f(@builtin(local_invocation_index) local_invocation_index : u32) {
+  {
+    v = i32();
+  }
+  workgroupBarrier();
+  _ = v;
+}
+
+var<workgroup> v : i32;
+)";
+
+  auto got = Run<ZeroInitWorkgroupMemory>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(ZeroInitWorkgroupMemoryTest,
        MultipleWorkgroupVar_ExistingLocalIndex_Size1) {
   auto* src = R"(
 struct S {
@@ -249,6 +365,70 @@
 }
 
 TEST_F(ZeroInitWorkgroupMemoryTest,
+       MultipleWorkgroupVar_ExistingLocalIndex_Size1_OutOfOrder) {
+  auto* src = R"(
+@stage(compute) @workgroup_size(1)
+fn f(@builtin(local_invocation_index) local_idx : u32) {
+  _ = a; // Initialization should be inserted above this statement
+  _ = b;
+  _ = c;
+}
+
+var<workgroup> a : i32;
+
+var<workgroup> b : S;
+
+var<workgroup> c : array<S, 32>;
+
+struct S {
+  x : i32;
+  y : array<i32, 8>;
+};
+)";
+  auto* expect = R"(
+@stage(compute) @workgroup_size(1)
+fn f(@builtin(local_invocation_index) local_idx : u32) {
+  {
+    a = i32();
+    b.x = i32();
+  }
+  for(var idx : u32 = local_idx; (idx < 8u); idx = (idx + 1u)) {
+    let i : u32 = idx;
+    b.y[i] = i32();
+  }
+  for(var idx_1 : u32 = local_idx; (idx_1 < 32u); idx_1 = (idx_1 + 1u)) {
+    let i_1 : u32 = idx_1;
+    c[i_1].x = i32();
+  }
+  for(var idx_2 : u32 = local_idx; (idx_2 < 256u); idx_2 = (idx_2 + 1u)) {
+    let i_2 : u32 = (idx_2 / 8u);
+    let i : u32 = (idx_2 % 8u);
+    c[i_2].y[i] = i32();
+  }
+  workgroupBarrier();
+  _ = a;
+  _ = b;
+  _ = c;
+}
+
+var<workgroup> a : i32;
+
+var<workgroup> b : S;
+
+var<workgroup> c : array<S, 32>;
+
+struct S {
+  x : i32;
+  y : array<i32, 8>;
+}
+)";
+
+  auto got = Run<ZeroInitWorkgroupMemory>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(ZeroInitWorkgroupMemoryTest,
        MultipleWorkgroupVar_ExistingLocalIndex_Size_2_3) {
   auto* src = R"(
 struct S {
@@ -534,6 +714,70 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(ZeroInitWorkgroupMemoryTest,
+       MultipleWorkgroupVar_InjectedLocalIndex_OutOfOrder) {
+  auto* src = R"(
+@stage(compute) @workgroup_size(1)
+fn f(@builtin(local_invocation_id) local_invocation_id : vec3<u32>) {
+  _ = a; // Initialization should be inserted above this statement
+  _ = b;
+  _ = c;
+}
+
+var<workgroup> a : i32;
+
+var<workgroup> b : S;
+
+var<workgroup> c : array<S, 32>;
+
+struct S {
+  x : i32;
+  y : array<i32, 8>;
+};
+)";
+  auto* expect = R"(
+@stage(compute) @workgroup_size(1)
+fn f(@builtin(local_invocation_id) local_invocation_id : vec3<u32>, @builtin(local_invocation_index) local_invocation_index : u32) {
+  {
+    a = i32();
+    b.x = i32();
+  }
+  for(var idx : u32 = local_invocation_index; (idx < 8u); idx = (idx + 1u)) {
+    let i : u32 = idx;
+    b.y[i] = i32();
+  }
+  for(var idx_1 : u32 = local_invocation_index; (idx_1 < 32u); idx_1 = (idx_1 + 1u)) {
+    let i_1 : u32 = idx_1;
+    c[i_1].x = i32();
+  }
+  for(var idx_2 : u32 = local_invocation_index; (idx_2 < 256u); idx_2 = (idx_2 + 1u)) {
+    let i_2 : u32 = (idx_2 / 8u);
+    let i : u32 = (idx_2 % 8u);
+    c[i_2].y[i] = i32();
+  }
+  workgroupBarrier();
+  _ = a;
+  _ = b;
+  _ = c;
+}
+
+var<workgroup> a : i32;
+
+var<workgroup> b : S;
+
+var<workgroup> c : array<S, 32>;
+
+struct S {
+  x : i32;
+  y : array<i32, 8>;
+}
+)";
+
+  auto got = Run<ZeroInitWorkgroupMemory>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(ZeroInitWorkgroupMemoryTest, MultipleWorkgroupVar_MultipleEntryPoints) {
   auto* src = R"(
 struct S {
@@ -633,6 +877,106 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(ZeroInitWorkgroupMemoryTest,
+       MultipleWorkgroupVar_MultipleEntryPoints_OutOfOrder) {
+  auto* src = R"(
+@stage(compute) @workgroup_size(1)
+fn f1() {
+  _ = a; // Initialization should be inserted above this statement
+  _ = c;
+}
+
+@stage(compute) @workgroup_size(1, 2, 3)
+fn f2(@builtin(local_invocation_id) local_invocation_id : vec3<u32>) {
+  _ = b; // Initialization should be inserted above this statement
+}
+
+@stage(compute) @workgroup_size(4, 5, 6)
+fn f3() {
+  _ = c; // Initialization should be inserted above this statement
+  _ = a;
+}
+
+var<workgroup> a : i32;
+
+var<workgroup> b : S;
+
+var<workgroup> c : array<S, 32>;
+
+struct S {
+  x : i32;
+  y : array<i32, 8>;
+};
+)";
+  auto* expect = R"(
+@stage(compute) @workgroup_size(1)
+fn f1(@builtin(local_invocation_index) local_invocation_index : u32) {
+  {
+    a = i32();
+  }
+  for(var idx : u32 = local_invocation_index; (idx < 32u); idx = (idx + 1u)) {
+    let i : u32 = idx;
+    c[i].x = i32();
+  }
+  for(var idx_1 : u32 = local_invocation_index; (idx_1 < 256u); idx_1 = (idx_1 + 1u)) {
+    let i_1 : u32 = (idx_1 / 8u);
+    let i_2 : u32 = (idx_1 % 8u);
+    c[i_1].y[i_2] = i32();
+  }
+  workgroupBarrier();
+  _ = a;
+  _ = c;
+}
+
+@stage(compute) @workgroup_size(1, 2, 3)
+fn f2(@builtin(local_invocation_id) local_invocation_id : vec3<u32>, @builtin(local_invocation_index) local_invocation_index_1 : u32) {
+  if ((local_invocation_index_1 < 1u)) {
+    b.x = i32();
+  }
+  for(var idx_2 : u32 = local_invocation_index_1; (idx_2 < 8u); idx_2 = (idx_2 + 6u)) {
+    let i_3 : u32 = idx_2;
+    b.y[i_3] = i32();
+  }
+  workgroupBarrier();
+  _ = b;
+}
+
+@stage(compute) @workgroup_size(4, 5, 6)
+fn f3(@builtin(local_invocation_index) local_invocation_index_2 : u32) {
+  if ((local_invocation_index_2 < 1u)) {
+    a = i32();
+  }
+  if ((local_invocation_index_2 < 32u)) {
+    let i_4 : u32 = local_invocation_index_2;
+    c[i_4].x = i32();
+  }
+  for(var idx_3 : u32 = local_invocation_index_2; (idx_3 < 256u); idx_3 = (idx_3 + 120u)) {
+    let i_5 : u32 = (idx_3 / 8u);
+    let i_6 : u32 = (idx_3 % 8u);
+    c[i_5].y[i_6] = i32();
+  }
+  workgroupBarrier();
+  _ = c;
+  _ = a;
+}
+
+var<workgroup> a : i32;
+
+var<workgroup> b : S;
+
+var<workgroup> c : array<S, 32>;
+
+struct S {
+  x : i32;
+  y : array<i32, 8>;
+}
+)";
+
+  auto got = Run<ZeroInitWorkgroupMemory>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(ZeroInitWorkgroupMemoryTest, TransitiveUsage) {
   auto* src = R"(
 var<workgroup> v : i32;
@@ -676,6 +1020,49 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(ZeroInitWorkgroupMemoryTest, TransitiveUsage_OutOfOrder) {
+  auto* src = R"(
+@stage(compute) @workgroup_size(1)
+fn f(@builtin(local_invocation_index) local_idx : u32) {
+  call_use_v(); // Initialization should be inserted above this statement
+}
+
+fn call_use_v() {
+  use_v();
+}
+
+fn use_v() {
+  _ = v;
+}
+
+var<workgroup> v : i32;
+)";
+  auto* expect = R"(
+@stage(compute) @workgroup_size(1)
+fn f(@builtin(local_invocation_index) local_idx : u32) {
+  {
+    v = i32();
+  }
+  workgroupBarrier();
+  call_use_v();
+}
+
+fn call_use_v() {
+  use_v();
+}
+
+fn use_v() {
+  _ = v;
+}
+
+var<workgroup> v : i32;
+)";
+
+  auto got = Run<ZeroInitWorkgroupMemory>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(ZeroInitWorkgroupMemoryTest, WorkgroupAtomics) {
   auto* src = R"(
 var<workgroup> i : atomic<i32>;
@@ -709,6 +1096,39 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(ZeroInitWorkgroupMemoryTest, WorkgroupAtomics_OutOfOrder) {
+  auto* src = R"(
+@stage(compute) @workgroup_size(1)
+fn f() {
+  atomicLoad(&(i)); // Initialization should be inserted above this statement
+  atomicLoad(&(u));
+}
+
+var<workgroup> i : atomic<i32>;
+var<workgroup> u : atomic<u32>;
+)";
+  auto* expect = R"(
+@stage(compute) @workgroup_size(1)
+fn f(@builtin(local_invocation_index) local_invocation_index : u32) {
+  {
+    atomicStore(&(i), i32());
+    atomicStore(&(u), u32());
+  }
+  workgroupBarrier();
+  atomicLoad(&(i));
+  atomicLoad(&(u));
+}
+
+var<workgroup> i : atomic<i32>;
+
+var<workgroup> u : atomic<u32>;
+)";
+
+  auto got = Run<ZeroInitWorkgroupMemory>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(ZeroInitWorkgroupMemoryTest, WorkgroupStructOfAtomics) {
   auto* src = R"(
 struct S {
@@ -756,6 +1176,53 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(ZeroInitWorkgroupMemoryTest, WorkgroupStructOfAtomics_OutOfOrder) {
+  auto* src = R"(
+@stage(compute) @workgroup_size(1)
+fn f() {
+  _ = w.a; // Initialization should be inserted above this statement
+}
+
+var<workgroup> w : S;
+
+struct S {
+  a : i32;
+  i : atomic<i32>;
+  b : f32;
+  u : atomic<u32>;
+  c : u32;
+};
+)";
+  auto* expect = R"(
+@stage(compute) @workgroup_size(1)
+fn f(@builtin(local_invocation_index) local_invocation_index : u32) {
+  {
+    w.a = i32();
+    atomicStore(&(w.i), i32());
+    w.b = f32();
+    atomicStore(&(w.u), u32());
+    w.c = u32();
+  }
+  workgroupBarrier();
+  _ = w.a;
+}
+
+var<workgroup> w : S;
+
+struct S {
+  a : i32;
+  i : atomic<i32>;
+  b : f32;
+  u : atomic<u32>;
+  c : u32;
+}
+)";
+
+  auto got = Run<ZeroInitWorkgroupMemory>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(ZeroInitWorkgroupMemoryTest, WorkgroupArrayOfAtomics) {
   auto* src = R"(
 var<workgroup> w : array<atomic<u32>, 4>;
@@ -784,6 +1251,34 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(ZeroInitWorkgroupMemoryTest, WorkgroupArrayOfAtomics_OutOfOrder) {
+  auto* src = R"(
+@stage(compute) @workgroup_size(1)
+fn f() {
+  atomicLoad(&w[0]); // Initialization should be inserted above this statement
+}
+
+var<workgroup> w : array<atomic<u32>, 4>;
+)";
+  auto* expect = R"(
+@stage(compute) @workgroup_size(1)
+fn f(@builtin(local_invocation_index) local_invocation_index : u32) {
+  for(var idx : u32 = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+    let i : u32 = idx;
+    atomicStore(&(w[i]), u32());
+  }
+  workgroupBarrier();
+  atomicLoad(&(w[0]));
+}
+
+var<workgroup> w : array<atomic<u32>, 4>;
+)";
+
+  auto got = Run<ZeroInitWorkgroupMemory>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 TEST_F(ZeroInitWorkgroupMemoryTest, WorkgroupArrayOfStructOfAtomics) {
   auto* src = R"(
 struct S {
@@ -832,6 +1327,55 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(ZeroInitWorkgroupMemoryTest,
+       WorkgroupArrayOfStructOfAtomics_OutOfOrder) {
+  auto* src = R"(
+@stage(compute) @workgroup_size(1)
+fn f() {
+  _ = w[0].a; // Initialization should be inserted above this statement
+}
+
+var<workgroup> w : array<S, 4>;
+
+struct S {
+  a : i32;
+  i : atomic<i32>;
+  b : f32;
+  u : atomic<u32>;
+  c : u32;
+};
+)";
+  auto* expect = R"(
+@stage(compute) @workgroup_size(1)
+fn f(@builtin(local_invocation_index) local_invocation_index : u32) {
+  for(var idx : u32 = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+    let i_1 : u32 = idx;
+    w[i_1].a = i32();
+    atomicStore(&(w[i_1].i), i32());
+    w[i_1].b = f32();
+    atomicStore(&(w[i_1].u), u32());
+    w[i_1].c = u32();
+  }
+  workgroupBarrier();
+  _ = w[0].a;
+}
+
+var<workgroup> w : array<S, 4>;
+
+struct S {
+  a : i32;
+  i : atomic<i32>;
+  b : f32;
+  u : atomic<u32>;
+  c : u32;
+}
+)";
+
+  auto got = Run<ZeroInitWorkgroupMemory>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 }  // namespace
 }  // namespace transform
 }  // namespace tint
diff --git a/src/writer/hlsl/generator_impl_sanitizer_test.cc b/src/writer/hlsl/generator_impl_sanitizer_test.cc
index d17bdca..41f5840 100644
--- a/src/writer/hlsl/generator_impl_sanitizer_test.cc
+++ b/src/writer/hlsl/generator_impl_sanitizer_test.cc
@@ -181,7 +181,6 @@
   auto* expect = R"(cbuffer cbuffer_tint_symbol_1 : register(b4, space3) {
   uint4 tint_symbol_1[2];
 };
-
 ByteAddressBuffer b : register(t1, space2);
 ByteAddressBuffer c : register(t2, space2);
 
diff --git a/test/out_of_order_decls/alias/alias.wgsl b/test/out_of_order_decls/alias/alias.wgsl
new file mode 100644
index 0000000..b1c9e66
--- /dev/null
+++ b/test/out_of_order_decls/alias/alias.wgsl
@@ -0,0 +1,7 @@
+type T1 = T2;
+type T2 = i32;
+
+@stage(fragment)
+fn f() {
+  var v : T1;
+}
diff --git a/test/out_of_order_decls/alias/alias.wgsl.expected.glsl b/test/out_of_order_decls/alias/alias.wgsl.expected.glsl
new file mode 100644
index 0000000..e1e01c7
--- /dev/null
+++ b/test/out_of_order_decls/alias/alias.wgsl.expected.glsl
@@ -0,0 +1,11 @@
+#version 310 es
+precision mediump float;
+
+void f() {
+  int v = 0;
+}
+
+void main() {
+  f();
+  return;
+}
diff --git a/test/out_of_order_decls/alias/alias.wgsl.expected.hlsl b/test/out_of_order_decls/alias/alias.wgsl.expected.hlsl
new file mode 100644
index 0000000..9047109
--- /dev/null
+++ b/test/out_of_order_decls/alias/alias.wgsl.expected.hlsl
@@ -0,0 +1,4 @@
+void f() {
+  int v = 0;
+  return;
+}
diff --git a/test/out_of_order_decls/alias/alias.wgsl.expected.msl b/test/out_of_order_decls/alias/alias.wgsl.expected.msl
new file mode 100644
index 0000000..3054a16
--- /dev/null
+++ b/test/out_of_order_decls/alias/alias.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+fragment void f() {
+  int v = 0;
+  return;
+}
+
diff --git a/test/out_of_order_decls/alias/alias.wgsl.expected.spvasm b/test/out_of_order_decls/alias/alias.wgsl.expected.spvasm
new file mode 100644
index 0000000..5afeefa
--- /dev/null
+++ b/test/out_of_order_decls/alias/alias.wgsl.expected.spvasm
@@ -0,0 +1,21 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 9
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %f "f"
+               OpExecutionMode %f OriginUpperLeft
+               OpName %f "f"
+               OpName %v "v"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+        %int = OpTypeInt 32 1
+%_ptr_Function_int = OpTypePointer Function %int
+          %8 = OpConstantNull %int
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+          %v = OpVariable %_ptr_Function_int Function %8
+               OpReturn
+               OpFunctionEnd
diff --git a/test/out_of_order_decls/alias/alias.wgsl.expected.wgsl b/test/out_of_order_decls/alias/alias.wgsl.expected.wgsl
new file mode 100644
index 0000000..ca3ee03
--- /dev/null
+++ b/test/out_of_order_decls/alias/alias.wgsl.expected.wgsl
@@ -0,0 +1,8 @@
+type T1 = T2;
+
+type T2 = i32;
+
+@stage(fragment)
+fn f() {
+  var v : T1;
+}
diff --git a/test/out_of_order_decls/alias/struct.wgsl b/test/out_of_order_decls/alias/struct.wgsl
new file mode 100644
index 0000000..20f80a4
--- /dev/null
+++ b/test/out_of_order_decls/alias/struct.wgsl
@@ -0,0 +1,10 @@
+type T = S;
+
+struct S {
+  m : i32;
+}
+
+@stage(fragment)
+fn f() {
+  var v : T;
+}
diff --git a/test/out_of_order_decls/alias/struct.wgsl.expected.glsl b/test/out_of_order_decls/alias/struct.wgsl.expected.glsl
new file mode 100644
index 0000000..508e315
--- /dev/null
+++ b/test/out_of_order_decls/alias/struct.wgsl.expected.glsl
@@ -0,0 +1,15 @@
+#version 310 es
+precision mediump float;
+
+struct S {
+  int m;
+};
+
+void f() {
+  S v = S(0);
+}
+
+void main() {
+  f();
+  return;
+}
diff --git a/test/out_of_order_decls/alias/struct.wgsl.expected.hlsl b/test/out_of_order_decls/alias/struct.wgsl.expected.hlsl
new file mode 100644
index 0000000..c113dac
--- /dev/null
+++ b/test/out_of_order_decls/alias/struct.wgsl.expected.hlsl
@@ -0,0 +1,8 @@
+struct S {
+  int m;
+};
+
+void f() {
+  S v = (S)0;
+  return;
+}
diff --git a/test/out_of_order_decls/alias/struct.wgsl.expected.msl b/test/out_of_order_decls/alias/struct.wgsl.expected.msl
new file mode 100644
index 0000000..c2a67d0
--- /dev/null
+++ b/test/out_of_order_decls/alias/struct.wgsl.expected.msl
@@ -0,0 +1,12 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct S {
+  int m;
+};
+
+fragment void f() {
+  S v = {};
+  return;
+}
+
diff --git a/test/out_of_order_decls/alias/struct.wgsl.expected.spvasm b/test/out_of_order_decls/alias/struct.wgsl.expected.spvasm
new file mode 100644
index 0000000..4194956
--- /dev/null
+++ b/test/out_of_order_decls/alias/struct.wgsl.expected.spvasm
@@ -0,0 +1,25 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 10
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %f "f"
+               OpExecutionMode %f OriginUpperLeft
+               OpName %f "f"
+               OpName %S "S"
+               OpMemberName %S 0 "m"
+               OpName %v "v"
+               OpMemberDecorate %S 0 Offset 0
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+        %int = OpTypeInt 32 1
+          %S = OpTypeStruct %int
+%_ptr_Function_S = OpTypePointer Function %S
+          %9 = OpConstantNull %S
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+          %v = OpVariable %_ptr_Function_S Function %9
+               OpReturn
+               OpFunctionEnd
diff --git a/test/out_of_order_decls/alias/struct.wgsl.expected.wgsl b/test/out_of_order_decls/alias/struct.wgsl.expected.wgsl
new file mode 100644
index 0000000..20f80a4
--- /dev/null
+++ b/test/out_of_order_decls/alias/struct.wgsl.expected.wgsl
@@ -0,0 +1,10 @@
+type T = S;
+
+struct S {
+  m : i32;
+}
+
+@stage(fragment)
+fn f() {
+  var v : T;
+}
diff --git a/test/out_of_order_decls/array/alias.wgsl b/test/out_of_order_decls/array/alias.wgsl
new file mode 100644
index 0000000..95cec5a
--- /dev/null
+++ b/test/out_of_order_decls/array/alias.wgsl
@@ -0,0 +1,7 @@
+var<private> A : array<T, 4>;
+type T = i32;
+
+@stage(fragment)
+fn f() {
+  A[0] = 1;
+}
diff --git a/test/out_of_order_decls/array/alias.wgsl.expected.glsl b/test/out_of_order_decls/array/alias.wgsl.expected.glsl
new file mode 100644
index 0000000..91dd20a
--- /dev/null
+++ b/test/out_of_order_decls/array/alias.wgsl.expected.glsl
@@ -0,0 +1,12 @@
+#version 310 es
+precision mediump float;
+
+int A[4] = int[4](0, 0, 0, 0);
+void f() {
+  A[0] = 1;
+}
+
+void main() {
+  f();
+  return;
+}
diff --git a/test/out_of_order_decls/array/alias.wgsl.expected.hlsl b/test/out_of_order_decls/array/alias.wgsl.expected.hlsl
new file mode 100644
index 0000000..c2ce6c2
--- /dev/null
+++ b/test/out_of_order_decls/array/alias.wgsl.expected.hlsl
@@ -0,0 +1,6 @@
+static int A[4] = (int[4])0;
+
+void f() {
+  A[0] = 1;
+  return;
+}
diff --git a/test/out_of_order_decls/array/alias.wgsl.expected.msl b/test/out_of_order_decls/array/alias.wgsl.expected.msl
new file mode 100644
index 0000000..e345a6d
--- /dev/null
+++ b/test/out_of_order_decls/array/alias.wgsl.expected.msl
@@ -0,0 +1,13 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct tint_array_wrapper {
+  int arr[4];
+};
+
+fragment void f() {
+  thread tint_array_wrapper tint_symbol = {};
+  tint_symbol.arr[0] = 1;
+  return;
+}
+
diff --git a/test/out_of_order_decls/array/alias.wgsl.expected.spvasm b/test/out_of_order_decls/array/alias.wgsl.expected.spvasm
new file mode 100644
index 0000000..0daa352
--- /dev/null
+++ b/test/out_of_order_decls/array/alias.wgsl.expected.spvasm
@@ -0,0 +1,30 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 16
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %f "f"
+               OpExecutionMode %f OriginUpperLeft
+               OpName %A "A"
+               OpName %f "f"
+               OpDecorate %_arr_int_uint_4 ArrayStride 4
+        %int = OpTypeInt 32 1
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_int_uint_4 = OpTypeArray %int %uint_4
+%_ptr_Private__arr_int_uint_4 = OpTypePointer Private %_arr_int_uint_4
+          %7 = OpConstantNull %_arr_int_uint_4
+          %A = OpVariable %_ptr_Private__arr_int_uint_4 Private %7
+       %void = OpTypeVoid
+          %8 = OpTypeFunction %void
+      %int_0 = OpConstant %int 0
+%_ptr_Private_int = OpTypePointer Private %int
+      %int_1 = OpConstant %int 1
+          %f = OpFunction %void None %8
+         %11 = OpLabel
+         %14 = OpAccessChain %_ptr_Private_int %A %int_0
+               OpStore %14 %int_1
+               OpReturn
+               OpFunctionEnd
diff --git a/test/out_of_order_decls/array/alias.wgsl.expected.wgsl b/test/out_of_order_decls/array/alias.wgsl.expected.wgsl
new file mode 100644
index 0000000..1e581e0
--- /dev/null
+++ b/test/out_of_order_decls/array/alias.wgsl.expected.wgsl
@@ -0,0 +1,8 @@
+var<private> A : array<T, 4>;
+
+type T = i32;
+
+@stage(fragment)
+fn f() {
+  A[0] = 1;
+}
diff --git a/test/out_of_order_decls/array/struct.wgsl b/test/out_of_order_decls/array/struct.wgsl
new file mode 100644
index 0000000..ab88948
--- /dev/null
+++ b/test/out_of_order_decls/array/struct.wgsl
@@ -0,0 +1,9 @@
+var<private> A : array<S, 4>;
+struct S {
+  m : i32;
+};
+
+@stage(fragment)
+fn f() {
+  A[0] = S(1);
+}
diff --git a/test/out_of_order_decls/array/struct.wgsl.expected.glsl b/test/out_of_order_decls/array/struct.wgsl.expected.glsl
new file mode 100644
index 0000000..2f4eab1
--- /dev/null
+++ b/test/out_of_order_decls/array/struct.wgsl.expected.glsl
@@ -0,0 +1,17 @@
+#version 310 es
+precision mediump float;
+
+struct S {
+  int m;
+};
+
+S A[4] = S[4](S(0), S(0), S(0), S(0));
+void f() {
+  S tint_symbol = S(1);
+  A[0] = tint_symbol;
+}
+
+void main() {
+  f();
+  return;
+}
diff --git a/test/out_of_order_decls/array/struct.wgsl.expected.hlsl b/test/out_of_order_decls/array/struct.wgsl.expected.hlsl
new file mode 100644
index 0000000..a708176
--- /dev/null
+++ b/test/out_of_order_decls/array/struct.wgsl.expected.hlsl
@@ -0,0 +1,11 @@
+struct S {
+  int m;
+};
+
+static S A[4] = (S[4])0;
+
+void f() {
+  const S tint_symbol = {1};
+  A[0] = tint_symbol;
+  return;
+}
diff --git a/test/out_of_order_decls/array/struct.wgsl.expected.msl b/test/out_of_order_decls/array/struct.wgsl.expected.msl
new file mode 100644
index 0000000..4e91e2e
--- /dev/null
+++ b/test/out_of_order_decls/array/struct.wgsl.expected.msl
@@ -0,0 +1,18 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct S {
+  int m;
+};
+
+struct tint_array_wrapper {
+  S arr[4];
+};
+
+fragment void f() {
+  thread tint_array_wrapper tint_symbol_1 = {};
+  S const tint_symbol = {.m=1};
+  tint_symbol_1.arr[0] = tint_symbol;
+  return;
+}
+
diff --git a/test/out_of_order_decls/array/struct.wgsl.expected.spvasm b/test/out_of_order_decls/array/struct.wgsl.expected.spvasm
new file mode 100644
index 0000000..317a445
--- /dev/null
+++ b/test/out_of_order_decls/array/struct.wgsl.expected.spvasm
@@ -0,0 +1,35 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 18
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %f "f"
+               OpExecutionMode %f OriginUpperLeft
+               OpName %S "S"
+               OpMemberName %S 0 "m"
+               OpName %A "A"
+               OpName %f "f"
+               OpMemberDecorate %S 0 Offset 0
+               OpDecorate %_arr_S_uint_4 ArrayStride 4
+        %int = OpTypeInt 32 1
+          %S = OpTypeStruct %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+%_ptr_Private__arr_S_uint_4 = OpTypePointer Private %_arr_S_uint_4
+          %8 = OpConstantNull %_arr_S_uint_4
+          %A = OpVariable %_ptr_Private__arr_S_uint_4 Private %8
+       %void = OpTypeVoid
+          %9 = OpTypeFunction %void
+      %int_0 = OpConstant %int 0
+%_ptr_Private_S = OpTypePointer Private %S
+      %int_1 = OpConstant %int 1
+         %17 = OpConstantComposite %S %int_1
+          %f = OpFunction %void None %9
+         %12 = OpLabel
+         %15 = OpAccessChain %_ptr_Private_S %A %int_0
+               OpStore %15 %17
+               OpReturn
+               OpFunctionEnd
diff --git a/test/out_of_order_decls/array/struct.wgsl.expected.wgsl b/test/out_of_order_decls/array/struct.wgsl.expected.wgsl
new file mode 100644
index 0000000..3e57163
--- /dev/null
+++ b/test/out_of_order_decls/array/struct.wgsl.expected.wgsl
@@ -0,0 +1,10 @@
+var<private> A : array<S, 4>;
+
+struct S {
+  m : i32;
+}
+
+@stage(fragment)
+fn f() {
+  A[0] = S(1);
+}
diff --git a/test/out_of_order_decls/func/func.wgsl b/test/out_of_order_decls/func/func.wgsl
new file mode 100644
index 0000000..1a0f212
--- /dev/null
+++ b/test/out_of_order_decls/func/func.wgsl
@@ -0,0 +1,7 @@
+@stage(fragment)
+fn f1() {
+  f2();
+}
+
+fn f2() {
+}
diff --git a/test/out_of_order_decls/func/func.wgsl.expected.glsl b/test/out_of_order_decls/func/func.wgsl.expected.glsl
new file mode 100644
index 0000000..4a87ea7
--- /dev/null
+++ b/test/out_of_order_decls/func/func.wgsl.expected.glsl
@@ -0,0 +1,14 @@
+#version 310 es
+precision mediump float;
+
+void f2() {
+}
+
+void f1() {
+  f2();
+}
+
+void main() {
+  f1();
+  return;
+}
diff --git a/test/out_of_order_decls/func/func.wgsl.expected.hlsl b/test/out_of_order_decls/func/func.wgsl.expected.hlsl
new file mode 100644
index 0000000..620afd7
--- /dev/null
+++ b/test/out_of_order_decls/func/func.wgsl.expected.hlsl
@@ -0,0 +1,7 @@
+void f2() {
+}
+
+void f1() {
+  f2();
+  return;
+}
diff --git a/test/out_of_order_decls/func/func.wgsl.expected.msl b/test/out_of_order_decls/func/func.wgsl.expected.msl
new file mode 100644
index 0000000..e04a45a
--- /dev/null
+++ b/test/out_of_order_decls/func/func.wgsl.expected.msl
@@ -0,0 +1,11 @@
+#include <metal_stdlib>
+
+using namespace metal;
+void f2() {
+}
+
+fragment void f1() {
+  f2();
+  return;
+}
+
diff --git a/test/out_of_order_decls/func/func.wgsl.expected.spvasm b/test/out_of_order_decls/func/func.wgsl.expected.spvasm
new file mode 100644
index 0000000..19570a4
--- /dev/null
+++ b/test/out_of_order_decls/func/func.wgsl.expected.spvasm
@@ -0,0 +1,22 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 8
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %f1 "f1"
+               OpExecutionMode %f1 OriginUpperLeft
+               OpName %f2 "f2"
+               OpName %f1 "f1"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+         %f2 = OpFunction %void None %1
+          %4 = OpLabel
+               OpReturn
+               OpFunctionEnd
+         %f1 = OpFunction %void None %1
+          %6 = OpLabel
+          %7 = OpFunctionCall %void %f2
+               OpReturn
+               OpFunctionEnd
diff --git a/test/out_of_order_decls/func/func.wgsl.expected.wgsl b/test/out_of_order_decls/func/func.wgsl.expected.wgsl
new file mode 100644
index 0000000..1a0f212
--- /dev/null
+++ b/test/out_of_order_decls/func/func.wgsl.expected.wgsl
@@ -0,0 +1,7 @@
+@stage(fragment)
+fn f1() {
+  f2();
+}
+
+fn f2() {
+}
diff --git a/test/out_of_order_decls/func/let.wgsl b/test/out_of_order_decls/func/let.wgsl
new file mode 100644
index 0000000..25a56c6
--- /dev/null
+++ b/test/out_of_order_decls/func/let.wgsl
@@ -0,0 +1,6 @@
+@stage(fragment)
+fn f() {
+  let b = a;
+}
+
+let a : i32 = 1;
diff --git a/test/out_of_order_decls/func/let.wgsl.expected.glsl b/test/out_of_order_decls/func/let.wgsl.expected.glsl
new file mode 100644
index 0000000..f308959
--- /dev/null
+++ b/test/out_of_order_decls/func/let.wgsl.expected.glsl
@@ -0,0 +1,12 @@
+#version 310 es
+precision mediump float;
+
+const int a = 1;
+void f() {
+  int b = a;
+}
+
+void main() {
+  f();
+  return;
+}
diff --git a/test/out_of_order_decls/func/let.wgsl.expected.hlsl b/test/out_of_order_decls/func/let.wgsl.expected.hlsl
new file mode 100644
index 0000000..c35c250
--- /dev/null
+++ b/test/out_of_order_decls/func/let.wgsl.expected.hlsl
@@ -0,0 +1,6 @@
+static const int a = 1;
+
+void f() {
+  const int b = a;
+  return;
+}
diff --git a/test/out_of_order_decls/func/let.wgsl.expected.msl b/test/out_of_order_decls/func/let.wgsl.expected.msl
new file mode 100644
index 0000000..2509d6c
--- /dev/null
+++ b/test/out_of_order_decls/func/let.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+constant int a = 1;
+
+fragment void f() {
+  int const b = a;
+  return;
+}
+
diff --git a/test/out_of_order_decls/func/let.wgsl.expected.spvasm b/test/out_of_order_decls/func/let.wgsl.expected.spvasm
new file mode 100644
index 0000000..452861f
--- /dev/null
+++ b/test/out_of_order_decls/func/let.wgsl.expected.spvasm
@@ -0,0 +1,19 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 7
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %f "f"
+               OpExecutionMode %f OriginUpperLeft
+               OpName %a "a"
+               OpName %f "f"
+        %int = OpTypeInt 32 1
+          %a = OpConstant %int 1
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+          %f = OpFunction %void None %3
+          %6 = OpLabel
+               OpReturn
+               OpFunctionEnd
diff --git a/test/out_of_order_decls/func/let.wgsl.expected.wgsl b/test/out_of_order_decls/func/let.wgsl.expected.wgsl
new file mode 100644
index 0000000..25a56c6
--- /dev/null
+++ b/test/out_of_order_decls/func/let.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+@stage(fragment)
+fn f() {
+  let b = a;
+}
+
+let a : i32 = 1;
diff --git a/test/out_of_order_decls/func/type.wgsl b/test/out_of_order_decls/func/type.wgsl
new file mode 100644
index 0000000..4810fc1
--- /dev/null
+++ b/test/out_of_order_decls/func/type.wgsl
@@ -0,0 +1,6 @@
+@stage(fragment)
+fn f() {
+  var b : T;
+}
+
+type T = i32;
diff --git a/test/out_of_order_decls/func/type.wgsl.expected.glsl b/test/out_of_order_decls/func/type.wgsl.expected.glsl
new file mode 100644
index 0000000..573558e
--- /dev/null
+++ b/test/out_of_order_decls/func/type.wgsl.expected.glsl
@@ -0,0 +1,11 @@
+#version 310 es
+precision mediump float;
+
+void f() {
+  int b = 0;
+}
+
+void main() {
+  f();
+  return;
+}
diff --git a/test/out_of_order_decls/func/type.wgsl.expected.hlsl b/test/out_of_order_decls/func/type.wgsl.expected.hlsl
new file mode 100644
index 0000000..f4b327c
--- /dev/null
+++ b/test/out_of_order_decls/func/type.wgsl.expected.hlsl
@@ -0,0 +1,4 @@
+void f() {
+  int b = 0;
+  return;
+}
diff --git a/test/out_of_order_decls/func/type.wgsl.expected.msl b/test/out_of_order_decls/func/type.wgsl.expected.msl
new file mode 100644
index 0000000..438c74f
--- /dev/null
+++ b/test/out_of_order_decls/func/type.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+fragment void f() {
+  int b = 0;
+  return;
+}
+
diff --git a/test/out_of_order_decls/func/type.wgsl.expected.spvasm b/test/out_of_order_decls/func/type.wgsl.expected.spvasm
new file mode 100644
index 0000000..1de57b4
--- /dev/null
+++ b/test/out_of_order_decls/func/type.wgsl.expected.spvasm
@@ -0,0 +1,21 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 9
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %f "f"
+               OpExecutionMode %f OriginUpperLeft
+               OpName %f "f"
+               OpName %b "b"
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+        %int = OpTypeInt 32 1
+%_ptr_Function_int = OpTypePointer Function %int
+          %8 = OpConstantNull %int
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+          %b = OpVariable %_ptr_Function_int Function %8
+               OpReturn
+               OpFunctionEnd
diff --git a/test/out_of_order_decls/func/type.wgsl.expected.wgsl b/test/out_of_order_decls/func/type.wgsl.expected.wgsl
new file mode 100644
index 0000000..4810fc1
--- /dev/null
+++ b/test/out_of_order_decls/func/type.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+@stage(fragment)
+fn f() {
+  var b : T;
+}
+
+type T = i32;
diff --git a/test/out_of_order_decls/func/var.wgsl b/test/out_of_order_decls/func/var.wgsl
new file mode 100644
index 0000000..d77a968
--- /dev/null
+++ b/test/out_of_order_decls/func/var.wgsl
@@ -0,0 +1,6 @@
+@stage(fragment)
+fn f() {
+  let b = a;
+}
+
+var<private> a : i32 = 1;
diff --git a/test/out_of_order_decls/func/var.wgsl.expected.glsl b/test/out_of_order_decls/func/var.wgsl.expected.glsl
new file mode 100644
index 0000000..6cf55fb
--- /dev/null
+++ b/test/out_of_order_decls/func/var.wgsl.expected.glsl
@@ -0,0 +1,12 @@
+#version 310 es
+precision mediump float;
+
+int a = 1;
+void f() {
+  int b = a;
+}
+
+void main() {
+  f();
+  return;
+}
diff --git a/test/out_of_order_decls/func/var.wgsl.expected.hlsl b/test/out_of_order_decls/func/var.wgsl.expected.hlsl
new file mode 100644
index 0000000..813886a
--- /dev/null
+++ b/test/out_of_order_decls/func/var.wgsl.expected.hlsl
@@ -0,0 +1,6 @@
+static int a = 1;
+
+void f() {
+  const int b = a;
+  return;
+}
diff --git a/test/out_of_order_decls/func/var.wgsl.expected.msl b/test/out_of_order_decls/func/var.wgsl.expected.msl
new file mode 100644
index 0000000..832e2eb
--- /dev/null
+++ b/test/out_of_order_decls/func/var.wgsl.expected.msl
@@ -0,0 +1,9 @@
+#include <metal_stdlib>
+
+using namespace metal;
+fragment void f() {
+  thread int tint_symbol = 1;
+  int const b = tint_symbol;
+  return;
+}
+
diff --git a/test/out_of_order_decls/func/var.wgsl.expected.spvasm b/test/out_of_order_decls/func/var.wgsl.expected.spvasm
new file mode 100644
index 0000000..16c9dc9
--- /dev/null
+++ b/test/out_of_order_decls/func/var.wgsl.expected.spvasm
@@ -0,0 +1,22 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 10
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %f "f"
+               OpExecutionMode %f OriginUpperLeft
+               OpName %a "a"
+               OpName %f "f"
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Private_int = OpTypePointer Private %int
+          %a = OpVariable %_ptr_Private_int Private %int_1
+       %void = OpTypeVoid
+          %5 = OpTypeFunction %void
+          %f = OpFunction %void None %5
+          %8 = OpLabel
+          %9 = OpLoad %int %a
+               OpReturn
+               OpFunctionEnd
diff --git a/test/out_of_order_decls/func/var.wgsl.expected.wgsl b/test/out_of_order_decls/func/var.wgsl.expected.wgsl
new file mode 100644
index 0000000..d77a968
--- /dev/null
+++ b/test/out_of_order_decls/func/var.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+@stage(fragment)
+fn f() {
+  let b = a;
+}
+
+var<private> a : i32 = 1;
diff --git a/test/out_of_order_decls/struct/alias.wgsl b/test/out_of_order_decls/struct/alias.wgsl
new file mode 100644
index 0000000..e225a73
--- /dev/null
+++ b/test/out_of_order_decls/struct/alias.wgsl
@@ -0,0 +1,10 @@
+struct S {
+  m : T;
+}
+
+type T = i32;
+
+@stage(fragment)
+fn f() {
+  var v : S;
+}
diff --git a/test/out_of_order_decls/struct/alias.wgsl.expected.glsl b/test/out_of_order_decls/struct/alias.wgsl.expected.glsl
new file mode 100644
index 0000000..508e315
--- /dev/null
+++ b/test/out_of_order_decls/struct/alias.wgsl.expected.glsl
@@ -0,0 +1,15 @@
+#version 310 es
+precision mediump float;
+
+struct S {
+  int m;
+};
+
+void f() {
+  S v = S(0);
+}
+
+void main() {
+  f();
+  return;
+}
diff --git a/test/out_of_order_decls/struct/alias.wgsl.expected.hlsl b/test/out_of_order_decls/struct/alias.wgsl.expected.hlsl
new file mode 100644
index 0000000..c113dac
--- /dev/null
+++ b/test/out_of_order_decls/struct/alias.wgsl.expected.hlsl
@@ -0,0 +1,8 @@
+struct S {
+  int m;
+};
+
+void f() {
+  S v = (S)0;
+  return;
+}
diff --git a/test/out_of_order_decls/struct/alias.wgsl.expected.msl b/test/out_of_order_decls/struct/alias.wgsl.expected.msl
new file mode 100644
index 0000000..c2a67d0
--- /dev/null
+++ b/test/out_of_order_decls/struct/alias.wgsl.expected.msl
@@ -0,0 +1,12 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct S {
+  int m;
+};
+
+fragment void f() {
+  S v = {};
+  return;
+}
+
diff --git a/test/out_of_order_decls/struct/alias.wgsl.expected.spvasm b/test/out_of_order_decls/struct/alias.wgsl.expected.spvasm
new file mode 100644
index 0000000..4194956
--- /dev/null
+++ b/test/out_of_order_decls/struct/alias.wgsl.expected.spvasm
@@ -0,0 +1,25 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 10
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %f "f"
+               OpExecutionMode %f OriginUpperLeft
+               OpName %f "f"
+               OpName %S "S"
+               OpMemberName %S 0 "m"
+               OpName %v "v"
+               OpMemberDecorate %S 0 Offset 0
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+        %int = OpTypeInt 32 1
+          %S = OpTypeStruct %int
+%_ptr_Function_S = OpTypePointer Function %S
+          %9 = OpConstantNull %S
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+          %v = OpVariable %_ptr_Function_S Function %9
+               OpReturn
+               OpFunctionEnd
diff --git a/test/out_of_order_decls/struct/alias.wgsl.expected.wgsl b/test/out_of_order_decls/struct/alias.wgsl.expected.wgsl
new file mode 100644
index 0000000..e225a73
--- /dev/null
+++ b/test/out_of_order_decls/struct/alias.wgsl.expected.wgsl
@@ -0,0 +1,10 @@
+struct S {
+  m : T;
+}
+
+type T = i32;
+
+@stage(fragment)
+fn f() {
+  var v : S;
+}
diff --git a/test/out_of_order_decls/struct/struct.wgsl b/test/out_of_order_decls/struct/struct.wgsl
new file mode 100644
index 0000000..d4e405f
--- /dev/null
+++ b/test/out_of_order_decls/struct/struct.wgsl
@@ -0,0 +1,12 @@
+struct S1 {
+  m : S2;
+}
+
+struct S2 {
+  m : i32;
+}
+
+@stage(fragment)
+fn f() {
+  var v : S1;
+}
diff --git a/test/out_of_order_decls/struct/struct.wgsl.expected.glsl b/test/out_of_order_decls/struct/struct.wgsl.expected.glsl
new file mode 100644
index 0000000..a95a80d
--- /dev/null
+++ b/test/out_of_order_decls/struct/struct.wgsl.expected.glsl
@@ -0,0 +1,19 @@
+#version 310 es
+precision mediump float;
+
+struct S2 {
+  int m;
+};
+
+struct S1 {
+  S2 m;
+};
+
+void f() {
+  S1 v = S1(S2(0));
+}
+
+void main() {
+  f();
+  return;
+}
diff --git a/test/out_of_order_decls/struct/struct.wgsl.expected.hlsl b/test/out_of_order_decls/struct/struct.wgsl.expected.hlsl
new file mode 100644
index 0000000..2f48847
--- /dev/null
+++ b/test/out_of_order_decls/struct/struct.wgsl.expected.hlsl
@@ -0,0 +1,11 @@
+struct S2 {
+  int m;
+};
+struct S1 {
+  S2 m;
+};
+
+void f() {
+  S1 v = (S1)0;
+  return;
+}
diff --git a/test/out_of_order_decls/struct/struct.wgsl.expected.msl b/test/out_of_order_decls/struct/struct.wgsl.expected.msl
new file mode 100644
index 0000000..6dcac2b
--- /dev/null
+++ b/test/out_of_order_decls/struct/struct.wgsl.expected.msl
@@ -0,0 +1,16 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct S2 {
+  int m;
+};
+
+struct S1 {
+  S2 m;
+};
+
+fragment void f() {
+  S1 v = {};
+  return;
+}
+
diff --git a/test/out_of_order_decls/struct/struct.wgsl.expected.spvasm b/test/out_of_order_decls/struct/struct.wgsl.expected.spvasm
new file mode 100644
index 0000000..30b44c5
--- /dev/null
+++ b/test/out_of_order_decls/struct/struct.wgsl.expected.spvasm
@@ -0,0 +1,29 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 11
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %f "f"
+               OpExecutionMode %f OriginUpperLeft
+               OpName %f "f"
+               OpName %S1 "S1"
+               OpMemberName %S1 0 "m"
+               OpName %S2 "S2"
+               OpMemberName %S2 0 "m"
+               OpName %v "v"
+               OpMemberDecorate %S1 0 Offset 0
+               OpMemberDecorate %S2 0 Offset 0
+       %void = OpTypeVoid
+          %1 = OpTypeFunction %void
+        %int = OpTypeInt 32 1
+         %S2 = OpTypeStruct %int
+         %S1 = OpTypeStruct %S2
+%_ptr_Function_S1 = OpTypePointer Function %S1
+         %10 = OpConstantNull %S1
+          %f = OpFunction %void None %1
+          %4 = OpLabel
+          %v = OpVariable %_ptr_Function_S1 Function %10
+               OpReturn
+               OpFunctionEnd
diff --git a/test/out_of_order_decls/struct/struct.wgsl.expected.wgsl b/test/out_of_order_decls/struct/struct.wgsl.expected.wgsl
new file mode 100644
index 0000000..d4e405f
--- /dev/null
+++ b/test/out_of_order_decls/struct/struct.wgsl.expected.wgsl
@@ -0,0 +1,12 @@
+struct S1 {
+  m : S2;
+}
+
+struct S2 {
+  m : i32;
+}
+
+@stage(fragment)
+fn f() {
+  var v : S1;
+}