[msl] Key PackedVec3 helpers on pointer type

Using the same composite type from multiple address spaces was causing
collisions in the helper functions that meant they were being reused
across different address spaces.

Fixed: 366037039
Change-Id: I72927b90febd26fa23cb7acd4153b70af1c69fbe
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/206375
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
diff --git a/src/tint/lang/msl/writer/raise/packed_vec3.cc b/src/tint/lang/msl/writer/raise/packed_vec3.cc
index 586b9d1..058bb03 100644
--- a/src/tint/lang/msl/writer/raise/packed_vec3.cc
+++ b/src/tint/lang/msl/writer/raise/packed_vec3.cc
@@ -64,11 +64,11 @@
     /// when inside an array.
     Hashmap<const core::type::Type*, const core::type::Struct*, 4> packed_array_element_types{};
 
-    // A map from an unpacked type to a helper function that will load it from a packed pointer.
-    Hashmap<const core::type::Type*, core::ir::Function*, 4> packed_load_helpers{};
+    // A map from a packed pointer type to a helper function that will load it to an unpacked type.
+    Hashmap<const core::type::Pointer*, core::ir::Function*, 4> packed_load_helpers{};
 
-    // A map from an unpacked type to a helper function that will store it to a packed pointer.
-    Hashmap<const core::type::Type*, core::ir::Function*, 4> packed_store_helpers{};
+    // A map from a packed pointer type to a helper function that will store an unpacked type to it.
+    Hashmap<const core::type::Pointer*, core::ir::Function*, 4> packed_store_helpers{};
 
     /// Process the module.
     void Process() {
@@ -410,7 +410,7 @@
     /// @returns the helper function
     core::ir::Function* LoadPackedArrayHelper(const core::type::Array* unpacked_arr,
                                               const core::type::Pointer* packed_ptr_type) {
-        return packed_load_helpers.GetOrAdd(unpacked_arr, [&] {
+        return packed_load_helpers.GetOrAdd(packed_ptr_type, [&] {
             auto* func = b.Function(sym.New("tint_load_array_packed_vec3").Name(), unpacked_arr);
             auto* from = b.FunctionParam("from", packed_ptr_type);
             func->SetParams({from});
@@ -472,7 +472,7 @@
     /// @returns the helper function
     core::ir::Function* LoadPackedStructHelper(const core::type::Struct* unpacked_str,
                                                const core::type::Pointer* packed_ptr_type) {
-        return packed_load_helpers.GetOrAdd(unpacked_str, [&] {
+        return packed_load_helpers.GetOrAdd(packed_ptr_type, [&] {
             auto* func = b.Function(sym.New("tint_load_struct_packed_vec3").Name(), unpacked_str);
             auto* from = b.FunctionParam("from", packed_ptr_type);
             func->SetParams({from});
@@ -547,7 +547,7 @@
     /// @returns the helper function
     core::ir::Function* StorePackedArrayHelper(const core::type::Array* unpacked_arr,
                                                const core::type::Pointer* packed_ptr_type) {
-        return packed_store_helpers.GetOrAdd(unpacked_arr, [&] {
+        return packed_store_helpers.GetOrAdd(packed_ptr_type, [&] {
             auto* func = b.Function(sym.New("tint_store_array_packed_vec3").Name(), ty.void_());
             auto* to = b.FunctionParam("to", packed_ptr_type);
             auto* value = b.FunctionParam("value", unpacked_arr);
@@ -603,7 +603,7 @@
     /// @returns the helper function
     core::ir::Function* StorePackedStructHelper(const core::type::Struct* unpacked_str,
                                                 const core::type::Pointer* packed_ptr_type) {
-        return packed_store_helpers.GetOrAdd(unpacked_str, [&] {
+        return packed_store_helpers.GetOrAdd(packed_ptr_type, [&] {
             auto* func = b.Function(sym.New("tint_store_array_packed_vec3").Name(), ty.void_());
             auto* to = b.FunctionParam("to", packed_ptr_type);
             auto* value = b.FunctionParam("value", unpacked_str);
diff --git a/src/tint/lang/msl/writer/raise/packed_vec3_test.cc b/src/tint/lang/msl/writer/raise/packed_vec3_test.cc
index c977028..e7704aa 100644
--- a/src/tint/lang/msl/writer/raise/packed_vec3_test.cc
+++ b/src/tint/lang/msl/writer/raise/packed_vec3_test.cc
@@ -3297,5 +3297,400 @@
     EXPECT_EQ(expect, str());
 }
 
+TEST_F(MslWriter_PackedVec3Test, MultipleAddressSpaces_LoadArray) {
+    auto* uvar = b.Var<uniform, array<vec3<f32>, 2>>("u");
+    uvar->SetBindingPoint(0, 0);
+    mod.root_block->Append(uvar);
+    auto* svar = b.Var<storage, array<vec3<f32>, 2>>("s");
+    svar->SetBindingPoint(0, 1);
+    mod.root_block->Append(svar);
+    auto* wvar = b.Var<workgroup, array<vec3<f32>, 2>>("w");
+    mod.root_block->Append(wvar);
+
+    auto* func = b.Function("foo", ty.void_());
+    b.Append(func->Block(), [&] {  //
+        b.Let("u_load", b.Load(uvar));
+        b.Let("s_load", b.Load(svar));
+        b.Let("w_load", b.Load(wvar));
+        b.Return(func);
+    });
+
+    auto* src = R"(
+$B1: {  # root
+  %u:ptr<uniform, array<vec3<f32>, 2>, read> = var @binding_point(0, 0)
+  %s:ptr<storage, array<vec3<f32>, 2>, read_write> = var @binding_point(0, 1)
+  %w:ptr<workgroup, array<vec3<f32>, 2>, read_write> = var
+}
+
+%foo = func():void {
+  $B2: {
+    %5:array<vec3<f32>, 2> = load %u
+    %u_load:array<vec3<f32>, 2> = let %5
+    %7:array<vec3<f32>, 2> = load %s
+    %s_load:array<vec3<f32>, 2> = let %7
+    %9:array<vec3<f32>, 2> = load %w
+    %w_load:array<vec3<f32>, 2> = let %9
+    ret
+  }
+}
+)";
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+tint_packed_vec3_f32_array_element = struct @align(16) {
+  packed:__packed_vec3<f32> @offset(0)
+}
+
+$B1: {  # root
+  %u:ptr<uniform, array<tint_packed_vec3_f32_array_element, 2>, read> = var @binding_point(0, 0)
+  %s:ptr<storage, array<tint_packed_vec3_f32_array_element, 2>, read_write> = var @binding_point(0, 1)
+  %w:ptr<workgroup, array<tint_packed_vec3_f32_array_element, 2>, read_write> = var
+}
+
+%foo = func():void {
+  $B2: {
+    %5:array<vec3<f32>, 2> = call %tint_load_array_packed_vec3, %u
+    %u_load:array<vec3<f32>, 2> = let %5
+    %8:array<vec3<f32>, 2> = call %tint_load_array_packed_vec3_1, %s
+    %s_load:array<vec3<f32>, 2> = let %8
+    %11:array<vec3<f32>, 2> = call %tint_load_array_packed_vec3_2, %w
+    %w_load:array<vec3<f32>, 2> = let %11
+    ret
+  }
+}
+%tint_load_array_packed_vec3 = func(%from:ptr<uniform, array<tint_packed_vec3_f32_array_element, 2>, read>):array<vec3<f32>, 2> {
+  $B3: {
+    %15:ptr<uniform, __packed_vec3<f32>, read> = access %from, 0u, 0u
+    %16:__packed_vec3<f32> = load %15
+    %17:vec3<f32> = convert %16
+    %18:ptr<uniform, __packed_vec3<f32>, read> = access %from, 1u, 0u
+    %19:__packed_vec3<f32> = load %18
+    %20:vec3<f32> = convert %19
+    %21:array<vec3<f32>, 2> = construct %17, %20
+    ret %21
+  }
+}
+%tint_load_array_packed_vec3_1 = func(%from_1:ptr<storage, array<tint_packed_vec3_f32_array_element, 2>, read_write>):array<vec3<f32>, 2> {  # %from_1: 'from'
+  $B4: {
+    %23:ptr<storage, __packed_vec3<f32>, read_write> = access %from_1, 0u, 0u
+    %24:__packed_vec3<f32> = load %23
+    %25:vec3<f32> = convert %24
+    %26:ptr<storage, __packed_vec3<f32>, read_write> = access %from_1, 1u, 0u
+    %27:__packed_vec3<f32> = load %26
+    %28:vec3<f32> = convert %27
+    %29:array<vec3<f32>, 2> = construct %25, %28
+    ret %29
+  }
+}
+%tint_load_array_packed_vec3_2 = func(%from_2:ptr<workgroup, array<tint_packed_vec3_f32_array_element, 2>, read_write>):array<vec3<f32>, 2> {  # %from_2: 'from'
+  $B5: {
+    %31:ptr<workgroup, __packed_vec3<f32>, read_write> = access %from_2, 0u, 0u
+    %32:__packed_vec3<f32> = load %31
+    %33:vec3<f32> = convert %32
+    %34:ptr<workgroup, __packed_vec3<f32>, read_write> = access %from_2, 1u, 0u
+    %35:__packed_vec3<f32> = load %34
+    %36:vec3<f32> = convert %35
+    %37:array<vec3<f32>, 2> = construct %33, %36
+    ret %37
+  }
+}
+)";
+
+    Run(PackedVec3);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(MslWriter_PackedVec3Test, MultipleAddressSpaces_StoreArray) {
+    auto* svar = b.Var<storage, array<vec3<f32>, 2>>("s");
+    svar->SetBindingPoint(0, 0);
+    mod.root_block->Append(svar);
+    auto* wvar = b.Var<workgroup, array<vec3<f32>, 2>>("w");
+    mod.root_block->Append(wvar);
+
+    auto* func = b.Function("foo", ty.void_());
+    b.Append(func->Block(), [&] {  //
+        b.Store(svar, b.Zero<array<vec3<f32>, 2>>());
+        b.Store(wvar, b.Zero<array<vec3<f32>, 2>>());
+        b.Return(func);
+    });
+
+    auto* src = R"(
+$B1: {  # root
+  %s:ptr<storage, array<vec3<f32>, 2>, read_write> = var @binding_point(0, 0)
+  %w:ptr<workgroup, array<vec3<f32>, 2>, read_write> = var
+}
+
+%foo = func():void {
+  $B2: {
+    store %s, array<vec3<f32>, 2>(vec3<f32>(0.0f))
+    store %w, array<vec3<f32>, 2>(vec3<f32>(0.0f))
+    ret
+  }
+}
+)";
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+tint_packed_vec3_f32_array_element = struct @align(16) {
+  packed:__packed_vec3<f32> @offset(0)
+}
+
+$B1: {  # root
+  %s:ptr<storage, array<tint_packed_vec3_f32_array_element, 2>, read_write> = var @binding_point(0, 0)
+  %w:ptr<workgroup, array<tint_packed_vec3_f32_array_element, 2>, read_write> = var
+}
+
+%foo = func():void {
+  $B2: {
+    %4:void = call %tint_store_array_packed_vec3, %s, array<vec3<f32>, 2>(vec3<f32>(0.0f))
+    %6:void = call %tint_store_array_packed_vec3_1, %w, array<vec3<f32>, 2>(vec3<f32>(0.0f))
+    ret
+  }
+}
+%tint_store_array_packed_vec3 = func(%to:ptr<storage, array<tint_packed_vec3_f32_array_element, 2>, read_write>, %value:array<vec3<f32>, 2>):void {
+  $B3: {
+    %10:vec3<f32> = access %value, 0u
+    %11:ptr<storage, __packed_vec3<f32>, read_write> = access %to, 0u, 0u
+    %12:__packed_vec3<f32> = convert %10
+    store %11, %12
+    %13:vec3<f32> = access %value, 1u
+    %14:ptr<storage, __packed_vec3<f32>, read_write> = access %to, 1u, 0u
+    %15:__packed_vec3<f32> = convert %13
+    store %14, %15
+    ret
+  }
+}
+%tint_store_array_packed_vec3_1 = func(%to_1:ptr<workgroup, array<tint_packed_vec3_f32_array_element, 2>, read_write>, %value_1:array<vec3<f32>, 2>):void {  # %to_1: 'to', %value_1: 'value'
+  $B4: {
+    %18:vec3<f32> = access %value_1, 0u
+    %19:ptr<workgroup, __packed_vec3<f32>, read_write> = access %to_1, 0u, 0u
+    %20:__packed_vec3<f32> = convert %18
+    store %19, %20
+    %21:vec3<f32> = access %value_1, 1u
+    %22:ptr<workgroup, __packed_vec3<f32>, read_write> = access %to_1, 1u, 0u
+    %23:__packed_vec3<f32> = convert %21
+    store %22, %23
+    ret
+  }
+}
+)";
+
+    Run(PackedVec3);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(MslWriter_PackedVec3Test, MultipleAddressSpaces_LoadStruct) {
+    auto* s = ty.Struct(mod.symbols.New("S"), {
+                                                  {mod.symbols.Register("vec"), ty.vec3<u32>()},
+                                                  {mod.symbols.Register("u"), ty.u32()},
+                                              });
+
+    auto* uvar = b.Var("u", ty.ptr<uniform>(s));
+    uvar->SetBindingPoint(0, 0);
+    mod.root_block->Append(uvar);
+    auto* svar = b.Var("s", ty.ptr<storage>(s));
+    svar->SetBindingPoint(0, 1);
+    mod.root_block->Append(svar);
+    auto* wvar = b.Var("w", ty.ptr<workgroup>(s));
+    mod.root_block->Append(wvar);
+
+    auto* func = b.Function("foo", ty.void_());
+    b.Append(func->Block(), [&] {  //
+        b.Let("u_load", b.Load(uvar));
+        b.Let("s_load", b.Load(svar));
+        b.Let("w_load", b.Load(wvar));
+        b.Return(func);
+    });
+
+    auto* src = R"(
+S = struct @align(16) {
+  vec:vec3<u32> @offset(0)
+  u:u32 @offset(12)
+}
+
+$B1: {  # root
+  %u:ptr<uniform, S, read> = var @binding_point(0, 0)
+  %s:ptr<storage, S, read_write> = var @binding_point(0, 1)
+  %w:ptr<workgroup, S, read_write> = var
+}
+
+%foo = func():void {
+  $B2: {
+    %5:S = load %u
+    %u_load:S = let %5
+    %7:S = load %s
+    %s_load:S = let %7
+    %9:S = load %w
+    %w_load:S = let %9
+    ret
+  }
+}
+)";
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+S = struct @align(16) {
+  vec:vec3<u32> @offset(0)
+  u:u32 @offset(12)
+}
+
+S_packed_vec3 = struct @align(16) {
+  vec:__packed_vec3<u32> @offset(0)
+  u:u32 @offset(12)
+}
+
+$B1: {  # root
+  %u:ptr<uniform, S_packed_vec3, read> = var @binding_point(0, 0)
+  %s:ptr<storage, S_packed_vec3, read_write> = var @binding_point(0, 1)
+  %w:ptr<workgroup, S_packed_vec3, read_write> = var
+}
+
+%foo = func():void {
+  $B2: {
+    %5:S = call %tint_load_struct_packed_vec3, %u
+    %u_load:S = let %5
+    %8:S = call %tint_load_struct_packed_vec3_1, %s
+    %s_load:S = let %8
+    %11:S = call %tint_load_struct_packed_vec3_2, %w
+    %w_load:S = let %11
+    ret
+  }
+}
+%tint_load_struct_packed_vec3 = func(%from:ptr<uniform, S_packed_vec3, read>):S {
+  $B3: {
+    %15:ptr<uniform, __packed_vec3<u32>, read> = access %from, 0u
+    %16:__packed_vec3<u32> = load %15
+    %17:vec3<u32> = convert %16
+    %18:ptr<uniform, u32, read> = access %from, 1u
+    %19:u32 = load %18
+    %20:S = construct %17, %19
+    ret %20
+  }
+}
+%tint_load_struct_packed_vec3_1 = func(%from_1:ptr<storage, S_packed_vec3, read_write>):S {  # %from_1: 'from'
+  $B4: {
+    %22:ptr<storage, __packed_vec3<u32>, read_write> = access %from_1, 0u
+    %23:__packed_vec3<u32> = load %22
+    %24:vec3<u32> = convert %23
+    %25:ptr<storage, u32, read_write> = access %from_1, 1u
+    %26:u32 = load %25
+    %27:S = construct %24, %26
+    ret %27
+  }
+}
+%tint_load_struct_packed_vec3_2 = func(%from_2:ptr<workgroup, S_packed_vec3, read_write>):S {  # %from_2: 'from'
+  $B5: {
+    %29:ptr<workgroup, __packed_vec3<u32>, read_write> = access %from_2, 0u
+    %30:__packed_vec3<u32> = load %29
+    %31:vec3<u32> = convert %30
+    %32:ptr<workgroup, u32, read_write> = access %from_2, 1u
+    %33:u32 = load %32
+    %34:S = construct %31, %33
+    ret %34
+  }
+}
+)";
+
+    Run(PackedVec3);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(MslWriter_PackedVec3Test, MultipleAddressSpaces_StoreStruct) {
+    auto* s = ty.Struct(mod.symbols.New("S"), {
+                                                  {mod.symbols.Register("vec"), ty.vec3<u32>()},
+                                                  {mod.symbols.Register("u"), ty.u32()},
+                                              });
+
+    auto* svar = b.Var("s", ty.ptr<storage>(s));
+    svar->SetBindingPoint(0, 0);
+    mod.root_block->Append(svar);
+    auto* wvar = b.Var("w", ty.ptr<workgroup>(s));
+    mod.root_block->Append(wvar);
+
+    auto* func = b.Function("foo", ty.void_());
+    b.Append(func->Block(), [&] {  //
+        b.Store(svar, b.Zero(s));
+        b.Store(wvar, b.Zero(s));
+        b.Return(func);
+    });
+
+    auto* src = R"(
+S = struct @align(16) {
+  vec:vec3<u32> @offset(0)
+  u:u32 @offset(12)
+}
+
+$B1: {  # root
+  %s:ptr<storage, S, read_write> = var @binding_point(0, 0)
+  %w:ptr<workgroup, S, read_write> = var
+}
+
+%foo = func():void {
+  $B2: {
+    store %s, S(vec3<u32>(0u), 0u)
+    store %w, S(vec3<u32>(0u), 0u)
+    ret
+  }
+}
+)";
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+S = struct @align(16) {
+  vec:vec3<u32> @offset(0)
+  u:u32 @offset(12)
+}
+
+S_packed_vec3 = struct @align(16) {
+  vec:__packed_vec3<u32> @offset(0)
+  u:u32 @offset(12)
+}
+
+$B1: {  # root
+  %s:ptr<storage, S_packed_vec3, read_write> = var @binding_point(0, 0)
+  %w:ptr<workgroup, S_packed_vec3, read_write> = var
+}
+
+%foo = func():void {
+  $B2: {
+    %4:void = call %tint_store_array_packed_vec3, %s, S(vec3<u32>(0u), 0u)
+    %6:void = call %tint_store_array_packed_vec3_1, %w, S(vec3<u32>(0u), 0u)
+    ret
+  }
+}
+%tint_store_array_packed_vec3 = func(%to:ptr<storage, S_packed_vec3, read_write>, %value:S):void {
+  $B3: {
+    %10:vec3<u32> = access %value, 0u
+    %11:ptr<storage, __packed_vec3<u32>, read_write> = access %to, 0u
+    %12:__packed_vec3<u32> = convert %10
+    store %11, %12
+    %13:u32 = access %value, 1u
+    %14:ptr<storage, u32, read_write> = access %to, 1u
+    store %14, %13
+    ret
+  }
+}
+%tint_store_array_packed_vec3_1 = func(%to_1:ptr<workgroup, S_packed_vec3, read_write>, %value_1:S):void {  # %to_1: 'to', %value_1: 'value'
+  $B4: {
+    %17:vec3<u32> = access %value_1, 0u
+    %18:ptr<workgroup, __packed_vec3<u32>, read_write> = access %to_1, 0u
+    %19:__packed_vec3<u32> = convert %17
+    store %18, %19
+    %20:u32 = access %value_1, 1u
+    %21:ptr<workgroup, u32, read_write> = access %to_1, 1u
+    store %21, %20
+    ret
+  }
+}
+)";
+
+    Run(PackedVec3);
+
+    EXPECT_EQ(expect, str());
+}
+
 }  // namespace
 }  // namespace tint::msl::writer::raise
diff --git a/test/tint/bug/tint/366037039.wgsl b/test/tint/bug/tint/366037039.wgsl
new file mode 100644
index 0000000..73fcbcc
--- /dev/null
+++ b/test/tint/bug/tint/366037039.wgsl
@@ -0,0 +1,20 @@
+struct S {
+  a : vec3u,
+  b : u32,
+  c : array<vec3u, 4>,
+}
+
+@group(0) @binding(0)
+var<uniform> ubuffer : S;
+@group(0) @binding(1)
+var<storage, read_write> sbuffer : S;
+var<workgroup> wbuffer : S;
+
+fn foo() {
+  let u = ubuffer;
+  let s = sbuffer;
+  let w = sbuffer;
+
+  sbuffer = S();
+  wbuffer = S();
+}
diff --git a/test/tint/bug/tint/366037039.wgsl.expected.dxc.hlsl b/test/tint/bug/tint/366037039.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..1d64aea
--- /dev/null
+++ b/test/tint/bug/tint/366037039.wgsl.expected.dxc.hlsl
@@ -0,0 +1,76 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+struct S {
+  uint3 a;
+  uint b;
+  uint3 c[4];
+};
+
+cbuffer cbuffer_ubuffer : register(b0) {
+  uint4 ubuffer[5];
+};
+RWByteAddressBuffer sbuffer : register(u1);
+groupshared S wbuffer;
+
+typedef uint3 ubuffer_load_3_ret[4];
+ubuffer_load_3_ret ubuffer_load_3(uint offset) {
+  uint3 arr[4] = (uint3[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      const uint scalar_offset = ((offset + (i * 16u))) / 4;
+      arr[i] = ubuffer[scalar_offset / 4].xyz;
+    }
+  }
+  return arr;
+}
+
+S ubuffer_load(uint offset) {
+  const uint scalar_offset_1 = ((offset + 0u)) / 4;
+  const uint scalar_offset_2 = ((offset + 12u)) / 4;
+  S tint_symbol = {ubuffer[scalar_offset_1 / 4].xyz, ubuffer[scalar_offset_2 / 4][scalar_offset_2 % 4], ubuffer_load_3((offset + 16u))};
+  return tint_symbol;
+}
+
+typedef uint3 sbuffer_load_3_ret[4];
+sbuffer_load_3_ret sbuffer_load_3(uint offset) {
+  uint3 arr_1[4] = (uint3[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr_1[i_1] = sbuffer.Load3((offset + (i_1 * 16u)));
+    }
+  }
+  return arr_1;
+}
+
+S sbuffer_load(uint offset) {
+  S tint_symbol_1 = {sbuffer.Load3((offset + 0u)), sbuffer.Load((offset + 12u)), sbuffer_load_3((offset + 16u))};
+  return tint_symbol_1;
+}
+
+void sbuffer_store_3(uint offset, uint3 value[4]) {
+  uint3 array_1[4] = value;
+  {
+    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
+      sbuffer.Store3((offset + (i_2 * 16u)), asuint(array_1[i_2]));
+    }
+  }
+}
+
+void sbuffer_store(uint offset, S value) {
+  sbuffer.Store3((offset + 0u), asuint(value.a));
+  sbuffer.Store((offset + 12u), asuint(value.b));
+  sbuffer_store_3((offset + 16u), value.c);
+}
+
+void foo() {
+  S u = ubuffer_load(0u);
+  S s = sbuffer_load(0u);
+  S w = sbuffer_load(0u);
+  S tint_symbol_2 = (S)0;
+  sbuffer_store(0u, tint_symbol_2);
+  S tint_symbol_3 = (S)0;
+  wbuffer = tint_symbol_3;
+}
diff --git a/test/tint/bug/tint/366037039.wgsl.expected.fxc.hlsl b/test/tint/bug/tint/366037039.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..1d64aea
--- /dev/null
+++ b/test/tint/bug/tint/366037039.wgsl.expected.fxc.hlsl
@@ -0,0 +1,76 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+  return;
+}
+
+struct S {
+  uint3 a;
+  uint b;
+  uint3 c[4];
+};
+
+cbuffer cbuffer_ubuffer : register(b0) {
+  uint4 ubuffer[5];
+};
+RWByteAddressBuffer sbuffer : register(u1);
+groupshared S wbuffer;
+
+typedef uint3 ubuffer_load_3_ret[4];
+ubuffer_load_3_ret ubuffer_load_3(uint offset) {
+  uint3 arr[4] = (uint3[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      const uint scalar_offset = ((offset + (i * 16u))) / 4;
+      arr[i] = ubuffer[scalar_offset / 4].xyz;
+    }
+  }
+  return arr;
+}
+
+S ubuffer_load(uint offset) {
+  const uint scalar_offset_1 = ((offset + 0u)) / 4;
+  const uint scalar_offset_2 = ((offset + 12u)) / 4;
+  S tint_symbol = {ubuffer[scalar_offset_1 / 4].xyz, ubuffer[scalar_offset_2 / 4][scalar_offset_2 % 4], ubuffer_load_3((offset + 16u))};
+  return tint_symbol;
+}
+
+typedef uint3 sbuffer_load_3_ret[4];
+sbuffer_load_3_ret sbuffer_load_3(uint offset) {
+  uint3 arr_1[4] = (uint3[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr_1[i_1] = sbuffer.Load3((offset + (i_1 * 16u)));
+    }
+  }
+  return arr_1;
+}
+
+S sbuffer_load(uint offset) {
+  S tint_symbol_1 = {sbuffer.Load3((offset + 0u)), sbuffer.Load((offset + 12u)), sbuffer_load_3((offset + 16u))};
+  return tint_symbol_1;
+}
+
+void sbuffer_store_3(uint offset, uint3 value[4]) {
+  uint3 array_1[4] = value;
+  {
+    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
+      sbuffer.Store3((offset + (i_2 * 16u)), asuint(array_1[i_2]));
+    }
+  }
+}
+
+void sbuffer_store(uint offset, S value) {
+  sbuffer.Store3((offset + 0u), asuint(value.a));
+  sbuffer.Store((offset + 12u), asuint(value.b));
+  sbuffer_store_3((offset + 16u), value.c);
+}
+
+void foo() {
+  S u = ubuffer_load(0u);
+  S s = sbuffer_load(0u);
+  S w = sbuffer_load(0u);
+  S tint_symbol_2 = (S)0;
+  sbuffer_store(0u, tint_symbol_2);
+  S tint_symbol_3 = (S)0;
+  wbuffer = tint_symbol_3;
+}
diff --git a/test/tint/bug/tint/366037039.wgsl.expected.glsl b/test/tint/bug/tint/366037039.wgsl.expected.glsl
new file mode 100644
index 0000000..784a03f
--- /dev/null
+++ b/test/tint/bug/tint/366037039.wgsl.expected.glsl
@@ -0,0 +1,45 @@
+#version 310 es
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void unused_entry_point() {
+  return;
+}
+struct S {
+  uvec3 a;
+  uint b;
+  uvec3 c[4];
+};
+
+layout(binding = 0, std140) uniform ubuffer_block_ubo {
+  S inner;
+} ubuffer;
+
+layout(binding = 1, std430) buffer ubuffer_block_ssbo {
+  S inner;
+} sbuffer;
+
+shared S wbuffer;
+void assign_and_preserve_padding_1_sbuffer_inner_c(uvec3 value[4]) {
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      sbuffer.inner.c[i] = value[i];
+    }
+  }
+}
+
+void assign_and_preserve_padding_sbuffer_inner(S value) {
+  sbuffer.inner.a = value.a;
+  sbuffer.inner.b = value.b;
+  assign_and_preserve_padding_1_sbuffer_inner_c(value.c);
+}
+
+void foo() {
+  S u = ubuffer.inner;
+  S s = sbuffer.inner;
+  S w = sbuffer.inner;
+  S tint_symbol = S(uvec3(0u), 0u, uvec3[4](uvec3(0u), uvec3(0u), uvec3(0u), uvec3(0u)));
+  assign_and_preserve_padding_sbuffer_inner(tint_symbol);
+  S tint_symbol_1 = S(uvec3(0u), 0u, uvec3[4](uvec3(0u), uvec3(0u), uvec3(0u), uvec3(0u)));
+  wbuffer = tint_symbol_1;
+}
+
diff --git a/test/tint/bug/tint/366037039.wgsl.expected.ir.dxc.hlsl b/test/tint/bug/tint/366037039.wgsl.expected.ir.dxc.hlsl
new file mode 100644
index 0000000..6290db7
--- /dev/null
+++ b/test/tint/bug/tint/366037039.wgsl.expected.ir.dxc.hlsl
@@ -0,0 +1,111 @@
+struct S {
+  uint3 a;
+  uint b;
+  uint3 c[4];
+};
+
+
+cbuffer cbuffer_ubuffer : register(b0) {
+  uint4 ubuffer[5];
+};
+RWByteAddressBuffer sbuffer : register(u1);
+groupshared S wbuffer;
+void v(uint offset, uint3 obj[4]) {
+  {
+    uint v_1 = 0u;
+    v_1 = 0u;
+    while(true) {
+      uint v_2 = v_1;
+      if ((v_2 >= 4u)) {
+        break;
+      }
+      sbuffer.Store3((offset + (v_2 * 16u)), obj[v_2]);
+      {
+        v_1 = (v_2 + 1u);
+      }
+      continue;
+    }
+  }
+}
+
+void v_3(uint offset, S obj) {
+  sbuffer.Store3((offset + 0u), obj.a);
+  sbuffer.Store((offset + 12u), obj.b);
+  uint3 v_4[4] = obj.c;
+  v((offset + 16u), v_4);
+}
+
+typedef uint3 ary_ret[4];
+ary_ret v_5(uint offset) {
+  uint3 a[4] = (uint3[4])0;
+  {
+    uint v_6 = 0u;
+    v_6 = 0u;
+    while(true) {
+      uint v_7 = v_6;
+      if ((v_7 >= 4u)) {
+        break;
+      }
+      a[v_7] = sbuffer.Load3((offset + (v_7 * 16u)));
+      {
+        v_6 = (v_7 + 1u);
+      }
+      continue;
+    }
+  }
+  uint3 v_8[4] = a;
+  return v_8;
+}
+
+S v_9(uint offset) {
+  uint3 v_10 = sbuffer.Load3((offset + 0u));
+  uint v_11 = sbuffer.Load((offset + 12u));
+  uint3 v_12[4] = v_5((offset + 16u));
+  S v_13 = {v_10, v_11, v_12};
+  return v_13;
+}
+
+typedef uint3 ary_ret_1[4];
+ary_ret_1 v_14(uint start_byte_offset) {
+  uint3 a[4] = (uint3[4])0;
+  {
+    uint v_15 = 0u;
+    v_15 = 0u;
+    while(true) {
+      uint v_16 = v_15;
+      if ((v_16 >= 4u)) {
+        break;
+      }
+      a[v_16] = ubuffer[((start_byte_offset + (v_16 * 16u)) / 16u)].xyz;
+      {
+        v_15 = (v_16 + 1u);
+      }
+      continue;
+    }
+  }
+  uint3 v_17[4] = a;
+  return v_17;
+}
+
+S v_18(uint start_byte_offset) {
+  uint3 v_19 = ubuffer[(start_byte_offset / 16u)].xyz;
+  uint v_20 = ubuffer[((12u + start_byte_offset) / 16u)][(((12u + start_byte_offset) % 16u) / 4u)];
+  uint3 v_21[4] = v_14((16u + start_byte_offset));
+  S v_22 = {v_19, v_20, v_21};
+  return v_22;
+}
+
+void foo() {
+  S u = v_18(0u);
+  S s = v_9(0u);
+  S w = v_9(0u);
+  S v_23 = (S)0;
+  v_3(0u, v_23);
+  S v_24 = (S)0;
+  wbuffer = v_24;
+}
+
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+}
+
diff --git a/test/tint/bug/tint/366037039.wgsl.expected.ir.fxc.hlsl b/test/tint/bug/tint/366037039.wgsl.expected.ir.fxc.hlsl
new file mode 100644
index 0000000..6290db7
--- /dev/null
+++ b/test/tint/bug/tint/366037039.wgsl.expected.ir.fxc.hlsl
@@ -0,0 +1,111 @@
+struct S {
+  uint3 a;
+  uint b;
+  uint3 c[4];
+};
+
+
+cbuffer cbuffer_ubuffer : register(b0) {
+  uint4 ubuffer[5];
+};
+RWByteAddressBuffer sbuffer : register(u1);
+groupshared S wbuffer;
+void v(uint offset, uint3 obj[4]) {
+  {
+    uint v_1 = 0u;
+    v_1 = 0u;
+    while(true) {
+      uint v_2 = v_1;
+      if ((v_2 >= 4u)) {
+        break;
+      }
+      sbuffer.Store3((offset + (v_2 * 16u)), obj[v_2]);
+      {
+        v_1 = (v_2 + 1u);
+      }
+      continue;
+    }
+  }
+}
+
+void v_3(uint offset, S obj) {
+  sbuffer.Store3((offset + 0u), obj.a);
+  sbuffer.Store((offset + 12u), obj.b);
+  uint3 v_4[4] = obj.c;
+  v((offset + 16u), v_4);
+}
+
+typedef uint3 ary_ret[4];
+ary_ret v_5(uint offset) {
+  uint3 a[4] = (uint3[4])0;
+  {
+    uint v_6 = 0u;
+    v_6 = 0u;
+    while(true) {
+      uint v_7 = v_6;
+      if ((v_7 >= 4u)) {
+        break;
+      }
+      a[v_7] = sbuffer.Load3((offset + (v_7 * 16u)));
+      {
+        v_6 = (v_7 + 1u);
+      }
+      continue;
+    }
+  }
+  uint3 v_8[4] = a;
+  return v_8;
+}
+
+S v_9(uint offset) {
+  uint3 v_10 = sbuffer.Load3((offset + 0u));
+  uint v_11 = sbuffer.Load((offset + 12u));
+  uint3 v_12[4] = v_5((offset + 16u));
+  S v_13 = {v_10, v_11, v_12};
+  return v_13;
+}
+
+typedef uint3 ary_ret_1[4];
+ary_ret_1 v_14(uint start_byte_offset) {
+  uint3 a[4] = (uint3[4])0;
+  {
+    uint v_15 = 0u;
+    v_15 = 0u;
+    while(true) {
+      uint v_16 = v_15;
+      if ((v_16 >= 4u)) {
+        break;
+      }
+      a[v_16] = ubuffer[((start_byte_offset + (v_16 * 16u)) / 16u)].xyz;
+      {
+        v_15 = (v_16 + 1u);
+      }
+      continue;
+    }
+  }
+  uint3 v_17[4] = a;
+  return v_17;
+}
+
+S v_18(uint start_byte_offset) {
+  uint3 v_19 = ubuffer[(start_byte_offset / 16u)].xyz;
+  uint v_20 = ubuffer[((12u + start_byte_offset) / 16u)][(((12u + start_byte_offset) % 16u) / 4u)];
+  uint3 v_21[4] = v_14((16u + start_byte_offset));
+  S v_22 = {v_19, v_20, v_21};
+  return v_22;
+}
+
+void foo() {
+  S u = v_18(0u);
+  S s = v_9(0u);
+  S w = v_9(0u);
+  S v_23 = (S)0;
+  v_3(0u, v_23);
+  S v_24 = (S)0;
+  wbuffer = v_24;
+}
+
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+}
+
diff --git a/test/tint/bug/tint/366037039.wgsl.expected.ir.glsl b/test/tint/bug/tint/366037039.wgsl.expected.ir.glsl
new file mode 100644
index 0000000..a14b766
--- /dev/null
+++ b/test/tint/bug/tint/366037039.wgsl.expected.ir.glsl
@@ -0,0 +1,50 @@
+#version 310 es
+
+
+struct S {
+  uvec3 a;
+  uint b;
+  uvec3 c[4];
+};
+
+layout(binding = 0, std140)
+uniform tint_symbol_1_1_ubo {
+  S tint_symbol;
+} v;
+layout(binding = 1, std430)
+buffer tint_symbol_3_1_ssbo {
+  S tint_symbol_2;
+} v_1;
+shared S wbuffer;
+void tint_store_and_preserve_padding_1(inout uvec3 target[4], uvec3 value_param[4]) {
+  {
+    uint v_2 = 0u;
+    v_2 = 0u;
+    while(true) {
+      uint v_3 = v_2;
+      if ((v_3 >= 4u)) {
+        break;
+      }
+      target[v_3] = value_param[v_3];
+      {
+        v_2 = (v_3 + 1u);
+      }
+      continue;
+    }
+  }
+}
+void tint_store_and_preserve_padding(inout S target, S value_param) {
+  target.a = value_param.a;
+  target.b = value_param.b;
+  tint_store_and_preserve_padding_1(target.c, value_param.c);
+}
+void foo() {
+  S u = v.tint_symbol;
+  S s = v_1.tint_symbol_2;
+  S w = v_1.tint_symbol_2;
+  tint_store_and_preserve_padding(v_1.tint_symbol_2, S(uvec3(0u), 0u, uvec3[4](uvec3(0u), uvec3(0u), uvec3(0u), uvec3(0u))));
+  wbuffer = S(uvec3(0u), 0u, uvec3[4](uvec3(0u), uvec3(0u), uvec3(0u), uvec3(0u)));
+}
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+}
diff --git a/test/tint/bug/tint/366037039.wgsl.expected.ir.msl b/test/tint/bug/tint/366037039.wgsl.expected.ir.msl
new file mode 100644
index 0000000..3da7d69
--- /dev/null
+++ b/test/tint/bug/tint/366037039.wgsl.expected.ir.msl
@@ -0,0 +1,111 @@
+#include <metal_stdlib>
+using namespace metal;
+
+template<typename T, size_t N>
+struct tint_array {
+  const constant T& operator[](size_t i) const constant { return elements[i]; }
+  device T& operator[](size_t i) device { return elements[i]; }
+  const device T& operator[](size_t i) const device { return elements[i]; }
+  thread T& operator[](size_t i) thread { return elements[i]; }
+  const thread T& operator[](size_t i) const thread { return elements[i]; }
+  threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+  const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+  T elements[N];
+};
+
+struct tint_packed_vec3_u32_array_element {
+  packed_uint3 packed;
+};
+
+struct S_packed_vec3 {
+  packed_uint3 a;
+  uint b;
+  tint_array<tint_packed_vec3_u32_array_element, 4> c;
+};
+
+struct S {
+  uint3 a;
+  uint b;
+  tint_array<uint3, 4> c;
+};
+
+#define TINT_ISOLATE_UB(VOLATILE_NAME) \
+  volatile bool VOLATILE_NAME = true; \
+  if (VOLATILE_NAME)
+
+struct tint_module_vars_struct {
+  const constant S_packed_vec3* ubuffer;
+  device S_packed_vec3* sbuffer;
+  threadgroup S_packed_vec3* wbuffer;
+};
+
+void tint_store_array_packed_vec3_1(threadgroup tint_array<tint_packed_vec3_u32_array_element, 4>* const to, tint_array<uint3, 4> value) {
+  (*to)[0u].packed = packed_uint3(value[0u]);
+  (*to)[1u].packed = packed_uint3(value[1u]);
+  (*to)[2u].packed = packed_uint3(value[2u]);
+  (*to)[3u].packed = packed_uint3(value[3u]);
+}
+
+void tint_store_array_packed_vec3(threadgroup S_packed_vec3* const to, S value) {
+  (*to).a = packed_uint3(value.a);
+  (*to).b = value.b;
+  tint_store_array_packed_vec3_1((&(*to).c), value.c);
+}
+
+void tint_store_and_preserve_padding_1(device tint_array<tint_packed_vec3_u32_array_element, 4>* const target, tint_array<uint3, 4> value_param) {
+  {
+    uint v = 0u;
+    v = 0u;
+    TINT_ISOLATE_UB(tint_volatile_true) while(true) {
+      uint const v_1 = v;
+      if ((v_1 >= 4u)) {
+        break;
+      }
+      (*target)[v_1].packed = packed_uint3(value_param[v_1]);
+      {
+        v = (v_1 + 1u);
+      }
+      continue;
+    }
+  }
+}
+
+void tint_store_and_preserve_padding(device S_packed_vec3* const target, S value_param) {
+  (*target).a = packed_uint3(value_param.a);
+  (*target).b = value_param.b;
+  tint_store_and_preserve_padding_1((&(*target).c), value_param.c);
+}
+
+tint_array<uint3, 4> tint_load_array_packed_vec3_1(device tint_array<tint_packed_vec3_u32_array_element, 4>* const from) {
+  uint3 const v_2 = uint3((*from)[0u].packed);
+  uint3 const v_3 = uint3((*from)[1u].packed);
+  uint3 const v_4 = uint3((*from)[2u].packed);
+  return tint_array<uint3, 4>{v_2, v_3, v_4, uint3((*from)[3u].packed)};
+}
+
+S tint_load_struct_packed_vec3_1(device S_packed_vec3* const from) {
+  uint3 const v_5 = uint3((*from).a);
+  uint const v_6 = (*from).b;
+  return S{.a=v_5, .b=v_6, .c=tint_load_array_packed_vec3_1((&(*from).c))};
+}
+
+tint_array<uint3, 4> tint_load_array_packed_vec3(const constant tint_array<tint_packed_vec3_u32_array_element, 4>* const from) {
+  uint3 const v_7 = uint3((*from)[0u].packed);
+  uint3 const v_8 = uint3((*from)[1u].packed);
+  uint3 const v_9 = uint3((*from)[2u].packed);
+  return tint_array<uint3, 4>{v_7, v_8, v_9, uint3((*from)[3u].packed)};
+}
+
+S tint_load_struct_packed_vec3(const constant S_packed_vec3* const from) {
+  uint3 const v_10 = uint3((*from).a);
+  uint const v_11 = (*from).b;
+  return S{.a=v_10, .b=v_11, .c=tint_load_array_packed_vec3((&(*from).c))};
+}
+
+void foo(tint_module_vars_struct tint_module_vars) {
+  S const u = tint_load_struct_packed_vec3(tint_module_vars.ubuffer);
+  S const s = tint_load_struct_packed_vec3_1(tint_module_vars.sbuffer);
+  S const w = tint_load_struct_packed_vec3_1(tint_module_vars.sbuffer);
+  tint_store_and_preserve_padding(tint_module_vars.sbuffer, S{});
+  tint_store_array_packed_vec3(tint_module_vars.wbuffer, S{});
+}
diff --git a/test/tint/bug/tint/366037039.wgsl.expected.msl b/test/tint/bug/tint/366037039.wgsl.expected.msl
new file mode 100644
index 0000000..bf0f065
--- /dev/null
+++ b/test/tint/bug/tint/366037039.wgsl.expected.msl
@@ -0,0 +1,72 @@
+#include <metal_stdlib>
+
+using namespace metal;
+
+template<typename T, size_t N>
+struct tint_array {
+    const constant T& operator[](size_t i) const constant { return elements[i]; }
+    device T& operator[](size_t i) device { return elements[i]; }
+    const device T& operator[](size_t i) const device { return elements[i]; }
+    thread T& operator[](size_t i) thread { return elements[i]; }
+    const thread T& operator[](size_t i) const thread { return elements[i]; }
+    threadgroup T& operator[](size_t i) threadgroup { return elements[i]; }
+    const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; }
+    T elements[N];
+};
+
+#define TINT_ISOLATE_UB(VOLATILE_NAME) \
+  volatile bool VOLATILE_NAME = true; \
+  if (VOLATILE_NAME)
+
+struct tint_packed_vec3_u32_array_element {
+  /* 0x0000 */ packed_uint3 elements;
+  /* 0x000c */ tint_array<int8_t, 4> tint_pad;
+};
+
+struct S_tint_packed_vec3 {
+  /* 0x0000 */ packed_uint3 a;
+  /* 0x000c */ uint b;
+  /* 0x0010 */ tint_array<tint_packed_vec3_u32_array_element, 4> c;
+};
+
+tint_array<uint3, 4> tint_unpack_vec3_in_composite(tint_array<tint_packed_vec3_u32_array_element, 4> in) {
+  tint_array<uint3, 4> result = tint_array<uint3, 4>{uint3(in[0].elements), uint3(in[1].elements), uint3(in[2].elements), uint3(in[3].elements)};
+  return result;
+}
+
+struct S {
+  uint3 a;
+  uint b;
+  tint_array<uint3, 4> c;
+};
+
+S tint_unpack_vec3_in_composite_1(S_tint_packed_vec3 in) {
+  S result = {};
+  result.a = uint3(in.a);
+  result.b = in.b;
+  result.c = tint_unpack_vec3_in_composite(in.c);
+  return result;
+}
+
+void assign_and_preserve_padding_1(device tint_array<tint_packed_vec3_u32_array_element, 4>* const dest, tint_array<uint3, 4> value) {
+  TINT_ISOLATE_UB(tint_volatile_true) for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+    (*(dest))[i].elements = packed_uint3(value[i]);
+  }
+}
+
+void assign_and_preserve_padding(device S_tint_packed_vec3* const dest, S value) {
+  (*(dest)).a = packed_uint3(value.a);
+  (*(dest)).b = value.b;
+  assign_and_preserve_padding_1(&((*(dest)).c), value.c);
+}
+
+void foo(const constant S_tint_packed_vec3* const tint_symbol_2, device S_tint_packed_vec3* const tint_symbol_3, threadgroup S* const tint_symbol_4) {
+  S const u = tint_unpack_vec3_in_composite_1(*(tint_symbol_2));
+  S const s = tint_unpack_vec3_in_composite_1(*(tint_symbol_3));
+  S const w = tint_unpack_vec3_in_composite_1(*(tint_symbol_3));
+  S const tint_symbol = S{};
+  assign_and_preserve_padding(tint_symbol_3, tint_symbol);
+  S const tint_symbol_1 = S{};
+  *(tint_symbol_4) = tint_symbol_1;
+}
+
diff --git a/test/tint/bug/tint/366037039.wgsl.expected.spvasm b/test/tint/bug/tint/366037039.wgsl.expected.spvasm
new file mode 100644
index 0000000..b8facdf
--- /dev/null
+++ b/test/tint/bug/tint/366037039.wgsl.expected.spvasm
@@ -0,0 +1,128 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 1
+; Bound: 66
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+               OpExecutionMode %unused_entry_point LocalSize 1 1 1
+               OpMemberName %S 0 "a"
+               OpMemberName %S 1 "b"
+               OpMemberName %S 2 "c"
+               OpName %S "S"
+               OpMemberName %tint_symbol_1 0 "tint_symbol"
+               OpName %tint_symbol_1 "tint_symbol_1"
+               OpMemberName %tint_symbol_3 0 "tint_symbol_2"
+               OpName %tint_symbol_3 "tint_symbol_3"
+               OpName %wbuffer "wbuffer"
+               OpName %foo "foo"
+               OpName %u "u"
+               OpName %s "s"
+               OpName %w "w"
+               OpName %tint_store_and_preserve_padding "tint_store_and_preserve_padding"
+               OpName %value_param "value_param"
+               OpName %tint_store_and_preserve_padding_0 "tint_store_and_preserve_padding"
+               OpName %value_param_0 "value_param"
+               OpName %unused_entry_point "unused_entry_point"
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 12
+               OpDecorate %_arr_v3uint_uint_4 ArrayStride 16
+               OpMemberDecorate %S 2 Offset 16
+               OpMemberDecorate %tint_symbol_1 0 Offset 0
+               OpDecorate %tint_symbol_1 Block
+               OpDecorate %1 DescriptorSet 0
+               OpDecorate %1 Binding 0
+               OpDecorate %1 NonWritable
+               OpMemberDecorate %tint_symbol_3 0 Offset 0
+               OpDecorate %tint_symbol_3 Block
+               OpDecorate %9 DescriptorSet 0
+               OpDecorate %9 Binding 1
+               OpDecorate %9 Coherent
+       %uint = OpTypeInt 32 0
+     %v3uint = OpTypeVector %uint 3
+     %uint_4 = OpConstant %uint 4
+%_arr_v3uint_uint_4 = OpTypeArray %v3uint %uint_4
+          %S = OpTypeStruct %v3uint %uint %_arr_v3uint_uint_4
+%tint_symbol_1 = OpTypeStruct %S
+%_ptr_Uniform_tint_symbol_1 = OpTypePointer Uniform %tint_symbol_1
+          %1 = OpVariable %_ptr_Uniform_tint_symbol_1 Uniform
+%tint_symbol_3 = OpTypeStruct %S
+%_ptr_StorageBuffer_tint_symbol_3 = OpTypePointer StorageBuffer %tint_symbol_3
+          %9 = OpVariable %_ptr_StorageBuffer_tint_symbol_3 StorageBuffer
+%_ptr_Workgroup_S = OpTypePointer Workgroup %S
+    %wbuffer = OpVariable %_ptr_Workgroup_S Workgroup
+       %void = OpTypeVoid
+         %16 = OpTypeFunction %void
+%_ptr_Uniform_S = OpTypePointer Uniform %S
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
+         %29 = OpConstantNull %S
+         %31 = OpTypeFunction %void %S
+%_ptr_StorageBuffer_v3uint = OpTypePointer StorageBuffer %v3uint
+%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
+     %uint_1 = OpConstant %uint 1
+         %44 = OpTypeFunction %void %_arr_v3uint_uint_4
+%_ptr_Function__arr_v3uint_uint_4 = OpTypePointer Function %_arr_v3uint_uint_4
+       %bool = OpTypeBool
+     %uint_2 = OpConstant %uint 2
+%_ptr_Function_v3uint = OpTypePointer Function %v3uint
+        %foo = OpFunction %void None %16
+         %17 = OpLabel
+         %18 = OpAccessChain %_ptr_Uniform_S %1 %uint_0
+          %u = OpLoad %S %18 None
+         %22 = OpAccessChain %_ptr_StorageBuffer_S %9 %uint_0
+          %s = OpLoad %S %22 None
+         %25 = OpAccessChain %_ptr_StorageBuffer_S %9 %uint_0
+          %w = OpLoad %S %25 None
+         %27 = OpFunctionCall %void %tint_store_and_preserve_padding %29
+               OpStore %wbuffer %29 None
+               OpReturn
+               OpFunctionEnd
+%tint_store_and_preserve_padding = OpFunction %void None %31
+%value_param = OpFunctionParameter %S
+         %32 = OpLabel
+         %33 = OpAccessChain %_ptr_StorageBuffer_v3uint %9 %uint_0 %uint_0
+         %35 = OpCompositeExtract %v3uint %value_param 0
+               OpStore %33 %35 None
+         %36 = OpAccessChain %_ptr_StorageBuffer_uint %9 %uint_0 %uint_1
+         %39 = OpCompositeExtract %uint %value_param 1
+               OpStore %36 %39 None
+         %40 = OpCompositeExtract %_arr_v3uint_uint_4 %value_param 2
+         %41 = OpFunctionCall %void %tint_store_and_preserve_padding_0 %40
+               OpReturn
+               OpFunctionEnd
+%tint_store_and_preserve_padding_0 = OpFunction %void None %44
+%value_param_0 = OpFunctionParameter %_arr_v3uint_uint_4
+         %45 = OpLabel
+         %46 = OpVariable %_ptr_Function__arr_v3uint_uint_4 Function
+               OpStore %46 %value_param_0
+               OpBranch %48
+         %48 = OpLabel
+               OpBranch %51
+         %51 = OpLabel
+         %53 = OpPhi %uint %uint_0 %48 %54 %50
+               OpLoopMerge %52 %50 None
+               OpBranch %49
+         %49 = OpLabel
+         %55 = OpUGreaterThanEqual %bool %53 %uint_4
+               OpSelectionMerge %57 None
+               OpBranchConditional %55 %58 %57
+         %58 = OpLabel
+               OpBranch %52
+         %57 = OpLabel
+         %59 = OpAccessChain %_ptr_StorageBuffer_v3uint %9 %uint_0 %uint_2 %53
+         %61 = OpAccessChain %_ptr_Function_v3uint %46 %53
+         %63 = OpLoad %v3uint %61 None
+               OpStore %59 %63 None
+               OpBranch %50
+         %50 = OpLabel
+         %54 = OpIAdd %uint %53 %uint_1
+               OpBranch %51
+         %52 = OpLabel
+               OpReturn
+               OpFunctionEnd
+%unused_entry_point = OpFunction %void None %16
+         %65 = OpLabel
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/bug/tint/366037039.wgsl.expected.wgsl b/test/tint/bug/tint/366037039.wgsl.expected.wgsl
new file mode 100644
index 0000000..aa0d007
--- /dev/null
+++ b/test/tint/bug/tint/366037039.wgsl.expected.wgsl
@@ -0,0 +1,19 @@
+struct S {
+  a : vec3u,
+  b : u32,
+  c : array<vec3u, 4>,
+}
+
+@group(0) @binding(0) var<uniform> ubuffer : S;
+
+@group(0) @binding(1) var<storage, read_write> sbuffer : S;
+
+var<workgroup> wbuffer : S;
+
+fn foo() {
+  let u = ubuffer;
+  let s = sbuffer;
+  let w = sbuffer;
+  sbuffer = S();
+  wbuffer = S();
+}