Tint/E2E: Add f16 uniform/storage buffer E2E tests

This CL add Tint E2E tests for f16 types in uniform and storage buffers.

Bug: tint:1473, tint:1502
Change-Id: I325524d2df326240cc1b080a90abf5bd076b3da1
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/107543
Reviewed-by: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Zhaoming Jiang <zhaoming.jiang@intel.com>
diff --git a/test/tint/buffer/storage/dynamic_index/read.wgsl b/test/tint/buffer/storage/dynamic_index/read.wgsl
index 7c50c42..e0995f7 100644
--- a/test/tint/buffer/storage/dynamic_index/read.wgsl
+++ b/test/tint/buffer/storage/dynamic_index/read.wgsl
@@ -1,30 +1,56 @@
 struct Inner {
-    a : vec3<i32>,
-    b : i32,
-    c : vec3<u32>,
-    d : u32,
-    e : vec3<f32>,
-    f : f32,
-    g : mat2x3<f32>,
-    h : mat3x2<f32>,
-    i : array<vec4<i32>, 4>,
+    scalar_f32 : f32,
+    scalar_i32 : i32,
+    scalar_u32 : u32,
+    vec2_f32 : vec2<f32>,
+    vec2_i32 : vec2<i32>,
+    vec2_u32 : vec2<u32>,
+    vec3_f32 : vec3<f32>,
+    vec3_i32 : vec3<i32>,
+    vec3_u32 : vec3<u32>,
+    vec4_f32 : vec4<f32>,
+    vec4_i32 : vec4<i32>,
+    vec4_u32 : vec4<u32>,
+    mat2x2_f32 : mat2x2<f32>,
+    mat2x3_f32 : mat2x3<f32>,
+    mat2x4_f32 : mat2x4<f32>,
+    mat3x2_f32 : mat3x2<f32>,
+    mat3x3_f32 : mat3x3<f32>,
+    mat3x4_f32 : mat3x4<f32>,
+    mat4x2_f32 : mat4x2<f32>,
+    mat4x3_f32 : mat4x3<f32>,
+    mat4x4_f32 : mat4x4<f32>,
+    arr2_vec3_f32 : array<vec3<f32>, 2>,
 };
 
 struct S {
     arr : array<Inner>,
 };
 
-@binding(0) @group(0) var<storage, read> s : S;
+@binding(0) @group(0) var<storage, read> sb : S;
 
 @compute @workgroup_size(1)
 fn main(@builtin(local_invocation_index) idx : u32) {
-    let a = s.arr[idx].a;
-    let b = s.arr[idx].b;
-    let c = s.arr[idx].c;
-    let d = s.arr[idx].d;
-    let e = s.arr[idx].e;
-    let f = s.arr[idx].f;
-    let g = s.arr[idx].g;
-    let h = s.arr[idx].h;
-    let i = s.arr[idx].i;
+    let scalar_f32 : f32 = sb.arr[idx].scalar_f32;
+    let scalar_i32 : i32 = sb.arr[idx].scalar_i32;
+    let scalar_u32 : u32 = sb.arr[idx].scalar_u32;
+    let vec2_f32 : vec2<f32> = sb.arr[idx].vec2_f32;
+    let vec2_i32 : vec2<i32> = sb.arr[idx].vec2_i32;
+    let vec2_u32 : vec2<u32> = sb.arr[idx].vec2_u32;
+    let vec3_f32 : vec3<f32> = sb.arr[idx].vec3_f32;
+    let vec3_i32 : vec3<i32> = sb.arr[idx].vec3_i32;
+    let vec3_u32 : vec3<u32> = sb.arr[idx].vec3_u32;
+    let vec4_f32 : vec4<f32> = sb.arr[idx].vec4_f32;
+    let vec4_i32 : vec4<i32> = sb.arr[idx].vec4_i32;
+    let vec4_u32 : vec4<u32> = sb.arr[idx].vec4_u32;
+    let mat2x2_f32 : mat2x2<f32> = sb.arr[idx].mat2x2_f32;
+    let mat2x3_f32 : mat2x3<f32> = sb.arr[idx].mat2x3_f32;
+    let mat2x4_f32 : mat2x4<f32> = sb.arr[idx].mat2x4_f32;
+    let mat3x2_f32 : mat3x2<f32> = sb.arr[idx].mat3x2_f32;
+    let mat3x3_f32 : mat3x3<f32> = sb.arr[idx].mat3x3_f32;
+    let mat3x4_f32 : mat3x4<f32> = sb.arr[idx].mat3x4_f32;
+    let mat4x2_f32 : mat4x2<f32> = sb.arr[idx].mat4x2_f32;
+    let mat4x3_f32 : mat4x3<f32> = sb.arr[idx].mat4x3_f32;
+    let mat4x4_f32 : mat4x4<f32> = sb.arr[idx].mat4x4_f32;
+    let arr2_vec3_f32 : array<vec3<f32>, 2> = sb.arr[idx].arr2_vec3_f32;
 }
diff --git a/test/tint/buffer/storage/dynamic_index/read.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/dynamic_index/read.wgsl.expected.dxc.hlsl
index 789126b..17abe57 100644
--- a/test/tint/buffer/storage/dynamic_index/read.wgsl.expected.dxc.hlsl
+++ b/test/tint/buffer/storage/dynamic_index/read.wgsl.expected.dxc.hlsl
@@ -1,38 +1,79 @@
-ByteAddressBuffer s : register(t0, space0);
+ByteAddressBuffer sb : register(t0, space0);
 
 struct tint_symbol_1 {
   uint idx : SV_GroupIndex;
 };
 
-float2x3 tint_symbol_8(ByteAddressBuffer buffer, uint offset) {
+float2x2 tint_symbol_14(ByteAddressBuffer buffer, uint offset) {
+  return float2x2(asfloat(buffer.Load2((offset + 0u))), asfloat(buffer.Load2((offset + 8u))));
+}
+
+float2x3 tint_symbol_15(ByteAddressBuffer buffer, uint offset) {
   return float2x3(asfloat(buffer.Load3((offset + 0u))), asfloat(buffer.Load3((offset + 16u))));
 }
 
-float3x2 tint_symbol_9(ByteAddressBuffer buffer, uint offset) {
+float2x4 tint_symbol_16(ByteAddressBuffer buffer, uint offset) {
+  return float2x4(asfloat(buffer.Load4((offset + 0u))), asfloat(buffer.Load4((offset + 16u))));
+}
+
+float3x2 tint_symbol_17(ByteAddressBuffer buffer, uint offset) {
   return float3x2(asfloat(buffer.Load2((offset + 0u))), asfloat(buffer.Load2((offset + 8u))), asfloat(buffer.Load2((offset + 16u))));
 }
 
-typedef int4 tint_symbol_11_ret[4];
-tint_symbol_11_ret tint_symbol_11(ByteAddressBuffer buffer, uint offset) {
-  int4 arr_1[4] = (int4[4])0;
+float3x3 tint_symbol_18(ByteAddressBuffer buffer, uint offset) {
+  return float3x3(asfloat(buffer.Load3((offset + 0u))), asfloat(buffer.Load3((offset + 16u))), asfloat(buffer.Load3((offset + 32u))));
+}
+
+float3x4 tint_symbol_19(ByteAddressBuffer buffer, uint offset) {
+  return float3x4(asfloat(buffer.Load4((offset + 0u))), asfloat(buffer.Load4((offset + 16u))), asfloat(buffer.Load4((offset + 32u))));
+}
+
+float4x2 tint_symbol_20(ByteAddressBuffer buffer, uint offset) {
+  return float4x2(asfloat(buffer.Load2((offset + 0u))), asfloat(buffer.Load2((offset + 8u))), asfloat(buffer.Load2((offset + 16u))), asfloat(buffer.Load2((offset + 24u))));
+}
+
+float4x3 tint_symbol_21(ByteAddressBuffer buffer, uint offset) {
+  return float4x3(asfloat(buffer.Load3((offset + 0u))), asfloat(buffer.Load3((offset + 16u))), asfloat(buffer.Load3((offset + 32u))), asfloat(buffer.Load3((offset + 48u))));
+}
+
+float4x4 tint_symbol_22(ByteAddressBuffer buffer, uint offset) {
+  return float4x4(asfloat(buffer.Load4((offset + 0u))), asfloat(buffer.Load4((offset + 16u))), asfloat(buffer.Load4((offset + 32u))), asfloat(buffer.Load4((offset + 48u))));
+}
+
+typedef float3 tint_symbol_23_ret[2];
+tint_symbol_23_ret tint_symbol_23(ByteAddressBuffer buffer, uint offset) {
+  float3 arr_1[2] = (float3[2])0;
   {
-    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
-      arr_1[i_1] = asint(buffer.Load4((offset + (i_1 * 16u))));
+    for(uint i = 0u; (i < 2u); i = (i + 1u)) {
+      arr_1[i] = asfloat(buffer.Load3((offset + (i * 16u))));
     }
   }
   return arr_1;
 }
 
 void main_inner(uint idx) {
-  const int3 a = asint(s.Load3((176u * idx)));
-  const int b = asint(s.Load(((176u * idx) + 12u)));
-  const uint3 c = s.Load3(((176u * idx) + 16u));
-  const uint d = s.Load(((176u * idx) + 28u));
-  const float3 e = asfloat(s.Load3(((176u * idx) + 32u)));
-  const float f = asfloat(s.Load(((176u * idx) + 44u)));
-  const float2x3 g = tint_symbol_8(s, ((176u * idx) + 48u));
-  const float3x2 h = tint_symbol_9(s, ((176u * idx) + 80u));
-  const int4 i[4] = tint_symbol_11(s, ((176u * idx) + 112u));
+  const float scalar_f32 = asfloat(sb.Load((544u * idx)));
+  const int scalar_i32 = asint(sb.Load(((544u * idx) + 4u)));
+  const uint scalar_u32 = sb.Load(((544u * idx) + 8u));
+  const float2 vec2_f32 = asfloat(sb.Load2(((544u * idx) + 16u)));
+  const int2 vec2_i32 = asint(sb.Load2(((544u * idx) + 24u)));
+  const uint2 vec2_u32 = sb.Load2(((544u * idx) + 32u));
+  const float3 vec3_f32 = asfloat(sb.Load3(((544u * idx) + 48u)));
+  const int3 vec3_i32 = asint(sb.Load3(((544u * idx) + 64u)));
+  const uint3 vec3_u32 = sb.Load3(((544u * idx) + 80u));
+  const float4 vec4_f32 = asfloat(sb.Load4(((544u * idx) + 96u)));
+  const int4 vec4_i32 = asint(sb.Load4(((544u * idx) + 112u)));
+  const uint4 vec4_u32 = sb.Load4(((544u * idx) + 128u));
+  const float2x2 mat2x2_f32 = tint_symbol_14(sb, ((544u * idx) + 144u));
+  const float2x3 mat2x3_f32 = tint_symbol_15(sb, ((544u * idx) + 160u));
+  const float2x4 mat2x4_f32 = tint_symbol_16(sb, ((544u * idx) + 192u));
+  const float3x2 mat3x2_f32 = tint_symbol_17(sb, ((544u * idx) + 224u));
+  const float3x3 mat3x3_f32 = tint_symbol_18(sb, ((544u * idx) + 256u));
+  const float3x4 mat3x4_f32 = tint_symbol_19(sb, ((544u * idx) + 304u));
+  const float4x2 mat4x2_f32 = tint_symbol_20(sb, ((544u * idx) + 352u));
+  const float4x3 mat4x3_f32 = tint_symbol_21(sb, ((544u * idx) + 384u));
+  const float4x4 mat4x4_f32 = tint_symbol_22(sb, ((544u * idx) + 448u));
+  const float3 arr2_vec3_f32[2] = tint_symbol_23(sb, ((544u * idx) + 512u));
 }
 
 [numthreads(1, 1, 1)]
diff --git a/test/tint/buffer/storage/dynamic_index/read.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/dynamic_index/read.wgsl.expected.fxc.hlsl
index 789126b..17abe57 100644
--- a/test/tint/buffer/storage/dynamic_index/read.wgsl.expected.fxc.hlsl
+++ b/test/tint/buffer/storage/dynamic_index/read.wgsl.expected.fxc.hlsl
@@ -1,38 +1,79 @@
-ByteAddressBuffer s : register(t0, space0);
+ByteAddressBuffer sb : register(t0, space0);
 
 struct tint_symbol_1 {
   uint idx : SV_GroupIndex;
 };
 
-float2x3 tint_symbol_8(ByteAddressBuffer buffer, uint offset) {
+float2x2 tint_symbol_14(ByteAddressBuffer buffer, uint offset) {
+  return float2x2(asfloat(buffer.Load2((offset + 0u))), asfloat(buffer.Load2((offset + 8u))));
+}
+
+float2x3 tint_symbol_15(ByteAddressBuffer buffer, uint offset) {
   return float2x3(asfloat(buffer.Load3((offset + 0u))), asfloat(buffer.Load3((offset + 16u))));
 }
 
-float3x2 tint_symbol_9(ByteAddressBuffer buffer, uint offset) {
+float2x4 tint_symbol_16(ByteAddressBuffer buffer, uint offset) {
+  return float2x4(asfloat(buffer.Load4((offset + 0u))), asfloat(buffer.Load4((offset + 16u))));
+}
+
+float3x2 tint_symbol_17(ByteAddressBuffer buffer, uint offset) {
   return float3x2(asfloat(buffer.Load2((offset + 0u))), asfloat(buffer.Load2((offset + 8u))), asfloat(buffer.Load2((offset + 16u))));
 }
 
-typedef int4 tint_symbol_11_ret[4];
-tint_symbol_11_ret tint_symbol_11(ByteAddressBuffer buffer, uint offset) {
-  int4 arr_1[4] = (int4[4])0;
+float3x3 tint_symbol_18(ByteAddressBuffer buffer, uint offset) {
+  return float3x3(asfloat(buffer.Load3((offset + 0u))), asfloat(buffer.Load3((offset + 16u))), asfloat(buffer.Load3((offset + 32u))));
+}
+
+float3x4 tint_symbol_19(ByteAddressBuffer buffer, uint offset) {
+  return float3x4(asfloat(buffer.Load4((offset + 0u))), asfloat(buffer.Load4((offset + 16u))), asfloat(buffer.Load4((offset + 32u))));
+}
+
+float4x2 tint_symbol_20(ByteAddressBuffer buffer, uint offset) {
+  return float4x2(asfloat(buffer.Load2((offset + 0u))), asfloat(buffer.Load2((offset + 8u))), asfloat(buffer.Load2((offset + 16u))), asfloat(buffer.Load2((offset + 24u))));
+}
+
+float4x3 tint_symbol_21(ByteAddressBuffer buffer, uint offset) {
+  return float4x3(asfloat(buffer.Load3((offset + 0u))), asfloat(buffer.Load3((offset + 16u))), asfloat(buffer.Load3((offset + 32u))), asfloat(buffer.Load3((offset + 48u))));
+}
+
+float4x4 tint_symbol_22(ByteAddressBuffer buffer, uint offset) {
+  return float4x4(asfloat(buffer.Load4((offset + 0u))), asfloat(buffer.Load4((offset + 16u))), asfloat(buffer.Load4((offset + 32u))), asfloat(buffer.Load4((offset + 48u))));
+}
+
+typedef float3 tint_symbol_23_ret[2];
+tint_symbol_23_ret tint_symbol_23(ByteAddressBuffer buffer, uint offset) {
+  float3 arr_1[2] = (float3[2])0;
   {
-    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
-      arr_1[i_1] = asint(buffer.Load4((offset + (i_1 * 16u))));
+    for(uint i = 0u; (i < 2u); i = (i + 1u)) {
+      arr_1[i] = asfloat(buffer.Load3((offset + (i * 16u))));
     }
   }
   return arr_1;
 }
 
 void main_inner(uint idx) {
-  const int3 a = asint(s.Load3((176u * idx)));
-  const int b = asint(s.Load(((176u * idx) + 12u)));
-  const uint3 c = s.Load3(((176u * idx) + 16u));
-  const uint d = s.Load(((176u * idx) + 28u));
-  const float3 e = asfloat(s.Load3(((176u * idx) + 32u)));
-  const float f = asfloat(s.Load(((176u * idx) + 44u)));
-  const float2x3 g = tint_symbol_8(s, ((176u * idx) + 48u));
-  const float3x2 h = tint_symbol_9(s, ((176u * idx) + 80u));
-  const int4 i[4] = tint_symbol_11(s, ((176u * idx) + 112u));
+  const float scalar_f32 = asfloat(sb.Load((544u * idx)));
+  const int scalar_i32 = asint(sb.Load(((544u * idx) + 4u)));
+  const uint scalar_u32 = sb.Load(((544u * idx) + 8u));
+  const float2 vec2_f32 = asfloat(sb.Load2(((544u * idx) + 16u)));
+  const int2 vec2_i32 = asint(sb.Load2(((544u * idx) + 24u)));
+  const uint2 vec2_u32 = sb.Load2(((544u * idx) + 32u));
+  const float3 vec3_f32 = asfloat(sb.Load3(((544u * idx) + 48u)));
+  const int3 vec3_i32 = asint(sb.Load3(((544u * idx) + 64u)));
+  const uint3 vec3_u32 = sb.Load3(((544u * idx) + 80u));
+  const float4 vec4_f32 = asfloat(sb.Load4(((544u * idx) + 96u)));
+  const int4 vec4_i32 = asint(sb.Load4(((544u * idx) + 112u)));
+  const uint4 vec4_u32 = sb.Load4(((544u * idx) + 128u));
+  const float2x2 mat2x2_f32 = tint_symbol_14(sb, ((544u * idx) + 144u));
+  const float2x3 mat2x3_f32 = tint_symbol_15(sb, ((544u * idx) + 160u));
+  const float2x4 mat2x4_f32 = tint_symbol_16(sb, ((544u * idx) + 192u));
+  const float3x2 mat3x2_f32 = tint_symbol_17(sb, ((544u * idx) + 224u));
+  const float3x3 mat3x3_f32 = tint_symbol_18(sb, ((544u * idx) + 256u));
+  const float3x4 mat3x4_f32 = tint_symbol_19(sb, ((544u * idx) + 304u));
+  const float4x2 mat4x2_f32 = tint_symbol_20(sb, ((544u * idx) + 352u));
+  const float4x3 mat4x3_f32 = tint_symbol_21(sb, ((544u * idx) + 384u));
+  const float4x4 mat4x4_f32 = tint_symbol_22(sb, ((544u * idx) + 448u));
+  const float3 arr2_vec3_f32[2] = tint_symbol_23(sb, ((544u * idx) + 512u));
 }
 
 [numthreads(1, 1, 1)]
diff --git a/test/tint/buffer/storage/dynamic_index/read.wgsl.expected.glsl b/test/tint/buffer/storage/dynamic_index/read.wgsl.expected.glsl
index 704afa3..b497053 100644
--- a/test/tint/buffer/storage/dynamic_index/read.wgsl.expected.glsl
+++ b/test/tint/buffer/storage/dynamic_index/read.wgsl.expected.glsl
@@ -1,33 +1,65 @@
 #version 310 es
 
 struct Inner {
-  ivec3 a;
-  int b;
-  uvec3 c;
-  uint d;
-  vec3 e;
-  float f;
-  mat2x3 g;
-  mat3x2 h;
+  float scalar_f32;
+  int scalar_i32;
+  uint scalar_u32;
   uint pad;
+  vec2 vec2_f32;
+  ivec2 vec2_i32;
+  uvec2 vec2_u32;
   uint pad_1;
-  ivec4 i[4];
+  uint pad_2;
+  vec3 vec3_f32;
+  uint pad_3;
+  ivec3 vec3_i32;
+  uint pad_4;
+  uvec3 vec3_u32;
+  uint pad_5;
+  vec4 vec4_f32;
+  ivec4 vec4_i32;
+  uvec4 vec4_u32;
+  mat2 mat2x2_f32;
+  mat2x3 mat2x3_f32;
+  mat2x4 mat2x4_f32;
+  mat3x2 mat3x2_f32;
+  uint pad_6;
+  uint pad_7;
+  mat3 mat3x3_f32;
+  mat3x4 mat3x4_f32;
+  mat4x2 mat4x2_f32;
+  mat4x3 mat4x3_f32;
+  mat4 mat4x4_f32;
+  vec3 arr2_vec3_f32[2];
 };
 
 layout(binding = 0, std430) buffer S_ssbo {
   Inner arr[];
-} s;
+} sb;
 
 void tint_symbol(uint idx) {
-  ivec3 a = s.arr[idx].a;
-  int b = s.arr[idx].b;
-  uvec3 c = s.arr[idx].c;
-  uint d = s.arr[idx].d;
-  vec3 e = s.arr[idx].e;
-  float f = s.arr[idx].f;
-  mat2x3 g = s.arr[idx].g;
-  mat3x2 h = s.arr[idx].h;
-  ivec4 i[4] = s.arr[idx].i;
+  float scalar_f32 = sb.arr[idx].scalar_f32;
+  int scalar_i32 = sb.arr[idx].scalar_i32;
+  uint scalar_u32 = sb.arr[idx].scalar_u32;
+  vec2 vec2_f32 = sb.arr[idx].vec2_f32;
+  ivec2 vec2_i32 = sb.arr[idx].vec2_i32;
+  uvec2 vec2_u32 = sb.arr[idx].vec2_u32;
+  vec3 vec3_f32 = sb.arr[idx].vec3_f32;
+  ivec3 vec3_i32 = sb.arr[idx].vec3_i32;
+  uvec3 vec3_u32 = sb.arr[idx].vec3_u32;
+  vec4 vec4_f32 = sb.arr[idx].vec4_f32;
+  ivec4 vec4_i32 = sb.arr[idx].vec4_i32;
+  uvec4 vec4_u32 = sb.arr[idx].vec4_u32;
+  mat2 mat2x2_f32 = sb.arr[idx].mat2x2_f32;
+  mat2x3 mat2x3_f32 = sb.arr[idx].mat2x3_f32;
+  mat2x4 mat2x4_f32 = sb.arr[idx].mat2x4_f32;
+  mat3x2 mat3x2_f32 = sb.arr[idx].mat3x2_f32;
+  mat3 mat3x3_f32 = sb.arr[idx].mat3x3_f32;
+  mat3x4 mat3x4_f32 = sb.arr[idx].mat3x4_f32;
+  mat4x2 mat4x2_f32 = sb.arr[idx].mat4x2_f32;
+  mat4x3 mat4x3_f32 = sb.arr[idx].mat4x3_f32;
+  mat4 mat4x4_f32 = sb.arr[idx].mat4x4_f32;
+  vec3 arr2_vec3_f32[2] = sb.arr[idx].arr2_vec3_f32;
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/buffer/storage/dynamic_index/read.wgsl.expected.msl b/test/tint/buffer/storage/dynamic_index/read.wgsl.expected.msl
index 52e5e7d..06cc9d2 100644
--- a/test/tint/buffer/storage/dynamic_index/read.wgsl.expected.msl
+++ b/test/tint/buffer/storage/dynamic_index/read.wgsl.expected.msl
@@ -15,16 +15,34 @@
 };
 
 struct Inner {
-  /* 0x0000 */ packed_int3 a;
-  /* 0x000c */ int b;
-  /* 0x0010 */ packed_uint3 c;
-  /* 0x001c */ uint d;
-  /* 0x0020 */ packed_float3 e;
-  /* 0x002c */ float f;
-  /* 0x0030 */ float2x3 g;
-  /* 0x0050 */ float3x2 h;
-  /* 0x0068 */ tint_array<int8_t, 8> tint_pad;
-  /* 0x0070 */ tint_array<int4, 4> i;
+  /* 0x0000 */ float scalar_f32;
+  /* 0x0004 */ int scalar_i32;
+  /* 0x0008 */ uint scalar_u32;
+  /* 0x000c */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0010 */ float2 vec2_f32;
+  /* 0x0018 */ int2 vec2_i32;
+  /* 0x0020 */ uint2 vec2_u32;
+  /* 0x0028 */ tint_array<int8_t, 8> tint_pad_1;
+  /* 0x0030 */ packed_float3 vec3_f32;
+  /* 0x003c */ tint_array<int8_t, 4> tint_pad_2;
+  /* 0x0040 */ packed_int3 vec3_i32;
+  /* 0x004c */ tint_array<int8_t, 4> tint_pad_3;
+  /* 0x0050 */ packed_uint3 vec3_u32;
+  /* 0x005c */ tint_array<int8_t, 4> tint_pad_4;
+  /* 0x0060 */ float4 vec4_f32;
+  /* 0x0070 */ int4 vec4_i32;
+  /* 0x0080 */ uint4 vec4_u32;
+  /* 0x0090 */ float2x2 mat2x2_f32;
+  /* 0x00a0 */ float2x3 mat2x3_f32;
+  /* 0x00c0 */ float2x4 mat2x4_f32;
+  /* 0x00e0 */ float3x2 mat3x2_f32;
+  /* 0x00f8 */ tint_array<int8_t, 8> tint_pad_5;
+  /* 0x0100 */ float3x3 mat3x3_f32;
+  /* 0x0130 */ float3x4 mat3x4_f32;
+  /* 0x0160 */ float4x2 mat4x2_f32;
+  /* 0x0180 */ float4x3 mat4x3_f32;
+  /* 0x01c0 */ float4x4 mat4x4_f32;
+  /* 0x0200 */ tint_array<float3, 2> arr2_vec3_f32;
 };
 
 struct S {
@@ -32,15 +50,28 @@
 };
 
 void tint_symbol_inner(uint idx, const device S* const tint_symbol_1) {
-  int3 const a = int3((*(tint_symbol_1)).arr[idx].a);
-  int const b = (*(tint_symbol_1)).arr[idx].b;
-  uint3 const c = uint3((*(tint_symbol_1)).arr[idx].c);
-  uint const d = (*(tint_symbol_1)).arr[idx].d;
-  float3 const e = float3((*(tint_symbol_1)).arr[idx].e);
-  float const f = (*(tint_symbol_1)).arr[idx].f;
-  float2x3 const g = (*(tint_symbol_1)).arr[idx].g;
-  float3x2 const h = (*(tint_symbol_1)).arr[idx].h;
-  tint_array<int4, 4> const i = (*(tint_symbol_1)).arr[idx].i;
+  float const scalar_f32 = (*(tint_symbol_1)).arr[idx].scalar_f32;
+  int const scalar_i32 = (*(tint_symbol_1)).arr[idx].scalar_i32;
+  uint const scalar_u32 = (*(tint_symbol_1)).arr[idx].scalar_u32;
+  float2 const vec2_f32 = (*(tint_symbol_1)).arr[idx].vec2_f32;
+  int2 const vec2_i32 = (*(tint_symbol_1)).arr[idx].vec2_i32;
+  uint2 const vec2_u32 = (*(tint_symbol_1)).arr[idx].vec2_u32;
+  float3 const vec3_f32 = float3((*(tint_symbol_1)).arr[idx].vec3_f32);
+  int3 const vec3_i32 = int3((*(tint_symbol_1)).arr[idx].vec3_i32);
+  uint3 const vec3_u32 = uint3((*(tint_symbol_1)).arr[idx].vec3_u32);
+  float4 const vec4_f32 = (*(tint_symbol_1)).arr[idx].vec4_f32;
+  int4 const vec4_i32 = (*(tint_symbol_1)).arr[idx].vec4_i32;
+  uint4 const vec4_u32 = (*(tint_symbol_1)).arr[idx].vec4_u32;
+  float2x2 const mat2x2_f32 = (*(tint_symbol_1)).arr[idx].mat2x2_f32;
+  float2x3 const mat2x3_f32 = (*(tint_symbol_1)).arr[idx].mat2x3_f32;
+  float2x4 const mat2x4_f32 = (*(tint_symbol_1)).arr[idx].mat2x4_f32;
+  float3x2 const mat3x2_f32 = (*(tint_symbol_1)).arr[idx].mat3x2_f32;
+  float3x3 const mat3x3_f32 = (*(tint_symbol_1)).arr[idx].mat3x3_f32;
+  float3x4 const mat3x4_f32 = (*(tint_symbol_1)).arr[idx].mat3x4_f32;
+  float4x2 const mat4x2_f32 = (*(tint_symbol_1)).arr[idx].mat4x2_f32;
+  float4x3 const mat4x3_f32 = (*(tint_symbol_1)).arr[idx].mat4x3_f32;
+  float4x4 const mat4x4_f32 = (*(tint_symbol_1)).arr[idx].mat4x4_f32;
+  tint_array<float3, 2> const arr2_vec3_f32 = (*(tint_symbol_1)).arr[idx].arr2_vec3_f32;
 }
 
 kernel void tint_symbol(const device S* tint_symbol_2 [[buffer(0)]], uint idx [[thread_index_in_threadgroup]]) {
diff --git a/test/tint/buffer/storage/dynamic_index/read.wgsl.expected.spvasm b/test/tint/buffer/storage/dynamic_index/read.wgsl.expected.spvasm
index 22d8bab..ea7441a 100644
--- a/test/tint/buffer/storage/dynamic_index/read.wgsl.expected.spvasm
+++ b/test/tint/buffer/storage/dynamic_index/read.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 65
+; Bound: 128
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -11,16 +11,29 @@
                OpName %S "S"
                OpMemberName %S 0 "arr"
                OpName %Inner "Inner"
-               OpMemberName %Inner 0 "a"
-               OpMemberName %Inner 1 "b"
-               OpMemberName %Inner 2 "c"
-               OpMemberName %Inner 3 "d"
-               OpMemberName %Inner 4 "e"
-               OpMemberName %Inner 5 "f"
-               OpMemberName %Inner 6 "g"
-               OpMemberName %Inner 7 "h"
-               OpMemberName %Inner 8 "i"
-               OpName %s "s"
+               OpMemberName %Inner 0 "scalar_f32"
+               OpMemberName %Inner 1 "scalar_i32"
+               OpMemberName %Inner 2 "scalar_u32"
+               OpMemberName %Inner 3 "vec2_f32"
+               OpMemberName %Inner 4 "vec2_i32"
+               OpMemberName %Inner 5 "vec2_u32"
+               OpMemberName %Inner 6 "vec3_f32"
+               OpMemberName %Inner 7 "vec3_i32"
+               OpMemberName %Inner 8 "vec3_u32"
+               OpMemberName %Inner 9 "vec4_f32"
+               OpMemberName %Inner 10 "vec4_i32"
+               OpMemberName %Inner 11 "vec4_u32"
+               OpMemberName %Inner 12 "mat2x2_f32"
+               OpMemberName %Inner 13 "mat2x3_f32"
+               OpMemberName %Inner 14 "mat2x4_f32"
+               OpMemberName %Inner 15 "mat3x2_f32"
+               OpMemberName %Inner 16 "mat3x3_f32"
+               OpMemberName %Inner 17 "mat3x4_f32"
+               OpMemberName %Inner 18 "mat4x2_f32"
+               OpMemberName %Inner 19 "mat4x3_f32"
+               OpMemberName %Inner 20 "mat4x4_f32"
+               OpMemberName %Inner 21 "arr2_vec3_f32"
+               OpName %sb "sb"
                OpName %main_inner "main_inner"
                OpName %idx "idx"
                OpName %main "main"
@@ -28,88 +41,178 @@
                OpDecorate %S Block
                OpMemberDecorate %S 0 Offset 0
                OpMemberDecorate %Inner 0 Offset 0
-               OpMemberDecorate %Inner 1 Offset 12
-               OpMemberDecorate %Inner 2 Offset 16
-               OpMemberDecorate %Inner 3 Offset 28
-               OpMemberDecorate %Inner 4 Offset 32
-               OpMemberDecorate %Inner 5 Offset 44
+               OpMemberDecorate %Inner 1 Offset 4
+               OpMemberDecorate %Inner 2 Offset 8
+               OpMemberDecorate %Inner 3 Offset 16
+               OpMemberDecorate %Inner 4 Offset 24
+               OpMemberDecorate %Inner 5 Offset 32
                OpMemberDecorate %Inner 6 Offset 48
-               OpMemberDecorate %Inner 6 ColMajor
-               OpMemberDecorate %Inner 6 MatrixStride 16
-               OpMemberDecorate %Inner 7 Offset 80
-               OpMemberDecorate %Inner 7 ColMajor
-               OpMemberDecorate %Inner 7 MatrixStride 8
-               OpMemberDecorate %Inner 8 Offset 112
-               OpDecorate %_arr_v4int_uint_4 ArrayStride 16
-               OpDecorate %_runtimearr_Inner ArrayStride 176
-               OpDecorate %s NonWritable
-               OpDecorate %s Binding 0
-               OpDecorate %s DescriptorSet 0
+               OpMemberDecorate %Inner 7 Offset 64
+               OpMemberDecorate %Inner 8 Offset 80
+               OpMemberDecorate %Inner 9 Offset 96
+               OpMemberDecorate %Inner 10 Offset 112
+               OpMemberDecorate %Inner 11 Offset 128
+               OpMemberDecorate %Inner 12 Offset 144
+               OpMemberDecorate %Inner 12 ColMajor
+               OpMemberDecorate %Inner 12 MatrixStride 8
+               OpMemberDecorate %Inner 13 Offset 160
+               OpMemberDecorate %Inner 13 ColMajor
+               OpMemberDecorate %Inner 13 MatrixStride 16
+               OpMemberDecorate %Inner 14 Offset 192
+               OpMemberDecorate %Inner 14 ColMajor
+               OpMemberDecorate %Inner 14 MatrixStride 16
+               OpMemberDecorate %Inner 15 Offset 224
+               OpMemberDecorate %Inner 15 ColMajor
+               OpMemberDecorate %Inner 15 MatrixStride 8
+               OpMemberDecorate %Inner 16 Offset 256
+               OpMemberDecorate %Inner 16 ColMajor
+               OpMemberDecorate %Inner 16 MatrixStride 16
+               OpMemberDecorate %Inner 17 Offset 304
+               OpMemberDecorate %Inner 17 ColMajor
+               OpMemberDecorate %Inner 17 MatrixStride 16
+               OpMemberDecorate %Inner 18 Offset 352
+               OpMemberDecorate %Inner 18 ColMajor
+               OpMemberDecorate %Inner 18 MatrixStride 8
+               OpMemberDecorate %Inner 19 Offset 384
+               OpMemberDecorate %Inner 19 ColMajor
+               OpMemberDecorate %Inner 19 MatrixStride 16
+               OpMemberDecorate %Inner 20 Offset 448
+               OpMemberDecorate %Inner 20 ColMajor
+               OpMemberDecorate %Inner 20 MatrixStride 16
+               OpMemberDecorate %Inner 21 Offset 512
+               OpDecorate %_arr_v3float_uint_2 ArrayStride 16
+               OpDecorate %_runtimearr_Inner ArrayStride 544
+               OpDecorate %sb NonWritable
+               OpDecorate %sb Binding 0
+               OpDecorate %sb DescriptorSet 0
        %uint = OpTypeInt 32 0
 %_ptr_Input_uint = OpTypePointer Input %uint
       %idx_1 = OpVariable %_ptr_Input_uint Input
+      %float = OpTypeFloat 32
         %int = OpTypeInt 32 1
+    %v2float = OpTypeVector %float 2
+      %v2int = OpTypeVector %int 2
+     %v2uint = OpTypeVector %uint 2
+    %v3float = OpTypeVector %float 3
       %v3int = OpTypeVector %int 3
      %v3uint = OpTypeVector %uint 3
-      %float = OpTypeFloat 32
-    %v3float = OpTypeVector %float 3
-%mat2v3float = OpTypeMatrix %v3float 2
-    %v2float = OpTypeVector %float 2
-%mat3v2float = OpTypeMatrix %v2float 3
+    %v4float = OpTypeVector %float 4
       %v4int = OpTypeVector %int 4
-     %uint_4 = OpConstant %uint 4
-%_arr_v4int_uint_4 = OpTypeArray %v4int %uint_4
-      %Inner = OpTypeStruct %v3int %int %v3uint %uint %v3float %float %mat2v3float %mat3v2float %_arr_v4int_uint_4
+     %v4uint = OpTypeVector %uint 4
+%mat2v2float = OpTypeMatrix %v2float 2
+%mat2v3float = OpTypeMatrix %v3float 2
+%mat2v4float = OpTypeMatrix %v4float 2
+%mat3v2float = OpTypeMatrix %v2float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+%mat3v4float = OpTypeMatrix %v4float 3
+%mat4v2float = OpTypeMatrix %v2float 4
+%mat4v3float = OpTypeMatrix %v3float 4
+%mat4v4float = OpTypeMatrix %v4float 4
+     %uint_2 = OpConstant %uint 2
+%_arr_v3float_uint_2 = OpTypeArray %v3float %uint_2
+      %Inner = OpTypeStruct %float %int %uint %v2float %v2int %v2uint %v3float %v3int %v3uint %v4float %v4int %v4uint %mat2v2float %mat2v3float %mat2v4float %mat3v2float %mat3v3float %mat3v4float %mat4v2float %mat4v3float %mat4v4float %_arr_v3float_uint_2
 %_runtimearr_Inner = OpTypeRuntimeArray %Inner
           %S = OpTypeStruct %_runtimearr_Inner
 %_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
-          %s = OpVariable %_ptr_StorageBuffer_S StorageBuffer
+         %sb = OpVariable %_ptr_StorageBuffer_S StorageBuffer
        %void = OpTypeVoid
-         %20 = OpTypeFunction %void %uint
+         %31 = OpTypeFunction %void %uint
      %uint_0 = OpConstant %uint 0
-%_ptr_StorageBuffer_v3int = OpTypePointer StorageBuffer %v3int
+%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_int = OpTypePointer StorageBuffer %int
-     %uint_2 = OpConstant %uint 2
-%_ptr_StorageBuffer_v3uint = OpTypePointer StorageBuffer %v3uint
-     %uint_3 = OpConstant %uint 3
 %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
-%_ptr_StorageBuffer_v3float = OpTypePointer StorageBuffer %v3float
+     %uint_3 = OpConstant %uint 3
+%_ptr_StorageBuffer_v2float = OpTypePointer StorageBuffer %v2float
+     %uint_4 = OpConstant %uint 4
+%_ptr_StorageBuffer_v2int = OpTypePointer StorageBuffer %v2int
      %uint_5 = OpConstant %uint 5
-%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
+%_ptr_StorageBuffer_v2uint = OpTypePointer StorageBuffer %v2uint
      %uint_6 = OpConstant %uint 6
-%_ptr_StorageBuffer_mat2v3float = OpTypePointer StorageBuffer %mat2v3float
+%_ptr_StorageBuffer_v3float = OpTypePointer StorageBuffer %v3float
      %uint_7 = OpConstant %uint 7
-%_ptr_StorageBuffer_mat3v2float = OpTypePointer StorageBuffer %mat3v2float
+%_ptr_StorageBuffer_v3int = OpTypePointer StorageBuffer %v3int
      %uint_8 = OpConstant %uint 8
-%_ptr_StorageBuffer__arr_v4int_uint_4 = OpTypePointer StorageBuffer %_arr_v4int_uint_4
-         %60 = OpTypeFunction %void
- %main_inner = OpFunction %void None %20
+%_ptr_StorageBuffer_v3uint = OpTypePointer StorageBuffer %v3uint
+     %uint_9 = OpConstant %uint 9
+%_ptr_StorageBuffer_v4float = OpTypePointer StorageBuffer %v4float
+    %uint_10 = OpConstant %uint 10
+%_ptr_StorageBuffer_v4int = OpTypePointer StorageBuffer %v4int
+    %uint_11 = OpConstant %uint 11
+%_ptr_StorageBuffer_v4uint = OpTypePointer StorageBuffer %v4uint
+    %uint_12 = OpConstant %uint 12
+%_ptr_StorageBuffer_mat2v2float = OpTypePointer StorageBuffer %mat2v2float
+    %uint_13 = OpConstant %uint 13
+%_ptr_StorageBuffer_mat2v3float = OpTypePointer StorageBuffer %mat2v3float
+    %uint_14 = OpConstant %uint 14
+%_ptr_StorageBuffer_mat2v4float = OpTypePointer StorageBuffer %mat2v4float
+    %uint_15 = OpConstant %uint 15
+%_ptr_StorageBuffer_mat3v2float = OpTypePointer StorageBuffer %mat3v2float
+    %uint_16 = OpConstant %uint 16
+%_ptr_StorageBuffer_mat3v3float = OpTypePointer StorageBuffer %mat3v3float
+    %uint_17 = OpConstant %uint 17
+%_ptr_StorageBuffer_mat3v4float = OpTypePointer StorageBuffer %mat3v4float
+    %uint_18 = OpConstant %uint 18
+%_ptr_StorageBuffer_mat4v2float = OpTypePointer StorageBuffer %mat4v2float
+    %uint_19 = OpConstant %uint 19
+%_ptr_StorageBuffer_mat4v3float = OpTypePointer StorageBuffer %mat4v3float
+    %uint_20 = OpConstant %uint 20
+%_ptr_StorageBuffer_mat4v4float = OpTypePointer StorageBuffer %mat4v4float
+    %uint_21 = OpConstant %uint 21
+%_ptr_StorageBuffer__arr_v3float_uint_2 = OpTypePointer StorageBuffer %_arr_v3float_uint_2
+        %123 = OpTypeFunction %void
+ %main_inner = OpFunction %void None %31
         %idx = OpFunctionParameter %uint
-         %24 = OpLabel
-         %27 = OpAccessChain %_ptr_StorageBuffer_v3int %s %uint_0 %idx %uint_0
-         %28 = OpLoad %v3int %27
-         %31 = OpAccessChain %_ptr_StorageBuffer_int %s %uint_0 %idx %uint_1
-         %32 = OpLoad %int %31
-         %35 = OpAccessChain %_ptr_StorageBuffer_v3uint %s %uint_0 %idx %uint_2
-         %36 = OpLoad %v3uint %35
-         %39 = OpAccessChain %_ptr_StorageBuffer_uint %s %uint_0 %idx %uint_3
-         %40 = OpLoad %uint %39
-         %42 = OpAccessChain %_ptr_StorageBuffer_v3float %s %uint_0 %idx %uint_4
-         %43 = OpLoad %v3float %42
-         %46 = OpAccessChain %_ptr_StorageBuffer_float %s %uint_0 %idx %uint_5
-         %47 = OpLoad %float %46
-         %50 = OpAccessChain %_ptr_StorageBuffer_mat2v3float %s %uint_0 %idx %uint_6
-         %51 = OpLoad %mat2v3float %50
-         %54 = OpAccessChain %_ptr_StorageBuffer_mat3v2float %s %uint_0 %idx %uint_7
-         %55 = OpLoad %mat3v2float %54
-         %58 = OpAccessChain %_ptr_StorageBuffer__arr_v4int_uint_4 %s %uint_0 %idx %uint_8
-         %59 = OpLoad %_arr_v4int_uint_4 %58
+         %35 = OpLabel
+         %38 = OpAccessChain %_ptr_StorageBuffer_float %sb %uint_0 %idx %uint_0
+         %39 = OpLoad %float %38
+         %42 = OpAccessChain %_ptr_StorageBuffer_int %sb %uint_0 %idx %uint_1
+         %43 = OpLoad %int %42
+         %45 = OpAccessChain %_ptr_StorageBuffer_uint %sb %uint_0 %idx %uint_2
+         %46 = OpLoad %uint %45
+         %49 = OpAccessChain %_ptr_StorageBuffer_v2float %sb %uint_0 %idx %uint_3
+         %50 = OpLoad %v2float %49
+         %53 = OpAccessChain %_ptr_StorageBuffer_v2int %sb %uint_0 %idx %uint_4
+         %54 = OpLoad %v2int %53
+         %57 = OpAccessChain %_ptr_StorageBuffer_v2uint %sb %uint_0 %idx %uint_5
+         %58 = OpLoad %v2uint %57
+         %61 = OpAccessChain %_ptr_StorageBuffer_v3float %sb %uint_0 %idx %uint_6
+         %62 = OpLoad %v3float %61
+         %65 = OpAccessChain %_ptr_StorageBuffer_v3int %sb %uint_0 %idx %uint_7
+         %66 = OpLoad %v3int %65
+         %69 = OpAccessChain %_ptr_StorageBuffer_v3uint %sb %uint_0 %idx %uint_8
+         %70 = OpLoad %v3uint %69
+         %73 = OpAccessChain %_ptr_StorageBuffer_v4float %sb %uint_0 %idx %uint_9
+         %74 = OpLoad %v4float %73
+         %77 = OpAccessChain %_ptr_StorageBuffer_v4int %sb %uint_0 %idx %uint_10
+         %78 = OpLoad %v4int %77
+         %81 = OpAccessChain %_ptr_StorageBuffer_v4uint %sb %uint_0 %idx %uint_11
+         %82 = OpLoad %v4uint %81
+         %85 = OpAccessChain %_ptr_StorageBuffer_mat2v2float %sb %uint_0 %idx %uint_12
+         %86 = OpLoad %mat2v2float %85
+         %89 = OpAccessChain %_ptr_StorageBuffer_mat2v3float %sb %uint_0 %idx %uint_13
+         %90 = OpLoad %mat2v3float %89
+         %93 = OpAccessChain %_ptr_StorageBuffer_mat2v4float %sb %uint_0 %idx %uint_14
+         %94 = OpLoad %mat2v4float %93
+         %97 = OpAccessChain %_ptr_StorageBuffer_mat3v2float %sb %uint_0 %idx %uint_15
+         %98 = OpLoad %mat3v2float %97
+        %101 = OpAccessChain %_ptr_StorageBuffer_mat3v3float %sb %uint_0 %idx %uint_16
+        %102 = OpLoad %mat3v3float %101
+        %105 = OpAccessChain %_ptr_StorageBuffer_mat3v4float %sb %uint_0 %idx %uint_17
+        %106 = OpLoad %mat3v4float %105
+        %109 = OpAccessChain %_ptr_StorageBuffer_mat4v2float %sb %uint_0 %idx %uint_18
+        %110 = OpLoad %mat4v2float %109
+        %113 = OpAccessChain %_ptr_StorageBuffer_mat4v3float %sb %uint_0 %idx %uint_19
+        %114 = OpLoad %mat4v3float %113
+        %117 = OpAccessChain %_ptr_StorageBuffer_mat4v4float %sb %uint_0 %idx %uint_20
+        %118 = OpLoad %mat4v4float %117
+        %121 = OpAccessChain %_ptr_StorageBuffer__arr_v3float_uint_2 %sb %uint_0 %idx %uint_21
+        %122 = OpLoad %_arr_v3float_uint_2 %121
                OpReturn
                OpFunctionEnd
-       %main = OpFunction %void None %60
-         %62 = OpLabel
-         %64 = OpLoad %uint %idx_1
-         %63 = OpFunctionCall %void %main_inner %64
+       %main = OpFunction %void None %123
+        %125 = OpLabel
+        %127 = OpLoad %uint %idx_1
+        %126 = OpFunctionCall %void %main_inner %127
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/buffer/storage/dynamic_index/read.wgsl.expected.wgsl b/test/tint/buffer/storage/dynamic_index/read.wgsl.expected.wgsl
index f082887..6e7b7b7 100644
--- a/test/tint/buffer/storage/dynamic_index/read.wgsl.expected.wgsl
+++ b/test/tint/buffer/storage/dynamic_index/read.wgsl.expected.wgsl
@@ -1,30 +1,56 @@
 struct Inner {
-  a : vec3<i32>,
-  b : i32,
-  c : vec3<u32>,
-  d : u32,
-  e : vec3<f32>,
-  f : f32,
-  g : mat2x3<f32>,
-  h : mat3x2<f32>,
-  i : array<vec4<i32>, 4>,
+  scalar_f32 : f32,
+  scalar_i32 : i32,
+  scalar_u32 : u32,
+  vec2_f32 : vec2<f32>,
+  vec2_i32 : vec2<i32>,
+  vec2_u32 : vec2<u32>,
+  vec3_f32 : vec3<f32>,
+  vec3_i32 : vec3<i32>,
+  vec3_u32 : vec3<u32>,
+  vec4_f32 : vec4<f32>,
+  vec4_i32 : vec4<i32>,
+  vec4_u32 : vec4<u32>,
+  mat2x2_f32 : mat2x2<f32>,
+  mat2x3_f32 : mat2x3<f32>,
+  mat2x4_f32 : mat2x4<f32>,
+  mat3x2_f32 : mat3x2<f32>,
+  mat3x3_f32 : mat3x3<f32>,
+  mat3x4_f32 : mat3x4<f32>,
+  mat4x2_f32 : mat4x2<f32>,
+  mat4x3_f32 : mat4x3<f32>,
+  mat4x4_f32 : mat4x4<f32>,
+  arr2_vec3_f32 : array<vec3<f32>, 2>,
 }
 
 struct S {
   arr : array<Inner>,
 }
 
-@binding(0) @group(0) var<storage, read> s : S;
+@binding(0) @group(0) var<storage, read> sb : S;
 
 @compute @workgroup_size(1)
 fn main(@builtin(local_invocation_index) idx : u32) {
-  let a = s.arr[idx].a;
-  let b = s.arr[idx].b;
-  let c = s.arr[idx].c;
-  let d = s.arr[idx].d;
-  let e = s.arr[idx].e;
-  let f = s.arr[idx].f;
-  let g = s.arr[idx].g;
-  let h = s.arr[idx].h;
-  let i = s.arr[idx].i;
+  let scalar_f32 : f32 = sb.arr[idx].scalar_f32;
+  let scalar_i32 : i32 = sb.arr[idx].scalar_i32;
+  let scalar_u32 : u32 = sb.arr[idx].scalar_u32;
+  let vec2_f32 : vec2<f32> = sb.arr[idx].vec2_f32;
+  let vec2_i32 : vec2<i32> = sb.arr[idx].vec2_i32;
+  let vec2_u32 : vec2<u32> = sb.arr[idx].vec2_u32;
+  let vec3_f32 : vec3<f32> = sb.arr[idx].vec3_f32;
+  let vec3_i32 : vec3<i32> = sb.arr[idx].vec3_i32;
+  let vec3_u32 : vec3<u32> = sb.arr[idx].vec3_u32;
+  let vec4_f32 : vec4<f32> = sb.arr[idx].vec4_f32;
+  let vec4_i32 : vec4<i32> = sb.arr[idx].vec4_i32;
+  let vec4_u32 : vec4<u32> = sb.arr[idx].vec4_u32;
+  let mat2x2_f32 : mat2x2<f32> = sb.arr[idx].mat2x2_f32;
+  let mat2x3_f32 : mat2x3<f32> = sb.arr[idx].mat2x3_f32;
+  let mat2x4_f32 : mat2x4<f32> = sb.arr[idx].mat2x4_f32;
+  let mat3x2_f32 : mat3x2<f32> = sb.arr[idx].mat3x2_f32;
+  let mat3x3_f32 : mat3x3<f32> = sb.arr[idx].mat3x3_f32;
+  let mat3x4_f32 : mat3x4<f32> = sb.arr[idx].mat3x4_f32;
+  let mat4x2_f32 : mat4x2<f32> = sb.arr[idx].mat4x2_f32;
+  let mat4x3_f32 : mat4x3<f32> = sb.arr[idx].mat4x3_f32;
+  let mat4x4_f32 : mat4x4<f32> = sb.arr[idx].mat4x4_f32;
+  let arr2_vec3_f32 : array<vec3<f32>, 2> = sb.arr[idx].arr2_vec3_f32;
 }
diff --git a/test/tint/buffer/storage/dynamic_index/read_f16.wgsl b/test/tint/buffer/storage/dynamic_index/read_f16.wgsl
new file mode 100644
index 0000000..9351d4b
--- /dev/null
+++ b/test/tint/buffer/storage/dynamic_index/read_f16.wgsl
@@ -0,0 +1,86 @@
+enable f16;
+
+struct Inner {
+    scalar_f32 : f32,
+    scalar_i32 : i32,
+    scalar_u32 : u32,
+    scalar_f16 : f16,
+    vec2_f32 : vec2<f32>,
+    vec2_i32 : vec2<i32>,
+    vec2_u32 : vec2<u32>,
+    vec2_f16 : vec2<f16>,
+    vec3_f32 : vec3<f32>,
+    vec3_i32 : vec3<i32>,
+    vec3_u32 : vec3<u32>,
+    vec3_f16 : vec3<f16>,
+    vec4_f32 : vec4<f32>,
+    vec4_i32 : vec4<i32>,
+    vec4_u32 : vec4<u32>,
+    vec4_f16 : vec4<f16>,
+    mat2x2_f32 : mat2x2<f32>,
+    mat2x3_f32 : mat2x3<f32>,
+    mat2x4_f32 : mat2x4<f32>,
+    mat3x2_f32 : mat3x2<f32>,
+    mat3x3_f32 : mat3x3<f32>,
+    mat3x4_f32 : mat3x4<f32>,
+    mat4x2_f32 : mat4x2<f32>,
+    mat4x3_f32 : mat4x3<f32>,
+    mat4x4_f32 : mat4x4<f32>,
+    mat2x2_f16 : mat2x2<f16>,
+    mat2x3_f16 : mat2x3<f16>,
+    mat2x4_f16 : mat2x4<f16>,
+    mat3x2_f16 : mat3x2<f16>,
+    mat3x3_f16 : mat3x3<f16>,
+    mat3x4_f16 : mat3x4<f16>,
+    mat4x2_f16 : mat4x2<f16>,
+    mat4x3_f16 : mat4x3<f16>,
+    mat4x4_f16 : mat4x4<f16>,
+    arr2_vec3_f32 : array<vec3<f32>, 2>,
+    arr2_mat4x2_f16 : array<mat4x2<f16>, 2>,
+};
+
+struct S {
+    arr : array<Inner>,
+};
+
+@binding(0) @group(0) var<storage, read> sb : S;
+
+@compute @workgroup_size(1)
+fn main(@builtin(local_invocation_index) idx : u32) {
+    let scalar_f32 : f32 = sb.arr[idx].scalar_f32;
+    let scalar_i32 : i32 = sb.arr[idx].scalar_i32;
+    let scalar_u32 : u32 = sb.arr[idx].scalar_u32;
+    let scalar_f16 : f16 = sb.arr[idx].scalar_f16;
+    let vec2_f32 : vec2<f32> = sb.arr[idx].vec2_f32;
+    let vec2_i32 : vec2<i32> = sb.arr[idx].vec2_i32;
+    let vec2_u32 : vec2<u32> = sb.arr[idx].vec2_u32;
+    let vec2_f16 : vec2<f16> = sb.arr[idx].vec2_f16;
+    let vec3_f32 : vec3<f32> = sb.arr[idx].vec3_f32;
+    let vec3_i32 : vec3<i32> = sb.arr[idx].vec3_i32;
+    let vec3_u32 : vec3<u32> = sb.arr[idx].vec3_u32;
+    let vec3_f16 : vec3<f16> = sb.arr[idx].vec3_f16;
+    let vec4_f32 : vec4<f32> = sb.arr[idx].vec4_f32;
+    let vec4_i32 : vec4<i32> = sb.arr[idx].vec4_i32;
+    let vec4_u32 : vec4<u32> = sb.arr[idx].vec4_u32;
+    let vec4_f16 : vec4<f16> = sb.arr[idx].vec4_f16;
+    let mat2x2_f32 : mat2x2<f32> = sb.arr[idx].mat2x2_f32;
+    let mat2x3_f32 : mat2x3<f32> = sb.arr[idx].mat2x3_f32;
+    let mat2x4_f32 : mat2x4<f32> = sb.arr[idx].mat2x4_f32;
+    let mat3x2_f32 : mat3x2<f32> = sb.arr[idx].mat3x2_f32;
+    let mat3x3_f32 : mat3x3<f32> = sb.arr[idx].mat3x3_f32;
+    let mat3x4_f32 : mat3x4<f32> = sb.arr[idx].mat3x4_f32;
+    let mat4x2_f32 : mat4x2<f32> = sb.arr[idx].mat4x2_f32;
+    let mat4x3_f32 : mat4x3<f32> = sb.arr[idx].mat4x3_f32;
+    let mat4x4_f32 : mat4x4<f32> = sb.arr[idx].mat4x4_f32;
+    let mat2x2_f16 : mat2x2<f16> = sb.arr[idx].mat2x2_f16;
+    let mat2x3_f16 : mat2x3<f16> = sb.arr[idx].mat2x3_f16;
+    let mat2x4_f16 : mat2x4<f16> = sb.arr[idx].mat2x4_f16;
+    let mat3x2_f16 : mat3x2<f16> = sb.arr[idx].mat3x2_f16;
+    let mat3x3_f16 : mat3x3<f16> = sb.arr[idx].mat3x3_f16;
+    let mat3x4_f16 : mat3x4<f16> = sb.arr[idx].mat3x4_f16;
+    let mat4x2_f16 : mat4x2<f16> = sb.arr[idx].mat4x2_f16;
+    let mat4x3_f16 : mat4x3<f16> = sb.arr[idx].mat4x3_f16;
+    let mat4x4_f16 : mat4x4<f16> = sb.arr[idx].mat4x4_f16;
+    let arr2_vec3_f32 : array<vec3<f32>, 2> = sb.arr[idx].arr2_vec3_f32;
+    let arr2_mat4x2_f16 : array<mat4x2<f16>, 2> = sb.arr[idx].arr2_mat4x2_f16;
+}
diff --git a/test/tint/buffer/storage/dynamic_index/read_f16.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/dynamic_index/read_f16.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..e14b161
--- /dev/null
+++ b/test/tint/buffer/storage/dynamic_index/read_f16.wgsl.expected.dxc.hlsl
@@ -0,0 +1,144 @@
+ByteAddressBuffer sb : register(t0, space0);
+
+struct tint_symbol_1 {
+  uint idx : SV_GroupIndex;
+};
+
+float2x2 tint_symbol_18(ByteAddressBuffer buffer, uint offset) {
+  return float2x2(asfloat(buffer.Load2((offset + 0u))), asfloat(buffer.Load2((offset + 8u))));
+}
+
+float2x3 tint_symbol_19(ByteAddressBuffer buffer, uint offset) {
+  return float2x3(asfloat(buffer.Load3((offset + 0u))), asfloat(buffer.Load3((offset + 16u))));
+}
+
+float2x4 tint_symbol_20(ByteAddressBuffer buffer, uint offset) {
+  return float2x4(asfloat(buffer.Load4((offset + 0u))), asfloat(buffer.Load4((offset + 16u))));
+}
+
+float3x2 tint_symbol_21(ByteAddressBuffer buffer, uint offset) {
+  return float3x2(asfloat(buffer.Load2((offset + 0u))), asfloat(buffer.Load2((offset + 8u))), asfloat(buffer.Load2((offset + 16u))));
+}
+
+float3x3 tint_symbol_22(ByteAddressBuffer buffer, uint offset) {
+  return float3x3(asfloat(buffer.Load3((offset + 0u))), asfloat(buffer.Load3((offset + 16u))), asfloat(buffer.Load3((offset + 32u))));
+}
+
+float3x4 tint_symbol_23(ByteAddressBuffer buffer, uint offset) {
+  return float3x4(asfloat(buffer.Load4((offset + 0u))), asfloat(buffer.Load4((offset + 16u))), asfloat(buffer.Load4((offset + 32u))));
+}
+
+float4x2 tint_symbol_24(ByteAddressBuffer buffer, uint offset) {
+  return float4x2(asfloat(buffer.Load2((offset + 0u))), asfloat(buffer.Load2((offset + 8u))), asfloat(buffer.Load2((offset + 16u))), asfloat(buffer.Load2((offset + 24u))));
+}
+
+float4x3 tint_symbol_25(ByteAddressBuffer buffer, uint offset) {
+  return float4x3(asfloat(buffer.Load3((offset + 0u))), asfloat(buffer.Load3((offset + 16u))), asfloat(buffer.Load3((offset + 32u))), asfloat(buffer.Load3((offset + 48u))));
+}
+
+float4x4 tint_symbol_26(ByteAddressBuffer buffer, uint offset) {
+  return float4x4(asfloat(buffer.Load4((offset + 0u))), asfloat(buffer.Load4((offset + 16u))), asfloat(buffer.Load4((offset + 32u))), asfloat(buffer.Load4((offset + 48u))));
+}
+
+matrix<float16_t, 2, 2> tint_symbol_27(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 2, 2>(buffer.Load<vector<float16_t, 2> >((offset + 0u)), buffer.Load<vector<float16_t, 2> >((offset + 4u)));
+}
+
+matrix<float16_t, 2, 3> tint_symbol_28(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 2, 3>(buffer.Load<vector<float16_t, 3> >((offset + 0u)), buffer.Load<vector<float16_t, 3> >((offset + 8u)));
+}
+
+matrix<float16_t, 2, 4> tint_symbol_29(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 2, 4>(buffer.Load<vector<float16_t, 4> >((offset + 0u)), buffer.Load<vector<float16_t, 4> >((offset + 8u)));
+}
+
+matrix<float16_t, 3, 2> tint_symbol_30(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 3, 2>(buffer.Load<vector<float16_t, 2> >((offset + 0u)), buffer.Load<vector<float16_t, 2> >((offset + 4u)), buffer.Load<vector<float16_t, 2> >((offset + 8u)));
+}
+
+matrix<float16_t, 3, 3> tint_symbol_31(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 3, 3>(buffer.Load<vector<float16_t, 3> >((offset + 0u)), buffer.Load<vector<float16_t, 3> >((offset + 8u)), buffer.Load<vector<float16_t, 3> >((offset + 16u)));
+}
+
+matrix<float16_t, 3, 4> tint_symbol_32(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 3, 4>(buffer.Load<vector<float16_t, 4> >((offset + 0u)), buffer.Load<vector<float16_t, 4> >((offset + 8u)), buffer.Load<vector<float16_t, 4> >((offset + 16u)));
+}
+
+matrix<float16_t, 4, 2> tint_symbol_33(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 4, 2>(buffer.Load<vector<float16_t, 2> >((offset + 0u)), buffer.Load<vector<float16_t, 2> >((offset + 4u)), buffer.Load<vector<float16_t, 2> >((offset + 8u)), buffer.Load<vector<float16_t, 2> >((offset + 12u)));
+}
+
+matrix<float16_t, 4, 3> tint_symbol_34(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 4, 3>(buffer.Load<vector<float16_t, 3> >((offset + 0u)), buffer.Load<vector<float16_t, 3> >((offset + 8u)), buffer.Load<vector<float16_t, 3> >((offset + 16u)), buffer.Load<vector<float16_t, 3> >((offset + 24u)));
+}
+
+matrix<float16_t, 4, 4> tint_symbol_35(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 4, 4>(buffer.Load<vector<float16_t, 4> >((offset + 0u)), buffer.Load<vector<float16_t, 4> >((offset + 8u)), buffer.Load<vector<float16_t, 4> >((offset + 16u)), buffer.Load<vector<float16_t, 4> >((offset + 24u)));
+}
+
+typedef float3 tint_symbol_36_ret[2];
+tint_symbol_36_ret tint_symbol_36(ByteAddressBuffer buffer, uint offset) {
+  float3 arr_1[2] = (float3[2])0;
+  {
+    for(uint i = 0u; (i < 2u); i = (i + 1u)) {
+      arr_1[i] = asfloat(buffer.Load3((offset + (i * 16u))));
+    }
+  }
+  return arr_1;
+}
+
+typedef matrix<float16_t, 4, 2> tint_symbol_37_ret[2];
+tint_symbol_37_ret tint_symbol_37(ByteAddressBuffer buffer, uint offset) {
+  matrix<float16_t, 4, 2> arr_2[2] = (matrix<float16_t, 4, 2>[2])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
+      arr_2[i_1] = tint_symbol_33(buffer, (offset + (i_1 * 16u)));
+    }
+  }
+  return arr_2;
+}
+
+void main_inner(uint idx) {
+  const float scalar_f32 = asfloat(sb.Load((800u * idx)));
+  const int scalar_i32 = asint(sb.Load(((800u * idx) + 4u)));
+  const uint scalar_u32 = sb.Load(((800u * idx) + 8u));
+  const float16_t scalar_f16 = sb.Load<float16_t>(((800u * idx) + 12u));
+  const float2 vec2_f32 = asfloat(sb.Load2(((800u * idx) + 16u)));
+  const int2 vec2_i32 = asint(sb.Load2(((800u * idx) + 24u)));
+  const uint2 vec2_u32 = sb.Load2(((800u * idx) + 32u));
+  const vector<float16_t, 2> vec2_f16 = sb.Load<vector<float16_t, 2> >(((800u * idx) + 40u));
+  const float3 vec3_f32 = asfloat(sb.Load3(((800u * idx) + 48u)));
+  const int3 vec3_i32 = asint(sb.Load3(((800u * idx) + 64u)));
+  const uint3 vec3_u32 = sb.Load3(((800u * idx) + 80u));
+  const vector<float16_t, 3> vec3_f16 = sb.Load<vector<float16_t, 3> >(((800u * idx) + 96u));
+  const float4 vec4_f32 = asfloat(sb.Load4(((800u * idx) + 112u)));
+  const int4 vec4_i32 = asint(sb.Load4(((800u * idx) + 128u)));
+  const uint4 vec4_u32 = sb.Load4(((800u * idx) + 144u));
+  const vector<float16_t, 4> vec4_f16 = sb.Load<vector<float16_t, 4> >(((800u * idx) + 160u));
+  const float2x2 mat2x2_f32 = tint_symbol_18(sb, ((800u * idx) + 168u));
+  const float2x3 mat2x3_f32 = tint_symbol_19(sb, ((800u * idx) + 192u));
+  const float2x4 mat2x4_f32 = tint_symbol_20(sb, ((800u * idx) + 224u));
+  const float3x2 mat3x2_f32 = tint_symbol_21(sb, ((800u * idx) + 256u));
+  const float3x3 mat3x3_f32 = tint_symbol_22(sb, ((800u * idx) + 288u));
+  const float3x4 mat3x4_f32 = tint_symbol_23(sb, ((800u * idx) + 336u));
+  const float4x2 mat4x2_f32 = tint_symbol_24(sb, ((800u * idx) + 384u));
+  const float4x3 mat4x3_f32 = tint_symbol_25(sb, ((800u * idx) + 416u));
+  const float4x4 mat4x4_f32 = tint_symbol_26(sb, ((800u * idx) + 480u));
+  const matrix<float16_t, 2, 2> mat2x2_f16 = tint_symbol_27(sb, ((800u * idx) + 544u));
+  const matrix<float16_t, 2, 3> mat2x3_f16 = tint_symbol_28(sb, ((800u * idx) + 552u));
+  const matrix<float16_t, 2, 4> mat2x4_f16 = tint_symbol_29(sb, ((800u * idx) + 568u));
+  const matrix<float16_t, 3, 2> mat3x2_f16 = tint_symbol_30(sb, ((800u * idx) + 584u));
+  const matrix<float16_t, 3, 3> mat3x3_f16 = tint_symbol_31(sb, ((800u * idx) + 600u));
+  const matrix<float16_t, 3, 4> mat3x4_f16 = tint_symbol_32(sb, ((800u * idx) + 624u));
+  const matrix<float16_t, 4, 2> mat4x2_f16 = tint_symbol_33(sb, ((800u * idx) + 648u));
+  const matrix<float16_t, 4, 3> mat4x3_f16 = tint_symbol_34(sb, ((800u * idx) + 664u));
+  const matrix<float16_t, 4, 4> mat4x4_f16 = tint_symbol_35(sb, ((800u * idx) + 696u));
+  const float3 arr2_vec3_f32[2] = tint_symbol_36(sb, ((800u * idx) + 736u));
+  const matrix<float16_t, 4, 2> arr2_mat4x2_f16[2] = tint_symbol_37(sb, ((800u * idx) + 768u));
+}
+
+[numthreads(1, 1, 1)]
+void main(tint_symbol_1 tint_symbol) {
+  main_inner(tint_symbol.idx);
+  return;
+}
diff --git a/test/tint/buffer/storage/dynamic_index/read_f16.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/dynamic_index/read_f16.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..220cc92
--- /dev/null
+++ b/test/tint/buffer/storage/dynamic_index/read_f16.wgsl.expected.fxc.hlsl
@@ -0,0 +1,149 @@
+SKIP: FAILED
+
+ByteAddressBuffer sb : register(t0, space0);
+
+struct tint_symbol_1 {
+  uint idx : SV_GroupIndex;
+};
+
+float2x2 tint_symbol_18(ByteAddressBuffer buffer, uint offset) {
+  return float2x2(asfloat(buffer.Load2((offset + 0u))), asfloat(buffer.Load2((offset + 8u))));
+}
+
+float2x3 tint_symbol_19(ByteAddressBuffer buffer, uint offset) {
+  return float2x3(asfloat(buffer.Load3((offset + 0u))), asfloat(buffer.Load3((offset + 16u))));
+}
+
+float2x4 tint_symbol_20(ByteAddressBuffer buffer, uint offset) {
+  return float2x4(asfloat(buffer.Load4((offset + 0u))), asfloat(buffer.Load4((offset + 16u))));
+}
+
+float3x2 tint_symbol_21(ByteAddressBuffer buffer, uint offset) {
+  return float3x2(asfloat(buffer.Load2((offset + 0u))), asfloat(buffer.Load2((offset + 8u))), asfloat(buffer.Load2((offset + 16u))));
+}
+
+float3x3 tint_symbol_22(ByteAddressBuffer buffer, uint offset) {
+  return float3x3(asfloat(buffer.Load3((offset + 0u))), asfloat(buffer.Load3((offset + 16u))), asfloat(buffer.Load3((offset + 32u))));
+}
+
+float3x4 tint_symbol_23(ByteAddressBuffer buffer, uint offset) {
+  return float3x4(asfloat(buffer.Load4((offset + 0u))), asfloat(buffer.Load4((offset + 16u))), asfloat(buffer.Load4((offset + 32u))));
+}
+
+float4x2 tint_symbol_24(ByteAddressBuffer buffer, uint offset) {
+  return float4x2(asfloat(buffer.Load2((offset + 0u))), asfloat(buffer.Load2((offset + 8u))), asfloat(buffer.Load2((offset + 16u))), asfloat(buffer.Load2((offset + 24u))));
+}
+
+float4x3 tint_symbol_25(ByteAddressBuffer buffer, uint offset) {
+  return float4x3(asfloat(buffer.Load3((offset + 0u))), asfloat(buffer.Load3((offset + 16u))), asfloat(buffer.Load3((offset + 32u))), asfloat(buffer.Load3((offset + 48u))));
+}
+
+float4x4 tint_symbol_26(ByteAddressBuffer buffer, uint offset) {
+  return float4x4(asfloat(buffer.Load4((offset + 0u))), asfloat(buffer.Load4((offset + 16u))), asfloat(buffer.Load4((offset + 32u))), asfloat(buffer.Load4((offset + 48u))));
+}
+
+matrix<float16_t, 2, 2> tint_symbol_27(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 2, 2>(buffer.Load<vector<float16_t, 2> >((offset + 0u)), buffer.Load<vector<float16_t, 2> >((offset + 4u)));
+}
+
+matrix<float16_t, 2, 3> tint_symbol_28(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 2, 3>(buffer.Load<vector<float16_t, 3> >((offset + 0u)), buffer.Load<vector<float16_t, 3> >((offset + 8u)));
+}
+
+matrix<float16_t, 2, 4> tint_symbol_29(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 2, 4>(buffer.Load<vector<float16_t, 4> >((offset + 0u)), buffer.Load<vector<float16_t, 4> >((offset + 8u)));
+}
+
+matrix<float16_t, 3, 2> tint_symbol_30(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 3, 2>(buffer.Load<vector<float16_t, 2> >((offset + 0u)), buffer.Load<vector<float16_t, 2> >((offset + 4u)), buffer.Load<vector<float16_t, 2> >((offset + 8u)));
+}
+
+matrix<float16_t, 3, 3> tint_symbol_31(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 3, 3>(buffer.Load<vector<float16_t, 3> >((offset + 0u)), buffer.Load<vector<float16_t, 3> >((offset + 8u)), buffer.Load<vector<float16_t, 3> >((offset + 16u)));
+}
+
+matrix<float16_t, 3, 4> tint_symbol_32(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 3, 4>(buffer.Load<vector<float16_t, 4> >((offset + 0u)), buffer.Load<vector<float16_t, 4> >((offset + 8u)), buffer.Load<vector<float16_t, 4> >((offset + 16u)));
+}
+
+matrix<float16_t, 4, 2> tint_symbol_33(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 4, 2>(buffer.Load<vector<float16_t, 2> >((offset + 0u)), buffer.Load<vector<float16_t, 2> >((offset + 4u)), buffer.Load<vector<float16_t, 2> >((offset + 8u)), buffer.Load<vector<float16_t, 2> >((offset + 12u)));
+}
+
+matrix<float16_t, 4, 3> tint_symbol_34(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 4, 3>(buffer.Load<vector<float16_t, 3> >((offset + 0u)), buffer.Load<vector<float16_t, 3> >((offset + 8u)), buffer.Load<vector<float16_t, 3> >((offset + 16u)), buffer.Load<vector<float16_t, 3> >((offset + 24u)));
+}
+
+matrix<float16_t, 4, 4> tint_symbol_35(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 4, 4>(buffer.Load<vector<float16_t, 4> >((offset + 0u)), buffer.Load<vector<float16_t, 4> >((offset + 8u)), buffer.Load<vector<float16_t, 4> >((offset + 16u)), buffer.Load<vector<float16_t, 4> >((offset + 24u)));
+}
+
+typedef float3 tint_symbol_36_ret[2];
+tint_symbol_36_ret tint_symbol_36(ByteAddressBuffer buffer, uint offset) {
+  float3 arr_1[2] = (float3[2])0;
+  {
+    for(uint i = 0u; (i < 2u); i = (i + 1u)) {
+      arr_1[i] = asfloat(buffer.Load3((offset + (i * 16u))));
+    }
+  }
+  return arr_1;
+}
+
+typedef matrix<float16_t, 4, 2> tint_symbol_37_ret[2];
+tint_symbol_37_ret tint_symbol_37(ByteAddressBuffer buffer, uint offset) {
+  matrix<float16_t, 4, 2> arr_2[2] = (matrix<float16_t, 4, 2>[2])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
+      arr_2[i_1] = tint_symbol_33(buffer, (offset + (i_1 * 16u)));
+    }
+  }
+  return arr_2;
+}
+
+void main_inner(uint idx) {
+  const float scalar_f32 = asfloat(sb.Load((800u * idx)));
+  const int scalar_i32 = asint(sb.Load(((800u * idx) + 4u)));
+  const uint scalar_u32 = sb.Load(((800u * idx) + 8u));
+  const float16_t scalar_f16 = sb.Load<float16_t>(((800u * idx) + 12u));
+  const float2 vec2_f32 = asfloat(sb.Load2(((800u * idx) + 16u)));
+  const int2 vec2_i32 = asint(sb.Load2(((800u * idx) + 24u)));
+  const uint2 vec2_u32 = sb.Load2(((800u * idx) + 32u));
+  const vector<float16_t, 2> vec2_f16 = sb.Load<vector<float16_t, 2> >(((800u * idx) + 40u));
+  const float3 vec3_f32 = asfloat(sb.Load3(((800u * idx) + 48u)));
+  const int3 vec3_i32 = asint(sb.Load3(((800u * idx) + 64u)));
+  const uint3 vec3_u32 = sb.Load3(((800u * idx) + 80u));
+  const vector<float16_t, 3> vec3_f16 = sb.Load<vector<float16_t, 3> >(((800u * idx) + 96u));
+  const float4 vec4_f32 = asfloat(sb.Load4(((800u * idx) + 112u)));
+  const int4 vec4_i32 = asint(sb.Load4(((800u * idx) + 128u)));
+  const uint4 vec4_u32 = sb.Load4(((800u * idx) + 144u));
+  const vector<float16_t, 4> vec4_f16 = sb.Load<vector<float16_t, 4> >(((800u * idx) + 160u));
+  const float2x2 mat2x2_f32 = tint_symbol_18(sb, ((800u * idx) + 168u));
+  const float2x3 mat2x3_f32 = tint_symbol_19(sb, ((800u * idx) + 192u));
+  const float2x4 mat2x4_f32 = tint_symbol_20(sb, ((800u * idx) + 224u));
+  const float3x2 mat3x2_f32 = tint_symbol_21(sb, ((800u * idx) + 256u));
+  const float3x3 mat3x3_f32 = tint_symbol_22(sb, ((800u * idx) + 288u));
+  const float3x4 mat3x4_f32 = tint_symbol_23(sb, ((800u * idx) + 336u));
+  const float4x2 mat4x2_f32 = tint_symbol_24(sb, ((800u * idx) + 384u));
+  const float4x3 mat4x3_f32 = tint_symbol_25(sb, ((800u * idx) + 416u));
+  const float4x4 mat4x4_f32 = tint_symbol_26(sb, ((800u * idx) + 480u));
+  const matrix<float16_t, 2, 2> mat2x2_f16 = tint_symbol_27(sb, ((800u * idx) + 544u));
+  const matrix<float16_t, 2, 3> mat2x3_f16 = tint_symbol_28(sb, ((800u * idx) + 552u));
+  const matrix<float16_t, 2, 4> mat2x4_f16 = tint_symbol_29(sb, ((800u * idx) + 568u));
+  const matrix<float16_t, 3, 2> mat3x2_f16 = tint_symbol_30(sb, ((800u * idx) + 584u));
+  const matrix<float16_t, 3, 3> mat3x3_f16 = tint_symbol_31(sb, ((800u * idx) + 600u));
+  const matrix<float16_t, 3, 4> mat3x4_f16 = tint_symbol_32(sb, ((800u * idx) + 624u));
+  const matrix<float16_t, 4, 2> mat4x2_f16 = tint_symbol_33(sb, ((800u * idx) + 648u));
+  const matrix<float16_t, 4, 3> mat4x3_f16 = tint_symbol_34(sb, ((800u * idx) + 664u));
+  const matrix<float16_t, 4, 4> mat4x4_f16 = tint_symbol_35(sb, ((800u * idx) + 696u));
+  const float3 arr2_vec3_f32[2] = tint_symbol_36(sb, ((800u * idx) + 736u));
+  const matrix<float16_t, 4, 2> arr2_mat4x2_f16[2] = tint_symbol_37(sb, ((800u * idx) + 768u));
+}
+
+[numthreads(1, 1, 1)]
+void main(tint_symbol_1 tint_symbol) {
+  main_inner(tint_symbol.idx);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000018A2D5DB890(43,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/storage/dynamic_index/read_f16.wgsl.expected.glsl b/test/tint/buffer/storage/dynamic_index/read_f16.wgsl.expected.glsl
new file mode 100644
index 0000000..d150509
--- /dev/null
+++ b/test/tint/buffer/storage/dynamic_index/read_f16.wgsl.expected.glsl
@@ -0,0 +1,103 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct Inner {
+  float scalar_f32;
+  int scalar_i32;
+  uint scalar_u32;
+  float16_t scalar_f16;
+  vec2 vec2_f32;
+  ivec2 vec2_i32;
+  uvec2 vec2_u32;
+  f16vec2 vec2_f16;
+  uint pad;
+  vec3 vec3_f32;
+  uint pad_1;
+  ivec3 vec3_i32;
+  uint pad_2;
+  uvec3 vec3_u32;
+  uint pad_3;
+  f16vec3 vec3_f16;
+  uint pad_4;
+  uint pad_5;
+  vec4 vec4_f32;
+  ivec4 vec4_i32;
+  uvec4 vec4_u32;
+  f16vec4 vec4_f16;
+  mat2 mat2x2_f32;
+  uint pad_6;
+  uint pad_7;
+  mat2x3 mat2x3_f32;
+  mat2x4 mat2x4_f32;
+  mat3x2 mat3x2_f32;
+  uint pad_8;
+  uint pad_9;
+  mat3 mat3x3_f32;
+  mat3x4 mat3x4_f32;
+  mat4x2 mat4x2_f32;
+  mat4x3 mat4x3_f32;
+  mat4 mat4x4_f32;
+  f16mat2 mat2x2_f16;
+  f16mat2x3 mat2x3_f16;
+  f16mat2x4 mat2x4_f16;
+  f16mat3x2 mat3x2_f16;
+  uint pad_10;
+  f16mat3 mat3x3_f16;
+  f16mat3x4 mat3x4_f16;
+  f16mat4x2 mat4x2_f16;
+  f16mat4x3 mat4x3_f16;
+  f16mat4 mat4x4_f16;
+  uint pad_11;
+  uint pad_12;
+  vec3 arr2_vec3_f32[2];
+  f16mat4x2 arr2_mat4x2_f16[2];
+};
+
+layout(binding = 0, std430) buffer S_ssbo {
+  Inner arr[];
+} sb;
+
+void tint_symbol(uint idx) {
+  float scalar_f32 = sb.arr[idx].scalar_f32;
+  int scalar_i32 = sb.arr[idx].scalar_i32;
+  uint scalar_u32 = sb.arr[idx].scalar_u32;
+  float16_t scalar_f16 = sb.arr[idx].scalar_f16;
+  vec2 vec2_f32 = sb.arr[idx].vec2_f32;
+  ivec2 vec2_i32 = sb.arr[idx].vec2_i32;
+  uvec2 vec2_u32 = sb.arr[idx].vec2_u32;
+  f16vec2 vec2_f16 = sb.arr[idx].vec2_f16;
+  vec3 vec3_f32 = sb.arr[idx].vec3_f32;
+  ivec3 vec3_i32 = sb.arr[idx].vec3_i32;
+  uvec3 vec3_u32 = sb.arr[idx].vec3_u32;
+  f16vec3 vec3_f16 = sb.arr[idx].vec3_f16;
+  vec4 vec4_f32 = sb.arr[idx].vec4_f32;
+  ivec4 vec4_i32 = sb.arr[idx].vec4_i32;
+  uvec4 vec4_u32 = sb.arr[idx].vec4_u32;
+  f16vec4 vec4_f16 = sb.arr[idx].vec4_f16;
+  mat2 mat2x2_f32 = sb.arr[idx].mat2x2_f32;
+  mat2x3 mat2x3_f32 = sb.arr[idx].mat2x3_f32;
+  mat2x4 mat2x4_f32 = sb.arr[idx].mat2x4_f32;
+  mat3x2 mat3x2_f32 = sb.arr[idx].mat3x2_f32;
+  mat3 mat3x3_f32 = sb.arr[idx].mat3x3_f32;
+  mat3x4 mat3x4_f32 = sb.arr[idx].mat3x4_f32;
+  mat4x2 mat4x2_f32 = sb.arr[idx].mat4x2_f32;
+  mat4x3 mat4x3_f32 = sb.arr[idx].mat4x3_f32;
+  mat4 mat4x4_f32 = sb.arr[idx].mat4x4_f32;
+  f16mat2 mat2x2_f16 = sb.arr[idx].mat2x2_f16;
+  f16mat2x3 mat2x3_f16 = sb.arr[idx].mat2x3_f16;
+  f16mat2x4 mat2x4_f16 = sb.arr[idx].mat2x4_f16;
+  f16mat3x2 mat3x2_f16 = sb.arr[idx].mat3x2_f16;
+  f16mat3 mat3x3_f16 = sb.arr[idx].mat3x3_f16;
+  f16mat3x4 mat3x4_f16 = sb.arr[idx].mat3x4_f16;
+  f16mat4x2 mat4x2_f16 = sb.arr[idx].mat4x2_f16;
+  f16mat4x3 mat4x3_f16 = sb.arr[idx].mat4x3_f16;
+  f16mat4 mat4x4_f16 = sb.arr[idx].mat4x4_f16;
+  vec3 arr2_vec3_f32[2] = sb.arr[idx].arr2_vec3_f32;
+  f16mat4x2 arr2_mat4x2_f16[2] = sb.arr[idx].arr2_mat4x2_f16;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/storage/dynamic_index/read_f16.wgsl.expected.msl b/test/tint/buffer/storage/dynamic_index/read_f16.wgsl.expected.msl
new file mode 100644
index 0000000..ee0138a
--- /dev/null
+++ b/test/tint/buffer/storage/dynamic_index/read_f16.wgsl.expected.msl
@@ -0,0 +1,113 @@
+#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 Inner {
+  /* 0x0000 */ float scalar_f32;
+  /* 0x0004 */ int scalar_i32;
+  /* 0x0008 */ uint scalar_u32;
+  /* 0x000c */ half scalar_f16;
+  /* 0x000e */ tint_array<int8_t, 2> tint_pad;
+  /* 0x0010 */ float2 vec2_f32;
+  /* 0x0018 */ int2 vec2_i32;
+  /* 0x0020 */ uint2 vec2_u32;
+  /* 0x0028 */ half2 vec2_f16;
+  /* 0x002c */ tint_array<int8_t, 4> tint_pad_1;
+  /* 0x0030 */ packed_float3 vec3_f32;
+  /* 0x003c */ tint_array<int8_t, 4> tint_pad_2;
+  /* 0x0040 */ packed_int3 vec3_i32;
+  /* 0x004c */ tint_array<int8_t, 4> tint_pad_3;
+  /* 0x0050 */ packed_uint3 vec3_u32;
+  /* 0x005c */ tint_array<int8_t, 4> tint_pad_4;
+  /* 0x0060 */ packed_half3 vec3_f16;
+  /* 0x0066 */ tint_array<int8_t, 10> tint_pad_5;
+  /* 0x0070 */ float4 vec4_f32;
+  /* 0x0080 */ int4 vec4_i32;
+  /* 0x0090 */ uint4 vec4_u32;
+  /* 0x00a0 */ half4 vec4_f16;
+  /* 0x00a8 */ float2x2 mat2x2_f32;
+  /* 0x00b8 */ tint_array<int8_t, 8> tint_pad_6;
+  /* 0x00c0 */ float2x3 mat2x3_f32;
+  /* 0x00e0 */ float2x4 mat2x4_f32;
+  /* 0x0100 */ float3x2 mat3x2_f32;
+  /* 0x0118 */ tint_array<int8_t, 8> tint_pad_7;
+  /* 0x0120 */ float3x3 mat3x3_f32;
+  /* 0x0150 */ float3x4 mat3x4_f32;
+  /* 0x0180 */ float4x2 mat4x2_f32;
+  /* 0x01a0 */ float4x3 mat4x3_f32;
+  /* 0x01e0 */ float4x4 mat4x4_f32;
+  /* 0x0220 */ half2x2 mat2x2_f16;
+  /* 0x0228 */ half2x3 mat2x3_f16;
+  /* 0x0238 */ half2x4 mat2x4_f16;
+  /* 0x0248 */ half3x2 mat3x2_f16;
+  /* 0x0254 */ tint_array<int8_t, 4> tint_pad_8;
+  /* 0x0258 */ half3x3 mat3x3_f16;
+  /* 0x0270 */ half3x4 mat3x4_f16;
+  /* 0x0288 */ half4x2 mat4x2_f16;
+  /* 0x0298 */ half4x3 mat4x3_f16;
+  /* 0x02b8 */ half4x4 mat4x4_f16;
+  /* 0x02d8 */ tint_array<int8_t, 8> tint_pad_9;
+  /* 0x02e0 */ tint_array<float3, 2> arr2_vec3_f32;
+  /* 0x0300 */ tint_array<half4x2, 2> arr2_mat4x2_f16;
+};
+
+struct S {
+  /* 0x0000 */ tint_array<Inner, 1> arr;
+};
+
+void tint_symbol_inner(uint idx, const device S* const tint_symbol_1) {
+  float const scalar_f32 = (*(tint_symbol_1)).arr[idx].scalar_f32;
+  int const scalar_i32 = (*(tint_symbol_1)).arr[idx].scalar_i32;
+  uint const scalar_u32 = (*(tint_symbol_1)).arr[idx].scalar_u32;
+  half const scalar_f16 = (*(tint_symbol_1)).arr[idx].scalar_f16;
+  float2 const vec2_f32 = (*(tint_symbol_1)).arr[idx].vec2_f32;
+  int2 const vec2_i32 = (*(tint_symbol_1)).arr[idx].vec2_i32;
+  uint2 const vec2_u32 = (*(tint_symbol_1)).arr[idx].vec2_u32;
+  half2 const vec2_f16 = (*(tint_symbol_1)).arr[idx].vec2_f16;
+  float3 const vec3_f32 = float3((*(tint_symbol_1)).arr[idx].vec3_f32);
+  int3 const vec3_i32 = int3((*(tint_symbol_1)).arr[idx].vec3_i32);
+  uint3 const vec3_u32 = uint3((*(tint_symbol_1)).arr[idx].vec3_u32);
+  half3 const vec3_f16 = half3((*(tint_symbol_1)).arr[idx].vec3_f16);
+  float4 const vec4_f32 = (*(tint_symbol_1)).arr[idx].vec4_f32;
+  int4 const vec4_i32 = (*(tint_symbol_1)).arr[idx].vec4_i32;
+  uint4 const vec4_u32 = (*(tint_symbol_1)).arr[idx].vec4_u32;
+  half4 const vec4_f16 = (*(tint_symbol_1)).arr[idx].vec4_f16;
+  float2x2 const mat2x2_f32 = (*(tint_symbol_1)).arr[idx].mat2x2_f32;
+  float2x3 const mat2x3_f32 = (*(tint_symbol_1)).arr[idx].mat2x3_f32;
+  float2x4 const mat2x4_f32 = (*(tint_symbol_1)).arr[idx].mat2x4_f32;
+  float3x2 const mat3x2_f32 = (*(tint_symbol_1)).arr[idx].mat3x2_f32;
+  float3x3 const mat3x3_f32 = (*(tint_symbol_1)).arr[idx].mat3x3_f32;
+  float3x4 const mat3x4_f32 = (*(tint_symbol_1)).arr[idx].mat3x4_f32;
+  float4x2 const mat4x2_f32 = (*(tint_symbol_1)).arr[idx].mat4x2_f32;
+  float4x3 const mat4x3_f32 = (*(tint_symbol_1)).arr[idx].mat4x3_f32;
+  float4x4 const mat4x4_f32 = (*(tint_symbol_1)).arr[idx].mat4x4_f32;
+  half2x2 const mat2x2_f16 = (*(tint_symbol_1)).arr[idx].mat2x2_f16;
+  half2x3 const mat2x3_f16 = (*(tint_symbol_1)).arr[idx].mat2x3_f16;
+  half2x4 const mat2x4_f16 = (*(tint_symbol_1)).arr[idx].mat2x4_f16;
+  half3x2 const mat3x2_f16 = (*(tint_symbol_1)).arr[idx].mat3x2_f16;
+  half3x3 const mat3x3_f16 = (*(tint_symbol_1)).arr[idx].mat3x3_f16;
+  half3x4 const mat3x4_f16 = (*(tint_symbol_1)).arr[idx].mat3x4_f16;
+  half4x2 const mat4x2_f16 = (*(tint_symbol_1)).arr[idx].mat4x2_f16;
+  half4x3 const mat4x3_f16 = (*(tint_symbol_1)).arr[idx].mat4x3_f16;
+  half4x4 const mat4x4_f16 = (*(tint_symbol_1)).arr[idx].mat4x4_f16;
+  tint_array<float3, 2> const arr2_vec3_f32 = (*(tint_symbol_1)).arr[idx].arr2_vec3_f32;
+  tint_array<half4x2, 2> const arr2_mat4x2_f16 = (*(tint_symbol_1)).arr[idx].arr2_mat4x2_f16;
+}
+
+kernel void tint_symbol(const device S* tint_symbol_2 [[buffer(0)]], uint idx [[thread_index_in_threadgroup]]) {
+  tint_symbol_inner(idx, tint_symbol_2);
+  return;
+}
+
diff --git a/test/tint/buffer/storage/dynamic_index/read_f16.wgsl.expected.spvasm b/test/tint/buffer/storage/dynamic_index/read_f16.wgsl.expected.spvasm
new file mode 100644
index 0000000..d5f4b75
--- /dev/null
+++ b/test/tint/buffer/storage/dynamic_index/read_f16.wgsl.expected.spvasm
@@ -0,0 +1,341 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 198
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main" %idx_1
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %idx_1 "idx_1"
+               OpName %S "S"
+               OpMemberName %S 0 "arr"
+               OpName %Inner "Inner"
+               OpMemberName %Inner 0 "scalar_f32"
+               OpMemberName %Inner 1 "scalar_i32"
+               OpMemberName %Inner 2 "scalar_u32"
+               OpMemberName %Inner 3 "scalar_f16"
+               OpMemberName %Inner 4 "vec2_f32"
+               OpMemberName %Inner 5 "vec2_i32"
+               OpMemberName %Inner 6 "vec2_u32"
+               OpMemberName %Inner 7 "vec2_f16"
+               OpMemberName %Inner 8 "vec3_f32"
+               OpMemberName %Inner 9 "vec3_i32"
+               OpMemberName %Inner 10 "vec3_u32"
+               OpMemberName %Inner 11 "vec3_f16"
+               OpMemberName %Inner 12 "vec4_f32"
+               OpMemberName %Inner 13 "vec4_i32"
+               OpMemberName %Inner 14 "vec4_u32"
+               OpMemberName %Inner 15 "vec4_f16"
+               OpMemberName %Inner 16 "mat2x2_f32"
+               OpMemberName %Inner 17 "mat2x3_f32"
+               OpMemberName %Inner 18 "mat2x4_f32"
+               OpMemberName %Inner 19 "mat3x2_f32"
+               OpMemberName %Inner 20 "mat3x3_f32"
+               OpMemberName %Inner 21 "mat3x4_f32"
+               OpMemberName %Inner 22 "mat4x2_f32"
+               OpMemberName %Inner 23 "mat4x3_f32"
+               OpMemberName %Inner 24 "mat4x4_f32"
+               OpMemberName %Inner 25 "mat2x2_f16"
+               OpMemberName %Inner 26 "mat2x3_f16"
+               OpMemberName %Inner 27 "mat2x4_f16"
+               OpMemberName %Inner 28 "mat3x2_f16"
+               OpMemberName %Inner 29 "mat3x3_f16"
+               OpMemberName %Inner 30 "mat3x4_f16"
+               OpMemberName %Inner 31 "mat4x2_f16"
+               OpMemberName %Inner 32 "mat4x3_f16"
+               OpMemberName %Inner 33 "mat4x4_f16"
+               OpMemberName %Inner 34 "arr2_vec3_f32"
+               OpMemberName %Inner 35 "arr2_mat4x2_f16"
+               OpName %sb "sb"
+               OpName %main_inner "main_inner"
+               OpName %idx "idx"
+               OpName %main "main"
+               OpDecorate %idx_1 BuiltIn LocalInvocationIndex
+               OpDecorate %S Block
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %Inner 0 Offset 0
+               OpMemberDecorate %Inner 1 Offset 4
+               OpMemberDecorate %Inner 2 Offset 8
+               OpMemberDecorate %Inner 3 Offset 12
+               OpMemberDecorate %Inner 4 Offset 16
+               OpMemberDecorate %Inner 5 Offset 24
+               OpMemberDecorate %Inner 6 Offset 32
+               OpMemberDecorate %Inner 7 Offset 40
+               OpMemberDecorate %Inner 8 Offset 48
+               OpMemberDecorate %Inner 9 Offset 64
+               OpMemberDecorate %Inner 10 Offset 80
+               OpMemberDecorate %Inner 11 Offset 96
+               OpMemberDecorate %Inner 12 Offset 112
+               OpMemberDecorate %Inner 13 Offset 128
+               OpMemberDecorate %Inner 14 Offset 144
+               OpMemberDecorate %Inner 15 Offset 160
+               OpMemberDecorate %Inner 16 Offset 168
+               OpMemberDecorate %Inner 16 ColMajor
+               OpMemberDecorate %Inner 16 MatrixStride 8
+               OpMemberDecorate %Inner 17 Offset 192
+               OpMemberDecorate %Inner 17 ColMajor
+               OpMemberDecorate %Inner 17 MatrixStride 16
+               OpMemberDecorate %Inner 18 Offset 224
+               OpMemberDecorate %Inner 18 ColMajor
+               OpMemberDecorate %Inner 18 MatrixStride 16
+               OpMemberDecorate %Inner 19 Offset 256
+               OpMemberDecorate %Inner 19 ColMajor
+               OpMemberDecorate %Inner 19 MatrixStride 8
+               OpMemberDecorate %Inner 20 Offset 288
+               OpMemberDecorate %Inner 20 ColMajor
+               OpMemberDecorate %Inner 20 MatrixStride 16
+               OpMemberDecorate %Inner 21 Offset 336
+               OpMemberDecorate %Inner 21 ColMajor
+               OpMemberDecorate %Inner 21 MatrixStride 16
+               OpMemberDecorate %Inner 22 Offset 384
+               OpMemberDecorate %Inner 22 ColMajor
+               OpMemberDecorate %Inner 22 MatrixStride 8
+               OpMemberDecorate %Inner 23 Offset 416
+               OpMemberDecorate %Inner 23 ColMajor
+               OpMemberDecorate %Inner 23 MatrixStride 16
+               OpMemberDecorate %Inner 24 Offset 480
+               OpMemberDecorate %Inner 24 ColMajor
+               OpMemberDecorate %Inner 24 MatrixStride 16
+               OpMemberDecorate %Inner 25 Offset 544
+               OpMemberDecorate %Inner 25 ColMajor
+               OpMemberDecorate %Inner 25 MatrixStride 4
+               OpMemberDecorate %Inner 26 Offset 552
+               OpMemberDecorate %Inner 26 ColMajor
+               OpMemberDecorate %Inner 26 MatrixStride 8
+               OpMemberDecorate %Inner 27 Offset 568
+               OpMemberDecorate %Inner 27 ColMajor
+               OpMemberDecorate %Inner 27 MatrixStride 8
+               OpMemberDecorate %Inner 28 Offset 584
+               OpMemberDecorate %Inner 28 ColMajor
+               OpMemberDecorate %Inner 28 MatrixStride 4
+               OpMemberDecorate %Inner 29 Offset 600
+               OpMemberDecorate %Inner 29 ColMajor
+               OpMemberDecorate %Inner 29 MatrixStride 8
+               OpMemberDecorate %Inner 30 Offset 624
+               OpMemberDecorate %Inner 30 ColMajor
+               OpMemberDecorate %Inner 30 MatrixStride 8
+               OpMemberDecorate %Inner 31 Offset 648
+               OpMemberDecorate %Inner 31 ColMajor
+               OpMemberDecorate %Inner 31 MatrixStride 4
+               OpMemberDecorate %Inner 32 Offset 664
+               OpMemberDecorate %Inner 32 ColMajor
+               OpMemberDecorate %Inner 32 MatrixStride 8
+               OpMemberDecorate %Inner 33 Offset 696
+               OpMemberDecorate %Inner 33 ColMajor
+               OpMemberDecorate %Inner 33 MatrixStride 8
+               OpMemberDecorate %Inner 34 Offset 736
+               OpDecorate %_arr_v3float_uint_2 ArrayStride 16
+               OpMemberDecorate %Inner 35 Offset 768
+               OpMemberDecorate %Inner 35 ColMajor
+               OpMemberDecorate %Inner 35 MatrixStride 4
+               OpDecorate %_arr_mat4v2half_uint_2 ArrayStride 16
+               OpDecorate %_runtimearr_Inner ArrayStride 800
+               OpDecorate %sb NonWritable
+               OpDecorate %sb Binding 0
+               OpDecorate %sb DescriptorSet 0
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+      %idx_1 = OpVariable %_ptr_Input_uint Input
+      %float = OpTypeFloat 32
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+    %v2float = OpTypeVector %float 2
+      %v2int = OpTypeVector %int 2
+     %v2uint = OpTypeVector %uint 2
+     %v2half = OpTypeVector %half 2
+    %v3float = OpTypeVector %float 3
+      %v3int = OpTypeVector %int 3
+     %v3uint = OpTypeVector %uint 3
+     %v3half = OpTypeVector %half 3
+    %v4float = OpTypeVector %float 4
+      %v4int = OpTypeVector %int 4
+     %v4uint = OpTypeVector %uint 4
+     %v4half = OpTypeVector %half 4
+%mat2v2float = OpTypeMatrix %v2float 2
+%mat2v3float = OpTypeMatrix %v3float 2
+%mat2v4float = OpTypeMatrix %v4float 2
+%mat3v2float = OpTypeMatrix %v2float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+%mat3v4float = OpTypeMatrix %v4float 3
+%mat4v2float = OpTypeMatrix %v2float 4
+%mat4v3float = OpTypeMatrix %v3float 4
+%mat4v4float = OpTypeMatrix %v4float 4
+ %mat2v2half = OpTypeMatrix %v2half 2
+ %mat2v3half = OpTypeMatrix %v3half 2
+ %mat2v4half = OpTypeMatrix %v4half 2
+ %mat3v2half = OpTypeMatrix %v2half 3
+ %mat3v3half = OpTypeMatrix %v3half 3
+ %mat3v4half = OpTypeMatrix %v4half 3
+ %mat4v2half = OpTypeMatrix %v2half 4
+ %mat4v3half = OpTypeMatrix %v3half 4
+ %mat4v4half = OpTypeMatrix %v4half 4
+     %uint_2 = OpConstant %uint 2
+%_arr_v3float_uint_2 = OpTypeArray %v3float %uint_2
+%_arr_mat4v2half_uint_2 = OpTypeArray %mat4v2half %uint_2
+      %Inner = OpTypeStruct %float %int %uint %half %v2float %v2int %v2uint %v2half %v3float %v3int %v3uint %v3half %v4float %v4int %v4uint %v4half %mat2v2float %mat2v3float %mat2v4float %mat3v2float %mat3v3float %mat3v4float %mat4v2float %mat4v3float %mat4v4float %mat2v2half %mat2v3half %mat2v4half %mat3v2half %mat3v3half %mat3v4half %mat4v2half %mat4v3half %mat4v4half %_arr_v3float_uint_2 %_arr_mat4v2half_uint_2
+%_runtimearr_Inner = OpTypeRuntimeArray %Inner
+          %S = OpTypeStruct %_runtimearr_Inner
+%_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
+         %sb = OpVariable %_ptr_StorageBuffer_S StorageBuffer
+       %void = OpTypeVoid
+         %45 = OpTypeFunction %void %uint
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
+     %uint_1 = OpConstant %uint 1
+%_ptr_StorageBuffer_int = OpTypePointer StorageBuffer %int
+%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
+     %uint_3 = OpConstant %uint 3
+%_ptr_StorageBuffer_half = OpTypePointer StorageBuffer %half
+     %uint_4 = OpConstant %uint 4
+%_ptr_StorageBuffer_v2float = OpTypePointer StorageBuffer %v2float
+     %uint_5 = OpConstant %uint 5
+%_ptr_StorageBuffer_v2int = OpTypePointer StorageBuffer %v2int
+     %uint_6 = OpConstant %uint 6
+%_ptr_StorageBuffer_v2uint = OpTypePointer StorageBuffer %v2uint
+     %uint_7 = OpConstant %uint 7
+%_ptr_StorageBuffer_v2half = OpTypePointer StorageBuffer %v2half
+     %uint_8 = OpConstant %uint 8
+%_ptr_StorageBuffer_v3float = OpTypePointer StorageBuffer %v3float
+     %uint_9 = OpConstant %uint 9
+%_ptr_StorageBuffer_v3int = OpTypePointer StorageBuffer %v3int
+    %uint_10 = OpConstant %uint 10
+%_ptr_StorageBuffer_v3uint = OpTypePointer StorageBuffer %v3uint
+    %uint_11 = OpConstant %uint 11
+%_ptr_StorageBuffer_v3half = OpTypePointer StorageBuffer %v3half
+    %uint_12 = OpConstant %uint 12
+%_ptr_StorageBuffer_v4float = OpTypePointer StorageBuffer %v4float
+    %uint_13 = OpConstant %uint 13
+%_ptr_StorageBuffer_v4int = OpTypePointer StorageBuffer %v4int
+    %uint_14 = OpConstant %uint 14
+%_ptr_StorageBuffer_v4uint = OpTypePointer StorageBuffer %v4uint
+    %uint_15 = OpConstant %uint 15
+%_ptr_StorageBuffer_v4half = OpTypePointer StorageBuffer %v4half
+    %uint_16 = OpConstant %uint 16
+%_ptr_StorageBuffer_mat2v2float = OpTypePointer StorageBuffer %mat2v2float
+    %uint_17 = OpConstant %uint 17
+%_ptr_StorageBuffer_mat2v3float = OpTypePointer StorageBuffer %mat2v3float
+    %uint_18 = OpConstant %uint 18
+%_ptr_StorageBuffer_mat2v4float = OpTypePointer StorageBuffer %mat2v4float
+    %uint_19 = OpConstant %uint 19
+%_ptr_StorageBuffer_mat3v2float = OpTypePointer StorageBuffer %mat3v2float
+    %uint_20 = OpConstant %uint 20
+%_ptr_StorageBuffer_mat3v3float = OpTypePointer StorageBuffer %mat3v3float
+    %uint_21 = OpConstant %uint 21
+%_ptr_StorageBuffer_mat3v4float = OpTypePointer StorageBuffer %mat3v4float
+    %uint_22 = OpConstant %uint 22
+%_ptr_StorageBuffer_mat4v2float = OpTypePointer StorageBuffer %mat4v2float
+    %uint_23 = OpConstant %uint 23
+%_ptr_StorageBuffer_mat4v3float = OpTypePointer StorageBuffer %mat4v3float
+    %uint_24 = OpConstant %uint 24
+%_ptr_StorageBuffer_mat4v4float = OpTypePointer StorageBuffer %mat4v4float
+    %uint_25 = OpConstant %uint 25
+%_ptr_StorageBuffer_mat2v2half = OpTypePointer StorageBuffer %mat2v2half
+    %uint_26 = OpConstant %uint 26
+%_ptr_StorageBuffer_mat2v3half = OpTypePointer StorageBuffer %mat2v3half
+    %uint_27 = OpConstant %uint 27
+%_ptr_StorageBuffer_mat2v4half = OpTypePointer StorageBuffer %mat2v4half
+    %uint_28 = OpConstant %uint 28
+%_ptr_StorageBuffer_mat3v2half = OpTypePointer StorageBuffer %mat3v2half
+    %uint_29 = OpConstant %uint 29
+%_ptr_StorageBuffer_mat3v3half = OpTypePointer StorageBuffer %mat3v3half
+    %uint_30 = OpConstant %uint 30
+%_ptr_StorageBuffer_mat3v4half = OpTypePointer StorageBuffer %mat3v4half
+    %uint_31 = OpConstant %uint 31
+%_ptr_StorageBuffer_mat4v2half = OpTypePointer StorageBuffer %mat4v2half
+    %uint_32 = OpConstant %uint 32
+%_ptr_StorageBuffer_mat4v3half = OpTypePointer StorageBuffer %mat4v3half
+    %uint_33 = OpConstant %uint 33
+%_ptr_StorageBuffer_mat4v4half = OpTypePointer StorageBuffer %mat4v4half
+    %uint_34 = OpConstant %uint 34
+%_ptr_StorageBuffer__arr_v3float_uint_2 = OpTypePointer StorageBuffer %_arr_v3float_uint_2
+    %uint_35 = OpConstant %uint 35
+%_ptr_StorageBuffer__arr_mat4v2half_uint_2 = OpTypePointer StorageBuffer %_arr_mat4v2half_uint_2
+        %193 = OpTypeFunction %void
+ %main_inner = OpFunction %void None %45
+        %idx = OpFunctionParameter %uint
+         %49 = OpLabel
+         %52 = OpAccessChain %_ptr_StorageBuffer_float %sb %uint_0 %idx %uint_0
+         %53 = OpLoad %float %52
+         %56 = OpAccessChain %_ptr_StorageBuffer_int %sb %uint_0 %idx %uint_1
+         %57 = OpLoad %int %56
+         %59 = OpAccessChain %_ptr_StorageBuffer_uint %sb %uint_0 %idx %uint_2
+         %60 = OpLoad %uint %59
+         %63 = OpAccessChain %_ptr_StorageBuffer_half %sb %uint_0 %idx %uint_3
+         %64 = OpLoad %half %63
+         %67 = OpAccessChain %_ptr_StorageBuffer_v2float %sb %uint_0 %idx %uint_4
+         %68 = OpLoad %v2float %67
+         %71 = OpAccessChain %_ptr_StorageBuffer_v2int %sb %uint_0 %idx %uint_5
+         %72 = OpLoad %v2int %71
+         %75 = OpAccessChain %_ptr_StorageBuffer_v2uint %sb %uint_0 %idx %uint_6
+         %76 = OpLoad %v2uint %75
+         %79 = OpAccessChain %_ptr_StorageBuffer_v2half %sb %uint_0 %idx %uint_7
+         %80 = OpLoad %v2half %79
+         %83 = OpAccessChain %_ptr_StorageBuffer_v3float %sb %uint_0 %idx %uint_8
+         %84 = OpLoad %v3float %83
+         %87 = OpAccessChain %_ptr_StorageBuffer_v3int %sb %uint_0 %idx %uint_9
+         %88 = OpLoad %v3int %87
+         %91 = OpAccessChain %_ptr_StorageBuffer_v3uint %sb %uint_0 %idx %uint_10
+         %92 = OpLoad %v3uint %91
+         %95 = OpAccessChain %_ptr_StorageBuffer_v3half %sb %uint_0 %idx %uint_11
+         %96 = OpLoad %v3half %95
+         %99 = OpAccessChain %_ptr_StorageBuffer_v4float %sb %uint_0 %idx %uint_12
+        %100 = OpLoad %v4float %99
+        %103 = OpAccessChain %_ptr_StorageBuffer_v4int %sb %uint_0 %idx %uint_13
+        %104 = OpLoad %v4int %103
+        %107 = OpAccessChain %_ptr_StorageBuffer_v4uint %sb %uint_0 %idx %uint_14
+        %108 = OpLoad %v4uint %107
+        %111 = OpAccessChain %_ptr_StorageBuffer_v4half %sb %uint_0 %idx %uint_15
+        %112 = OpLoad %v4half %111
+        %115 = OpAccessChain %_ptr_StorageBuffer_mat2v2float %sb %uint_0 %idx %uint_16
+        %116 = OpLoad %mat2v2float %115
+        %119 = OpAccessChain %_ptr_StorageBuffer_mat2v3float %sb %uint_0 %idx %uint_17
+        %120 = OpLoad %mat2v3float %119
+        %123 = OpAccessChain %_ptr_StorageBuffer_mat2v4float %sb %uint_0 %idx %uint_18
+        %124 = OpLoad %mat2v4float %123
+        %127 = OpAccessChain %_ptr_StorageBuffer_mat3v2float %sb %uint_0 %idx %uint_19
+        %128 = OpLoad %mat3v2float %127
+        %131 = OpAccessChain %_ptr_StorageBuffer_mat3v3float %sb %uint_0 %idx %uint_20
+        %132 = OpLoad %mat3v3float %131
+        %135 = OpAccessChain %_ptr_StorageBuffer_mat3v4float %sb %uint_0 %idx %uint_21
+        %136 = OpLoad %mat3v4float %135
+        %139 = OpAccessChain %_ptr_StorageBuffer_mat4v2float %sb %uint_0 %idx %uint_22
+        %140 = OpLoad %mat4v2float %139
+        %143 = OpAccessChain %_ptr_StorageBuffer_mat4v3float %sb %uint_0 %idx %uint_23
+        %144 = OpLoad %mat4v3float %143
+        %147 = OpAccessChain %_ptr_StorageBuffer_mat4v4float %sb %uint_0 %idx %uint_24
+        %148 = OpLoad %mat4v4float %147
+        %151 = OpAccessChain %_ptr_StorageBuffer_mat2v2half %sb %uint_0 %idx %uint_25
+        %152 = OpLoad %mat2v2half %151
+        %155 = OpAccessChain %_ptr_StorageBuffer_mat2v3half %sb %uint_0 %idx %uint_26
+        %156 = OpLoad %mat2v3half %155
+        %159 = OpAccessChain %_ptr_StorageBuffer_mat2v4half %sb %uint_0 %idx %uint_27
+        %160 = OpLoad %mat2v4half %159
+        %163 = OpAccessChain %_ptr_StorageBuffer_mat3v2half %sb %uint_0 %idx %uint_28
+        %164 = OpLoad %mat3v2half %163
+        %167 = OpAccessChain %_ptr_StorageBuffer_mat3v3half %sb %uint_0 %idx %uint_29
+        %168 = OpLoad %mat3v3half %167
+        %171 = OpAccessChain %_ptr_StorageBuffer_mat3v4half %sb %uint_0 %idx %uint_30
+        %172 = OpLoad %mat3v4half %171
+        %175 = OpAccessChain %_ptr_StorageBuffer_mat4v2half %sb %uint_0 %idx %uint_31
+        %176 = OpLoad %mat4v2half %175
+        %179 = OpAccessChain %_ptr_StorageBuffer_mat4v3half %sb %uint_0 %idx %uint_32
+        %180 = OpLoad %mat4v3half %179
+        %183 = OpAccessChain %_ptr_StorageBuffer_mat4v4half %sb %uint_0 %idx %uint_33
+        %184 = OpLoad %mat4v4half %183
+        %187 = OpAccessChain %_ptr_StorageBuffer__arr_v3float_uint_2 %sb %uint_0 %idx %uint_34
+        %188 = OpLoad %_arr_v3float_uint_2 %187
+        %191 = OpAccessChain %_ptr_StorageBuffer__arr_mat4v2half_uint_2 %sb %uint_0 %idx %uint_35
+        %192 = OpLoad %_arr_mat4v2half_uint_2 %191
+               OpReturn
+               OpFunctionEnd
+       %main = OpFunction %void None %193
+        %195 = OpLabel
+        %197 = OpLoad %uint %idx_1
+        %196 = OpFunctionCall %void %main_inner %197
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/storage/dynamic_index/read_f16.wgsl.expected.wgsl b/test/tint/buffer/storage/dynamic_index/read_f16.wgsl.expected.wgsl
new file mode 100644
index 0000000..5a5e16b
--- /dev/null
+++ b/test/tint/buffer/storage/dynamic_index/read_f16.wgsl.expected.wgsl
@@ -0,0 +1,86 @@
+enable f16;
+
+struct Inner {
+  scalar_f32 : f32,
+  scalar_i32 : i32,
+  scalar_u32 : u32,
+  scalar_f16 : f16,
+  vec2_f32 : vec2<f32>,
+  vec2_i32 : vec2<i32>,
+  vec2_u32 : vec2<u32>,
+  vec2_f16 : vec2<f16>,
+  vec3_f32 : vec3<f32>,
+  vec3_i32 : vec3<i32>,
+  vec3_u32 : vec3<u32>,
+  vec3_f16 : vec3<f16>,
+  vec4_f32 : vec4<f32>,
+  vec4_i32 : vec4<i32>,
+  vec4_u32 : vec4<u32>,
+  vec4_f16 : vec4<f16>,
+  mat2x2_f32 : mat2x2<f32>,
+  mat2x3_f32 : mat2x3<f32>,
+  mat2x4_f32 : mat2x4<f32>,
+  mat3x2_f32 : mat3x2<f32>,
+  mat3x3_f32 : mat3x3<f32>,
+  mat3x4_f32 : mat3x4<f32>,
+  mat4x2_f32 : mat4x2<f32>,
+  mat4x3_f32 : mat4x3<f32>,
+  mat4x4_f32 : mat4x4<f32>,
+  mat2x2_f16 : mat2x2<f16>,
+  mat2x3_f16 : mat2x3<f16>,
+  mat2x4_f16 : mat2x4<f16>,
+  mat3x2_f16 : mat3x2<f16>,
+  mat3x3_f16 : mat3x3<f16>,
+  mat3x4_f16 : mat3x4<f16>,
+  mat4x2_f16 : mat4x2<f16>,
+  mat4x3_f16 : mat4x3<f16>,
+  mat4x4_f16 : mat4x4<f16>,
+  arr2_vec3_f32 : array<vec3<f32>, 2>,
+  arr2_mat4x2_f16 : array<mat4x2<f16>, 2>,
+}
+
+struct S {
+  arr : array<Inner>,
+}
+
+@binding(0) @group(0) var<storage, read> sb : S;
+
+@compute @workgroup_size(1)
+fn main(@builtin(local_invocation_index) idx : u32) {
+  let scalar_f32 : f32 = sb.arr[idx].scalar_f32;
+  let scalar_i32 : i32 = sb.arr[idx].scalar_i32;
+  let scalar_u32 : u32 = sb.arr[idx].scalar_u32;
+  let scalar_f16 : f16 = sb.arr[idx].scalar_f16;
+  let vec2_f32 : vec2<f32> = sb.arr[idx].vec2_f32;
+  let vec2_i32 : vec2<i32> = sb.arr[idx].vec2_i32;
+  let vec2_u32 : vec2<u32> = sb.arr[idx].vec2_u32;
+  let vec2_f16 : vec2<f16> = sb.arr[idx].vec2_f16;
+  let vec3_f32 : vec3<f32> = sb.arr[idx].vec3_f32;
+  let vec3_i32 : vec3<i32> = sb.arr[idx].vec3_i32;
+  let vec3_u32 : vec3<u32> = sb.arr[idx].vec3_u32;
+  let vec3_f16 : vec3<f16> = sb.arr[idx].vec3_f16;
+  let vec4_f32 : vec4<f32> = sb.arr[idx].vec4_f32;
+  let vec4_i32 : vec4<i32> = sb.arr[idx].vec4_i32;
+  let vec4_u32 : vec4<u32> = sb.arr[idx].vec4_u32;
+  let vec4_f16 : vec4<f16> = sb.arr[idx].vec4_f16;
+  let mat2x2_f32 : mat2x2<f32> = sb.arr[idx].mat2x2_f32;
+  let mat2x3_f32 : mat2x3<f32> = sb.arr[idx].mat2x3_f32;
+  let mat2x4_f32 : mat2x4<f32> = sb.arr[idx].mat2x4_f32;
+  let mat3x2_f32 : mat3x2<f32> = sb.arr[idx].mat3x2_f32;
+  let mat3x3_f32 : mat3x3<f32> = sb.arr[idx].mat3x3_f32;
+  let mat3x4_f32 : mat3x4<f32> = sb.arr[idx].mat3x4_f32;
+  let mat4x2_f32 : mat4x2<f32> = sb.arr[idx].mat4x2_f32;
+  let mat4x3_f32 : mat4x3<f32> = sb.arr[idx].mat4x3_f32;
+  let mat4x4_f32 : mat4x4<f32> = sb.arr[idx].mat4x4_f32;
+  let mat2x2_f16 : mat2x2<f16> = sb.arr[idx].mat2x2_f16;
+  let mat2x3_f16 : mat2x3<f16> = sb.arr[idx].mat2x3_f16;
+  let mat2x4_f16 : mat2x4<f16> = sb.arr[idx].mat2x4_f16;
+  let mat3x2_f16 : mat3x2<f16> = sb.arr[idx].mat3x2_f16;
+  let mat3x3_f16 : mat3x3<f16> = sb.arr[idx].mat3x3_f16;
+  let mat3x4_f16 : mat3x4<f16> = sb.arr[idx].mat3x4_f16;
+  let mat4x2_f16 : mat4x2<f16> = sb.arr[idx].mat4x2_f16;
+  let mat4x3_f16 : mat4x3<f16> = sb.arr[idx].mat4x3_f16;
+  let mat4x4_f16 : mat4x4<f16> = sb.arr[idx].mat4x4_f16;
+  let arr2_vec3_f32 : array<vec3<f32>, 2> = sb.arr[idx].arr2_vec3_f32;
+  let arr2_mat4x2_f16 : array<mat4x2<f16>, 2> = sb.arr[idx].arr2_mat4x2_f16;
+}
diff --git a/test/tint/buffer/storage/dynamic_index/write.wgsl b/test/tint/buffer/storage/dynamic_index/write.wgsl
index 38f202c..454a809 100644
--- a/test/tint/buffer/storage/dynamic_index/write.wgsl
+++ b/test/tint/buffer/storage/dynamic_index/write.wgsl
@@ -1,30 +1,57 @@
 struct Inner {
-    a : vec3<i32>,
-    b : i32,
-    c : vec3<u32>,
-    d : u32,
-    e : vec3<f32>,
-    f : f32,
-    g : mat2x3<f32>,
-    h : mat3x2<f32>,
-    i : array<vec4<i32>, 4>,
+    scalar_f32 : f32,
+    scalar_i32 : i32,
+    scalar_u32 : u32,
+    vec2_f32 : vec2<f32>,
+    vec2_i32 : vec2<i32>,
+    vec2_u32 : vec2<u32>,
+    vec3_f32 : vec3<f32>,
+    vec3_i32 : vec3<i32>,
+    vec3_u32 : vec3<u32>,
+    vec4_f32 : vec4<f32>,
+    vec4_i32 : vec4<i32>,
+    vec4_u32 : vec4<u32>,
+    mat2x2_f32 : mat2x2<f32>,
+    mat2x3_f32 : mat2x3<f32>,
+    mat2x4_f32 : mat2x4<f32>,
+    mat3x2_f32 : mat3x2<f32>,
+    mat3x3_f32 : mat3x3<f32>,
+    mat3x4_f32 : mat3x4<f32>,
+    mat4x2_f32 : mat4x2<f32>,
+    mat4x3_f32 : mat4x3<f32>,
+    mat4x4_f32 : mat4x4<f32>,
+    arr2_vec3_f32 : array<vec3<f32>, 2>,
+
 };
 
 struct S {
     arr : array<Inner>,
 };
 
-@binding(0) @group(0) var<storage, read_write> s : S;
+@binding(0) @group(0) var<storage, read_write> sb : S;
 
 @compute @workgroup_size(1)
 fn main(@builtin(local_invocation_index) idx : u32) {
-    s.arr[idx].a = vec3<i32>();
-    s.arr[idx].b = i32();
-    s.arr[idx].c = vec3<u32>();
-    s.arr[idx].d = u32();
-    s.arr[idx].e = vec3<f32>();
-    s.arr[idx].f = f32();
-    s.arr[idx].g = mat2x3<f32>();
-    s.arr[idx].h = mat3x2<f32>();
-    s.arr[idx].i = array<vec4<i32>, 4>();
+    sb.arr[idx].scalar_f32 = f32();
+    sb.arr[idx].scalar_i32 = i32();
+    sb.arr[idx].scalar_u32 = u32();
+    sb.arr[idx].vec2_f32 = vec2<f32>();
+    sb.arr[idx].vec2_i32 = vec2<i32>();
+    sb.arr[idx].vec2_u32 = vec2<u32>();
+    sb.arr[idx].vec3_f32 = vec3<f32>();
+    sb.arr[idx].vec3_i32 = vec3<i32>();
+    sb.arr[idx].vec3_u32 = vec3<u32>();
+    sb.arr[idx].vec4_f32 = vec4<f32>();
+    sb.arr[idx].vec4_i32 = vec4<i32>();
+    sb.arr[idx].vec4_u32 = vec4<u32>();
+    sb.arr[idx].mat2x2_f32 = mat2x2<f32>();
+    sb.arr[idx].mat2x3_f32 = mat2x3<f32>();
+    sb.arr[idx].mat2x4_f32 = mat2x4<f32>();
+    sb.arr[idx].mat3x2_f32 = mat3x2<f32>();
+    sb.arr[idx].mat3x3_f32 = mat3x3<f32>();
+    sb.arr[idx].mat3x4_f32 = mat3x4<f32>();
+    sb.arr[idx].mat4x2_f32 = mat4x2<f32>();
+    sb.arr[idx].mat4x3_f32 = mat4x3<f32>();
+    sb.arr[idx].mat4x4_f32 = mat4x4<f32>();
+    sb.arr[idx].arr2_vec3_f32 = array<vec3<f32>, 2>();
 }
diff --git a/test/tint/buffer/storage/dynamic_index/write.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/dynamic_index/write.wgsl.expected.dxc.hlsl
index 87148c2..4bcc56d 100644
--- a/test/tint/buffer/storage/dynamic_index/write.wgsl.expected.dxc.hlsl
+++ b/test/tint/buffer/storage/dynamic_index/write.wgsl.expected.dxc.hlsl
@@ -1,40 +1,96 @@
-RWByteAddressBuffer s : register(u0, space0);
+RWByteAddressBuffer sb : register(u0, space0);
 
 struct tint_symbol_1 {
   uint idx : SV_GroupIndex;
 };
 
-void tint_symbol_8(RWByteAddressBuffer buffer, uint offset, float2x3 value) {
+void tint_symbol_14(RWByteAddressBuffer buffer, uint offset, float2x2 value) {
+  buffer.Store2((offset + 0u), asuint(value[0u]));
+  buffer.Store2((offset + 8u), asuint(value[1u]));
+}
+
+void tint_symbol_15(RWByteAddressBuffer buffer, uint offset, float2x3 value) {
   buffer.Store3((offset + 0u), asuint(value[0u]));
   buffer.Store3((offset + 16u), asuint(value[1u]));
 }
 
-void tint_symbol_9(RWByteAddressBuffer buffer, uint offset, float3x2 value) {
+void tint_symbol_16(RWByteAddressBuffer buffer, uint offset, float2x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+}
+
+void tint_symbol_17(RWByteAddressBuffer buffer, uint offset, float3x2 value) {
   buffer.Store2((offset + 0u), asuint(value[0u]));
   buffer.Store2((offset + 8u), asuint(value[1u]));
   buffer.Store2((offset + 16u), asuint(value[2u]));
 }
 
-void tint_symbol_11(RWByteAddressBuffer buffer, uint offset, int4 value[4]) {
-  int4 array[4] = value;
+void tint_symbol_18(RWByteAddressBuffer buffer, uint offset, float3x3 value) {
+  buffer.Store3((offset + 0u), asuint(value[0u]));
+  buffer.Store3((offset + 16u), asuint(value[1u]));
+  buffer.Store3((offset + 32u), asuint(value[2u]));
+}
+
+void tint_symbol_19(RWByteAddressBuffer buffer, uint offset, float3x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+  buffer.Store4((offset + 32u), asuint(value[2u]));
+}
+
+void tint_symbol_20(RWByteAddressBuffer buffer, uint offset, float4x2 value) {
+  buffer.Store2((offset + 0u), asuint(value[0u]));
+  buffer.Store2((offset + 8u), asuint(value[1u]));
+  buffer.Store2((offset + 16u), asuint(value[2u]));
+  buffer.Store2((offset + 24u), asuint(value[3u]));
+}
+
+void tint_symbol_21(RWByteAddressBuffer buffer, uint offset, float4x3 value) {
+  buffer.Store3((offset + 0u), asuint(value[0u]));
+  buffer.Store3((offset + 16u), asuint(value[1u]));
+  buffer.Store3((offset + 32u), asuint(value[2u]));
+  buffer.Store3((offset + 48u), asuint(value[3u]));
+}
+
+void tint_symbol_22(RWByteAddressBuffer buffer, uint offset, float4x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+  buffer.Store4((offset + 32u), asuint(value[2u]));
+  buffer.Store4((offset + 48u), asuint(value[3u]));
+}
+
+void tint_symbol_23(RWByteAddressBuffer buffer, uint offset, float3 value[2]) {
+  float3 array[2] = value;
   {
-    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
-      buffer.Store4((offset + (i_1 * 16u)), asuint(array[i_1]));
+    for(uint i = 0u; (i < 2u); i = (i + 1u)) {
+      buffer.Store3((offset + (i * 16u)), asuint(array[i]));
     }
   }
 }
 
 void main_inner(uint idx) {
-  s.Store3((176u * idx), asuint((0).xxx));
-  s.Store(((176u * idx) + 12u), asuint(0));
-  s.Store3(((176u * idx) + 16u), asuint((0u).xxx));
-  s.Store(((176u * idx) + 28u), asuint(0u));
-  s.Store3(((176u * idx) + 32u), asuint((0.0f).xxx));
-  s.Store(((176u * idx) + 44u), asuint(0.0f));
-  tint_symbol_8(s, ((176u * idx) + 48u), float2x3((0.0f).xxx, (0.0f).xxx));
-  tint_symbol_9(s, ((176u * idx) + 80u), float3x2((0.0f).xx, (0.0f).xx, (0.0f).xx));
-  const int4 tint_symbol_13[4] = (int4[4])0;
-  tint_symbol_11(s, ((176u * idx) + 112u), tint_symbol_13);
+  sb.Store((544u * idx), asuint(0.0f));
+  sb.Store(((544u * idx) + 4u), asuint(0));
+  sb.Store(((544u * idx) + 8u), asuint(0u));
+  sb.Store2(((544u * idx) + 16u), asuint((0.0f).xx));
+  sb.Store2(((544u * idx) + 24u), asuint((0).xx));
+  sb.Store2(((544u * idx) + 32u), asuint((0u).xx));
+  sb.Store3(((544u * idx) + 48u), asuint((0.0f).xxx));
+  sb.Store3(((544u * idx) + 64u), asuint((0).xxx));
+  sb.Store3(((544u * idx) + 80u), asuint((0u).xxx));
+  sb.Store4(((544u * idx) + 96u), asuint((0.0f).xxxx));
+  sb.Store4(((544u * idx) + 112u), asuint((0).xxxx));
+  sb.Store4(((544u * idx) + 128u), asuint((0u).xxxx));
+  tint_symbol_14(sb, ((544u * idx) + 144u), float2x2((0.0f).xx, (0.0f).xx));
+  tint_symbol_15(sb, ((544u * idx) + 160u), float2x3((0.0f).xxx, (0.0f).xxx));
+  tint_symbol_16(sb, ((544u * idx) + 192u), float2x4((0.0f).xxxx, (0.0f).xxxx));
+  tint_symbol_17(sb, ((544u * idx) + 224u), float3x2((0.0f).xx, (0.0f).xx, (0.0f).xx));
+  tint_symbol_18(sb, ((544u * idx) + 256u), float3x3((0.0f).xxx, (0.0f).xxx, (0.0f).xxx));
+  tint_symbol_19(sb, ((544u * idx) + 304u), float3x4((0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx));
+  tint_symbol_20(sb, ((544u * idx) + 352u), float4x2((0.0f).xx, (0.0f).xx, (0.0f).xx, (0.0f).xx));
+  tint_symbol_21(sb, ((544u * idx) + 384u), float4x3((0.0f).xxx, (0.0f).xxx, (0.0f).xxx, (0.0f).xxx));
+  tint_symbol_22(sb, ((544u * idx) + 448u), float4x4((0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx));
+  const float3 tint_symbol_24[2] = (float3[2])0;
+  tint_symbol_23(sb, ((544u * idx) + 512u), tint_symbol_24);
 }
 
 [numthreads(1, 1, 1)]
diff --git a/test/tint/buffer/storage/dynamic_index/write.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/dynamic_index/write.wgsl.expected.fxc.hlsl
index 87148c2..4bcc56d 100644
--- a/test/tint/buffer/storage/dynamic_index/write.wgsl.expected.fxc.hlsl
+++ b/test/tint/buffer/storage/dynamic_index/write.wgsl.expected.fxc.hlsl
@@ -1,40 +1,96 @@
-RWByteAddressBuffer s : register(u0, space0);
+RWByteAddressBuffer sb : register(u0, space0);
 
 struct tint_symbol_1 {
   uint idx : SV_GroupIndex;
 };
 
-void tint_symbol_8(RWByteAddressBuffer buffer, uint offset, float2x3 value) {
+void tint_symbol_14(RWByteAddressBuffer buffer, uint offset, float2x2 value) {
+  buffer.Store2((offset + 0u), asuint(value[0u]));
+  buffer.Store2((offset + 8u), asuint(value[1u]));
+}
+
+void tint_symbol_15(RWByteAddressBuffer buffer, uint offset, float2x3 value) {
   buffer.Store3((offset + 0u), asuint(value[0u]));
   buffer.Store3((offset + 16u), asuint(value[1u]));
 }
 
-void tint_symbol_9(RWByteAddressBuffer buffer, uint offset, float3x2 value) {
+void tint_symbol_16(RWByteAddressBuffer buffer, uint offset, float2x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+}
+
+void tint_symbol_17(RWByteAddressBuffer buffer, uint offset, float3x2 value) {
   buffer.Store2((offset + 0u), asuint(value[0u]));
   buffer.Store2((offset + 8u), asuint(value[1u]));
   buffer.Store2((offset + 16u), asuint(value[2u]));
 }
 
-void tint_symbol_11(RWByteAddressBuffer buffer, uint offset, int4 value[4]) {
-  int4 array[4] = value;
+void tint_symbol_18(RWByteAddressBuffer buffer, uint offset, float3x3 value) {
+  buffer.Store3((offset + 0u), asuint(value[0u]));
+  buffer.Store3((offset + 16u), asuint(value[1u]));
+  buffer.Store3((offset + 32u), asuint(value[2u]));
+}
+
+void tint_symbol_19(RWByteAddressBuffer buffer, uint offset, float3x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+  buffer.Store4((offset + 32u), asuint(value[2u]));
+}
+
+void tint_symbol_20(RWByteAddressBuffer buffer, uint offset, float4x2 value) {
+  buffer.Store2((offset + 0u), asuint(value[0u]));
+  buffer.Store2((offset + 8u), asuint(value[1u]));
+  buffer.Store2((offset + 16u), asuint(value[2u]));
+  buffer.Store2((offset + 24u), asuint(value[3u]));
+}
+
+void tint_symbol_21(RWByteAddressBuffer buffer, uint offset, float4x3 value) {
+  buffer.Store3((offset + 0u), asuint(value[0u]));
+  buffer.Store3((offset + 16u), asuint(value[1u]));
+  buffer.Store3((offset + 32u), asuint(value[2u]));
+  buffer.Store3((offset + 48u), asuint(value[3u]));
+}
+
+void tint_symbol_22(RWByteAddressBuffer buffer, uint offset, float4x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+  buffer.Store4((offset + 32u), asuint(value[2u]));
+  buffer.Store4((offset + 48u), asuint(value[3u]));
+}
+
+void tint_symbol_23(RWByteAddressBuffer buffer, uint offset, float3 value[2]) {
+  float3 array[2] = value;
   {
-    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
-      buffer.Store4((offset + (i_1 * 16u)), asuint(array[i_1]));
+    for(uint i = 0u; (i < 2u); i = (i + 1u)) {
+      buffer.Store3((offset + (i * 16u)), asuint(array[i]));
     }
   }
 }
 
 void main_inner(uint idx) {
-  s.Store3((176u * idx), asuint((0).xxx));
-  s.Store(((176u * idx) + 12u), asuint(0));
-  s.Store3(((176u * idx) + 16u), asuint((0u).xxx));
-  s.Store(((176u * idx) + 28u), asuint(0u));
-  s.Store3(((176u * idx) + 32u), asuint((0.0f).xxx));
-  s.Store(((176u * idx) + 44u), asuint(0.0f));
-  tint_symbol_8(s, ((176u * idx) + 48u), float2x3((0.0f).xxx, (0.0f).xxx));
-  tint_symbol_9(s, ((176u * idx) + 80u), float3x2((0.0f).xx, (0.0f).xx, (0.0f).xx));
-  const int4 tint_symbol_13[4] = (int4[4])0;
-  tint_symbol_11(s, ((176u * idx) + 112u), tint_symbol_13);
+  sb.Store((544u * idx), asuint(0.0f));
+  sb.Store(((544u * idx) + 4u), asuint(0));
+  sb.Store(((544u * idx) + 8u), asuint(0u));
+  sb.Store2(((544u * idx) + 16u), asuint((0.0f).xx));
+  sb.Store2(((544u * idx) + 24u), asuint((0).xx));
+  sb.Store2(((544u * idx) + 32u), asuint((0u).xx));
+  sb.Store3(((544u * idx) + 48u), asuint((0.0f).xxx));
+  sb.Store3(((544u * idx) + 64u), asuint((0).xxx));
+  sb.Store3(((544u * idx) + 80u), asuint((0u).xxx));
+  sb.Store4(((544u * idx) + 96u), asuint((0.0f).xxxx));
+  sb.Store4(((544u * idx) + 112u), asuint((0).xxxx));
+  sb.Store4(((544u * idx) + 128u), asuint((0u).xxxx));
+  tint_symbol_14(sb, ((544u * idx) + 144u), float2x2((0.0f).xx, (0.0f).xx));
+  tint_symbol_15(sb, ((544u * idx) + 160u), float2x3((0.0f).xxx, (0.0f).xxx));
+  tint_symbol_16(sb, ((544u * idx) + 192u), float2x4((0.0f).xxxx, (0.0f).xxxx));
+  tint_symbol_17(sb, ((544u * idx) + 224u), float3x2((0.0f).xx, (0.0f).xx, (0.0f).xx));
+  tint_symbol_18(sb, ((544u * idx) + 256u), float3x3((0.0f).xxx, (0.0f).xxx, (0.0f).xxx));
+  tint_symbol_19(sb, ((544u * idx) + 304u), float3x4((0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx));
+  tint_symbol_20(sb, ((544u * idx) + 352u), float4x2((0.0f).xx, (0.0f).xx, (0.0f).xx, (0.0f).xx));
+  tint_symbol_21(sb, ((544u * idx) + 384u), float4x3((0.0f).xxx, (0.0f).xxx, (0.0f).xxx, (0.0f).xxx));
+  tint_symbol_22(sb, ((544u * idx) + 448u), float4x4((0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx));
+  const float3 tint_symbol_24[2] = (float3[2])0;
+  tint_symbol_23(sb, ((544u * idx) + 512u), tint_symbol_24);
 }
 
 [numthreads(1, 1, 1)]
diff --git a/test/tint/buffer/storage/dynamic_index/write.wgsl.expected.glsl b/test/tint/buffer/storage/dynamic_index/write.wgsl.expected.glsl
index f26e111..5b3652e 100644
--- a/test/tint/buffer/storage/dynamic_index/write.wgsl.expected.glsl
+++ b/test/tint/buffer/storage/dynamic_index/write.wgsl.expected.glsl
@@ -1,34 +1,66 @@
 #version 310 es
 
 struct Inner {
-  ivec3 a;
-  int b;
-  uvec3 c;
-  uint d;
-  vec3 e;
-  float f;
-  mat2x3 g;
-  mat3x2 h;
+  float scalar_f32;
+  int scalar_i32;
+  uint scalar_u32;
   uint pad;
+  vec2 vec2_f32;
+  ivec2 vec2_i32;
+  uvec2 vec2_u32;
   uint pad_1;
-  ivec4 i[4];
+  uint pad_2;
+  vec3 vec3_f32;
+  uint pad_3;
+  ivec3 vec3_i32;
+  uint pad_4;
+  uvec3 vec3_u32;
+  uint pad_5;
+  vec4 vec4_f32;
+  ivec4 vec4_i32;
+  uvec4 vec4_u32;
+  mat2 mat2x2_f32;
+  mat2x3 mat2x3_f32;
+  mat2x4 mat2x4_f32;
+  mat3x2 mat3x2_f32;
+  uint pad_6;
+  uint pad_7;
+  mat3 mat3x3_f32;
+  mat3x4 mat3x4_f32;
+  mat4x2 mat4x2_f32;
+  mat4x3 mat4x3_f32;
+  mat4 mat4x4_f32;
+  vec3 arr2_vec3_f32[2];
 };
 
 layout(binding = 0, std430) buffer S_ssbo {
   Inner arr[];
-} s;
+} sb;
 
 void tint_symbol(uint idx) {
-  s.arr[idx].a = ivec3(0);
-  s.arr[idx].b = 0;
-  s.arr[idx].c = uvec3(0u);
-  s.arr[idx].d = 0u;
-  s.arr[idx].e = vec3(0.0f);
-  s.arr[idx].f = 0.0f;
-  s.arr[idx].g = mat2x3(vec3(0.0f), vec3(0.0f));
-  s.arr[idx].h = mat3x2(vec2(0.0f), vec2(0.0f), vec2(0.0f));
-  ivec4 tint_symbol_1[4] = ivec4[4](ivec4(0), ivec4(0), ivec4(0), ivec4(0));
-  s.arr[idx].i = tint_symbol_1;
+  sb.arr[idx].scalar_f32 = 0.0f;
+  sb.arr[idx].scalar_i32 = 0;
+  sb.arr[idx].scalar_u32 = 0u;
+  sb.arr[idx].vec2_f32 = vec2(0.0f);
+  sb.arr[idx].vec2_i32 = ivec2(0);
+  sb.arr[idx].vec2_u32 = uvec2(0u);
+  sb.arr[idx].vec3_f32 = vec3(0.0f);
+  sb.arr[idx].vec3_i32 = ivec3(0);
+  sb.arr[idx].vec3_u32 = uvec3(0u);
+  sb.arr[idx].vec4_f32 = vec4(0.0f);
+  sb.arr[idx].vec4_i32 = ivec4(0);
+  sb.arr[idx].vec4_u32 = uvec4(0u);
+  sb.arr[idx].mat2x2_f32 = mat2(vec2(0.0f), vec2(0.0f));
+  sb.arr[idx].mat2x3_f32 = mat2x3(vec3(0.0f), vec3(0.0f));
+  sb.arr[idx].mat2x4_f32 = mat2x4(vec4(0.0f), vec4(0.0f));
+  sb.arr[idx].mat3x2_f32 = mat3x2(vec2(0.0f), vec2(0.0f), vec2(0.0f));
+  sb.arr[idx].mat3x3_f32 = mat3(vec3(0.0f), vec3(0.0f), vec3(0.0f));
+  sb.arr[idx].mat3x4_f32 = mat3x4(vec4(0.0f), vec4(0.0f), vec4(0.0f));
+  sb.arr[idx].mat4x2_f32 = mat4x2(vec2(0.0f), vec2(0.0f), vec2(0.0f), vec2(0.0f));
+  sb.arr[idx].mat4x3_f32 = mat4x3(vec3(0.0f), vec3(0.0f), vec3(0.0f), vec3(0.0f));
+  sb.arr[idx].mat4x4_f32 = mat4(vec4(0.0f), vec4(0.0f), vec4(0.0f), vec4(0.0f));
+  vec3 tint_symbol_1[2] = vec3[2](vec3(0.0f), vec3(0.0f));
+  sb.arr[idx].arr2_vec3_f32 = tint_symbol_1;
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/buffer/storage/dynamic_index/write.wgsl.expected.msl b/test/tint/buffer/storage/dynamic_index/write.wgsl.expected.msl
index bb82069..4d2823b 100644
--- a/test/tint/buffer/storage/dynamic_index/write.wgsl.expected.msl
+++ b/test/tint/buffer/storage/dynamic_index/write.wgsl.expected.msl
@@ -15,16 +15,34 @@
 };
 
 struct Inner {
-  /* 0x0000 */ packed_int3 a;
-  /* 0x000c */ int b;
-  /* 0x0010 */ packed_uint3 c;
-  /* 0x001c */ uint d;
-  /* 0x0020 */ packed_float3 e;
-  /* 0x002c */ float f;
-  /* 0x0030 */ float2x3 g;
-  /* 0x0050 */ float3x2 h;
-  /* 0x0068 */ tint_array<int8_t, 8> tint_pad;
-  /* 0x0070 */ tint_array<int4, 4> i;
+  /* 0x0000 */ float scalar_f32;
+  /* 0x0004 */ int scalar_i32;
+  /* 0x0008 */ uint scalar_u32;
+  /* 0x000c */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0010 */ float2 vec2_f32;
+  /* 0x0018 */ int2 vec2_i32;
+  /* 0x0020 */ uint2 vec2_u32;
+  /* 0x0028 */ tint_array<int8_t, 8> tint_pad_1;
+  /* 0x0030 */ packed_float3 vec3_f32;
+  /* 0x003c */ tint_array<int8_t, 4> tint_pad_2;
+  /* 0x0040 */ packed_int3 vec3_i32;
+  /* 0x004c */ tint_array<int8_t, 4> tint_pad_3;
+  /* 0x0050 */ packed_uint3 vec3_u32;
+  /* 0x005c */ tint_array<int8_t, 4> tint_pad_4;
+  /* 0x0060 */ float4 vec4_f32;
+  /* 0x0070 */ int4 vec4_i32;
+  /* 0x0080 */ uint4 vec4_u32;
+  /* 0x0090 */ float2x2 mat2x2_f32;
+  /* 0x00a0 */ float2x3 mat2x3_f32;
+  /* 0x00c0 */ float2x4 mat2x4_f32;
+  /* 0x00e0 */ float3x2 mat3x2_f32;
+  /* 0x00f8 */ tint_array<int8_t, 8> tint_pad_5;
+  /* 0x0100 */ float3x3 mat3x3_f32;
+  /* 0x0130 */ float3x4 mat3x4_f32;
+  /* 0x0160 */ float4x2 mat4x2_f32;
+  /* 0x0180 */ float4x3 mat4x3_f32;
+  /* 0x01c0 */ float4x4 mat4x4_f32;
+  /* 0x0200 */ tint_array<float3, 2> arr2_vec3_f32;
 };
 
 struct S {
@@ -32,16 +50,29 @@
 };
 
 void tint_symbol_inner(uint idx, device S* const tint_symbol_2) {
-  (*(tint_symbol_2)).arr[idx].a = int3(0);
-  (*(tint_symbol_2)).arr[idx].b = 0;
-  (*(tint_symbol_2)).arr[idx].c = uint3(0u);
-  (*(tint_symbol_2)).arr[idx].d = 0u;
-  (*(tint_symbol_2)).arr[idx].e = float3(0.0f);
-  (*(tint_symbol_2)).arr[idx].f = 0.0f;
-  (*(tint_symbol_2)).arr[idx].g = float2x3(float3(0.0f), float3(0.0f));
-  (*(tint_symbol_2)).arr[idx].h = float3x2(float2(0.0f), float2(0.0f), float2(0.0f));
-  tint_array<int4, 4> const tint_symbol_1 = tint_array<int4, 4>{};
-  (*(tint_symbol_2)).arr[idx].i = tint_symbol_1;
+  (*(tint_symbol_2)).arr[idx].scalar_f32 = 0.0f;
+  (*(tint_symbol_2)).arr[idx].scalar_i32 = 0;
+  (*(tint_symbol_2)).arr[idx].scalar_u32 = 0u;
+  (*(tint_symbol_2)).arr[idx].vec2_f32 = float2(0.0f);
+  (*(tint_symbol_2)).arr[idx].vec2_i32 = int2(0);
+  (*(tint_symbol_2)).arr[idx].vec2_u32 = uint2(0u);
+  (*(tint_symbol_2)).arr[idx].vec3_f32 = float3(0.0f);
+  (*(tint_symbol_2)).arr[idx].vec3_i32 = int3(0);
+  (*(tint_symbol_2)).arr[idx].vec3_u32 = uint3(0u);
+  (*(tint_symbol_2)).arr[idx].vec4_f32 = float4(0.0f);
+  (*(tint_symbol_2)).arr[idx].vec4_i32 = int4(0);
+  (*(tint_symbol_2)).arr[idx].vec4_u32 = uint4(0u);
+  (*(tint_symbol_2)).arr[idx].mat2x2_f32 = float2x2(float2(0.0f), float2(0.0f));
+  (*(tint_symbol_2)).arr[idx].mat2x3_f32 = float2x3(float3(0.0f), float3(0.0f));
+  (*(tint_symbol_2)).arr[idx].mat2x4_f32 = float2x4(float4(0.0f), float4(0.0f));
+  (*(tint_symbol_2)).arr[idx].mat3x2_f32 = float3x2(float2(0.0f), float2(0.0f), float2(0.0f));
+  (*(tint_symbol_2)).arr[idx].mat3x3_f32 = float3x3(float3(0.0f), float3(0.0f), float3(0.0f));
+  (*(tint_symbol_2)).arr[idx].mat3x4_f32 = float3x4(float4(0.0f), float4(0.0f), float4(0.0f));
+  (*(tint_symbol_2)).arr[idx].mat4x2_f32 = float4x2(float2(0.0f), float2(0.0f), float2(0.0f), float2(0.0f));
+  (*(tint_symbol_2)).arr[idx].mat4x3_f32 = float4x3(float3(0.0f), float3(0.0f), float3(0.0f), float3(0.0f));
+  (*(tint_symbol_2)).arr[idx].mat4x4_f32 = float4x4(float4(0.0f), float4(0.0f), float4(0.0f), float4(0.0f));
+  tint_array<float3, 2> const tint_symbol_1 = tint_array<float3, 2>{};
+  (*(tint_symbol_2)).arr[idx].arr2_vec3_f32 = tint_symbol_1;
 }
 
 kernel void tint_symbol(device S* tint_symbol_3 [[buffer(0)]], uint idx [[thread_index_in_threadgroup]]) {
diff --git a/test/tint/buffer/storage/dynamic_index/write.wgsl.expected.spvasm b/test/tint/buffer/storage/dynamic_index/write.wgsl.expected.spvasm
index c7d951c..2ec199c 100644
--- a/test/tint/buffer/storage/dynamic_index/write.wgsl.expected.spvasm
+++ b/test/tint/buffer/storage/dynamic_index/write.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 65
+; Bound: 128
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -11,16 +11,29 @@
                OpName %S "S"
                OpMemberName %S 0 "arr"
                OpName %Inner "Inner"
-               OpMemberName %Inner 0 "a"
-               OpMemberName %Inner 1 "b"
-               OpMemberName %Inner 2 "c"
-               OpMemberName %Inner 3 "d"
-               OpMemberName %Inner 4 "e"
-               OpMemberName %Inner 5 "f"
-               OpMemberName %Inner 6 "g"
-               OpMemberName %Inner 7 "h"
-               OpMemberName %Inner 8 "i"
-               OpName %s "s"
+               OpMemberName %Inner 0 "scalar_f32"
+               OpMemberName %Inner 1 "scalar_i32"
+               OpMemberName %Inner 2 "scalar_u32"
+               OpMemberName %Inner 3 "vec2_f32"
+               OpMemberName %Inner 4 "vec2_i32"
+               OpMemberName %Inner 5 "vec2_u32"
+               OpMemberName %Inner 6 "vec3_f32"
+               OpMemberName %Inner 7 "vec3_i32"
+               OpMemberName %Inner 8 "vec3_u32"
+               OpMemberName %Inner 9 "vec4_f32"
+               OpMemberName %Inner 10 "vec4_i32"
+               OpMemberName %Inner 11 "vec4_u32"
+               OpMemberName %Inner 12 "mat2x2_f32"
+               OpMemberName %Inner 13 "mat2x3_f32"
+               OpMemberName %Inner 14 "mat2x4_f32"
+               OpMemberName %Inner 15 "mat3x2_f32"
+               OpMemberName %Inner 16 "mat3x3_f32"
+               OpMemberName %Inner 17 "mat3x4_f32"
+               OpMemberName %Inner 18 "mat4x2_f32"
+               OpMemberName %Inner 19 "mat4x3_f32"
+               OpMemberName %Inner 20 "mat4x4_f32"
+               OpMemberName %Inner 21 "arr2_vec3_f32"
+               OpName %sb "sb"
                OpName %main_inner "main_inner"
                OpName %idx "idx"
                OpName %main "main"
@@ -28,96 +41,199 @@
                OpDecorate %S Block
                OpMemberDecorate %S 0 Offset 0
                OpMemberDecorate %Inner 0 Offset 0
-               OpMemberDecorate %Inner 1 Offset 12
-               OpMemberDecorate %Inner 2 Offset 16
-               OpMemberDecorate %Inner 3 Offset 28
-               OpMemberDecorate %Inner 4 Offset 32
-               OpMemberDecorate %Inner 5 Offset 44
+               OpMemberDecorate %Inner 1 Offset 4
+               OpMemberDecorate %Inner 2 Offset 8
+               OpMemberDecorate %Inner 3 Offset 16
+               OpMemberDecorate %Inner 4 Offset 24
+               OpMemberDecorate %Inner 5 Offset 32
                OpMemberDecorate %Inner 6 Offset 48
-               OpMemberDecorate %Inner 6 ColMajor
-               OpMemberDecorate %Inner 6 MatrixStride 16
-               OpMemberDecorate %Inner 7 Offset 80
-               OpMemberDecorate %Inner 7 ColMajor
-               OpMemberDecorate %Inner 7 MatrixStride 8
-               OpMemberDecorate %Inner 8 Offset 112
-               OpDecorate %_arr_v4int_uint_4 ArrayStride 16
-               OpDecorate %_runtimearr_Inner ArrayStride 176
-               OpDecorate %s Binding 0
-               OpDecorate %s DescriptorSet 0
+               OpMemberDecorate %Inner 7 Offset 64
+               OpMemberDecorate %Inner 8 Offset 80
+               OpMemberDecorate %Inner 9 Offset 96
+               OpMemberDecorate %Inner 10 Offset 112
+               OpMemberDecorate %Inner 11 Offset 128
+               OpMemberDecorate %Inner 12 Offset 144
+               OpMemberDecorate %Inner 12 ColMajor
+               OpMemberDecorate %Inner 12 MatrixStride 8
+               OpMemberDecorate %Inner 13 Offset 160
+               OpMemberDecorate %Inner 13 ColMajor
+               OpMemberDecorate %Inner 13 MatrixStride 16
+               OpMemberDecorate %Inner 14 Offset 192
+               OpMemberDecorate %Inner 14 ColMajor
+               OpMemberDecorate %Inner 14 MatrixStride 16
+               OpMemberDecorate %Inner 15 Offset 224
+               OpMemberDecorate %Inner 15 ColMajor
+               OpMemberDecorate %Inner 15 MatrixStride 8
+               OpMemberDecorate %Inner 16 Offset 256
+               OpMemberDecorate %Inner 16 ColMajor
+               OpMemberDecorate %Inner 16 MatrixStride 16
+               OpMemberDecorate %Inner 17 Offset 304
+               OpMemberDecorate %Inner 17 ColMajor
+               OpMemberDecorate %Inner 17 MatrixStride 16
+               OpMemberDecorate %Inner 18 Offset 352
+               OpMemberDecorate %Inner 18 ColMajor
+               OpMemberDecorate %Inner 18 MatrixStride 8
+               OpMemberDecorate %Inner 19 Offset 384
+               OpMemberDecorate %Inner 19 ColMajor
+               OpMemberDecorate %Inner 19 MatrixStride 16
+               OpMemberDecorate %Inner 20 Offset 448
+               OpMemberDecorate %Inner 20 ColMajor
+               OpMemberDecorate %Inner 20 MatrixStride 16
+               OpMemberDecorate %Inner 21 Offset 512
+               OpDecorate %_arr_v3float_uint_2 ArrayStride 16
+               OpDecorate %_runtimearr_Inner ArrayStride 544
+               OpDecorate %sb Binding 0
+               OpDecorate %sb DescriptorSet 0
        %uint = OpTypeInt 32 0
 %_ptr_Input_uint = OpTypePointer Input %uint
       %idx_1 = OpVariable %_ptr_Input_uint Input
+      %float = OpTypeFloat 32
         %int = OpTypeInt 32 1
+    %v2float = OpTypeVector %float 2
+      %v2int = OpTypeVector %int 2
+     %v2uint = OpTypeVector %uint 2
+    %v3float = OpTypeVector %float 3
       %v3int = OpTypeVector %int 3
      %v3uint = OpTypeVector %uint 3
-      %float = OpTypeFloat 32
-    %v3float = OpTypeVector %float 3
-%mat2v3float = OpTypeMatrix %v3float 2
-    %v2float = OpTypeVector %float 2
-%mat3v2float = OpTypeMatrix %v2float 3
+    %v4float = OpTypeVector %float 4
       %v4int = OpTypeVector %int 4
-     %uint_4 = OpConstant %uint 4
-%_arr_v4int_uint_4 = OpTypeArray %v4int %uint_4
-      %Inner = OpTypeStruct %v3int %int %v3uint %uint %v3float %float %mat2v3float %mat3v2float %_arr_v4int_uint_4
+     %v4uint = OpTypeVector %uint 4
+%mat2v2float = OpTypeMatrix %v2float 2
+%mat2v3float = OpTypeMatrix %v3float 2
+%mat2v4float = OpTypeMatrix %v4float 2
+%mat3v2float = OpTypeMatrix %v2float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+%mat3v4float = OpTypeMatrix %v4float 3
+%mat4v2float = OpTypeMatrix %v2float 4
+%mat4v3float = OpTypeMatrix %v3float 4
+%mat4v4float = OpTypeMatrix %v4float 4
+     %uint_2 = OpConstant %uint 2
+%_arr_v3float_uint_2 = OpTypeArray %v3float %uint_2
+      %Inner = OpTypeStruct %float %int %uint %v2float %v2int %v2uint %v3float %v3int %v3uint %v4float %v4int %v4uint %mat2v2float %mat2v3float %mat2v4float %mat3v2float %mat3v3float %mat3v4float %mat4v2float %mat4v3float %mat4v4float %_arr_v3float_uint_2
 %_runtimearr_Inner = OpTypeRuntimeArray %Inner
           %S = OpTypeStruct %_runtimearr_Inner
 %_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
-          %s = OpVariable %_ptr_StorageBuffer_S StorageBuffer
+         %sb = OpVariable %_ptr_StorageBuffer_S StorageBuffer
        %void = OpTypeVoid
-         %20 = OpTypeFunction %void %uint
+         %31 = OpTypeFunction %void %uint
      %uint_0 = OpConstant %uint 0
-%_ptr_StorageBuffer_v3int = OpTypePointer StorageBuffer %v3int
-         %28 = OpConstantNull %v3int
+%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
+         %39 = OpConstantNull %float
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_int = OpTypePointer StorageBuffer %int
-         %32 = OpConstantNull %int
-     %uint_2 = OpConstant %uint 2
-%_ptr_StorageBuffer_v3uint = OpTypePointer StorageBuffer %v3uint
-         %36 = OpConstantNull %v3uint
-     %uint_3 = OpConstant %uint 3
+         %43 = OpConstantNull %int
 %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
-         %40 = OpConstantNull %uint
-%_ptr_StorageBuffer_v3float = OpTypePointer StorageBuffer %v3float
-         %43 = OpConstantNull %v3float
+         %46 = OpConstantNull %uint
+     %uint_3 = OpConstant %uint 3
+%_ptr_StorageBuffer_v2float = OpTypePointer StorageBuffer %v2float
+         %50 = OpConstantNull %v2float
+     %uint_4 = OpConstant %uint 4
+%_ptr_StorageBuffer_v2int = OpTypePointer StorageBuffer %v2int
+         %54 = OpConstantNull %v2int
      %uint_5 = OpConstant %uint 5
-%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
-         %47 = OpConstantNull %float
+%_ptr_StorageBuffer_v2uint = OpTypePointer StorageBuffer %v2uint
+         %58 = OpConstantNull %v2uint
      %uint_6 = OpConstant %uint 6
-%_ptr_StorageBuffer_mat2v3float = OpTypePointer StorageBuffer %mat2v3float
-         %51 = OpConstantNull %mat2v3float
+%_ptr_StorageBuffer_v3float = OpTypePointer StorageBuffer %v3float
+         %62 = OpConstantNull %v3float
      %uint_7 = OpConstant %uint 7
-%_ptr_StorageBuffer_mat3v2float = OpTypePointer StorageBuffer %mat3v2float
-         %55 = OpConstantNull %mat3v2float
+%_ptr_StorageBuffer_v3int = OpTypePointer StorageBuffer %v3int
+         %66 = OpConstantNull %v3int
      %uint_8 = OpConstant %uint 8
-%_ptr_StorageBuffer__arr_v4int_uint_4 = OpTypePointer StorageBuffer %_arr_v4int_uint_4
-         %59 = OpConstantNull %_arr_v4int_uint_4
-         %60 = OpTypeFunction %void
- %main_inner = OpFunction %void None %20
+%_ptr_StorageBuffer_v3uint = OpTypePointer StorageBuffer %v3uint
+         %70 = OpConstantNull %v3uint
+     %uint_9 = OpConstant %uint 9
+%_ptr_StorageBuffer_v4float = OpTypePointer StorageBuffer %v4float
+         %74 = OpConstantNull %v4float
+    %uint_10 = OpConstant %uint 10
+%_ptr_StorageBuffer_v4int = OpTypePointer StorageBuffer %v4int
+         %78 = OpConstantNull %v4int
+    %uint_11 = OpConstant %uint 11
+%_ptr_StorageBuffer_v4uint = OpTypePointer StorageBuffer %v4uint
+         %82 = OpConstantNull %v4uint
+    %uint_12 = OpConstant %uint 12
+%_ptr_StorageBuffer_mat2v2float = OpTypePointer StorageBuffer %mat2v2float
+         %86 = OpConstantNull %mat2v2float
+    %uint_13 = OpConstant %uint 13
+%_ptr_StorageBuffer_mat2v3float = OpTypePointer StorageBuffer %mat2v3float
+         %90 = OpConstantNull %mat2v3float
+    %uint_14 = OpConstant %uint 14
+%_ptr_StorageBuffer_mat2v4float = OpTypePointer StorageBuffer %mat2v4float
+         %94 = OpConstantNull %mat2v4float
+    %uint_15 = OpConstant %uint 15
+%_ptr_StorageBuffer_mat3v2float = OpTypePointer StorageBuffer %mat3v2float
+         %98 = OpConstantNull %mat3v2float
+    %uint_16 = OpConstant %uint 16
+%_ptr_StorageBuffer_mat3v3float = OpTypePointer StorageBuffer %mat3v3float
+        %102 = OpConstantNull %mat3v3float
+    %uint_17 = OpConstant %uint 17
+%_ptr_StorageBuffer_mat3v4float = OpTypePointer StorageBuffer %mat3v4float
+        %106 = OpConstantNull %mat3v4float
+    %uint_18 = OpConstant %uint 18
+%_ptr_StorageBuffer_mat4v2float = OpTypePointer StorageBuffer %mat4v2float
+        %110 = OpConstantNull %mat4v2float
+    %uint_19 = OpConstant %uint 19
+%_ptr_StorageBuffer_mat4v3float = OpTypePointer StorageBuffer %mat4v3float
+        %114 = OpConstantNull %mat4v3float
+    %uint_20 = OpConstant %uint 20
+%_ptr_StorageBuffer_mat4v4float = OpTypePointer StorageBuffer %mat4v4float
+        %118 = OpConstantNull %mat4v4float
+    %uint_21 = OpConstant %uint 21
+%_ptr_StorageBuffer__arr_v3float_uint_2 = OpTypePointer StorageBuffer %_arr_v3float_uint_2
+        %122 = OpConstantNull %_arr_v3float_uint_2
+        %123 = OpTypeFunction %void
+ %main_inner = OpFunction %void None %31
         %idx = OpFunctionParameter %uint
-         %24 = OpLabel
-         %27 = OpAccessChain %_ptr_StorageBuffer_v3int %s %uint_0 %idx %uint_0
-               OpStore %27 %28
-         %31 = OpAccessChain %_ptr_StorageBuffer_int %s %uint_0 %idx %uint_1
-               OpStore %31 %32
-         %35 = OpAccessChain %_ptr_StorageBuffer_v3uint %s %uint_0 %idx %uint_2
-               OpStore %35 %36
-         %39 = OpAccessChain %_ptr_StorageBuffer_uint %s %uint_0 %idx %uint_3
-               OpStore %39 %40
-         %42 = OpAccessChain %_ptr_StorageBuffer_v3float %s %uint_0 %idx %uint_4
+         %35 = OpLabel
+         %38 = OpAccessChain %_ptr_StorageBuffer_float %sb %uint_0 %idx %uint_0
+               OpStore %38 %39
+         %42 = OpAccessChain %_ptr_StorageBuffer_int %sb %uint_0 %idx %uint_1
                OpStore %42 %43
-         %46 = OpAccessChain %_ptr_StorageBuffer_float %s %uint_0 %idx %uint_5
-               OpStore %46 %47
-         %50 = OpAccessChain %_ptr_StorageBuffer_mat2v3float %s %uint_0 %idx %uint_6
-               OpStore %50 %51
-         %54 = OpAccessChain %_ptr_StorageBuffer_mat3v2float %s %uint_0 %idx %uint_7
-               OpStore %54 %55
-         %58 = OpAccessChain %_ptr_StorageBuffer__arr_v4int_uint_4 %s %uint_0 %idx %uint_8
-               OpStore %58 %59
+         %45 = OpAccessChain %_ptr_StorageBuffer_uint %sb %uint_0 %idx %uint_2
+               OpStore %45 %46
+         %49 = OpAccessChain %_ptr_StorageBuffer_v2float %sb %uint_0 %idx %uint_3
+               OpStore %49 %50
+         %53 = OpAccessChain %_ptr_StorageBuffer_v2int %sb %uint_0 %idx %uint_4
+               OpStore %53 %54
+         %57 = OpAccessChain %_ptr_StorageBuffer_v2uint %sb %uint_0 %idx %uint_5
+               OpStore %57 %58
+         %61 = OpAccessChain %_ptr_StorageBuffer_v3float %sb %uint_0 %idx %uint_6
+               OpStore %61 %62
+         %65 = OpAccessChain %_ptr_StorageBuffer_v3int %sb %uint_0 %idx %uint_7
+               OpStore %65 %66
+         %69 = OpAccessChain %_ptr_StorageBuffer_v3uint %sb %uint_0 %idx %uint_8
+               OpStore %69 %70
+         %73 = OpAccessChain %_ptr_StorageBuffer_v4float %sb %uint_0 %idx %uint_9
+               OpStore %73 %74
+         %77 = OpAccessChain %_ptr_StorageBuffer_v4int %sb %uint_0 %idx %uint_10
+               OpStore %77 %78
+         %81 = OpAccessChain %_ptr_StorageBuffer_v4uint %sb %uint_0 %idx %uint_11
+               OpStore %81 %82
+         %85 = OpAccessChain %_ptr_StorageBuffer_mat2v2float %sb %uint_0 %idx %uint_12
+               OpStore %85 %86
+         %89 = OpAccessChain %_ptr_StorageBuffer_mat2v3float %sb %uint_0 %idx %uint_13
+               OpStore %89 %90
+         %93 = OpAccessChain %_ptr_StorageBuffer_mat2v4float %sb %uint_0 %idx %uint_14
+               OpStore %93 %94
+         %97 = OpAccessChain %_ptr_StorageBuffer_mat3v2float %sb %uint_0 %idx %uint_15
+               OpStore %97 %98
+        %101 = OpAccessChain %_ptr_StorageBuffer_mat3v3float %sb %uint_0 %idx %uint_16
+               OpStore %101 %102
+        %105 = OpAccessChain %_ptr_StorageBuffer_mat3v4float %sb %uint_0 %idx %uint_17
+               OpStore %105 %106
+        %109 = OpAccessChain %_ptr_StorageBuffer_mat4v2float %sb %uint_0 %idx %uint_18
+               OpStore %109 %110
+        %113 = OpAccessChain %_ptr_StorageBuffer_mat4v3float %sb %uint_0 %idx %uint_19
+               OpStore %113 %114
+        %117 = OpAccessChain %_ptr_StorageBuffer_mat4v4float %sb %uint_0 %idx %uint_20
+               OpStore %117 %118
+        %121 = OpAccessChain %_ptr_StorageBuffer__arr_v3float_uint_2 %sb %uint_0 %idx %uint_21
+               OpStore %121 %122
                OpReturn
                OpFunctionEnd
-       %main = OpFunction %void None %60
-         %62 = OpLabel
-         %64 = OpLoad %uint %idx_1
-         %63 = OpFunctionCall %void %main_inner %64
+       %main = OpFunction %void None %123
+        %125 = OpLabel
+        %127 = OpLoad %uint %idx_1
+        %126 = OpFunctionCall %void %main_inner %127
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/buffer/storage/dynamic_index/write.wgsl.expected.wgsl b/test/tint/buffer/storage/dynamic_index/write.wgsl.expected.wgsl
index d2fbdff..33c5197 100644
--- a/test/tint/buffer/storage/dynamic_index/write.wgsl.expected.wgsl
+++ b/test/tint/buffer/storage/dynamic_index/write.wgsl.expected.wgsl
@@ -1,30 +1,56 @@
 struct Inner {
-  a : vec3<i32>,
-  b : i32,
-  c : vec3<u32>,
-  d : u32,
-  e : vec3<f32>,
-  f : f32,
-  g : mat2x3<f32>,
-  h : mat3x2<f32>,
-  i : array<vec4<i32>, 4>,
+  scalar_f32 : f32,
+  scalar_i32 : i32,
+  scalar_u32 : u32,
+  vec2_f32 : vec2<f32>,
+  vec2_i32 : vec2<i32>,
+  vec2_u32 : vec2<u32>,
+  vec3_f32 : vec3<f32>,
+  vec3_i32 : vec3<i32>,
+  vec3_u32 : vec3<u32>,
+  vec4_f32 : vec4<f32>,
+  vec4_i32 : vec4<i32>,
+  vec4_u32 : vec4<u32>,
+  mat2x2_f32 : mat2x2<f32>,
+  mat2x3_f32 : mat2x3<f32>,
+  mat2x4_f32 : mat2x4<f32>,
+  mat3x2_f32 : mat3x2<f32>,
+  mat3x3_f32 : mat3x3<f32>,
+  mat3x4_f32 : mat3x4<f32>,
+  mat4x2_f32 : mat4x2<f32>,
+  mat4x3_f32 : mat4x3<f32>,
+  mat4x4_f32 : mat4x4<f32>,
+  arr2_vec3_f32 : array<vec3<f32>, 2>,
 }
 
 struct S {
   arr : array<Inner>,
 }
 
-@binding(0) @group(0) var<storage, read_write> s : S;
+@binding(0) @group(0) var<storage, read_write> sb : S;
 
 @compute @workgroup_size(1)
 fn main(@builtin(local_invocation_index) idx : u32) {
-  s.arr[idx].a = vec3<i32>();
-  s.arr[idx].b = i32();
-  s.arr[idx].c = vec3<u32>();
-  s.arr[idx].d = u32();
-  s.arr[idx].e = vec3<f32>();
-  s.arr[idx].f = f32();
-  s.arr[idx].g = mat2x3<f32>();
-  s.arr[idx].h = mat3x2<f32>();
-  s.arr[idx].i = array<vec4<i32>, 4>();
+  sb.arr[idx].scalar_f32 = f32();
+  sb.arr[idx].scalar_i32 = i32();
+  sb.arr[idx].scalar_u32 = u32();
+  sb.arr[idx].vec2_f32 = vec2<f32>();
+  sb.arr[idx].vec2_i32 = vec2<i32>();
+  sb.arr[idx].vec2_u32 = vec2<u32>();
+  sb.arr[idx].vec3_f32 = vec3<f32>();
+  sb.arr[idx].vec3_i32 = vec3<i32>();
+  sb.arr[idx].vec3_u32 = vec3<u32>();
+  sb.arr[idx].vec4_f32 = vec4<f32>();
+  sb.arr[idx].vec4_i32 = vec4<i32>();
+  sb.arr[idx].vec4_u32 = vec4<u32>();
+  sb.arr[idx].mat2x2_f32 = mat2x2<f32>();
+  sb.arr[idx].mat2x3_f32 = mat2x3<f32>();
+  sb.arr[idx].mat2x4_f32 = mat2x4<f32>();
+  sb.arr[idx].mat3x2_f32 = mat3x2<f32>();
+  sb.arr[idx].mat3x3_f32 = mat3x3<f32>();
+  sb.arr[idx].mat3x4_f32 = mat3x4<f32>();
+  sb.arr[idx].mat4x2_f32 = mat4x2<f32>();
+  sb.arr[idx].mat4x3_f32 = mat4x3<f32>();
+  sb.arr[idx].mat4x4_f32 = mat4x4<f32>();
+  sb.arr[idx].arr2_vec3_f32 = array<vec3<f32>, 2>();
 }
diff --git a/test/tint/buffer/storage/dynamic_index/write_f16.wgsl b/test/tint/buffer/storage/dynamic_index/write_f16.wgsl
new file mode 100644
index 0000000..a683fe2
--- /dev/null
+++ b/test/tint/buffer/storage/dynamic_index/write_f16.wgsl
@@ -0,0 +1,87 @@
+enable f16;
+
+struct Inner {
+    scalar_f32 : f32,
+    scalar_i32 : i32,
+    scalar_u32 : u32,
+    scalar_f16 : f16,
+    vec2_f32 : vec2<f32>,
+    vec2_i32 : vec2<i32>,
+    vec2_u32 : vec2<u32>,
+    vec2_f16 : vec2<f16>,
+    vec3_f32 : vec3<f32>,
+    vec3_i32 : vec3<i32>,
+    vec3_u32 : vec3<u32>,
+    vec3_f16 : vec3<f16>,
+    vec4_f32 : vec4<f32>,
+    vec4_i32 : vec4<i32>,
+    vec4_u32 : vec4<u32>,
+    vec4_f16 : vec4<f16>,
+    mat2x2_f32 : mat2x2<f32>,
+    mat2x3_f32 : mat2x3<f32>,
+    mat2x4_f32 : mat2x4<f32>,
+    mat3x2_f32 : mat3x2<f32>,
+    mat3x3_f32 : mat3x3<f32>,
+    mat3x4_f32 : mat3x4<f32>,
+    mat4x2_f32 : mat4x2<f32>,
+    mat4x3_f32 : mat4x3<f32>,
+    mat4x4_f32 : mat4x4<f32>,
+    mat2x2_f16 : mat2x2<f16>,
+    mat2x3_f16 : mat2x3<f16>,
+    mat2x4_f16 : mat2x4<f16>,
+    mat3x2_f16 : mat3x2<f16>,
+    mat3x3_f16 : mat3x3<f16>,
+    mat3x4_f16 : mat3x4<f16>,
+    mat4x2_f16 : mat4x2<f16>,
+    mat4x3_f16 : mat4x3<f16>,
+    mat4x4_f16 : mat4x4<f16>,
+    arr2_vec3_f32 : array<vec3<f32>, 2>,
+    arr2_mat4x2_f16 : array<mat4x2<f16>, 2>,
+
+};
+
+struct S {
+    arr : array<Inner>,
+};
+
+@binding(0) @group(0) var<storage, read_write> sb : S;
+
+@compute @workgroup_size(1)
+fn main(@builtin(local_invocation_index) idx : u32) {
+    sb.arr[idx].scalar_f32 = f32();
+    sb.arr[idx].scalar_i32 = i32();
+    sb.arr[idx].scalar_u32 = u32();
+    sb.arr[idx].scalar_f16 = f16();
+    sb.arr[idx].vec2_f32 = vec2<f32>();
+    sb.arr[idx].vec2_i32 = vec2<i32>();
+    sb.arr[idx].vec2_u32 = vec2<u32>();
+    sb.arr[idx].vec2_f16 = vec2<f16>();
+    sb.arr[idx].vec3_f32 = vec3<f32>();
+    sb.arr[idx].vec3_i32 = vec3<i32>();
+    sb.arr[idx].vec3_u32 = vec3<u32>();
+    sb.arr[idx].vec3_f16 = vec3<f16>();
+    sb.arr[idx].vec4_f32 = vec4<f32>();
+    sb.arr[idx].vec4_i32 = vec4<i32>();
+    sb.arr[idx].vec4_u32 = vec4<u32>();
+    sb.arr[idx].vec4_f16 = vec4<f16>();
+    sb.arr[idx].mat2x2_f32 = mat2x2<f32>();
+    sb.arr[idx].mat2x3_f32 = mat2x3<f32>();
+    sb.arr[idx].mat2x4_f32 = mat2x4<f32>();
+    sb.arr[idx].mat3x2_f32 = mat3x2<f32>();
+    sb.arr[idx].mat3x3_f32 = mat3x3<f32>();
+    sb.arr[idx].mat3x4_f32 = mat3x4<f32>();
+    sb.arr[idx].mat4x2_f32 = mat4x2<f32>();
+    sb.arr[idx].mat4x3_f32 = mat4x3<f32>();
+    sb.arr[idx].mat4x4_f32 = mat4x4<f32>();
+    sb.arr[idx].mat2x2_f16 = mat2x2<f16>();
+    sb.arr[idx].mat2x3_f16 = mat2x3<f16>();
+    sb.arr[idx].mat2x4_f16 = mat2x4<f16>();
+    sb.arr[idx].mat3x2_f16 = mat3x2<f16>();
+    sb.arr[idx].mat3x3_f16 = mat3x3<f16>();
+    sb.arr[idx].mat3x4_f16 = mat3x4<f16>();
+    sb.arr[idx].mat4x2_f16 = mat4x2<f16>();
+    sb.arr[idx].mat4x3_f16 = mat4x3<f16>();
+    sb.arr[idx].mat4x4_f16 = mat4x4<f16>();
+    sb.arr[idx].arr2_vec3_f32 = array<vec3<f32>, 2>();
+    sb.arr[idx].arr2_mat4x2_f16 = array<mat4x2<f16>, 2>();
+}
diff --git a/test/tint/buffer/storage/dynamic_index/write_f16.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/dynamic_index/write_f16.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..fe9d9f0
--- /dev/null
+++ b/test/tint/buffer/storage/dynamic_index/write_f16.wgsl.expected.dxc.hlsl
@@ -0,0 +1,178 @@
+RWByteAddressBuffer sb : register(u0, space0);
+
+struct tint_symbol_1 {
+  uint idx : SV_GroupIndex;
+};
+
+void tint_symbol_18(RWByteAddressBuffer buffer, uint offset, float2x2 value) {
+  buffer.Store2((offset + 0u), asuint(value[0u]));
+  buffer.Store2((offset + 8u), asuint(value[1u]));
+}
+
+void tint_symbol_19(RWByteAddressBuffer buffer, uint offset, float2x3 value) {
+  buffer.Store3((offset + 0u), asuint(value[0u]));
+  buffer.Store3((offset + 16u), asuint(value[1u]));
+}
+
+void tint_symbol_20(RWByteAddressBuffer buffer, uint offset, float2x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+}
+
+void tint_symbol_21(RWByteAddressBuffer buffer, uint offset, float3x2 value) {
+  buffer.Store2((offset + 0u), asuint(value[0u]));
+  buffer.Store2((offset + 8u), asuint(value[1u]));
+  buffer.Store2((offset + 16u), asuint(value[2u]));
+}
+
+void tint_symbol_22(RWByteAddressBuffer buffer, uint offset, float3x3 value) {
+  buffer.Store3((offset + 0u), asuint(value[0u]));
+  buffer.Store3((offset + 16u), asuint(value[1u]));
+  buffer.Store3((offset + 32u), asuint(value[2u]));
+}
+
+void tint_symbol_23(RWByteAddressBuffer buffer, uint offset, float3x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+  buffer.Store4((offset + 32u), asuint(value[2u]));
+}
+
+void tint_symbol_24(RWByteAddressBuffer buffer, uint offset, float4x2 value) {
+  buffer.Store2((offset + 0u), asuint(value[0u]));
+  buffer.Store2((offset + 8u), asuint(value[1u]));
+  buffer.Store2((offset + 16u), asuint(value[2u]));
+  buffer.Store2((offset + 24u), asuint(value[3u]));
+}
+
+void tint_symbol_25(RWByteAddressBuffer buffer, uint offset, float4x3 value) {
+  buffer.Store3((offset + 0u), asuint(value[0u]));
+  buffer.Store3((offset + 16u), asuint(value[1u]));
+  buffer.Store3((offset + 32u), asuint(value[2u]));
+  buffer.Store3((offset + 48u), asuint(value[3u]));
+}
+
+void tint_symbol_26(RWByteAddressBuffer buffer, uint offset, float4x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+  buffer.Store4((offset + 32u), asuint(value[2u]));
+  buffer.Store4((offset + 48u), asuint(value[3u]));
+}
+
+void tint_symbol_27(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 2, 2> value) {
+  buffer.Store<vector<float16_t, 2> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 4u), value[1u]);
+}
+
+void tint_symbol_28(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 2, 3> value) {
+  buffer.Store<vector<float16_t, 3> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 8u), value[1u]);
+}
+
+void tint_symbol_29(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 2, 4> value) {
+  buffer.Store<vector<float16_t, 4> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 8u), value[1u]);
+}
+
+void tint_symbol_30(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 3, 2> value) {
+  buffer.Store<vector<float16_t, 2> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 4u), value[1u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 8u), value[2u]);
+}
+
+void tint_symbol_31(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 3, 3> value) {
+  buffer.Store<vector<float16_t, 3> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 8u), value[1u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 16u), value[2u]);
+}
+
+void tint_symbol_32(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 3, 4> value) {
+  buffer.Store<vector<float16_t, 4> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 8u), value[1u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 16u), value[2u]);
+}
+
+void tint_symbol_33(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 2> value) {
+  buffer.Store<vector<float16_t, 2> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 4u), value[1u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 8u), value[2u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 12u), value[3u]);
+}
+
+void tint_symbol_34(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 3> value) {
+  buffer.Store<vector<float16_t, 3> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 8u), value[1u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 16u), value[2u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 24u), value[3u]);
+}
+
+void tint_symbol_35(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 4> value) {
+  buffer.Store<vector<float16_t, 4> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 8u), value[1u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 16u), value[2u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 24u), value[3u]);
+}
+
+void tint_symbol_36(RWByteAddressBuffer buffer, uint offset, float3 value[2]) {
+  float3 array[2] = value;
+  {
+    for(uint i = 0u; (i < 2u); i = (i + 1u)) {
+      buffer.Store3((offset + (i * 16u)), asuint(array[i]));
+    }
+  }
+}
+
+void tint_symbol_37(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 2> value[2]) {
+  matrix<float16_t, 4, 2> array_1[2] = value;
+  {
+    for(uint i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
+      tint_symbol_33(buffer, (offset + (i_1 * 16u)), array_1[i_1]);
+    }
+  }
+}
+
+void main_inner(uint idx) {
+  sb.Store((800u * idx), asuint(0.0f));
+  sb.Store(((800u * idx) + 4u), asuint(0));
+  sb.Store(((800u * idx) + 8u), asuint(0u));
+  sb.Store<float16_t>(((800u * idx) + 12u), float16_t(0.0h));
+  sb.Store2(((800u * idx) + 16u), asuint((0.0f).xx));
+  sb.Store2(((800u * idx) + 24u), asuint((0).xx));
+  sb.Store2(((800u * idx) + 32u), asuint((0u).xx));
+  sb.Store<vector<float16_t, 2> >(((800u * idx) + 40u), (float16_t(0.0h)).xx);
+  sb.Store3(((800u * idx) + 48u), asuint((0.0f).xxx));
+  sb.Store3(((800u * idx) + 64u), asuint((0).xxx));
+  sb.Store3(((800u * idx) + 80u), asuint((0u).xxx));
+  sb.Store<vector<float16_t, 3> >(((800u * idx) + 96u), (float16_t(0.0h)).xxx);
+  sb.Store4(((800u * idx) + 112u), asuint((0.0f).xxxx));
+  sb.Store4(((800u * idx) + 128u), asuint((0).xxxx));
+  sb.Store4(((800u * idx) + 144u), asuint((0u).xxxx));
+  sb.Store<vector<float16_t, 4> >(((800u * idx) + 160u), (float16_t(0.0h)).xxxx);
+  tint_symbol_18(sb, ((800u * idx) + 168u), float2x2((0.0f).xx, (0.0f).xx));
+  tint_symbol_19(sb, ((800u * idx) + 192u), float2x3((0.0f).xxx, (0.0f).xxx));
+  tint_symbol_20(sb, ((800u * idx) + 224u), float2x4((0.0f).xxxx, (0.0f).xxxx));
+  tint_symbol_21(sb, ((800u * idx) + 256u), float3x2((0.0f).xx, (0.0f).xx, (0.0f).xx));
+  tint_symbol_22(sb, ((800u * idx) + 288u), float3x3((0.0f).xxx, (0.0f).xxx, (0.0f).xxx));
+  tint_symbol_23(sb, ((800u * idx) + 336u), float3x4((0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx));
+  tint_symbol_24(sb, ((800u * idx) + 384u), float4x2((0.0f).xx, (0.0f).xx, (0.0f).xx, (0.0f).xx));
+  tint_symbol_25(sb, ((800u * idx) + 416u), float4x3((0.0f).xxx, (0.0f).xxx, (0.0f).xxx, (0.0f).xxx));
+  tint_symbol_26(sb, ((800u * idx) + 480u), float4x4((0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx));
+  tint_symbol_27(sb, ((800u * idx) + 544u), matrix<float16_t, 2, 2>((float16_t(0.0h)).xx, (float16_t(0.0h)).xx));
+  tint_symbol_28(sb, ((800u * idx) + 552u), matrix<float16_t, 2, 3>((float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx));
+  tint_symbol_29(sb, ((800u * idx) + 568u), matrix<float16_t, 2, 4>((float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx));
+  tint_symbol_30(sb, ((800u * idx) + 584u), matrix<float16_t, 3, 2>((float16_t(0.0h)).xx, (float16_t(0.0h)).xx, (float16_t(0.0h)).xx));
+  tint_symbol_31(sb, ((800u * idx) + 600u), matrix<float16_t, 3, 3>((float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx));
+  tint_symbol_32(sb, ((800u * idx) + 624u), matrix<float16_t, 3, 4>((float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx));
+  tint_symbol_33(sb, ((800u * idx) + 648u), matrix<float16_t, 4, 2>((float16_t(0.0h)).xx, (float16_t(0.0h)).xx, (float16_t(0.0h)).xx, (float16_t(0.0h)).xx));
+  tint_symbol_34(sb, ((800u * idx) + 664u), matrix<float16_t, 4, 3>((float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx));
+  tint_symbol_35(sb, ((800u * idx) + 696u), matrix<float16_t, 4, 4>((float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx));
+  const float3 tint_symbol_38[2] = (float3[2])0;
+  tint_symbol_36(sb, ((800u * idx) + 736u), tint_symbol_38);
+  const matrix<float16_t, 4, 2> tint_symbol_39[2] = (matrix<float16_t, 4, 2>[2])0;
+  tint_symbol_37(sb, ((800u * idx) + 768u), tint_symbol_39);
+}
+
+[numthreads(1, 1, 1)]
+void main(tint_symbol_1 tint_symbol) {
+  main_inner(tint_symbol.idx);
+  return;
+}
diff --git a/test/tint/buffer/storage/dynamic_index/write_f16.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/dynamic_index/write_f16.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..8bd57ef
--- /dev/null
+++ b/test/tint/buffer/storage/dynamic_index/write_f16.wgsl.expected.fxc.hlsl
@@ -0,0 +1,184 @@
+SKIP: FAILED
+
+RWByteAddressBuffer sb : register(u0, space0);
+
+struct tint_symbol_1 {
+  uint idx : SV_GroupIndex;
+};
+
+void tint_symbol_18(RWByteAddressBuffer buffer, uint offset, float2x2 value) {
+  buffer.Store2((offset + 0u), asuint(value[0u]));
+  buffer.Store2((offset + 8u), asuint(value[1u]));
+}
+
+void tint_symbol_19(RWByteAddressBuffer buffer, uint offset, float2x3 value) {
+  buffer.Store3((offset + 0u), asuint(value[0u]));
+  buffer.Store3((offset + 16u), asuint(value[1u]));
+}
+
+void tint_symbol_20(RWByteAddressBuffer buffer, uint offset, float2x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+}
+
+void tint_symbol_21(RWByteAddressBuffer buffer, uint offset, float3x2 value) {
+  buffer.Store2((offset + 0u), asuint(value[0u]));
+  buffer.Store2((offset + 8u), asuint(value[1u]));
+  buffer.Store2((offset + 16u), asuint(value[2u]));
+}
+
+void tint_symbol_22(RWByteAddressBuffer buffer, uint offset, float3x3 value) {
+  buffer.Store3((offset + 0u), asuint(value[0u]));
+  buffer.Store3((offset + 16u), asuint(value[1u]));
+  buffer.Store3((offset + 32u), asuint(value[2u]));
+}
+
+void tint_symbol_23(RWByteAddressBuffer buffer, uint offset, float3x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+  buffer.Store4((offset + 32u), asuint(value[2u]));
+}
+
+void tint_symbol_24(RWByteAddressBuffer buffer, uint offset, float4x2 value) {
+  buffer.Store2((offset + 0u), asuint(value[0u]));
+  buffer.Store2((offset + 8u), asuint(value[1u]));
+  buffer.Store2((offset + 16u), asuint(value[2u]));
+  buffer.Store2((offset + 24u), asuint(value[3u]));
+}
+
+void tint_symbol_25(RWByteAddressBuffer buffer, uint offset, float4x3 value) {
+  buffer.Store3((offset + 0u), asuint(value[0u]));
+  buffer.Store3((offset + 16u), asuint(value[1u]));
+  buffer.Store3((offset + 32u), asuint(value[2u]));
+  buffer.Store3((offset + 48u), asuint(value[3u]));
+}
+
+void tint_symbol_26(RWByteAddressBuffer buffer, uint offset, float4x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+  buffer.Store4((offset + 32u), asuint(value[2u]));
+  buffer.Store4((offset + 48u), asuint(value[3u]));
+}
+
+void tint_symbol_27(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 2, 2> value) {
+  buffer.Store<vector<float16_t, 2> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 4u), value[1u]);
+}
+
+void tint_symbol_28(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 2, 3> value) {
+  buffer.Store<vector<float16_t, 3> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 8u), value[1u]);
+}
+
+void tint_symbol_29(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 2, 4> value) {
+  buffer.Store<vector<float16_t, 4> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 8u), value[1u]);
+}
+
+void tint_symbol_30(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 3, 2> value) {
+  buffer.Store<vector<float16_t, 2> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 4u), value[1u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 8u), value[2u]);
+}
+
+void tint_symbol_31(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 3, 3> value) {
+  buffer.Store<vector<float16_t, 3> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 8u), value[1u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 16u), value[2u]);
+}
+
+void tint_symbol_32(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 3, 4> value) {
+  buffer.Store<vector<float16_t, 4> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 8u), value[1u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 16u), value[2u]);
+}
+
+void tint_symbol_33(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 2> value) {
+  buffer.Store<vector<float16_t, 2> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 4u), value[1u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 8u), value[2u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 12u), value[3u]);
+}
+
+void tint_symbol_34(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 3> value) {
+  buffer.Store<vector<float16_t, 3> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 8u), value[1u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 16u), value[2u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 24u), value[3u]);
+}
+
+void tint_symbol_35(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 4> value) {
+  buffer.Store<vector<float16_t, 4> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 8u), value[1u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 16u), value[2u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 24u), value[3u]);
+}
+
+void tint_symbol_36(RWByteAddressBuffer buffer, uint offset, float3 value[2]) {
+  float3 array[2] = value;
+  {
+    for(uint i = 0u; (i < 2u); i = (i + 1u)) {
+      buffer.Store3((offset + (i * 16u)), asuint(array[i]));
+    }
+  }
+}
+
+void tint_symbol_37(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 2> value[2]) {
+  matrix<float16_t, 4, 2> array_1[2] = value;
+  {
+    for(uint i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
+      tint_symbol_33(buffer, (offset + (i_1 * 16u)), array_1[i_1]);
+    }
+  }
+}
+
+void main_inner(uint idx) {
+  sb.Store((800u * idx), asuint(0.0f));
+  sb.Store(((800u * idx) + 4u), asuint(0));
+  sb.Store(((800u * idx) + 8u), asuint(0u));
+  sb.Store<float16_t>(((800u * idx) + 12u), float16_t(0.0h));
+  sb.Store2(((800u * idx) + 16u), asuint((0.0f).xx));
+  sb.Store2(((800u * idx) + 24u), asuint((0).xx));
+  sb.Store2(((800u * idx) + 32u), asuint((0u).xx));
+  sb.Store<vector<float16_t, 2> >(((800u * idx) + 40u), (float16_t(0.0h)).xx);
+  sb.Store3(((800u * idx) + 48u), asuint((0.0f).xxx));
+  sb.Store3(((800u * idx) + 64u), asuint((0).xxx));
+  sb.Store3(((800u * idx) + 80u), asuint((0u).xxx));
+  sb.Store<vector<float16_t, 3> >(((800u * idx) + 96u), (float16_t(0.0h)).xxx);
+  sb.Store4(((800u * idx) + 112u), asuint((0.0f).xxxx));
+  sb.Store4(((800u * idx) + 128u), asuint((0).xxxx));
+  sb.Store4(((800u * idx) + 144u), asuint((0u).xxxx));
+  sb.Store<vector<float16_t, 4> >(((800u * idx) + 160u), (float16_t(0.0h)).xxxx);
+  tint_symbol_18(sb, ((800u * idx) + 168u), float2x2((0.0f).xx, (0.0f).xx));
+  tint_symbol_19(sb, ((800u * idx) + 192u), float2x3((0.0f).xxx, (0.0f).xxx));
+  tint_symbol_20(sb, ((800u * idx) + 224u), float2x4((0.0f).xxxx, (0.0f).xxxx));
+  tint_symbol_21(sb, ((800u * idx) + 256u), float3x2((0.0f).xx, (0.0f).xx, (0.0f).xx));
+  tint_symbol_22(sb, ((800u * idx) + 288u), float3x3((0.0f).xxx, (0.0f).xxx, (0.0f).xxx));
+  tint_symbol_23(sb, ((800u * idx) + 336u), float3x4((0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx));
+  tint_symbol_24(sb, ((800u * idx) + 384u), float4x2((0.0f).xx, (0.0f).xx, (0.0f).xx, (0.0f).xx));
+  tint_symbol_25(sb, ((800u * idx) + 416u), float4x3((0.0f).xxx, (0.0f).xxx, (0.0f).xxx, (0.0f).xxx));
+  tint_symbol_26(sb, ((800u * idx) + 480u), float4x4((0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx));
+  tint_symbol_27(sb, ((800u * idx) + 544u), matrix<float16_t, 2, 2>((float16_t(0.0h)).xx, (float16_t(0.0h)).xx));
+  tint_symbol_28(sb, ((800u * idx) + 552u), matrix<float16_t, 2, 3>((float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx));
+  tint_symbol_29(sb, ((800u * idx) + 568u), matrix<float16_t, 2, 4>((float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx));
+  tint_symbol_30(sb, ((800u * idx) + 584u), matrix<float16_t, 3, 2>((float16_t(0.0h)).xx, (float16_t(0.0h)).xx, (float16_t(0.0h)).xx));
+  tint_symbol_31(sb, ((800u * idx) + 600u), matrix<float16_t, 3, 3>((float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx));
+  tint_symbol_32(sb, ((800u * idx) + 624u), matrix<float16_t, 3, 4>((float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx));
+  tint_symbol_33(sb, ((800u * idx) + 648u), matrix<float16_t, 4, 2>((float16_t(0.0h)).xx, (float16_t(0.0h)).xx, (float16_t(0.0h)).xx, (float16_t(0.0h)).xx));
+  tint_symbol_34(sb, ((800u * idx) + 664u), matrix<float16_t, 4, 3>((float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx));
+  tint_symbol_35(sb, ((800u * idx) + 696u), matrix<float16_t, 4, 4>((float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx));
+  const float3 tint_symbol_38[2] = (float3[2])0;
+  tint_symbol_36(sb, ((800u * idx) + 736u), tint_symbol_38);
+  const matrix<float16_t, 4, 2> tint_symbol_39[2] = (matrix<float16_t, 4, 2>[2])0;
+  tint_symbol_37(sb, ((800u * idx) + 768u), tint_symbol_39);
+}
+
+[numthreads(1, 1, 1)]
+void main(tint_symbol_1 tint_symbol) {
+  main_inner(tint_symbol.idx);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000002B00914B0D0(61,69-77): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000002B00914B0D0(62,3-14): error X3018: invalid subscript 'Store'
+
diff --git a/test/tint/buffer/storage/dynamic_index/write_f16.wgsl.expected.glsl b/test/tint/buffer/storage/dynamic_index/write_f16.wgsl.expected.glsl
new file mode 100644
index 0000000..0b00be4
--- /dev/null
+++ b/test/tint/buffer/storage/dynamic_index/write_f16.wgsl.expected.glsl
@@ -0,0 +1,105 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct Inner {
+  float scalar_f32;
+  int scalar_i32;
+  uint scalar_u32;
+  float16_t scalar_f16;
+  vec2 vec2_f32;
+  ivec2 vec2_i32;
+  uvec2 vec2_u32;
+  f16vec2 vec2_f16;
+  uint pad;
+  vec3 vec3_f32;
+  uint pad_1;
+  ivec3 vec3_i32;
+  uint pad_2;
+  uvec3 vec3_u32;
+  uint pad_3;
+  f16vec3 vec3_f16;
+  uint pad_4;
+  uint pad_5;
+  vec4 vec4_f32;
+  ivec4 vec4_i32;
+  uvec4 vec4_u32;
+  f16vec4 vec4_f16;
+  mat2 mat2x2_f32;
+  uint pad_6;
+  uint pad_7;
+  mat2x3 mat2x3_f32;
+  mat2x4 mat2x4_f32;
+  mat3x2 mat3x2_f32;
+  uint pad_8;
+  uint pad_9;
+  mat3 mat3x3_f32;
+  mat3x4 mat3x4_f32;
+  mat4x2 mat4x2_f32;
+  mat4x3 mat4x3_f32;
+  mat4 mat4x4_f32;
+  f16mat2 mat2x2_f16;
+  f16mat2x3 mat2x3_f16;
+  f16mat2x4 mat2x4_f16;
+  f16mat3x2 mat3x2_f16;
+  uint pad_10;
+  f16mat3 mat3x3_f16;
+  f16mat3x4 mat3x4_f16;
+  f16mat4x2 mat4x2_f16;
+  f16mat4x3 mat4x3_f16;
+  f16mat4 mat4x4_f16;
+  uint pad_11;
+  uint pad_12;
+  vec3 arr2_vec3_f32[2];
+  f16mat4x2 arr2_mat4x2_f16[2];
+};
+
+layout(binding = 0, std430) buffer S_ssbo {
+  Inner arr[];
+} sb;
+
+void tint_symbol(uint idx) {
+  sb.arr[idx].scalar_f32 = 0.0f;
+  sb.arr[idx].scalar_i32 = 0;
+  sb.arr[idx].scalar_u32 = 0u;
+  sb.arr[idx].scalar_f16 = 0.0hf;
+  sb.arr[idx].vec2_f32 = vec2(0.0f);
+  sb.arr[idx].vec2_i32 = ivec2(0);
+  sb.arr[idx].vec2_u32 = uvec2(0u);
+  sb.arr[idx].vec2_f16 = f16vec2(0.0hf);
+  sb.arr[idx].vec3_f32 = vec3(0.0f);
+  sb.arr[idx].vec3_i32 = ivec3(0);
+  sb.arr[idx].vec3_u32 = uvec3(0u);
+  sb.arr[idx].vec3_f16 = f16vec3(0.0hf);
+  sb.arr[idx].vec4_f32 = vec4(0.0f);
+  sb.arr[idx].vec4_i32 = ivec4(0);
+  sb.arr[idx].vec4_u32 = uvec4(0u);
+  sb.arr[idx].vec4_f16 = f16vec4(0.0hf);
+  sb.arr[idx].mat2x2_f32 = mat2(vec2(0.0f), vec2(0.0f));
+  sb.arr[idx].mat2x3_f32 = mat2x3(vec3(0.0f), vec3(0.0f));
+  sb.arr[idx].mat2x4_f32 = mat2x4(vec4(0.0f), vec4(0.0f));
+  sb.arr[idx].mat3x2_f32 = mat3x2(vec2(0.0f), vec2(0.0f), vec2(0.0f));
+  sb.arr[idx].mat3x3_f32 = mat3(vec3(0.0f), vec3(0.0f), vec3(0.0f));
+  sb.arr[idx].mat3x4_f32 = mat3x4(vec4(0.0f), vec4(0.0f), vec4(0.0f));
+  sb.arr[idx].mat4x2_f32 = mat4x2(vec2(0.0f), vec2(0.0f), vec2(0.0f), vec2(0.0f));
+  sb.arr[idx].mat4x3_f32 = mat4x3(vec3(0.0f), vec3(0.0f), vec3(0.0f), vec3(0.0f));
+  sb.arr[idx].mat4x4_f32 = mat4(vec4(0.0f), vec4(0.0f), vec4(0.0f), vec4(0.0f));
+  sb.arr[idx].mat2x2_f16 = f16mat2(f16vec2(0.0hf), f16vec2(0.0hf));
+  sb.arr[idx].mat2x3_f16 = f16mat2x3(f16vec3(0.0hf), f16vec3(0.0hf));
+  sb.arr[idx].mat2x4_f16 = f16mat2x4(f16vec4(0.0hf), f16vec4(0.0hf));
+  sb.arr[idx].mat3x2_f16 = f16mat3x2(f16vec2(0.0hf), f16vec2(0.0hf), f16vec2(0.0hf));
+  sb.arr[idx].mat3x3_f16 = f16mat3(f16vec3(0.0hf), f16vec3(0.0hf), f16vec3(0.0hf));
+  sb.arr[idx].mat3x4_f16 = f16mat3x4(f16vec4(0.0hf), f16vec4(0.0hf), f16vec4(0.0hf));
+  sb.arr[idx].mat4x2_f16 = f16mat4x2(f16vec2(0.0hf), f16vec2(0.0hf), f16vec2(0.0hf), f16vec2(0.0hf));
+  sb.arr[idx].mat4x3_f16 = f16mat4x3(f16vec3(0.0hf), f16vec3(0.0hf), f16vec3(0.0hf), f16vec3(0.0hf));
+  sb.arr[idx].mat4x4_f16 = f16mat4(f16vec4(0.0hf), f16vec4(0.0hf), f16vec4(0.0hf), f16vec4(0.0hf));
+  vec3 tint_symbol_1[2] = vec3[2](vec3(0.0f), vec3(0.0f));
+  sb.arr[idx].arr2_vec3_f32 = tint_symbol_1;
+  f16mat4x2 tint_symbol_2[2] = f16mat4x2[2](f16mat4x2(f16vec2(0.0hf), f16vec2(0.0hf), f16vec2(0.0hf), f16vec2(0.0hf)), f16mat4x2(f16vec2(0.0hf), f16vec2(0.0hf), f16vec2(0.0hf), f16vec2(0.0hf)));
+  sb.arr[idx].arr2_mat4x2_f16 = tint_symbol_2;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/storage/dynamic_index/write_f16.wgsl.expected.msl b/test/tint/buffer/storage/dynamic_index/write_f16.wgsl.expected.msl
new file mode 100644
index 0000000..eb9bf7c
--- /dev/null
+++ b/test/tint/buffer/storage/dynamic_index/write_f16.wgsl.expected.msl
@@ -0,0 +1,115 @@
+#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 Inner {
+  /* 0x0000 */ float scalar_f32;
+  /* 0x0004 */ int scalar_i32;
+  /* 0x0008 */ uint scalar_u32;
+  /* 0x000c */ half scalar_f16;
+  /* 0x000e */ tint_array<int8_t, 2> tint_pad;
+  /* 0x0010 */ float2 vec2_f32;
+  /* 0x0018 */ int2 vec2_i32;
+  /* 0x0020 */ uint2 vec2_u32;
+  /* 0x0028 */ half2 vec2_f16;
+  /* 0x002c */ tint_array<int8_t, 4> tint_pad_1;
+  /* 0x0030 */ packed_float3 vec3_f32;
+  /* 0x003c */ tint_array<int8_t, 4> tint_pad_2;
+  /* 0x0040 */ packed_int3 vec3_i32;
+  /* 0x004c */ tint_array<int8_t, 4> tint_pad_3;
+  /* 0x0050 */ packed_uint3 vec3_u32;
+  /* 0x005c */ tint_array<int8_t, 4> tint_pad_4;
+  /* 0x0060 */ packed_half3 vec3_f16;
+  /* 0x0066 */ tint_array<int8_t, 10> tint_pad_5;
+  /* 0x0070 */ float4 vec4_f32;
+  /* 0x0080 */ int4 vec4_i32;
+  /* 0x0090 */ uint4 vec4_u32;
+  /* 0x00a0 */ half4 vec4_f16;
+  /* 0x00a8 */ float2x2 mat2x2_f32;
+  /* 0x00b8 */ tint_array<int8_t, 8> tint_pad_6;
+  /* 0x00c0 */ float2x3 mat2x3_f32;
+  /* 0x00e0 */ float2x4 mat2x4_f32;
+  /* 0x0100 */ float3x2 mat3x2_f32;
+  /* 0x0118 */ tint_array<int8_t, 8> tint_pad_7;
+  /* 0x0120 */ float3x3 mat3x3_f32;
+  /* 0x0150 */ float3x4 mat3x4_f32;
+  /* 0x0180 */ float4x2 mat4x2_f32;
+  /* 0x01a0 */ float4x3 mat4x3_f32;
+  /* 0x01e0 */ float4x4 mat4x4_f32;
+  /* 0x0220 */ half2x2 mat2x2_f16;
+  /* 0x0228 */ half2x3 mat2x3_f16;
+  /* 0x0238 */ half2x4 mat2x4_f16;
+  /* 0x0248 */ half3x2 mat3x2_f16;
+  /* 0x0254 */ tint_array<int8_t, 4> tint_pad_8;
+  /* 0x0258 */ half3x3 mat3x3_f16;
+  /* 0x0270 */ half3x4 mat3x4_f16;
+  /* 0x0288 */ half4x2 mat4x2_f16;
+  /* 0x0298 */ half4x3 mat4x3_f16;
+  /* 0x02b8 */ half4x4 mat4x4_f16;
+  /* 0x02d8 */ tint_array<int8_t, 8> tint_pad_9;
+  /* 0x02e0 */ tint_array<float3, 2> arr2_vec3_f32;
+  /* 0x0300 */ tint_array<half4x2, 2> arr2_mat4x2_f16;
+};
+
+struct S {
+  /* 0x0000 */ tint_array<Inner, 1> arr;
+};
+
+void tint_symbol_inner(uint idx, device S* const tint_symbol_3) {
+  (*(tint_symbol_3)).arr[idx].scalar_f32 = 0.0f;
+  (*(tint_symbol_3)).arr[idx].scalar_i32 = 0;
+  (*(tint_symbol_3)).arr[idx].scalar_u32 = 0u;
+  (*(tint_symbol_3)).arr[idx].scalar_f16 = 0.0h;
+  (*(tint_symbol_3)).arr[idx].vec2_f32 = float2(0.0f);
+  (*(tint_symbol_3)).arr[idx].vec2_i32 = int2(0);
+  (*(tint_symbol_3)).arr[idx].vec2_u32 = uint2(0u);
+  (*(tint_symbol_3)).arr[idx].vec2_f16 = half2(0.0h);
+  (*(tint_symbol_3)).arr[idx].vec3_f32 = float3(0.0f);
+  (*(tint_symbol_3)).arr[idx].vec3_i32 = int3(0);
+  (*(tint_symbol_3)).arr[idx].vec3_u32 = uint3(0u);
+  (*(tint_symbol_3)).arr[idx].vec3_f16 = half3(0.0h);
+  (*(tint_symbol_3)).arr[idx].vec4_f32 = float4(0.0f);
+  (*(tint_symbol_3)).arr[idx].vec4_i32 = int4(0);
+  (*(tint_symbol_3)).arr[idx].vec4_u32 = uint4(0u);
+  (*(tint_symbol_3)).arr[idx].vec4_f16 = half4(0.0h);
+  (*(tint_symbol_3)).arr[idx].mat2x2_f32 = float2x2(float2(0.0f), float2(0.0f));
+  (*(tint_symbol_3)).arr[idx].mat2x3_f32 = float2x3(float3(0.0f), float3(0.0f));
+  (*(tint_symbol_3)).arr[idx].mat2x4_f32 = float2x4(float4(0.0f), float4(0.0f));
+  (*(tint_symbol_3)).arr[idx].mat3x2_f32 = float3x2(float2(0.0f), float2(0.0f), float2(0.0f));
+  (*(tint_symbol_3)).arr[idx].mat3x3_f32 = float3x3(float3(0.0f), float3(0.0f), float3(0.0f));
+  (*(tint_symbol_3)).arr[idx].mat3x4_f32 = float3x4(float4(0.0f), float4(0.0f), float4(0.0f));
+  (*(tint_symbol_3)).arr[idx].mat4x2_f32 = float4x2(float2(0.0f), float2(0.0f), float2(0.0f), float2(0.0f));
+  (*(tint_symbol_3)).arr[idx].mat4x3_f32 = float4x3(float3(0.0f), float3(0.0f), float3(0.0f), float3(0.0f));
+  (*(tint_symbol_3)).arr[idx].mat4x4_f32 = float4x4(float4(0.0f), float4(0.0f), float4(0.0f), float4(0.0f));
+  (*(tint_symbol_3)).arr[idx].mat2x2_f16 = half2x2(half2(0.0h), half2(0.0h));
+  (*(tint_symbol_3)).arr[idx].mat2x3_f16 = half2x3(half3(0.0h), half3(0.0h));
+  (*(tint_symbol_3)).arr[idx].mat2x4_f16 = half2x4(half4(0.0h), half4(0.0h));
+  (*(tint_symbol_3)).arr[idx].mat3x2_f16 = half3x2(half2(0.0h), half2(0.0h), half2(0.0h));
+  (*(tint_symbol_3)).arr[idx].mat3x3_f16 = half3x3(half3(0.0h), half3(0.0h), half3(0.0h));
+  (*(tint_symbol_3)).arr[idx].mat3x4_f16 = half3x4(half4(0.0h), half4(0.0h), half4(0.0h));
+  (*(tint_symbol_3)).arr[idx].mat4x2_f16 = half4x2(half2(0.0h), half2(0.0h), half2(0.0h), half2(0.0h));
+  (*(tint_symbol_3)).arr[idx].mat4x3_f16 = half4x3(half3(0.0h), half3(0.0h), half3(0.0h), half3(0.0h));
+  (*(tint_symbol_3)).arr[idx].mat4x4_f16 = half4x4(half4(0.0h), half4(0.0h), half4(0.0h), half4(0.0h));
+  tint_array<float3, 2> const tint_symbol_1 = tint_array<float3, 2>{};
+  (*(tint_symbol_3)).arr[idx].arr2_vec3_f32 = tint_symbol_1;
+  tint_array<half4x2, 2> const tint_symbol_2 = tint_array<half4x2, 2>{};
+  (*(tint_symbol_3)).arr[idx].arr2_mat4x2_f16 = tint_symbol_2;
+}
+
+kernel void tint_symbol(device S* tint_symbol_4 [[buffer(0)]], uint idx [[thread_index_in_threadgroup]]) {
+  tint_symbol_inner(idx, tint_symbol_4);
+  return;
+}
+
diff --git a/test/tint/buffer/storage/dynamic_index/write_f16.wgsl.expected.spvasm b/test/tint/buffer/storage/dynamic_index/write_f16.wgsl.expected.spvasm
new file mode 100644
index 0000000..dfd8ef7
--- /dev/null
+++ b/test/tint/buffer/storage/dynamic_index/write_f16.wgsl.expected.spvasm
@@ -0,0 +1,376 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 198
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main" %idx_1
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %idx_1 "idx_1"
+               OpName %S "S"
+               OpMemberName %S 0 "arr"
+               OpName %Inner "Inner"
+               OpMemberName %Inner 0 "scalar_f32"
+               OpMemberName %Inner 1 "scalar_i32"
+               OpMemberName %Inner 2 "scalar_u32"
+               OpMemberName %Inner 3 "scalar_f16"
+               OpMemberName %Inner 4 "vec2_f32"
+               OpMemberName %Inner 5 "vec2_i32"
+               OpMemberName %Inner 6 "vec2_u32"
+               OpMemberName %Inner 7 "vec2_f16"
+               OpMemberName %Inner 8 "vec3_f32"
+               OpMemberName %Inner 9 "vec3_i32"
+               OpMemberName %Inner 10 "vec3_u32"
+               OpMemberName %Inner 11 "vec3_f16"
+               OpMemberName %Inner 12 "vec4_f32"
+               OpMemberName %Inner 13 "vec4_i32"
+               OpMemberName %Inner 14 "vec4_u32"
+               OpMemberName %Inner 15 "vec4_f16"
+               OpMemberName %Inner 16 "mat2x2_f32"
+               OpMemberName %Inner 17 "mat2x3_f32"
+               OpMemberName %Inner 18 "mat2x4_f32"
+               OpMemberName %Inner 19 "mat3x2_f32"
+               OpMemberName %Inner 20 "mat3x3_f32"
+               OpMemberName %Inner 21 "mat3x4_f32"
+               OpMemberName %Inner 22 "mat4x2_f32"
+               OpMemberName %Inner 23 "mat4x3_f32"
+               OpMemberName %Inner 24 "mat4x4_f32"
+               OpMemberName %Inner 25 "mat2x2_f16"
+               OpMemberName %Inner 26 "mat2x3_f16"
+               OpMemberName %Inner 27 "mat2x4_f16"
+               OpMemberName %Inner 28 "mat3x2_f16"
+               OpMemberName %Inner 29 "mat3x3_f16"
+               OpMemberName %Inner 30 "mat3x4_f16"
+               OpMemberName %Inner 31 "mat4x2_f16"
+               OpMemberName %Inner 32 "mat4x3_f16"
+               OpMemberName %Inner 33 "mat4x4_f16"
+               OpMemberName %Inner 34 "arr2_vec3_f32"
+               OpMemberName %Inner 35 "arr2_mat4x2_f16"
+               OpName %sb "sb"
+               OpName %main_inner "main_inner"
+               OpName %idx "idx"
+               OpName %main "main"
+               OpDecorate %idx_1 BuiltIn LocalInvocationIndex
+               OpDecorate %S Block
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %Inner 0 Offset 0
+               OpMemberDecorate %Inner 1 Offset 4
+               OpMemberDecorate %Inner 2 Offset 8
+               OpMemberDecorate %Inner 3 Offset 12
+               OpMemberDecorate %Inner 4 Offset 16
+               OpMemberDecorate %Inner 5 Offset 24
+               OpMemberDecorate %Inner 6 Offset 32
+               OpMemberDecorate %Inner 7 Offset 40
+               OpMemberDecorate %Inner 8 Offset 48
+               OpMemberDecorate %Inner 9 Offset 64
+               OpMemberDecorate %Inner 10 Offset 80
+               OpMemberDecorate %Inner 11 Offset 96
+               OpMemberDecorate %Inner 12 Offset 112
+               OpMemberDecorate %Inner 13 Offset 128
+               OpMemberDecorate %Inner 14 Offset 144
+               OpMemberDecorate %Inner 15 Offset 160
+               OpMemberDecorate %Inner 16 Offset 168
+               OpMemberDecorate %Inner 16 ColMajor
+               OpMemberDecorate %Inner 16 MatrixStride 8
+               OpMemberDecorate %Inner 17 Offset 192
+               OpMemberDecorate %Inner 17 ColMajor
+               OpMemberDecorate %Inner 17 MatrixStride 16
+               OpMemberDecorate %Inner 18 Offset 224
+               OpMemberDecorate %Inner 18 ColMajor
+               OpMemberDecorate %Inner 18 MatrixStride 16
+               OpMemberDecorate %Inner 19 Offset 256
+               OpMemberDecorate %Inner 19 ColMajor
+               OpMemberDecorate %Inner 19 MatrixStride 8
+               OpMemberDecorate %Inner 20 Offset 288
+               OpMemberDecorate %Inner 20 ColMajor
+               OpMemberDecorate %Inner 20 MatrixStride 16
+               OpMemberDecorate %Inner 21 Offset 336
+               OpMemberDecorate %Inner 21 ColMajor
+               OpMemberDecorate %Inner 21 MatrixStride 16
+               OpMemberDecorate %Inner 22 Offset 384
+               OpMemberDecorate %Inner 22 ColMajor
+               OpMemberDecorate %Inner 22 MatrixStride 8
+               OpMemberDecorate %Inner 23 Offset 416
+               OpMemberDecorate %Inner 23 ColMajor
+               OpMemberDecorate %Inner 23 MatrixStride 16
+               OpMemberDecorate %Inner 24 Offset 480
+               OpMemberDecorate %Inner 24 ColMajor
+               OpMemberDecorate %Inner 24 MatrixStride 16
+               OpMemberDecorate %Inner 25 Offset 544
+               OpMemberDecorate %Inner 25 ColMajor
+               OpMemberDecorate %Inner 25 MatrixStride 4
+               OpMemberDecorate %Inner 26 Offset 552
+               OpMemberDecorate %Inner 26 ColMajor
+               OpMemberDecorate %Inner 26 MatrixStride 8
+               OpMemberDecorate %Inner 27 Offset 568
+               OpMemberDecorate %Inner 27 ColMajor
+               OpMemberDecorate %Inner 27 MatrixStride 8
+               OpMemberDecorate %Inner 28 Offset 584
+               OpMemberDecorate %Inner 28 ColMajor
+               OpMemberDecorate %Inner 28 MatrixStride 4
+               OpMemberDecorate %Inner 29 Offset 600
+               OpMemberDecorate %Inner 29 ColMajor
+               OpMemberDecorate %Inner 29 MatrixStride 8
+               OpMemberDecorate %Inner 30 Offset 624
+               OpMemberDecorate %Inner 30 ColMajor
+               OpMemberDecorate %Inner 30 MatrixStride 8
+               OpMemberDecorate %Inner 31 Offset 648
+               OpMemberDecorate %Inner 31 ColMajor
+               OpMemberDecorate %Inner 31 MatrixStride 4
+               OpMemberDecorate %Inner 32 Offset 664
+               OpMemberDecorate %Inner 32 ColMajor
+               OpMemberDecorate %Inner 32 MatrixStride 8
+               OpMemberDecorate %Inner 33 Offset 696
+               OpMemberDecorate %Inner 33 ColMajor
+               OpMemberDecorate %Inner 33 MatrixStride 8
+               OpMemberDecorate %Inner 34 Offset 736
+               OpDecorate %_arr_v3float_uint_2 ArrayStride 16
+               OpMemberDecorate %Inner 35 Offset 768
+               OpMemberDecorate %Inner 35 ColMajor
+               OpMemberDecorate %Inner 35 MatrixStride 4
+               OpDecorate %_arr_mat4v2half_uint_2 ArrayStride 16
+               OpDecorate %_runtimearr_Inner ArrayStride 800
+               OpDecorate %sb Binding 0
+               OpDecorate %sb DescriptorSet 0
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+      %idx_1 = OpVariable %_ptr_Input_uint Input
+      %float = OpTypeFloat 32
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+    %v2float = OpTypeVector %float 2
+      %v2int = OpTypeVector %int 2
+     %v2uint = OpTypeVector %uint 2
+     %v2half = OpTypeVector %half 2
+    %v3float = OpTypeVector %float 3
+      %v3int = OpTypeVector %int 3
+     %v3uint = OpTypeVector %uint 3
+     %v3half = OpTypeVector %half 3
+    %v4float = OpTypeVector %float 4
+      %v4int = OpTypeVector %int 4
+     %v4uint = OpTypeVector %uint 4
+     %v4half = OpTypeVector %half 4
+%mat2v2float = OpTypeMatrix %v2float 2
+%mat2v3float = OpTypeMatrix %v3float 2
+%mat2v4float = OpTypeMatrix %v4float 2
+%mat3v2float = OpTypeMatrix %v2float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+%mat3v4float = OpTypeMatrix %v4float 3
+%mat4v2float = OpTypeMatrix %v2float 4
+%mat4v3float = OpTypeMatrix %v3float 4
+%mat4v4float = OpTypeMatrix %v4float 4
+ %mat2v2half = OpTypeMatrix %v2half 2
+ %mat2v3half = OpTypeMatrix %v3half 2
+ %mat2v4half = OpTypeMatrix %v4half 2
+ %mat3v2half = OpTypeMatrix %v2half 3
+ %mat3v3half = OpTypeMatrix %v3half 3
+ %mat3v4half = OpTypeMatrix %v4half 3
+ %mat4v2half = OpTypeMatrix %v2half 4
+ %mat4v3half = OpTypeMatrix %v3half 4
+ %mat4v4half = OpTypeMatrix %v4half 4
+     %uint_2 = OpConstant %uint 2
+%_arr_v3float_uint_2 = OpTypeArray %v3float %uint_2
+%_arr_mat4v2half_uint_2 = OpTypeArray %mat4v2half %uint_2
+      %Inner = OpTypeStruct %float %int %uint %half %v2float %v2int %v2uint %v2half %v3float %v3int %v3uint %v3half %v4float %v4int %v4uint %v4half %mat2v2float %mat2v3float %mat2v4float %mat3v2float %mat3v3float %mat3v4float %mat4v2float %mat4v3float %mat4v4float %mat2v2half %mat2v3half %mat2v4half %mat3v2half %mat3v3half %mat3v4half %mat4v2half %mat4v3half %mat4v4half %_arr_v3float_uint_2 %_arr_mat4v2half_uint_2
+%_runtimearr_Inner = OpTypeRuntimeArray %Inner
+          %S = OpTypeStruct %_runtimearr_Inner
+%_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
+         %sb = OpVariable %_ptr_StorageBuffer_S StorageBuffer
+       %void = OpTypeVoid
+         %45 = OpTypeFunction %void %uint
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
+         %53 = OpConstantNull %float
+     %uint_1 = OpConstant %uint 1
+%_ptr_StorageBuffer_int = OpTypePointer StorageBuffer %int
+         %57 = OpConstantNull %int
+%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
+         %60 = OpConstantNull %uint
+     %uint_3 = OpConstant %uint 3
+%_ptr_StorageBuffer_half = OpTypePointer StorageBuffer %half
+         %64 = OpConstantNull %half
+     %uint_4 = OpConstant %uint 4
+%_ptr_StorageBuffer_v2float = OpTypePointer StorageBuffer %v2float
+         %68 = OpConstantNull %v2float
+     %uint_5 = OpConstant %uint 5
+%_ptr_StorageBuffer_v2int = OpTypePointer StorageBuffer %v2int
+         %72 = OpConstantNull %v2int
+     %uint_6 = OpConstant %uint 6
+%_ptr_StorageBuffer_v2uint = OpTypePointer StorageBuffer %v2uint
+         %76 = OpConstantNull %v2uint
+     %uint_7 = OpConstant %uint 7
+%_ptr_StorageBuffer_v2half = OpTypePointer StorageBuffer %v2half
+         %80 = OpConstantNull %v2half
+     %uint_8 = OpConstant %uint 8
+%_ptr_StorageBuffer_v3float = OpTypePointer StorageBuffer %v3float
+         %84 = OpConstantNull %v3float
+     %uint_9 = OpConstant %uint 9
+%_ptr_StorageBuffer_v3int = OpTypePointer StorageBuffer %v3int
+         %88 = OpConstantNull %v3int
+    %uint_10 = OpConstant %uint 10
+%_ptr_StorageBuffer_v3uint = OpTypePointer StorageBuffer %v3uint
+         %92 = OpConstantNull %v3uint
+    %uint_11 = OpConstant %uint 11
+%_ptr_StorageBuffer_v3half = OpTypePointer StorageBuffer %v3half
+         %96 = OpConstantNull %v3half
+    %uint_12 = OpConstant %uint 12
+%_ptr_StorageBuffer_v4float = OpTypePointer StorageBuffer %v4float
+        %100 = OpConstantNull %v4float
+    %uint_13 = OpConstant %uint 13
+%_ptr_StorageBuffer_v4int = OpTypePointer StorageBuffer %v4int
+        %104 = OpConstantNull %v4int
+    %uint_14 = OpConstant %uint 14
+%_ptr_StorageBuffer_v4uint = OpTypePointer StorageBuffer %v4uint
+        %108 = OpConstantNull %v4uint
+    %uint_15 = OpConstant %uint 15
+%_ptr_StorageBuffer_v4half = OpTypePointer StorageBuffer %v4half
+        %112 = OpConstantNull %v4half
+    %uint_16 = OpConstant %uint 16
+%_ptr_StorageBuffer_mat2v2float = OpTypePointer StorageBuffer %mat2v2float
+        %116 = OpConstantNull %mat2v2float
+    %uint_17 = OpConstant %uint 17
+%_ptr_StorageBuffer_mat2v3float = OpTypePointer StorageBuffer %mat2v3float
+        %120 = OpConstantNull %mat2v3float
+    %uint_18 = OpConstant %uint 18
+%_ptr_StorageBuffer_mat2v4float = OpTypePointer StorageBuffer %mat2v4float
+        %124 = OpConstantNull %mat2v4float
+    %uint_19 = OpConstant %uint 19
+%_ptr_StorageBuffer_mat3v2float = OpTypePointer StorageBuffer %mat3v2float
+        %128 = OpConstantNull %mat3v2float
+    %uint_20 = OpConstant %uint 20
+%_ptr_StorageBuffer_mat3v3float = OpTypePointer StorageBuffer %mat3v3float
+        %132 = OpConstantNull %mat3v3float
+    %uint_21 = OpConstant %uint 21
+%_ptr_StorageBuffer_mat3v4float = OpTypePointer StorageBuffer %mat3v4float
+        %136 = OpConstantNull %mat3v4float
+    %uint_22 = OpConstant %uint 22
+%_ptr_StorageBuffer_mat4v2float = OpTypePointer StorageBuffer %mat4v2float
+        %140 = OpConstantNull %mat4v2float
+    %uint_23 = OpConstant %uint 23
+%_ptr_StorageBuffer_mat4v3float = OpTypePointer StorageBuffer %mat4v3float
+        %144 = OpConstantNull %mat4v3float
+    %uint_24 = OpConstant %uint 24
+%_ptr_StorageBuffer_mat4v4float = OpTypePointer StorageBuffer %mat4v4float
+        %148 = OpConstantNull %mat4v4float
+    %uint_25 = OpConstant %uint 25
+%_ptr_StorageBuffer_mat2v2half = OpTypePointer StorageBuffer %mat2v2half
+        %152 = OpConstantNull %mat2v2half
+    %uint_26 = OpConstant %uint 26
+%_ptr_StorageBuffer_mat2v3half = OpTypePointer StorageBuffer %mat2v3half
+        %156 = OpConstantNull %mat2v3half
+    %uint_27 = OpConstant %uint 27
+%_ptr_StorageBuffer_mat2v4half = OpTypePointer StorageBuffer %mat2v4half
+        %160 = OpConstantNull %mat2v4half
+    %uint_28 = OpConstant %uint 28
+%_ptr_StorageBuffer_mat3v2half = OpTypePointer StorageBuffer %mat3v2half
+        %164 = OpConstantNull %mat3v2half
+    %uint_29 = OpConstant %uint 29
+%_ptr_StorageBuffer_mat3v3half = OpTypePointer StorageBuffer %mat3v3half
+        %168 = OpConstantNull %mat3v3half
+    %uint_30 = OpConstant %uint 30
+%_ptr_StorageBuffer_mat3v4half = OpTypePointer StorageBuffer %mat3v4half
+        %172 = OpConstantNull %mat3v4half
+    %uint_31 = OpConstant %uint 31
+%_ptr_StorageBuffer_mat4v2half = OpTypePointer StorageBuffer %mat4v2half
+        %176 = OpConstantNull %mat4v2half
+    %uint_32 = OpConstant %uint 32
+%_ptr_StorageBuffer_mat4v3half = OpTypePointer StorageBuffer %mat4v3half
+        %180 = OpConstantNull %mat4v3half
+    %uint_33 = OpConstant %uint 33
+%_ptr_StorageBuffer_mat4v4half = OpTypePointer StorageBuffer %mat4v4half
+        %184 = OpConstantNull %mat4v4half
+    %uint_34 = OpConstant %uint 34
+%_ptr_StorageBuffer__arr_v3float_uint_2 = OpTypePointer StorageBuffer %_arr_v3float_uint_2
+        %188 = OpConstantNull %_arr_v3float_uint_2
+    %uint_35 = OpConstant %uint 35
+%_ptr_StorageBuffer__arr_mat4v2half_uint_2 = OpTypePointer StorageBuffer %_arr_mat4v2half_uint_2
+        %192 = OpConstantNull %_arr_mat4v2half_uint_2
+        %193 = OpTypeFunction %void
+ %main_inner = OpFunction %void None %45
+        %idx = OpFunctionParameter %uint
+         %49 = OpLabel
+         %52 = OpAccessChain %_ptr_StorageBuffer_float %sb %uint_0 %idx %uint_0
+               OpStore %52 %53
+         %56 = OpAccessChain %_ptr_StorageBuffer_int %sb %uint_0 %idx %uint_1
+               OpStore %56 %57
+         %59 = OpAccessChain %_ptr_StorageBuffer_uint %sb %uint_0 %idx %uint_2
+               OpStore %59 %60
+         %63 = OpAccessChain %_ptr_StorageBuffer_half %sb %uint_0 %idx %uint_3
+               OpStore %63 %64
+         %67 = OpAccessChain %_ptr_StorageBuffer_v2float %sb %uint_0 %idx %uint_4
+               OpStore %67 %68
+         %71 = OpAccessChain %_ptr_StorageBuffer_v2int %sb %uint_0 %idx %uint_5
+               OpStore %71 %72
+         %75 = OpAccessChain %_ptr_StorageBuffer_v2uint %sb %uint_0 %idx %uint_6
+               OpStore %75 %76
+         %79 = OpAccessChain %_ptr_StorageBuffer_v2half %sb %uint_0 %idx %uint_7
+               OpStore %79 %80
+         %83 = OpAccessChain %_ptr_StorageBuffer_v3float %sb %uint_0 %idx %uint_8
+               OpStore %83 %84
+         %87 = OpAccessChain %_ptr_StorageBuffer_v3int %sb %uint_0 %idx %uint_9
+               OpStore %87 %88
+         %91 = OpAccessChain %_ptr_StorageBuffer_v3uint %sb %uint_0 %idx %uint_10
+               OpStore %91 %92
+         %95 = OpAccessChain %_ptr_StorageBuffer_v3half %sb %uint_0 %idx %uint_11
+               OpStore %95 %96
+         %99 = OpAccessChain %_ptr_StorageBuffer_v4float %sb %uint_0 %idx %uint_12
+               OpStore %99 %100
+        %103 = OpAccessChain %_ptr_StorageBuffer_v4int %sb %uint_0 %idx %uint_13
+               OpStore %103 %104
+        %107 = OpAccessChain %_ptr_StorageBuffer_v4uint %sb %uint_0 %idx %uint_14
+               OpStore %107 %108
+        %111 = OpAccessChain %_ptr_StorageBuffer_v4half %sb %uint_0 %idx %uint_15
+               OpStore %111 %112
+        %115 = OpAccessChain %_ptr_StorageBuffer_mat2v2float %sb %uint_0 %idx %uint_16
+               OpStore %115 %116
+        %119 = OpAccessChain %_ptr_StorageBuffer_mat2v3float %sb %uint_0 %idx %uint_17
+               OpStore %119 %120
+        %123 = OpAccessChain %_ptr_StorageBuffer_mat2v4float %sb %uint_0 %idx %uint_18
+               OpStore %123 %124
+        %127 = OpAccessChain %_ptr_StorageBuffer_mat3v2float %sb %uint_0 %idx %uint_19
+               OpStore %127 %128
+        %131 = OpAccessChain %_ptr_StorageBuffer_mat3v3float %sb %uint_0 %idx %uint_20
+               OpStore %131 %132
+        %135 = OpAccessChain %_ptr_StorageBuffer_mat3v4float %sb %uint_0 %idx %uint_21
+               OpStore %135 %136
+        %139 = OpAccessChain %_ptr_StorageBuffer_mat4v2float %sb %uint_0 %idx %uint_22
+               OpStore %139 %140
+        %143 = OpAccessChain %_ptr_StorageBuffer_mat4v3float %sb %uint_0 %idx %uint_23
+               OpStore %143 %144
+        %147 = OpAccessChain %_ptr_StorageBuffer_mat4v4float %sb %uint_0 %idx %uint_24
+               OpStore %147 %148
+        %151 = OpAccessChain %_ptr_StorageBuffer_mat2v2half %sb %uint_0 %idx %uint_25
+               OpStore %151 %152
+        %155 = OpAccessChain %_ptr_StorageBuffer_mat2v3half %sb %uint_0 %idx %uint_26
+               OpStore %155 %156
+        %159 = OpAccessChain %_ptr_StorageBuffer_mat2v4half %sb %uint_0 %idx %uint_27
+               OpStore %159 %160
+        %163 = OpAccessChain %_ptr_StorageBuffer_mat3v2half %sb %uint_0 %idx %uint_28
+               OpStore %163 %164
+        %167 = OpAccessChain %_ptr_StorageBuffer_mat3v3half %sb %uint_0 %idx %uint_29
+               OpStore %167 %168
+        %171 = OpAccessChain %_ptr_StorageBuffer_mat3v4half %sb %uint_0 %idx %uint_30
+               OpStore %171 %172
+        %175 = OpAccessChain %_ptr_StorageBuffer_mat4v2half %sb %uint_0 %idx %uint_31
+               OpStore %175 %176
+        %179 = OpAccessChain %_ptr_StorageBuffer_mat4v3half %sb %uint_0 %idx %uint_32
+               OpStore %179 %180
+        %183 = OpAccessChain %_ptr_StorageBuffer_mat4v4half %sb %uint_0 %idx %uint_33
+               OpStore %183 %184
+        %187 = OpAccessChain %_ptr_StorageBuffer__arr_v3float_uint_2 %sb %uint_0 %idx %uint_34
+               OpStore %187 %188
+        %191 = OpAccessChain %_ptr_StorageBuffer__arr_mat4v2half_uint_2 %sb %uint_0 %idx %uint_35
+               OpStore %191 %192
+               OpReturn
+               OpFunctionEnd
+       %main = OpFunction %void None %193
+        %195 = OpLabel
+        %197 = OpLoad %uint %idx_1
+        %196 = OpFunctionCall %void %main_inner %197
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/storage/dynamic_index/write_f16.wgsl.expected.wgsl b/test/tint/buffer/storage/dynamic_index/write_f16.wgsl.expected.wgsl
new file mode 100644
index 0000000..c81934c
--- /dev/null
+++ b/test/tint/buffer/storage/dynamic_index/write_f16.wgsl.expected.wgsl
@@ -0,0 +1,86 @@
+enable f16;
+
+struct Inner {
+  scalar_f32 : f32,
+  scalar_i32 : i32,
+  scalar_u32 : u32,
+  scalar_f16 : f16,
+  vec2_f32 : vec2<f32>,
+  vec2_i32 : vec2<i32>,
+  vec2_u32 : vec2<u32>,
+  vec2_f16 : vec2<f16>,
+  vec3_f32 : vec3<f32>,
+  vec3_i32 : vec3<i32>,
+  vec3_u32 : vec3<u32>,
+  vec3_f16 : vec3<f16>,
+  vec4_f32 : vec4<f32>,
+  vec4_i32 : vec4<i32>,
+  vec4_u32 : vec4<u32>,
+  vec4_f16 : vec4<f16>,
+  mat2x2_f32 : mat2x2<f32>,
+  mat2x3_f32 : mat2x3<f32>,
+  mat2x4_f32 : mat2x4<f32>,
+  mat3x2_f32 : mat3x2<f32>,
+  mat3x3_f32 : mat3x3<f32>,
+  mat3x4_f32 : mat3x4<f32>,
+  mat4x2_f32 : mat4x2<f32>,
+  mat4x3_f32 : mat4x3<f32>,
+  mat4x4_f32 : mat4x4<f32>,
+  mat2x2_f16 : mat2x2<f16>,
+  mat2x3_f16 : mat2x3<f16>,
+  mat2x4_f16 : mat2x4<f16>,
+  mat3x2_f16 : mat3x2<f16>,
+  mat3x3_f16 : mat3x3<f16>,
+  mat3x4_f16 : mat3x4<f16>,
+  mat4x2_f16 : mat4x2<f16>,
+  mat4x3_f16 : mat4x3<f16>,
+  mat4x4_f16 : mat4x4<f16>,
+  arr2_vec3_f32 : array<vec3<f32>, 2>,
+  arr2_mat4x2_f16 : array<mat4x2<f16>, 2>,
+}
+
+struct S {
+  arr : array<Inner>,
+}
+
+@binding(0) @group(0) var<storage, read_write> sb : S;
+
+@compute @workgroup_size(1)
+fn main(@builtin(local_invocation_index) idx : u32) {
+  sb.arr[idx].scalar_f32 = f32();
+  sb.arr[idx].scalar_i32 = i32();
+  sb.arr[idx].scalar_u32 = u32();
+  sb.arr[idx].scalar_f16 = f16();
+  sb.arr[idx].vec2_f32 = vec2<f32>();
+  sb.arr[idx].vec2_i32 = vec2<i32>();
+  sb.arr[idx].vec2_u32 = vec2<u32>();
+  sb.arr[idx].vec2_f16 = vec2<f16>();
+  sb.arr[idx].vec3_f32 = vec3<f32>();
+  sb.arr[idx].vec3_i32 = vec3<i32>();
+  sb.arr[idx].vec3_u32 = vec3<u32>();
+  sb.arr[idx].vec3_f16 = vec3<f16>();
+  sb.arr[idx].vec4_f32 = vec4<f32>();
+  sb.arr[idx].vec4_i32 = vec4<i32>();
+  sb.arr[idx].vec4_u32 = vec4<u32>();
+  sb.arr[idx].vec4_f16 = vec4<f16>();
+  sb.arr[idx].mat2x2_f32 = mat2x2<f32>();
+  sb.arr[idx].mat2x3_f32 = mat2x3<f32>();
+  sb.arr[idx].mat2x4_f32 = mat2x4<f32>();
+  sb.arr[idx].mat3x2_f32 = mat3x2<f32>();
+  sb.arr[idx].mat3x3_f32 = mat3x3<f32>();
+  sb.arr[idx].mat3x4_f32 = mat3x4<f32>();
+  sb.arr[idx].mat4x2_f32 = mat4x2<f32>();
+  sb.arr[idx].mat4x3_f32 = mat4x3<f32>();
+  sb.arr[idx].mat4x4_f32 = mat4x4<f32>();
+  sb.arr[idx].mat2x2_f16 = mat2x2<f16>();
+  sb.arr[idx].mat2x3_f16 = mat2x3<f16>();
+  sb.arr[idx].mat2x4_f16 = mat2x4<f16>();
+  sb.arr[idx].mat3x2_f16 = mat3x2<f16>();
+  sb.arr[idx].mat3x3_f16 = mat3x3<f16>();
+  sb.arr[idx].mat3x4_f16 = mat3x4<f16>();
+  sb.arr[idx].mat4x2_f16 = mat4x2<f16>();
+  sb.arr[idx].mat4x3_f16 = mat4x3<f16>();
+  sb.arr[idx].mat4x4_f16 = mat4x4<f16>();
+  sb.arr[idx].arr2_vec3_f32 = array<vec3<f32>, 2>();
+  sb.arr[idx].arr2_mat4x2_f16 = array<mat4x2<f16>, 2>();
+}
diff --git a/test/tint/buffer/storage/static_index/read.wgsl b/test/tint/buffer/storage/static_index/read.wgsl
index 84c5148..80b9d10 100644
--- a/test/tint/buffer/storage/static_index/read.wgsl
+++ b/test/tint/buffer/storage/static_index/read.wgsl
@@ -1,32 +1,61 @@
 struct Inner {
-    x : i32,
+    scalar_i32 : i32,
+    scalar_f32 : f32,
 };
 
 struct S {
-    a : vec3<i32>,
-    b : i32,
-    c : vec3<u32>,
-    d : u32,
-    e : vec3<f32>,
-    f : f32,
-    g : mat2x3<f32>,
-    h : mat3x2<f32>,
-    i : Inner,
-    j : array<Inner, 4>,
+    scalar_f32 : f32,
+    scalar_i32 : i32,
+    scalar_u32 : u32,
+    vec2_f32 : vec2<f32>,
+    vec2_i32 : vec2<i32>,
+    vec2_u32 : vec2<u32>,
+    vec3_f32 : vec3<f32>,
+    vec3_i32 : vec3<i32>,
+    vec3_u32 : vec3<u32>,
+    vec4_f32 : vec4<f32>,
+    vec4_i32 : vec4<i32>,
+    vec4_u32 : vec4<u32>,
+    mat2x2_f32 : mat2x2<f32>,
+    mat2x3_f32 : mat2x3<f32>,
+    mat2x4_f32 : mat2x4<f32>,
+    mat3x2_f32 : mat3x2<f32>,
+    mat3x3_f32 : mat3x3<f32>,
+    mat3x4_f32 : mat3x4<f32>,
+    mat4x2_f32 : mat4x2<f32>,
+    mat4x3_f32 : mat4x3<f32>,
+    mat4x4_f32 : mat4x4<f32>,
+    arr2_vec3_f32 : array<vec3<f32>, 2>,
+    struct_inner : Inner,
+    array_struct_inner : array<Inner, 4>,
 };
 
-@binding(0) @group(0) var<storage, read> s : S;
+@binding(0) @group(0) var<storage, read> sb : S;
 
 @compute @workgroup_size(1)
 fn main() {
-    let a = s.a;
-    let b = s.b;
-    let c = s.c;
-    let d = s.d;
-    let e = s.e;
-    let f = s.f;
-    let g = s.g;
-    let h = s.h;
-    let i = s.i;
-    let j = s.j;
+    let scalar_f32 = sb.scalar_f32;
+    let scalar_i32 = sb.scalar_i32;
+    let scalar_u32 = sb.scalar_u32;
+    let vec2_f32 = sb.vec2_f32;
+    let vec2_i32 = sb.vec2_i32;
+    let vec2_u32 = sb.vec2_u32;
+    let vec3_f32 = sb.vec3_f32;
+    let vec3_i32 = sb.vec3_i32;
+    let vec3_u32 = sb.vec3_u32;
+    let vec4_f32 = sb.vec4_f32;
+    let vec4_i32 = sb.vec4_i32;
+    let vec4_u32 = sb.vec4_u32;
+    let mat2x2_f32 = sb.mat2x2_f32;
+    let mat2x3_f32 = sb.mat2x3_f32;
+    let mat2x4_f32 = sb.mat2x4_f32;
+    let mat3x2_f32 = sb.mat3x2_f32;
+    let mat3x3_f32 = sb.mat3x3_f32;
+    let mat3x4_f32 = sb.mat3x4_f32;
+    let mat4x2_f32 = sb.mat4x2_f32;
+    let mat4x3_f32 = sb.mat4x3_f32;
+    let mat4x4_f32 = sb.mat4x4_f32;
+    let arr2_vec3_f32 = sb.arr2_vec3_f32;
+    let struct_inner = sb.struct_inner;
+    let array_struct_inner = sb.array_struct_inner;
 }
diff --git a/test/tint/buffer/storage/static_index/read.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/static_index/read.wgsl.expected.dxc.hlsl
index 501435d..49b16b2 100644
--- a/test/tint/buffer/storage/static_index/read.wgsl.expected.dxc.hlsl
+++ b/test/tint/buffer/storage/static_index/read.wgsl.expected.dxc.hlsl
@@ -1,44 +1,98 @@
 struct Inner {
-  int x;
+  int scalar_i32;
+  float scalar_f32;
 };
 
-ByteAddressBuffer s : register(t0, space0);
+ByteAddressBuffer sb : register(t0, space0);
 
-float2x3 tint_symbol_6(ByteAddressBuffer buffer, uint offset) {
+float2x2 tint_symbol_12(ByteAddressBuffer buffer, uint offset) {
+  return float2x2(asfloat(buffer.Load2((offset + 0u))), asfloat(buffer.Load2((offset + 8u))));
+}
+
+float2x3 tint_symbol_13(ByteAddressBuffer buffer, uint offset) {
   return float2x3(asfloat(buffer.Load3((offset + 0u))), asfloat(buffer.Load3((offset + 16u))));
 }
 
-float3x2 tint_symbol_7(ByteAddressBuffer buffer, uint offset) {
+float2x4 tint_symbol_14(ByteAddressBuffer buffer, uint offset) {
+  return float2x4(asfloat(buffer.Load4((offset + 0u))), asfloat(buffer.Load4((offset + 16u))));
+}
+
+float3x2 tint_symbol_15(ByteAddressBuffer buffer, uint offset) {
   return float3x2(asfloat(buffer.Load2((offset + 0u))), asfloat(buffer.Load2((offset + 8u))), asfloat(buffer.Load2((offset + 16u))));
 }
 
-Inner tint_symbol_9(ByteAddressBuffer buffer, uint offset) {
-  const Inner tint_symbol_11 = {asint(buffer.Load((offset + 0u)))};
-  return tint_symbol_11;
+float3x3 tint_symbol_16(ByteAddressBuffer buffer, uint offset) {
+  return float3x3(asfloat(buffer.Load3((offset + 0u))), asfloat(buffer.Load3((offset + 16u))), asfloat(buffer.Load3((offset + 32u))));
 }
 
-typedef Inner tint_symbol_10_ret[4];
-tint_symbol_10_ret tint_symbol_10(ByteAddressBuffer buffer, uint offset) {
-  Inner arr[4] = (Inner[4])0;
+float3x4 tint_symbol_17(ByteAddressBuffer buffer, uint offset) {
+  return float3x4(asfloat(buffer.Load4((offset + 0u))), asfloat(buffer.Load4((offset + 16u))), asfloat(buffer.Load4((offset + 32u))));
+}
+
+float4x2 tint_symbol_18(ByteAddressBuffer buffer, uint offset) {
+  return float4x2(asfloat(buffer.Load2((offset + 0u))), asfloat(buffer.Load2((offset + 8u))), asfloat(buffer.Load2((offset + 16u))), asfloat(buffer.Load2((offset + 24u))));
+}
+
+float4x3 tint_symbol_19(ByteAddressBuffer buffer, uint offset) {
+  return float4x3(asfloat(buffer.Load3((offset + 0u))), asfloat(buffer.Load3((offset + 16u))), asfloat(buffer.Load3((offset + 32u))), asfloat(buffer.Load3((offset + 48u))));
+}
+
+float4x4 tint_symbol_20(ByteAddressBuffer buffer, uint offset) {
+  return float4x4(asfloat(buffer.Load4((offset + 0u))), asfloat(buffer.Load4((offset + 16u))), asfloat(buffer.Load4((offset + 32u))), asfloat(buffer.Load4((offset + 48u))));
+}
+
+typedef float3 tint_symbol_21_ret[2];
+tint_symbol_21_ret tint_symbol_21(ByteAddressBuffer buffer, uint offset) {
+  float3 arr[2] = (float3[2])0;
   {
-    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
-      arr[i_1] = tint_symbol_9(buffer, (offset + (i_1 * 4u)));
+    for(uint i = 0u; (i < 2u); i = (i + 1u)) {
+      arr[i] = asfloat(buffer.Load3((offset + (i * 16u))));
     }
   }
   return arr;
 }
 
+Inner tint_symbol_22(ByteAddressBuffer buffer, uint offset) {
+  const Inner tint_symbol_24 = {asint(buffer.Load((offset + 0u))), asfloat(buffer.Load((offset + 4u)))};
+  return tint_symbol_24;
+}
+
+typedef Inner tint_symbol_23_ret[4];
+tint_symbol_23_ret tint_symbol_23(ByteAddressBuffer buffer, uint offset) {
+  Inner arr_1[4] = (Inner[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr_1[i_1] = tint_symbol_22(buffer, (offset + (i_1 * 8u)));
+    }
+  }
+  return arr_1;
+}
+
 [numthreads(1, 1, 1)]
 void main() {
-  const int3 a = asint(s.Load3(0u));
-  const int b = asint(s.Load(12u));
-  const uint3 c = s.Load3(16u);
-  const uint d = s.Load(28u);
-  const float3 e = asfloat(s.Load3(32u));
-  const float f = asfloat(s.Load(44u));
-  const float2x3 g = tint_symbol_6(s, 48u);
-  const float3x2 h = tint_symbol_7(s, 80u);
-  const Inner i = tint_symbol_9(s, 104u);
-  const Inner j[4] = tint_symbol_10(s, 108u);
+  const float scalar_f32 = asfloat(sb.Load(0u));
+  const int scalar_i32 = asint(sb.Load(4u));
+  const uint scalar_u32 = sb.Load(8u);
+  const float2 vec2_f32 = asfloat(sb.Load2(16u));
+  const int2 vec2_i32 = asint(sb.Load2(24u));
+  const uint2 vec2_u32 = sb.Load2(32u);
+  const float3 vec3_f32 = asfloat(sb.Load3(48u));
+  const int3 vec3_i32 = asint(sb.Load3(64u));
+  const uint3 vec3_u32 = sb.Load3(80u);
+  const float4 vec4_f32 = asfloat(sb.Load4(96u));
+  const int4 vec4_i32 = asint(sb.Load4(112u));
+  const uint4 vec4_u32 = sb.Load4(128u);
+  const float2x2 mat2x2_f32 = tint_symbol_12(sb, 144u);
+  const float2x3 mat2x3_f32 = tint_symbol_13(sb, 160u);
+  const float2x4 mat2x4_f32 = tint_symbol_14(sb, 192u);
+  const float3x2 mat3x2_f32 = tint_symbol_15(sb, 224u);
+  const float3x3 mat3x3_f32 = tint_symbol_16(sb, 256u);
+  const float3x4 mat3x4_f32 = tint_symbol_17(sb, 304u);
+  const float4x2 mat4x2_f32 = tint_symbol_18(sb, 352u);
+  const float4x3 mat4x3_f32 = tint_symbol_19(sb, 384u);
+  const float4x4 mat4x4_f32 = tint_symbol_20(sb, 448u);
+  const float3 arr2_vec3_f32[2] = tint_symbol_21(sb, 512u);
+  const Inner struct_inner = tint_symbol_22(sb, 544u);
+  const Inner array_struct_inner[4] = tint_symbol_23(sb, 552u);
   return;
 }
diff --git a/test/tint/buffer/storage/static_index/read.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/static_index/read.wgsl.expected.fxc.hlsl
index 501435d..49b16b2 100644
--- a/test/tint/buffer/storage/static_index/read.wgsl.expected.fxc.hlsl
+++ b/test/tint/buffer/storage/static_index/read.wgsl.expected.fxc.hlsl
@@ -1,44 +1,98 @@
 struct Inner {
-  int x;
+  int scalar_i32;
+  float scalar_f32;
 };
 
-ByteAddressBuffer s : register(t0, space0);
+ByteAddressBuffer sb : register(t0, space0);
 
-float2x3 tint_symbol_6(ByteAddressBuffer buffer, uint offset) {
+float2x2 tint_symbol_12(ByteAddressBuffer buffer, uint offset) {
+  return float2x2(asfloat(buffer.Load2((offset + 0u))), asfloat(buffer.Load2((offset + 8u))));
+}
+
+float2x3 tint_symbol_13(ByteAddressBuffer buffer, uint offset) {
   return float2x3(asfloat(buffer.Load3((offset + 0u))), asfloat(buffer.Load3((offset + 16u))));
 }
 
-float3x2 tint_symbol_7(ByteAddressBuffer buffer, uint offset) {
+float2x4 tint_symbol_14(ByteAddressBuffer buffer, uint offset) {
+  return float2x4(asfloat(buffer.Load4((offset + 0u))), asfloat(buffer.Load4((offset + 16u))));
+}
+
+float3x2 tint_symbol_15(ByteAddressBuffer buffer, uint offset) {
   return float3x2(asfloat(buffer.Load2((offset + 0u))), asfloat(buffer.Load2((offset + 8u))), asfloat(buffer.Load2((offset + 16u))));
 }
 
-Inner tint_symbol_9(ByteAddressBuffer buffer, uint offset) {
-  const Inner tint_symbol_11 = {asint(buffer.Load((offset + 0u)))};
-  return tint_symbol_11;
+float3x3 tint_symbol_16(ByteAddressBuffer buffer, uint offset) {
+  return float3x3(asfloat(buffer.Load3((offset + 0u))), asfloat(buffer.Load3((offset + 16u))), asfloat(buffer.Load3((offset + 32u))));
 }
 
-typedef Inner tint_symbol_10_ret[4];
-tint_symbol_10_ret tint_symbol_10(ByteAddressBuffer buffer, uint offset) {
-  Inner arr[4] = (Inner[4])0;
+float3x4 tint_symbol_17(ByteAddressBuffer buffer, uint offset) {
+  return float3x4(asfloat(buffer.Load4((offset + 0u))), asfloat(buffer.Load4((offset + 16u))), asfloat(buffer.Load4((offset + 32u))));
+}
+
+float4x2 tint_symbol_18(ByteAddressBuffer buffer, uint offset) {
+  return float4x2(asfloat(buffer.Load2((offset + 0u))), asfloat(buffer.Load2((offset + 8u))), asfloat(buffer.Load2((offset + 16u))), asfloat(buffer.Load2((offset + 24u))));
+}
+
+float4x3 tint_symbol_19(ByteAddressBuffer buffer, uint offset) {
+  return float4x3(asfloat(buffer.Load3((offset + 0u))), asfloat(buffer.Load3((offset + 16u))), asfloat(buffer.Load3((offset + 32u))), asfloat(buffer.Load3((offset + 48u))));
+}
+
+float4x4 tint_symbol_20(ByteAddressBuffer buffer, uint offset) {
+  return float4x4(asfloat(buffer.Load4((offset + 0u))), asfloat(buffer.Load4((offset + 16u))), asfloat(buffer.Load4((offset + 32u))), asfloat(buffer.Load4((offset + 48u))));
+}
+
+typedef float3 tint_symbol_21_ret[2];
+tint_symbol_21_ret tint_symbol_21(ByteAddressBuffer buffer, uint offset) {
+  float3 arr[2] = (float3[2])0;
   {
-    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
-      arr[i_1] = tint_symbol_9(buffer, (offset + (i_1 * 4u)));
+    for(uint i = 0u; (i < 2u); i = (i + 1u)) {
+      arr[i] = asfloat(buffer.Load3((offset + (i * 16u))));
     }
   }
   return arr;
 }
 
+Inner tint_symbol_22(ByteAddressBuffer buffer, uint offset) {
+  const Inner tint_symbol_24 = {asint(buffer.Load((offset + 0u))), asfloat(buffer.Load((offset + 4u)))};
+  return tint_symbol_24;
+}
+
+typedef Inner tint_symbol_23_ret[4];
+tint_symbol_23_ret tint_symbol_23(ByteAddressBuffer buffer, uint offset) {
+  Inner arr_1[4] = (Inner[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr_1[i_1] = tint_symbol_22(buffer, (offset + (i_1 * 8u)));
+    }
+  }
+  return arr_1;
+}
+
 [numthreads(1, 1, 1)]
 void main() {
-  const int3 a = asint(s.Load3(0u));
-  const int b = asint(s.Load(12u));
-  const uint3 c = s.Load3(16u);
-  const uint d = s.Load(28u);
-  const float3 e = asfloat(s.Load3(32u));
-  const float f = asfloat(s.Load(44u));
-  const float2x3 g = tint_symbol_6(s, 48u);
-  const float3x2 h = tint_symbol_7(s, 80u);
-  const Inner i = tint_symbol_9(s, 104u);
-  const Inner j[4] = tint_symbol_10(s, 108u);
+  const float scalar_f32 = asfloat(sb.Load(0u));
+  const int scalar_i32 = asint(sb.Load(4u));
+  const uint scalar_u32 = sb.Load(8u);
+  const float2 vec2_f32 = asfloat(sb.Load2(16u));
+  const int2 vec2_i32 = asint(sb.Load2(24u));
+  const uint2 vec2_u32 = sb.Load2(32u);
+  const float3 vec3_f32 = asfloat(sb.Load3(48u));
+  const int3 vec3_i32 = asint(sb.Load3(64u));
+  const uint3 vec3_u32 = sb.Load3(80u);
+  const float4 vec4_f32 = asfloat(sb.Load4(96u));
+  const int4 vec4_i32 = asint(sb.Load4(112u));
+  const uint4 vec4_u32 = sb.Load4(128u);
+  const float2x2 mat2x2_f32 = tint_symbol_12(sb, 144u);
+  const float2x3 mat2x3_f32 = tint_symbol_13(sb, 160u);
+  const float2x4 mat2x4_f32 = tint_symbol_14(sb, 192u);
+  const float3x2 mat3x2_f32 = tint_symbol_15(sb, 224u);
+  const float3x3 mat3x3_f32 = tint_symbol_16(sb, 256u);
+  const float3x4 mat3x4_f32 = tint_symbol_17(sb, 304u);
+  const float4x2 mat4x2_f32 = tint_symbol_18(sb, 352u);
+  const float4x3 mat4x3_f32 = tint_symbol_19(sb, 384u);
+  const float4x4 mat4x4_f32 = tint_symbol_20(sb, 448u);
+  const float3 arr2_vec3_f32[2] = tint_symbol_21(sb, 512u);
+  const Inner struct_inner = tint_symbol_22(sb, 544u);
+  const Inner array_struct_inner[4] = tint_symbol_23(sb, 552u);
   return;
 }
diff --git a/test/tint/buffer/storage/static_index/read.wgsl.expected.glsl b/test/tint/buffer/storage/static_index/read.wgsl.expected.glsl
index d2e4edd..59613b5 100644
--- a/test/tint/buffer/storage/static_index/read.wgsl.expected.glsl
+++ b/test/tint/buffer/storage/static_index/read.wgsl.expected.glsl
@@ -1,38 +1,76 @@
 #version 310 es
 
 struct Inner {
-  int x;
+  int scalar_i32;
+  float scalar_f32;
 };
 
 struct S {
-  ivec3 a;
-  int b;
-  uvec3 c;
-  uint d;
-  vec3 e;
-  float f;
-  mat2x3 g;
-  mat3x2 h;
-  Inner i;
-  Inner j[4];
+  float scalar_f32;
+  int scalar_i32;
+  uint scalar_u32;
   uint pad;
+  vec2 vec2_f32;
+  ivec2 vec2_i32;
+  uvec2 vec2_u32;
+  uint pad_1;
+  uint pad_2;
+  vec3 vec3_f32;
+  uint pad_3;
+  ivec3 vec3_i32;
+  uint pad_4;
+  uvec3 vec3_u32;
+  uint pad_5;
+  vec4 vec4_f32;
+  ivec4 vec4_i32;
+  uvec4 vec4_u32;
+  mat2 mat2x2_f32;
+  mat2x3 mat2x3_f32;
+  mat2x4 mat2x4_f32;
+  mat3x2 mat3x2_f32;
+  uint pad_6;
+  uint pad_7;
+  mat3 mat3x3_f32;
+  mat3x4 mat3x4_f32;
+  mat4x2 mat4x2_f32;
+  mat4x3 mat4x3_f32;
+  mat4 mat4x4_f32;
+  vec3 arr2_vec3_f32[2];
+  Inner struct_inner;
+  Inner array_struct_inner[4];
+  uint pad_8;
+  uint pad_9;
 };
 
-layout(binding = 0, std430) buffer s_block_ssbo {
+layout(binding = 0, std430) buffer sb_block_ssbo {
   S inner;
-} s;
+} sb;
 
 void tint_symbol() {
-  ivec3 a = s.inner.a;
-  int b = s.inner.b;
-  uvec3 c = s.inner.c;
-  uint d = s.inner.d;
-  vec3 e = s.inner.e;
-  float f = s.inner.f;
-  mat2x3 g = s.inner.g;
-  mat3x2 h = s.inner.h;
-  Inner i = s.inner.i;
-  Inner j[4] = s.inner.j;
+  float scalar_f32 = sb.inner.scalar_f32;
+  int scalar_i32 = sb.inner.scalar_i32;
+  uint scalar_u32 = sb.inner.scalar_u32;
+  vec2 vec2_f32 = sb.inner.vec2_f32;
+  ivec2 vec2_i32 = sb.inner.vec2_i32;
+  uvec2 vec2_u32 = sb.inner.vec2_u32;
+  vec3 vec3_f32 = sb.inner.vec3_f32;
+  ivec3 vec3_i32 = sb.inner.vec3_i32;
+  uvec3 vec3_u32 = sb.inner.vec3_u32;
+  vec4 vec4_f32 = sb.inner.vec4_f32;
+  ivec4 vec4_i32 = sb.inner.vec4_i32;
+  uvec4 vec4_u32 = sb.inner.vec4_u32;
+  mat2 mat2x2_f32 = sb.inner.mat2x2_f32;
+  mat2x3 mat2x3_f32 = sb.inner.mat2x3_f32;
+  mat2x4 mat2x4_f32 = sb.inner.mat2x4_f32;
+  mat3x2 mat3x2_f32 = sb.inner.mat3x2_f32;
+  mat3 mat3x3_f32 = sb.inner.mat3x3_f32;
+  mat3x4 mat3x4_f32 = sb.inner.mat3x4_f32;
+  mat4x2 mat4x2_f32 = sb.inner.mat4x2_f32;
+  mat4x3 mat4x3_f32 = sb.inner.mat4x3_f32;
+  mat4 mat4x4_f32 = sb.inner.mat4x4_f32;
+  vec3 arr2_vec3_f32[2] = sb.inner.arr2_vec3_f32;
+  Inner struct_inner = sb.inner.struct_inner;
+  Inner array_struct_inner[4] = sb.inner.array_struct_inner;
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/buffer/storage/static_index/read.wgsl.expected.msl b/test/tint/buffer/storage/static_index/read.wgsl.expected.msl
index db51912..b0707fe 100644
--- a/test/tint/buffer/storage/static_index/read.wgsl.expected.msl
+++ b/test/tint/buffer/storage/static_index/read.wgsl.expected.msl
@@ -15,34 +15,69 @@
 };
 
 struct Inner {
-  /* 0x0000 */ int x;
+  /* 0x0000 */ int scalar_i32;
+  /* 0x0004 */ float scalar_f32;
 };
 
 struct S {
-  /* 0x0000 */ packed_int3 a;
-  /* 0x000c */ int b;
-  /* 0x0010 */ packed_uint3 c;
-  /* 0x001c */ uint d;
-  /* 0x0020 */ packed_float3 e;
-  /* 0x002c */ float f;
-  /* 0x0030 */ float2x3 g;
-  /* 0x0050 */ float3x2 h;
-  /* 0x0068 */ Inner i;
-  /* 0x006c */ tint_array<Inner, 4> j;
-  /* 0x007c */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0000 */ float scalar_f32;
+  /* 0x0004 */ int scalar_i32;
+  /* 0x0008 */ uint scalar_u32;
+  /* 0x000c */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0010 */ float2 vec2_f32;
+  /* 0x0018 */ int2 vec2_i32;
+  /* 0x0020 */ uint2 vec2_u32;
+  /* 0x0028 */ tint_array<int8_t, 8> tint_pad_1;
+  /* 0x0030 */ packed_float3 vec3_f32;
+  /* 0x003c */ tint_array<int8_t, 4> tint_pad_2;
+  /* 0x0040 */ packed_int3 vec3_i32;
+  /* 0x004c */ tint_array<int8_t, 4> tint_pad_3;
+  /* 0x0050 */ packed_uint3 vec3_u32;
+  /* 0x005c */ tint_array<int8_t, 4> tint_pad_4;
+  /* 0x0060 */ float4 vec4_f32;
+  /* 0x0070 */ int4 vec4_i32;
+  /* 0x0080 */ uint4 vec4_u32;
+  /* 0x0090 */ float2x2 mat2x2_f32;
+  /* 0x00a0 */ float2x3 mat2x3_f32;
+  /* 0x00c0 */ float2x4 mat2x4_f32;
+  /* 0x00e0 */ float3x2 mat3x2_f32;
+  /* 0x00f8 */ tint_array<int8_t, 8> tint_pad_5;
+  /* 0x0100 */ float3x3 mat3x3_f32;
+  /* 0x0130 */ float3x4 mat3x4_f32;
+  /* 0x0160 */ float4x2 mat4x2_f32;
+  /* 0x0180 */ float4x3 mat4x3_f32;
+  /* 0x01c0 */ float4x4 mat4x4_f32;
+  /* 0x0200 */ tint_array<float3, 2> arr2_vec3_f32;
+  /* 0x0220 */ Inner struct_inner;
+  /* 0x0228 */ tint_array<Inner, 4> array_struct_inner;
+  /* 0x0248 */ tint_array<int8_t, 8> tint_pad_6;
 };
 
 kernel void tint_symbol(const device S* tint_symbol_1 [[buffer(0)]]) {
-  int3 const a = int3((*(tint_symbol_1)).a);
-  int const b = (*(tint_symbol_1)).b;
-  uint3 const c = uint3((*(tint_symbol_1)).c);
-  uint const d = (*(tint_symbol_1)).d;
-  float3 const e = float3((*(tint_symbol_1)).e);
-  float const f = (*(tint_symbol_1)).f;
-  float2x3 const g = (*(tint_symbol_1)).g;
-  float3x2 const h = (*(tint_symbol_1)).h;
-  Inner const i = (*(tint_symbol_1)).i;
-  tint_array<Inner, 4> const j = (*(tint_symbol_1)).j;
+  float const scalar_f32 = (*(tint_symbol_1)).scalar_f32;
+  int const scalar_i32 = (*(tint_symbol_1)).scalar_i32;
+  uint const scalar_u32 = (*(tint_symbol_1)).scalar_u32;
+  float2 const vec2_f32 = (*(tint_symbol_1)).vec2_f32;
+  int2 const vec2_i32 = (*(tint_symbol_1)).vec2_i32;
+  uint2 const vec2_u32 = (*(tint_symbol_1)).vec2_u32;
+  float3 const vec3_f32 = float3((*(tint_symbol_1)).vec3_f32);
+  int3 const vec3_i32 = int3((*(tint_symbol_1)).vec3_i32);
+  uint3 const vec3_u32 = uint3((*(tint_symbol_1)).vec3_u32);
+  float4 const vec4_f32 = (*(tint_symbol_1)).vec4_f32;
+  int4 const vec4_i32 = (*(tint_symbol_1)).vec4_i32;
+  uint4 const vec4_u32 = (*(tint_symbol_1)).vec4_u32;
+  float2x2 const mat2x2_f32 = (*(tint_symbol_1)).mat2x2_f32;
+  float2x3 const mat2x3_f32 = (*(tint_symbol_1)).mat2x3_f32;
+  float2x4 const mat2x4_f32 = (*(tint_symbol_1)).mat2x4_f32;
+  float3x2 const mat3x2_f32 = (*(tint_symbol_1)).mat3x2_f32;
+  float3x3 const mat3x3_f32 = (*(tint_symbol_1)).mat3x3_f32;
+  float3x4 const mat3x4_f32 = (*(tint_symbol_1)).mat3x4_f32;
+  float4x2 const mat4x2_f32 = (*(tint_symbol_1)).mat4x2_f32;
+  float4x3 const mat4x3_f32 = (*(tint_symbol_1)).mat4x3_f32;
+  float4x4 const mat4x4_f32 = (*(tint_symbol_1)).mat4x4_f32;
+  tint_array<float3, 2> const arr2_vec3_f32 = (*(tint_symbol_1)).arr2_vec3_f32;
+  Inner const struct_inner = (*(tint_symbol_1)).struct_inner;
+  tint_array<Inner, 4> const array_struct_inner = (*(tint_symbol_1)).array_struct_inner;
   return;
 }
 
diff --git a/test/tint/buffer/storage/static_index/read.wgsl.expected.spvasm b/test/tint/buffer/storage/static_index/read.wgsl.expected.spvasm
index e301a46..c137494 100644
--- a/test/tint/buffer/storage/static_index/read.wgsl.expected.spvasm
+++ b/test/tint/buffer/storage/static_index/read.wgsl.expected.spvasm
@@ -1,108 +1,222 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 60
+; Bound: 129
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %main "main"
                OpExecutionMode %main LocalSize 1 1 1
-               OpName %s_block "s_block"
-               OpMemberName %s_block 0 "inner"
+               OpName %sb_block "sb_block"
+               OpMemberName %sb_block 0 "inner"
                OpName %S "S"
-               OpMemberName %S 0 "a"
-               OpMemberName %S 1 "b"
-               OpMemberName %S 2 "c"
-               OpMemberName %S 3 "d"
-               OpMemberName %S 4 "e"
-               OpMemberName %S 5 "f"
-               OpMemberName %S 6 "g"
-               OpMemberName %S 7 "h"
-               OpMemberName %S 8 "i"
+               OpMemberName %S 0 "scalar_f32"
+               OpMemberName %S 1 "scalar_i32"
+               OpMemberName %S 2 "scalar_u32"
+               OpMemberName %S 3 "vec2_f32"
+               OpMemberName %S 4 "vec2_i32"
+               OpMemberName %S 5 "vec2_u32"
+               OpMemberName %S 6 "vec3_f32"
+               OpMemberName %S 7 "vec3_i32"
+               OpMemberName %S 8 "vec3_u32"
+               OpMemberName %S 9 "vec4_f32"
+               OpMemberName %S 10 "vec4_i32"
+               OpMemberName %S 11 "vec4_u32"
+               OpMemberName %S 12 "mat2x2_f32"
+               OpMemberName %S 13 "mat2x3_f32"
+               OpMemberName %S 14 "mat2x4_f32"
+               OpMemberName %S 15 "mat3x2_f32"
+               OpMemberName %S 16 "mat3x3_f32"
+               OpMemberName %S 17 "mat3x4_f32"
+               OpMemberName %S 18 "mat4x2_f32"
+               OpMemberName %S 19 "mat4x3_f32"
+               OpMemberName %S 20 "mat4x4_f32"
+               OpMemberName %S 21 "arr2_vec3_f32"
+               OpMemberName %S 22 "struct_inner"
                OpName %Inner "Inner"
-               OpMemberName %Inner 0 "x"
-               OpMemberName %S 9 "j"
-               OpName %s "s"
+               OpMemberName %Inner 0 "scalar_i32"
+               OpMemberName %Inner 1 "scalar_f32"
+               OpMemberName %S 23 "array_struct_inner"
+               OpName %sb "sb"
                OpName %main "main"
-               OpDecorate %s_block Block
-               OpMemberDecorate %s_block 0 Offset 0
+               OpDecorate %sb_block Block
+               OpMemberDecorate %sb_block 0 Offset 0
                OpMemberDecorate %S 0 Offset 0
-               OpMemberDecorate %S 1 Offset 12
-               OpMemberDecorate %S 2 Offset 16
-               OpMemberDecorate %S 3 Offset 28
-               OpMemberDecorate %S 4 Offset 32
-               OpMemberDecorate %S 5 Offset 44
+               OpMemberDecorate %S 1 Offset 4
+               OpMemberDecorate %S 2 Offset 8
+               OpMemberDecorate %S 3 Offset 16
+               OpMemberDecorate %S 4 Offset 24
+               OpMemberDecorate %S 5 Offset 32
                OpMemberDecorate %S 6 Offset 48
-               OpMemberDecorate %S 6 ColMajor
-               OpMemberDecorate %S 6 MatrixStride 16
-               OpMemberDecorate %S 7 Offset 80
-               OpMemberDecorate %S 7 ColMajor
-               OpMemberDecorate %S 7 MatrixStride 8
-               OpMemberDecorate %S 8 Offset 104
+               OpMemberDecorate %S 7 Offset 64
+               OpMemberDecorate %S 8 Offset 80
+               OpMemberDecorate %S 9 Offset 96
+               OpMemberDecorate %S 10 Offset 112
+               OpMemberDecorate %S 11 Offset 128
+               OpMemberDecorate %S 12 Offset 144
+               OpMemberDecorate %S 12 ColMajor
+               OpMemberDecorate %S 12 MatrixStride 8
+               OpMemberDecorate %S 13 Offset 160
+               OpMemberDecorate %S 13 ColMajor
+               OpMemberDecorate %S 13 MatrixStride 16
+               OpMemberDecorate %S 14 Offset 192
+               OpMemberDecorate %S 14 ColMajor
+               OpMemberDecorate %S 14 MatrixStride 16
+               OpMemberDecorate %S 15 Offset 224
+               OpMemberDecorate %S 15 ColMajor
+               OpMemberDecorate %S 15 MatrixStride 8
+               OpMemberDecorate %S 16 Offset 256
+               OpMemberDecorate %S 16 ColMajor
+               OpMemberDecorate %S 16 MatrixStride 16
+               OpMemberDecorate %S 17 Offset 304
+               OpMemberDecorate %S 17 ColMajor
+               OpMemberDecorate %S 17 MatrixStride 16
+               OpMemberDecorate %S 18 Offset 352
+               OpMemberDecorate %S 18 ColMajor
+               OpMemberDecorate %S 18 MatrixStride 8
+               OpMemberDecorate %S 19 Offset 384
+               OpMemberDecorate %S 19 ColMajor
+               OpMemberDecorate %S 19 MatrixStride 16
+               OpMemberDecorate %S 20 Offset 448
+               OpMemberDecorate %S 20 ColMajor
+               OpMemberDecorate %S 20 MatrixStride 16
+               OpMemberDecorate %S 21 Offset 512
+               OpDecorate %_arr_v3float_uint_2 ArrayStride 16
+               OpMemberDecorate %S 22 Offset 544
                OpMemberDecorate %Inner 0 Offset 0
-               OpMemberDecorate %S 9 Offset 108
-               OpDecorate %_arr_Inner_uint_4 ArrayStride 4
-               OpDecorate %s NonWritable
-               OpDecorate %s Binding 0
-               OpDecorate %s DescriptorSet 0
-        %int = OpTypeInt 32 1
-      %v3int = OpTypeVector %int 3
-       %uint = OpTypeInt 32 0
-     %v3uint = OpTypeVector %uint 3
+               OpMemberDecorate %Inner 1 Offset 4
+               OpMemberDecorate %S 23 Offset 552
+               OpDecorate %_arr_Inner_uint_4 ArrayStride 8
+               OpDecorate %sb NonWritable
+               OpDecorate %sb Binding 0
+               OpDecorate %sb DescriptorSet 0
       %float = OpTypeFloat 32
-    %v3float = OpTypeVector %float 3
-%mat2v3float = OpTypeMatrix %v3float 2
+        %int = OpTypeInt 32 1
+       %uint = OpTypeInt 32 0
     %v2float = OpTypeVector %float 2
+      %v2int = OpTypeVector %int 2
+     %v2uint = OpTypeVector %uint 2
+    %v3float = OpTypeVector %float 3
+      %v3int = OpTypeVector %int 3
+     %v3uint = OpTypeVector %uint 3
+    %v4float = OpTypeVector %float 4
+      %v4int = OpTypeVector %int 4
+     %v4uint = OpTypeVector %uint 4
+%mat2v2float = OpTypeMatrix %v2float 2
+%mat2v3float = OpTypeMatrix %v3float 2
+%mat2v4float = OpTypeMatrix %v4float 2
 %mat3v2float = OpTypeMatrix %v2float 3
-      %Inner = OpTypeStruct %int
+%mat3v3float = OpTypeMatrix %v3float 3
+%mat3v4float = OpTypeMatrix %v4float 3
+%mat4v2float = OpTypeMatrix %v2float 4
+%mat4v3float = OpTypeMatrix %v3float 4
+%mat4v4float = OpTypeMatrix %v4float 4
+     %uint_2 = OpConstant %uint 2
+%_arr_v3float_uint_2 = OpTypeArray %v3float %uint_2
+      %Inner = OpTypeStruct %int %float
      %uint_4 = OpConstant %uint 4
 %_arr_Inner_uint_4 = OpTypeArray %Inner %uint_4
-          %S = OpTypeStruct %v3int %int %v3uint %uint %v3float %float %mat2v3float %mat3v2float %Inner %_arr_Inner_uint_4
-    %s_block = OpTypeStruct %S
-%_ptr_StorageBuffer_s_block = OpTypePointer StorageBuffer %s_block
-          %s = OpVariable %_ptr_StorageBuffer_s_block StorageBuffer
+          %S = OpTypeStruct %float %int %uint %v2float %v2int %v2uint %v3float %v3int %v3uint %v4float %v4int %v4uint %mat2v2float %mat2v3float %mat2v4float %mat3v2float %mat3v3float %mat3v4float %mat4v2float %mat4v3float %mat4v4float %_arr_v3float_uint_2 %Inner %_arr_Inner_uint_4
+   %sb_block = OpTypeStruct %S
+%_ptr_StorageBuffer_sb_block = OpTypePointer StorageBuffer %sb_block
+         %sb = OpVariable %_ptr_StorageBuffer_sb_block StorageBuffer
        %void = OpTypeVoid
-         %17 = OpTypeFunction %void
+         %31 = OpTypeFunction %void
      %uint_0 = OpConstant %uint 0
-%_ptr_StorageBuffer_v3int = OpTypePointer StorageBuffer %v3int
+%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_int = OpTypePointer StorageBuffer %int
-     %uint_2 = OpConstant %uint 2
-%_ptr_StorageBuffer_v3uint = OpTypePointer StorageBuffer %v3uint
-     %uint_3 = OpConstant %uint 3
 %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
-%_ptr_StorageBuffer_v3float = OpTypePointer StorageBuffer %v3float
+     %uint_3 = OpConstant %uint 3
+%_ptr_StorageBuffer_v2float = OpTypePointer StorageBuffer %v2float
+%_ptr_StorageBuffer_v2int = OpTypePointer StorageBuffer %v2int
      %uint_5 = OpConstant %uint 5
-%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
+%_ptr_StorageBuffer_v2uint = OpTypePointer StorageBuffer %v2uint
      %uint_6 = OpConstant %uint 6
-%_ptr_StorageBuffer_mat2v3float = OpTypePointer StorageBuffer %mat2v3float
+%_ptr_StorageBuffer_v3float = OpTypePointer StorageBuffer %v3float
      %uint_7 = OpConstant %uint 7
-%_ptr_StorageBuffer_mat3v2float = OpTypePointer StorageBuffer %mat3v2float
+%_ptr_StorageBuffer_v3int = OpTypePointer StorageBuffer %v3int
      %uint_8 = OpConstant %uint 8
-%_ptr_StorageBuffer_Inner = OpTypePointer StorageBuffer %Inner
+%_ptr_StorageBuffer_v3uint = OpTypePointer StorageBuffer %v3uint
      %uint_9 = OpConstant %uint 9
+%_ptr_StorageBuffer_v4float = OpTypePointer StorageBuffer %v4float
+    %uint_10 = OpConstant %uint 10
+%_ptr_StorageBuffer_v4int = OpTypePointer StorageBuffer %v4int
+    %uint_11 = OpConstant %uint 11
+%_ptr_StorageBuffer_v4uint = OpTypePointer StorageBuffer %v4uint
+    %uint_12 = OpConstant %uint 12
+%_ptr_StorageBuffer_mat2v2float = OpTypePointer StorageBuffer %mat2v2float
+    %uint_13 = OpConstant %uint 13
+%_ptr_StorageBuffer_mat2v3float = OpTypePointer StorageBuffer %mat2v3float
+    %uint_14 = OpConstant %uint 14
+%_ptr_StorageBuffer_mat2v4float = OpTypePointer StorageBuffer %mat2v4float
+    %uint_15 = OpConstant %uint 15
+%_ptr_StorageBuffer_mat3v2float = OpTypePointer StorageBuffer %mat3v2float
+    %uint_16 = OpConstant %uint 16
+%_ptr_StorageBuffer_mat3v3float = OpTypePointer StorageBuffer %mat3v3float
+    %uint_17 = OpConstant %uint 17
+%_ptr_StorageBuffer_mat3v4float = OpTypePointer StorageBuffer %mat3v4float
+    %uint_18 = OpConstant %uint 18
+%_ptr_StorageBuffer_mat4v2float = OpTypePointer StorageBuffer %mat4v2float
+    %uint_19 = OpConstant %uint 19
+%_ptr_StorageBuffer_mat4v3float = OpTypePointer StorageBuffer %mat4v3float
+    %uint_20 = OpConstant %uint 20
+%_ptr_StorageBuffer_mat4v4float = OpTypePointer StorageBuffer %mat4v4float
+    %uint_21 = OpConstant %uint 21
+%_ptr_StorageBuffer__arr_v3float_uint_2 = OpTypePointer StorageBuffer %_arr_v3float_uint_2
+    %uint_22 = OpConstant %uint 22
+%_ptr_StorageBuffer_Inner = OpTypePointer StorageBuffer %Inner
+    %uint_23 = OpConstant %uint 23
 %_ptr_StorageBuffer__arr_Inner_uint_4 = OpTypePointer StorageBuffer %_arr_Inner_uint_4
-       %main = OpFunction %void None %17
-         %20 = OpLabel
-         %23 = OpAccessChain %_ptr_StorageBuffer_v3int %s %uint_0 %uint_0
-         %24 = OpLoad %v3int %23
-         %27 = OpAccessChain %_ptr_StorageBuffer_int %s %uint_0 %uint_1
-         %28 = OpLoad %int %27
-         %31 = OpAccessChain %_ptr_StorageBuffer_v3uint %s %uint_0 %uint_2
-         %32 = OpLoad %v3uint %31
-         %35 = OpAccessChain %_ptr_StorageBuffer_uint %s %uint_0 %uint_3
-         %36 = OpLoad %uint %35
-         %38 = OpAccessChain %_ptr_StorageBuffer_v3float %s %uint_0 %uint_4
-         %39 = OpLoad %v3float %38
-         %42 = OpAccessChain %_ptr_StorageBuffer_float %s %uint_0 %uint_5
-         %43 = OpLoad %float %42
-         %46 = OpAccessChain %_ptr_StorageBuffer_mat2v3float %s %uint_0 %uint_6
-         %47 = OpLoad %mat2v3float %46
-         %50 = OpAccessChain %_ptr_StorageBuffer_mat3v2float %s %uint_0 %uint_7
-         %51 = OpLoad %mat3v2float %50
-         %54 = OpAccessChain %_ptr_StorageBuffer_Inner %s %uint_0 %uint_8
-         %55 = OpLoad %Inner %54
-         %58 = OpAccessChain %_ptr_StorageBuffer__arr_Inner_uint_4 %s %uint_0 %uint_9
-         %59 = OpLoad %_arr_Inner_uint_4 %58
+       %main = OpFunction %void None %31
+         %34 = OpLabel
+         %37 = OpAccessChain %_ptr_StorageBuffer_float %sb %uint_0 %uint_0
+         %38 = OpLoad %float %37
+         %41 = OpAccessChain %_ptr_StorageBuffer_int %sb %uint_0 %uint_1
+         %42 = OpLoad %int %41
+         %44 = OpAccessChain %_ptr_StorageBuffer_uint %sb %uint_0 %uint_2
+         %45 = OpLoad %uint %44
+         %48 = OpAccessChain %_ptr_StorageBuffer_v2float %sb %uint_0 %uint_3
+         %49 = OpLoad %v2float %48
+         %51 = OpAccessChain %_ptr_StorageBuffer_v2int %sb %uint_0 %uint_4
+         %52 = OpLoad %v2int %51
+         %55 = OpAccessChain %_ptr_StorageBuffer_v2uint %sb %uint_0 %uint_5
+         %56 = OpLoad %v2uint %55
+         %59 = OpAccessChain %_ptr_StorageBuffer_v3float %sb %uint_0 %uint_6
+         %60 = OpLoad %v3float %59
+         %63 = OpAccessChain %_ptr_StorageBuffer_v3int %sb %uint_0 %uint_7
+         %64 = OpLoad %v3int %63
+         %67 = OpAccessChain %_ptr_StorageBuffer_v3uint %sb %uint_0 %uint_8
+         %68 = OpLoad %v3uint %67
+         %71 = OpAccessChain %_ptr_StorageBuffer_v4float %sb %uint_0 %uint_9
+         %72 = OpLoad %v4float %71
+         %75 = OpAccessChain %_ptr_StorageBuffer_v4int %sb %uint_0 %uint_10
+         %76 = OpLoad %v4int %75
+         %79 = OpAccessChain %_ptr_StorageBuffer_v4uint %sb %uint_0 %uint_11
+         %80 = OpLoad %v4uint %79
+         %83 = OpAccessChain %_ptr_StorageBuffer_mat2v2float %sb %uint_0 %uint_12
+         %84 = OpLoad %mat2v2float %83
+         %87 = OpAccessChain %_ptr_StorageBuffer_mat2v3float %sb %uint_0 %uint_13
+         %88 = OpLoad %mat2v3float %87
+         %91 = OpAccessChain %_ptr_StorageBuffer_mat2v4float %sb %uint_0 %uint_14
+         %92 = OpLoad %mat2v4float %91
+         %95 = OpAccessChain %_ptr_StorageBuffer_mat3v2float %sb %uint_0 %uint_15
+         %96 = OpLoad %mat3v2float %95
+         %99 = OpAccessChain %_ptr_StorageBuffer_mat3v3float %sb %uint_0 %uint_16
+        %100 = OpLoad %mat3v3float %99
+        %103 = OpAccessChain %_ptr_StorageBuffer_mat3v4float %sb %uint_0 %uint_17
+        %104 = OpLoad %mat3v4float %103
+        %107 = OpAccessChain %_ptr_StorageBuffer_mat4v2float %sb %uint_0 %uint_18
+        %108 = OpLoad %mat4v2float %107
+        %111 = OpAccessChain %_ptr_StorageBuffer_mat4v3float %sb %uint_0 %uint_19
+        %112 = OpLoad %mat4v3float %111
+        %115 = OpAccessChain %_ptr_StorageBuffer_mat4v4float %sb %uint_0 %uint_20
+        %116 = OpLoad %mat4v4float %115
+        %119 = OpAccessChain %_ptr_StorageBuffer__arr_v3float_uint_2 %sb %uint_0 %uint_21
+        %120 = OpLoad %_arr_v3float_uint_2 %119
+        %123 = OpAccessChain %_ptr_StorageBuffer_Inner %sb %uint_0 %uint_22
+        %124 = OpLoad %Inner %123
+        %127 = OpAccessChain %_ptr_StorageBuffer__arr_Inner_uint_4 %sb %uint_0 %uint_23
+        %128 = OpLoad %_arr_Inner_uint_4 %127
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/buffer/storage/static_index/read.wgsl.expected.wgsl b/test/tint/buffer/storage/static_index/read.wgsl.expected.wgsl
index 89ab3c2..a978937 100644
--- a/test/tint/buffer/storage/static_index/read.wgsl.expected.wgsl
+++ b/test/tint/buffer/storage/static_index/read.wgsl.expected.wgsl
@@ -1,32 +1,61 @@
 struct Inner {
-  x : i32,
+  scalar_i32 : i32,
+  scalar_f32 : f32,
 }
 
 struct S {
-  a : vec3<i32>,
-  b : i32,
-  c : vec3<u32>,
-  d : u32,
-  e : vec3<f32>,
-  f : f32,
-  g : mat2x3<f32>,
-  h : mat3x2<f32>,
-  i : Inner,
-  j : array<Inner, 4>,
+  scalar_f32 : f32,
+  scalar_i32 : i32,
+  scalar_u32 : u32,
+  vec2_f32 : vec2<f32>,
+  vec2_i32 : vec2<i32>,
+  vec2_u32 : vec2<u32>,
+  vec3_f32 : vec3<f32>,
+  vec3_i32 : vec3<i32>,
+  vec3_u32 : vec3<u32>,
+  vec4_f32 : vec4<f32>,
+  vec4_i32 : vec4<i32>,
+  vec4_u32 : vec4<u32>,
+  mat2x2_f32 : mat2x2<f32>,
+  mat2x3_f32 : mat2x3<f32>,
+  mat2x4_f32 : mat2x4<f32>,
+  mat3x2_f32 : mat3x2<f32>,
+  mat3x3_f32 : mat3x3<f32>,
+  mat3x4_f32 : mat3x4<f32>,
+  mat4x2_f32 : mat4x2<f32>,
+  mat4x3_f32 : mat4x3<f32>,
+  mat4x4_f32 : mat4x4<f32>,
+  arr2_vec3_f32 : array<vec3<f32>, 2>,
+  struct_inner : Inner,
+  array_struct_inner : array<Inner, 4>,
 }
 
-@binding(0) @group(0) var<storage, read> s : S;
+@binding(0) @group(0) var<storage, read> sb : S;
 
 @compute @workgroup_size(1)
 fn main() {
-  let a = s.a;
-  let b = s.b;
-  let c = s.c;
-  let d = s.d;
-  let e = s.e;
-  let f = s.f;
-  let g = s.g;
-  let h = s.h;
-  let i = s.i;
-  let j = s.j;
+  let scalar_f32 = sb.scalar_f32;
+  let scalar_i32 = sb.scalar_i32;
+  let scalar_u32 = sb.scalar_u32;
+  let vec2_f32 = sb.vec2_f32;
+  let vec2_i32 = sb.vec2_i32;
+  let vec2_u32 = sb.vec2_u32;
+  let vec3_f32 = sb.vec3_f32;
+  let vec3_i32 = sb.vec3_i32;
+  let vec3_u32 = sb.vec3_u32;
+  let vec4_f32 = sb.vec4_f32;
+  let vec4_i32 = sb.vec4_i32;
+  let vec4_u32 = sb.vec4_u32;
+  let mat2x2_f32 = sb.mat2x2_f32;
+  let mat2x3_f32 = sb.mat2x3_f32;
+  let mat2x4_f32 = sb.mat2x4_f32;
+  let mat3x2_f32 = sb.mat3x2_f32;
+  let mat3x3_f32 = sb.mat3x3_f32;
+  let mat3x4_f32 = sb.mat3x4_f32;
+  let mat4x2_f32 = sb.mat4x2_f32;
+  let mat4x3_f32 = sb.mat4x3_f32;
+  let mat4x4_f32 = sb.mat4x4_f32;
+  let arr2_vec3_f32 = sb.arr2_vec3_f32;
+  let struct_inner = sb.struct_inner;
+  let array_struct_inner = sb.array_struct_inner;
 }
diff --git a/test/tint/buffer/storage/static_index/read_f16.wgsl b/test/tint/buffer/storage/static_index/read_f16.wgsl
new file mode 100644
index 0000000..5e8d2d1
--- /dev/null
+++ b/test/tint/buffer/storage/static_index/read_f16.wgsl
@@ -0,0 +1,92 @@
+enable f16;
+
+struct Inner {
+    scalar_i32 : i32,
+    scalar_f32 : f32,
+    scalar_f16 : f16,
+};
+
+struct S {
+    scalar_f32 : f32,
+    scalar_i32 : i32,
+    scalar_u32 : u32,
+    scalar_f16 : f16,
+    vec2_f32 : vec2<f32>,
+    vec2_i32 : vec2<i32>,
+    vec2_u32 : vec2<u32>,
+    vec2_f16 : vec2<f16>,
+    vec3_f32 : vec3<f32>,
+    vec3_i32 : vec3<i32>,
+    vec3_u32 : vec3<u32>,
+    vec3_f16 : vec3<f16>,
+    vec4_f32 : vec4<f32>,
+    vec4_i32 : vec4<i32>,
+    vec4_u32 : vec4<u32>,
+    vec4_f16 : vec4<f16>,
+    mat2x2_f32 : mat2x2<f32>,
+    mat2x3_f32 : mat2x3<f32>,
+    mat2x4_f32 : mat2x4<f32>,
+    mat3x2_f32 : mat3x2<f32>,
+    mat3x3_f32 : mat3x3<f32>,
+    mat3x4_f32 : mat3x4<f32>,
+    mat4x2_f32 : mat4x2<f32>,
+    mat4x3_f32 : mat4x3<f32>,
+    mat4x4_f32 : mat4x4<f32>,
+    mat2x2_f16 : mat2x2<f16>,
+    mat2x3_f16 : mat2x3<f16>,
+    mat2x4_f16 : mat2x4<f16>,
+    mat3x2_f16 : mat3x2<f16>,
+    mat3x3_f16 : mat3x3<f16>,
+    mat3x4_f16 : mat3x4<f16>,
+    mat4x2_f16 : mat4x2<f16>,
+    mat4x3_f16 : mat4x3<f16>,
+    mat4x4_f16 : mat4x4<f16>,
+    arr2_vec3_f32 : array<vec3<f32>, 2>,
+    arr2_mat4x2_f16 : array<mat4x2<f16>, 2>,
+    struct_inner : Inner,
+    array_struct_inner : array<Inner, 4>,
+};
+
+@binding(0) @group(0) var<storage, read> sb : S;
+
+@compute @workgroup_size(1)
+fn main() {
+    let scalar_f32 = sb.scalar_f32;
+    let scalar_i32 = sb.scalar_i32;
+    let scalar_u32 = sb.scalar_u32;
+    let scalar_f16 = sb.scalar_f16;
+    let vec2_f32 = sb.vec2_f32;
+    let vec2_i32 = sb.vec2_i32;
+    let vec2_u32 = sb.vec2_u32;
+    let vec2_f16 = sb.vec2_f16;
+    let vec3_f32 = sb.vec3_f32;
+    let vec3_i32 = sb.vec3_i32;
+    let vec3_u32 = sb.vec3_u32;
+    let vec3_f16 = sb.vec3_f16;
+    let vec4_f32 = sb.vec4_f32;
+    let vec4_i32 = sb.vec4_i32;
+    let vec4_u32 = sb.vec4_u32;
+    let vec4_f16 = sb.vec4_f16;
+    let mat2x2_f32 = sb.mat2x2_f32;
+    let mat2x3_f32 = sb.mat2x3_f32;
+    let mat2x4_f32 = sb.mat2x4_f32;
+    let mat3x2_f32 = sb.mat3x2_f32;
+    let mat3x3_f32 = sb.mat3x3_f32;
+    let mat3x4_f32 = sb.mat3x4_f32;
+    let mat4x2_f32 = sb.mat4x2_f32;
+    let mat4x3_f32 = sb.mat4x3_f32;
+    let mat4x4_f32 = sb.mat4x4_f32;
+    let mat2x2_f16 = sb.mat2x2_f16;
+    let mat2x3_f16 = sb.mat2x3_f16;
+    let mat2x4_f16 = sb.mat2x4_f16;
+    let mat3x2_f16 = sb.mat3x2_f16;
+    let mat3x3_f16 = sb.mat3x3_f16;
+    let mat3x4_f16 = sb.mat3x4_f16;
+    let mat4x2_f16 = sb.mat4x2_f16;
+    let mat4x3_f16 = sb.mat4x3_f16;
+    let mat4x4_f16 = sb.mat4x4_f16;
+    let arr2_vec3_f32 = sb.arr2_vec3_f32;
+    let arr2_mat4x2_f16 = sb.arr2_mat4x2_f16;
+    let struct_inner = sb.struct_inner;
+    let array_struct_inner = sb.array_struct_inner;
+}
diff --git a/test/tint/buffer/storage/static_index/read_f16.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/static_index/read_f16.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..e0be8a3
--- /dev/null
+++ b/test/tint/buffer/storage/static_index/read_f16.wgsl.expected.dxc.hlsl
@@ -0,0 +1,160 @@
+struct Inner {
+  int scalar_i32;
+  float scalar_f32;
+  float16_t scalar_f16;
+};
+
+ByteAddressBuffer sb : register(t0, space0);
+
+float2x2 tint_symbol_16(ByteAddressBuffer buffer, uint offset) {
+  return float2x2(asfloat(buffer.Load2((offset + 0u))), asfloat(buffer.Load2((offset + 8u))));
+}
+
+float2x3 tint_symbol_17(ByteAddressBuffer buffer, uint offset) {
+  return float2x3(asfloat(buffer.Load3((offset + 0u))), asfloat(buffer.Load3((offset + 16u))));
+}
+
+float2x4 tint_symbol_18(ByteAddressBuffer buffer, uint offset) {
+  return float2x4(asfloat(buffer.Load4((offset + 0u))), asfloat(buffer.Load4((offset + 16u))));
+}
+
+float3x2 tint_symbol_19(ByteAddressBuffer buffer, uint offset) {
+  return float3x2(asfloat(buffer.Load2((offset + 0u))), asfloat(buffer.Load2((offset + 8u))), asfloat(buffer.Load2((offset + 16u))));
+}
+
+float3x3 tint_symbol_20(ByteAddressBuffer buffer, uint offset) {
+  return float3x3(asfloat(buffer.Load3((offset + 0u))), asfloat(buffer.Load3((offset + 16u))), asfloat(buffer.Load3((offset + 32u))));
+}
+
+float3x4 tint_symbol_21(ByteAddressBuffer buffer, uint offset) {
+  return float3x4(asfloat(buffer.Load4((offset + 0u))), asfloat(buffer.Load4((offset + 16u))), asfloat(buffer.Load4((offset + 32u))));
+}
+
+float4x2 tint_symbol_22(ByteAddressBuffer buffer, uint offset) {
+  return float4x2(asfloat(buffer.Load2((offset + 0u))), asfloat(buffer.Load2((offset + 8u))), asfloat(buffer.Load2((offset + 16u))), asfloat(buffer.Load2((offset + 24u))));
+}
+
+float4x3 tint_symbol_23(ByteAddressBuffer buffer, uint offset) {
+  return float4x3(asfloat(buffer.Load3((offset + 0u))), asfloat(buffer.Load3((offset + 16u))), asfloat(buffer.Load3((offset + 32u))), asfloat(buffer.Load3((offset + 48u))));
+}
+
+float4x4 tint_symbol_24(ByteAddressBuffer buffer, uint offset) {
+  return float4x4(asfloat(buffer.Load4((offset + 0u))), asfloat(buffer.Load4((offset + 16u))), asfloat(buffer.Load4((offset + 32u))), asfloat(buffer.Load4((offset + 48u))));
+}
+
+matrix<float16_t, 2, 2> tint_symbol_25(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 2, 2>(buffer.Load<vector<float16_t, 2> >((offset + 0u)), buffer.Load<vector<float16_t, 2> >((offset + 4u)));
+}
+
+matrix<float16_t, 2, 3> tint_symbol_26(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 2, 3>(buffer.Load<vector<float16_t, 3> >((offset + 0u)), buffer.Load<vector<float16_t, 3> >((offset + 8u)));
+}
+
+matrix<float16_t, 2, 4> tint_symbol_27(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 2, 4>(buffer.Load<vector<float16_t, 4> >((offset + 0u)), buffer.Load<vector<float16_t, 4> >((offset + 8u)));
+}
+
+matrix<float16_t, 3, 2> tint_symbol_28(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 3, 2>(buffer.Load<vector<float16_t, 2> >((offset + 0u)), buffer.Load<vector<float16_t, 2> >((offset + 4u)), buffer.Load<vector<float16_t, 2> >((offset + 8u)));
+}
+
+matrix<float16_t, 3, 3> tint_symbol_29(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 3, 3>(buffer.Load<vector<float16_t, 3> >((offset + 0u)), buffer.Load<vector<float16_t, 3> >((offset + 8u)), buffer.Load<vector<float16_t, 3> >((offset + 16u)));
+}
+
+matrix<float16_t, 3, 4> tint_symbol_30(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 3, 4>(buffer.Load<vector<float16_t, 4> >((offset + 0u)), buffer.Load<vector<float16_t, 4> >((offset + 8u)), buffer.Load<vector<float16_t, 4> >((offset + 16u)));
+}
+
+matrix<float16_t, 4, 2> tint_symbol_31(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 4, 2>(buffer.Load<vector<float16_t, 2> >((offset + 0u)), buffer.Load<vector<float16_t, 2> >((offset + 4u)), buffer.Load<vector<float16_t, 2> >((offset + 8u)), buffer.Load<vector<float16_t, 2> >((offset + 12u)));
+}
+
+matrix<float16_t, 4, 3> tint_symbol_32(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 4, 3>(buffer.Load<vector<float16_t, 3> >((offset + 0u)), buffer.Load<vector<float16_t, 3> >((offset + 8u)), buffer.Load<vector<float16_t, 3> >((offset + 16u)), buffer.Load<vector<float16_t, 3> >((offset + 24u)));
+}
+
+matrix<float16_t, 4, 4> tint_symbol_33(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 4, 4>(buffer.Load<vector<float16_t, 4> >((offset + 0u)), buffer.Load<vector<float16_t, 4> >((offset + 8u)), buffer.Load<vector<float16_t, 4> >((offset + 16u)), buffer.Load<vector<float16_t, 4> >((offset + 24u)));
+}
+
+typedef float3 tint_symbol_34_ret[2];
+tint_symbol_34_ret tint_symbol_34(ByteAddressBuffer buffer, uint offset) {
+  float3 arr[2] = (float3[2])0;
+  {
+    for(uint i = 0u; (i < 2u); i = (i + 1u)) {
+      arr[i] = asfloat(buffer.Load3((offset + (i * 16u))));
+    }
+  }
+  return arr;
+}
+
+typedef matrix<float16_t, 4, 2> tint_symbol_35_ret[2];
+tint_symbol_35_ret tint_symbol_35(ByteAddressBuffer buffer, uint offset) {
+  matrix<float16_t, 4, 2> arr_1[2] = (matrix<float16_t, 4, 2>[2])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
+      arr_1[i_1] = tint_symbol_31(buffer, (offset + (i_1 * 16u)));
+    }
+  }
+  return arr_1;
+}
+
+Inner tint_symbol_36(ByteAddressBuffer buffer, uint offset) {
+  const Inner tint_symbol_38 = {asint(buffer.Load((offset + 0u))), asfloat(buffer.Load((offset + 4u))), buffer.Load<float16_t>((offset + 8u))};
+  return tint_symbol_38;
+}
+
+typedef Inner tint_symbol_37_ret[4];
+tint_symbol_37_ret tint_symbol_37(ByteAddressBuffer buffer, uint offset) {
+  Inner arr_2[4] = (Inner[4])0;
+  {
+    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
+      arr_2[i_2] = tint_symbol_36(buffer, (offset + (i_2 * 12u)));
+    }
+  }
+  return arr_2;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  const float scalar_f32 = asfloat(sb.Load(0u));
+  const int scalar_i32 = asint(sb.Load(4u));
+  const uint scalar_u32 = sb.Load(8u);
+  const float16_t scalar_f16 = sb.Load<float16_t>(12u);
+  const float2 vec2_f32 = asfloat(sb.Load2(16u));
+  const int2 vec2_i32 = asint(sb.Load2(24u));
+  const uint2 vec2_u32 = sb.Load2(32u);
+  const vector<float16_t, 2> vec2_f16 = sb.Load<vector<float16_t, 2> >(40u);
+  const float3 vec3_f32 = asfloat(sb.Load3(48u));
+  const int3 vec3_i32 = asint(sb.Load3(64u));
+  const uint3 vec3_u32 = sb.Load3(80u);
+  const vector<float16_t, 3> vec3_f16 = sb.Load<vector<float16_t, 3> >(96u);
+  const float4 vec4_f32 = asfloat(sb.Load4(112u));
+  const int4 vec4_i32 = asint(sb.Load4(128u));
+  const uint4 vec4_u32 = sb.Load4(144u);
+  const vector<float16_t, 4> vec4_f16 = sb.Load<vector<float16_t, 4> >(160u);
+  const float2x2 mat2x2_f32 = tint_symbol_16(sb, 168u);
+  const float2x3 mat2x3_f32 = tint_symbol_17(sb, 192u);
+  const float2x4 mat2x4_f32 = tint_symbol_18(sb, 224u);
+  const float3x2 mat3x2_f32 = tint_symbol_19(sb, 256u);
+  const float3x3 mat3x3_f32 = tint_symbol_20(sb, 288u);
+  const float3x4 mat3x4_f32 = tint_symbol_21(sb, 336u);
+  const float4x2 mat4x2_f32 = tint_symbol_22(sb, 384u);
+  const float4x3 mat4x3_f32 = tint_symbol_23(sb, 416u);
+  const float4x4 mat4x4_f32 = tint_symbol_24(sb, 480u);
+  const matrix<float16_t, 2, 2> mat2x2_f16 = tint_symbol_25(sb, 544u);
+  const matrix<float16_t, 2, 3> mat2x3_f16 = tint_symbol_26(sb, 552u);
+  const matrix<float16_t, 2, 4> mat2x4_f16 = tint_symbol_27(sb, 568u);
+  const matrix<float16_t, 3, 2> mat3x2_f16 = tint_symbol_28(sb, 584u);
+  const matrix<float16_t, 3, 3> mat3x3_f16 = tint_symbol_29(sb, 600u);
+  const matrix<float16_t, 3, 4> mat3x4_f16 = tint_symbol_30(sb, 624u);
+  const matrix<float16_t, 4, 2> mat4x2_f16 = tint_symbol_31(sb, 648u);
+  const matrix<float16_t, 4, 3> mat4x3_f16 = tint_symbol_32(sb, 664u);
+  const matrix<float16_t, 4, 4> mat4x4_f16 = tint_symbol_33(sb, 696u);
+  const float3 arr2_vec3_f32[2] = tint_symbol_34(sb, 736u);
+  const matrix<float16_t, 4, 2> arr2_mat4x2_f16[2] = tint_symbol_35(sb, 768u);
+  const Inner struct_inner = tint_symbol_36(sb, 800u);
+  const Inner array_struct_inner[4] = tint_symbol_37(sb, 812u);
+  return;
+}
diff --git a/test/tint/buffer/storage/static_index/read_f16.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/static_index/read_f16.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..ae92995
--- /dev/null
+++ b/test/tint/buffer/storage/static_index/read_f16.wgsl.expected.fxc.hlsl
@@ -0,0 +1,165 @@
+SKIP: FAILED
+
+struct Inner {
+  int scalar_i32;
+  float scalar_f32;
+  float16_t scalar_f16;
+};
+
+ByteAddressBuffer sb : register(t0, space0);
+
+float2x2 tint_symbol_16(ByteAddressBuffer buffer, uint offset) {
+  return float2x2(asfloat(buffer.Load2((offset + 0u))), asfloat(buffer.Load2((offset + 8u))));
+}
+
+float2x3 tint_symbol_17(ByteAddressBuffer buffer, uint offset) {
+  return float2x3(asfloat(buffer.Load3((offset + 0u))), asfloat(buffer.Load3((offset + 16u))));
+}
+
+float2x4 tint_symbol_18(ByteAddressBuffer buffer, uint offset) {
+  return float2x4(asfloat(buffer.Load4((offset + 0u))), asfloat(buffer.Load4((offset + 16u))));
+}
+
+float3x2 tint_symbol_19(ByteAddressBuffer buffer, uint offset) {
+  return float3x2(asfloat(buffer.Load2((offset + 0u))), asfloat(buffer.Load2((offset + 8u))), asfloat(buffer.Load2((offset + 16u))));
+}
+
+float3x3 tint_symbol_20(ByteAddressBuffer buffer, uint offset) {
+  return float3x3(asfloat(buffer.Load3((offset + 0u))), asfloat(buffer.Load3((offset + 16u))), asfloat(buffer.Load3((offset + 32u))));
+}
+
+float3x4 tint_symbol_21(ByteAddressBuffer buffer, uint offset) {
+  return float3x4(asfloat(buffer.Load4((offset + 0u))), asfloat(buffer.Load4((offset + 16u))), asfloat(buffer.Load4((offset + 32u))));
+}
+
+float4x2 tint_symbol_22(ByteAddressBuffer buffer, uint offset) {
+  return float4x2(asfloat(buffer.Load2((offset + 0u))), asfloat(buffer.Load2((offset + 8u))), asfloat(buffer.Load2((offset + 16u))), asfloat(buffer.Load2((offset + 24u))));
+}
+
+float4x3 tint_symbol_23(ByteAddressBuffer buffer, uint offset) {
+  return float4x3(asfloat(buffer.Load3((offset + 0u))), asfloat(buffer.Load3((offset + 16u))), asfloat(buffer.Load3((offset + 32u))), asfloat(buffer.Load3((offset + 48u))));
+}
+
+float4x4 tint_symbol_24(ByteAddressBuffer buffer, uint offset) {
+  return float4x4(asfloat(buffer.Load4((offset + 0u))), asfloat(buffer.Load4((offset + 16u))), asfloat(buffer.Load4((offset + 32u))), asfloat(buffer.Load4((offset + 48u))));
+}
+
+matrix<float16_t, 2, 2> tint_symbol_25(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 2, 2>(buffer.Load<vector<float16_t, 2> >((offset + 0u)), buffer.Load<vector<float16_t, 2> >((offset + 4u)));
+}
+
+matrix<float16_t, 2, 3> tint_symbol_26(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 2, 3>(buffer.Load<vector<float16_t, 3> >((offset + 0u)), buffer.Load<vector<float16_t, 3> >((offset + 8u)));
+}
+
+matrix<float16_t, 2, 4> tint_symbol_27(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 2, 4>(buffer.Load<vector<float16_t, 4> >((offset + 0u)), buffer.Load<vector<float16_t, 4> >((offset + 8u)));
+}
+
+matrix<float16_t, 3, 2> tint_symbol_28(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 3, 2>(buffer.Load<vector<float16_t, 2> >((offset + 0u)), buffer.Load<vector<float16_t, 2> >((offset + 4u)), buffer.Load<vector<float16_t, 2> >((offset + 8u)));
+}
+
+matrix<float16_t, 3, 3> tint_symbol_29(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 3, 3>(buffer.Load<vector<float16_t, 3> >((offset + 0u)), buffer.Load<vector<float16_t, 3> >((offset + 8u)), buffer.Load<vector<float16_t, 3> >((offset + 16u)));
+}
+
+matrix<float16_t, 3, 4> tint_symbol_30(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 3, 4>(buffer.Load<vector<float16_t, 4> >((offset + 0u)), buffer.Load<vector<float16_t, 4> >((offset + 8u)), buffer.Load<vector<float16_t, 4> >((offset + 16u)));
+}
+
+matrix<float16_t, 4, 2> tint_symbol_31(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 4, 2>(buffer.Load<vector<float16_t, 2> >((offset + 0u)), buffer.Load<vector<float16_t, 2> >((offset + 4u)), buffer.Load<vector<float16_t, 2> >((offset + 8u)), buffer.Load<vector<float16_t, 2> >((offset + 12u)));
+}
+
+matrix<float16_t, 4, 3> tint_symbol_32(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 4, 3>(buffer.Load<vector<float16_t, 3> >((offset + 0u)), buffer.Load<vector<float16_t, 3> >((offset + 8u)), buffer.Load<vector<float16_t, 3> >((offset + 16u)), buffer.Load<vector<float16_t, 3> >((offset + 24u)));
+}
+
+matrix<float16_t, 4, 4> tint_symbol_33(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 4, 4>(buffer.Load<vector<float16_t, 4> >((offset + 0u)), buffer.Load<vector<float16_t, 4> >((offset + 8u)), buffer.Load<vector<float16_t, 4> >((offset + 16u)), buffer.Load<vector<float16_t, 4> >((offset + 24u)));
+}
+
+typedef float3 tint_symbol_34_ret[2];
+tint_symbol_34_ret tint_symbol_34(ByteAddressBuffer buffer, uint offset) {
+  float3 arr[2] = (float3[2])0;
+  {
+    for(uint i = 0u; (i < 2u); i = (i + 1u)) {
+      arr[i] = asfloat(buffer.Load3((offset + (i * 16u))));
+    }
+  }
+  return arr;
+}
+
+typedef matrix<float16_t, 4, 2> tint_symbol_35_ret[2];
+tint_symbol_35_ret tint_symbol_35(ByteAddressBuffer buffer, uint offset) {
+  matrix<float16_t, 4, 2> arr_1[2] = (matrix<float16_t, 4, 2>[2])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
+      arr_1[i_1] = tint_symbol_31(buffer, (offset + (i_1 * 16u)));
+    }
+  }
+  return arr_1;
+}
+
+Inner tint_symbol_36(ByteAddressBuffer buffer, uint offset) {
+  const Inner tint_symbol_38 = {asint(buffer.Load((offset + 0u))), asfloat(buffer.Load((offset + 4u))), buffer.Load<float16_t>((offset + 8u))};
+  return tint_symbol_38;
+}
+
+typedef Inner tint_symbol_37_ret[4];
+tint_symbol_37_ret tint_symbol_37(ByteAddressBuffer buffer, uint offset) {
+  Inner arr_2[4] = (Inner[4])0;
+  {
+    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
+      arr_2[i_2] = tint_symbol_36(buffer, (offset + (i_2 * 12u)));
+    }
+  }
+  return arr_2;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  const float scalar_f32 = asfloat(sb.Load(0u));
+  const int scalar_i32 = asint(sb.Load(4u));
+  const uint scalar_u32 = sb.Load(8u);
+  const float16_t scalar_f16 = sb.Load<float16_t>(12u);
+  const float2 vec2_f32 = asfloat(sb.Load2(16u));
+  const int2 vec2_i32 = asint(sb.Load2(24u));
+  const uint2 vec2_u32 = sb.Load2(32u);
+  const vector<float16_t, 2> vec2_f16 = sb.Load<vector<float16_t, 2> >(40u);
+  const float3 vec3_f32 = asfloat(sb.Load3(48u));
+  const int3 vec3_i32 = asint(sb.Load3(64u));
+  const uint3 vec3_u32 = sb.Load3(80u);
+  const vector<float16_t, 3> vec3_f16 = sb.Load<vector<float16_t, 3> >(96u);
+  const float4 vec4_f32 = asfloat(sb.Load4(112u));
+  const int4 vec4_i32 = asint(sb.Load4(128u));
+  const uint4 vec4_u32 = sb.Load4(144u);
+  const vector<float16_t, 4> vec4_f16 = sb.Load<vector<float16_t, 4> >(160u);
+  const float2x2 mat2x2_f32 = tint_symbol_16(sb, 168u);
+  const float2x3 mat2x3_f32 = tint_symbol_17(sb, 192u);
+  const float2x4 mat2x4_f32 = tint_symbol_18(sb, 224u);
+  const float3x2 mat3x2_f32 = tint_symbol_19(sb, 256u);
+  const float3x3 mat3x3_f32 = tint_symbol_20(sb, 288u);
+  const float3x4 mat3x4_f32 = tint_symbol_21(sb, 336u);
+  const float4x2 mat4x2_f32 = tint_symbol_22(sb, 384u);
+  const float4x3 mat4x3_f32 = tint_symbol_23(sb, 416u);
+  const float4x4 mat4x4_f32 = tint_symbol_24(sb, 480u);
+  const matrix<float16_t, 2, 2> mat2x2_f16 = tint_symbol_25(sb, 544u);
+  const matrix<float16_t, 2, 3> mat2x3_f16 = tint_symbol_26(sb, 552u);
+  const matrix<float16_t, 2, 4> mat2x4_f16 = tint_symbol_27(sb, 568u);
+  const matrix<float16_t, 3, 2> mat3x2_f16 = tint_symbol_28(sb, 584u);
+  const matrix<float16_t, 3, 3> mat3x3_f16 = tint_symbol_29(sb, 600u);
+  const matrix<float16_t, 3, 4> mat3x4_f16 = tint_symbol_30(sb, 624u);
+  const matrix<float16_t, 4, 2> mat4x2_f16 = tint_symbol_31(sb, 648u);
+  const matrix<float16_t, 4, 3> mat4x3_f16 = tint_symbol_32(sb, 664u);
+  const matrix<float16_t, 4, 4> mat4x4_f16 = tint_symbol_33(sb, 696u);
+  const float3 arr2_vec3_f32[2] = tint_symbol_34(sb, 736u);
+  const matrix<float16_t, 4, 2> arr2_mat4x2_f16[2] = tint_symbol_35(sb, 768u);
+  const Inner struct_inner = tint_symbol_36(sb, 800u);
+  const Inner array_struct_inner[4] = tint_symbol_37(sb, 812u);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000002348228CC10(4,3-11): error X3000: unrecognized identifier 'float16_t'
+
diff --git a/test/tint/buffer/storage/static_index/read_f16.wgsl.expected.glsl b/test/tint/buffer/storage/static_index/read_f16.wgsl.expected.glsl
new file mode 100644
index 0000000..49d5d53
--- /dev/null
+++ b/test/tint/buffer/storage/static_index/read_f16.wgsl.expected.glsl
@@ -0,0 +1,114 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct Inner {
+  int scalar_i32;
+  float scalar_f32;
+  float16_t scalar_f16;
+};
+
+struct S {
+  float scalar_f32;
+  int scalar_i32;
+  uint scalar_u32;
+  float16_t scalar_f16;
+  vec2 vec2_f32;
+  ivec2 vec2_i32;
+  uvec2 vec2_u32;
+  f16vec2 vec2_f16;
+  uint pad;
+  vec3 vec3_f32;
+  uint pad_1;
+  ivec3 vec3_i32;
+  uint pad_2;
+  uvec3 vec3_u32;
+  uint pad_3;
+  f16vec3 vec3_f16;
+  uint pad_4;
+  uint pad_5;
+  vec4 vec4_f32;
+  ivec4 vec4_i32;
+  uvec4 vec4_u32;
+  f16vec4 vec4_f16;
+  mat2 mat2x2_f32;
+  uint pad_6;
+  uint pad_7;
+  mat2x3 mat2x3_f32;
+  mat2x4 mat2x4_f32;
+  mat3x2 mat3x2_f32;
+  uint pad_8;
+  uint pad_9;
+  mat3 mat3x3_f32;
+  mat3x4 mat3x4_f32;
+  mat4x2 mat4x2_f32;
+  mat4x3 mat4x3_f32;
+  mat4 mat4x4_f32;
+  f16mat2 mat2x2_f16;
+  f16mat2x3 mat2x3_f16;
+  f16mat2x4 mat2x4_f16;
+  f16mat3x2 mat3x2_f16;
+  uint pad_10;
+  f16mat3 mat3x3_f16;
+  f16mat3x4 mat3x4_f16;
+  f16mat4x2 mat4x2_f16;
+  f16mat4x3 mat4x3_f16;
+  f16mat4 mat4x4_f16;
+  uint pad_11;
+  uint pad_12;
+  vec3 arr2_vec3_f32[2];
+  f16mat4x2 arr2_mat4x2_f16[2];
+  Inner struct_inner;
+  Inner array_struct_inner[4];
+  uint pad_13;
+};
+
+layout(binding = 0, std430) buffer sb_block_ssbo {
+  S inner;
+} sb;
+
+void tint_symbol() {
+  float scalar_f32 = sb.inner.scalar_f32;
+  int scalar_i32 = sb.inner.scalar_i32;
+  uint scalar_u32 = sb.inner.scalar_u32;
+  float16_t scalar_f16 = sb.inner.scalar_f16;
+  vec2 vec2_f32 = sb.inner.vec2_f32;
+  ivec2 vec2_i32 = sb.inner.vec2_i32;
+  uvec2 vec2_u32 = sb.inner.vec2_u32;
+  f16vec2 vec2_f16 = sb.inner.vec2_f16;
+  vec3 vec3_f32 = sb.inner.vec3_f32;
+  ivec3 vec3_i32 = sb.inner.vec3_i32;
+  uvec3 vec3_u32 = sb.inner.vec3_u32;
+  f16vec3 vec3_f16 = sb.inner.vec3_f16;
+  vec4 vec4_f32 = sb.inner.vec4_f32;
+  ivec4 vec4_i32 = sb.inner.vec4_i32;
+  uvec4 vec4_u32 = sb.inner.vec4_u32;
+  f16vec4 vec4_f16 = sb.inner.vec4_f16;
+  mat2 mat2x2_f32 = sb.inner.mat2x2_f32;
+  mat2x3 mat2x3_f32 = sb.inner.mat2x3_f32;
+  mat2x4 mat2x4_f32 = sb.inner.mat2x4_f32;
+  mat3x2 mat3x2_f32 = sb.inner.mat3x2_f32;
+  mat3 mat3x3_f32 = sb.inner.mat3x3_f32;
+  mat3x4 mat3x4_f32 = sb.inner.mat3x4_f32;
+  mat4x2 mat4x2_f32 = sb.inner.mat4x2_f32;
+  mat4x3 mat4x3_f32 = sb.inner.mat4x3_f32;
+  mat4 mat4x4_f32 = sb.inner.mat4x4_f32;
+  f16mat2 mat2x2_f16 = sb.inner.mat2x2_f16;
+  f16mat2x3 mat2x3_f16 = sb.inner.mat2x3_f16;
+  f16mat2x4 mat2x4_f16 = sb.inner.mat2x4_f16;
+  f16mat3x2 mat3x2_f16 = sb.inner.mat3x2_f16;
+  f16mat3 mat3x3_f16 = sb.inner.mat3x3_f16;
+  f16mat3x4 mat3x4_f16 = sb.inner.mat3x4_f16;
+  f16mat4x2 mat4x2_f16 = sb.inner.mat4x2_f16;
+  f16mat4x3 mat4x3_f16 = sb.inner.mat4x3_f16;
+  f16mat4 mat4x4_f16 = sb.inner.mat4x4_f16;
+  vec3 arr2_vec3_f32[2] = sb.inner.arr2_vec3_f32;
+  f16mat4x2 arr2_mat4x2_f16[2] = sb.inner.arr2_mat4x2_f16;
+  Inner struct_inner = sb.inner.struct_inner;
+  Inner array_struct_inner[4] = sb.inner.array_struct_inner;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol();
+  return;
+}
diff --git a/test/tint/buffer/storage/static_index/read_f16.wgsl.expected.msl b/test/tint/buffer/storage/static_index/read_f16.wgsl.expected.msl
new file mode 100644
index 0000000..461e002
--- /dev/null
+++ b/test/tint/buffer/storage/static_index/read_f16.wgsl.expected.msl
@@ -0,0 +1,117 @@
+#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 Inner {
+  /* 0x0000 */ int scalar_i32;
+  /* 0x0004 */ float scalar_f32;
+  /* 0x0008 */ half scalar_f16;
+  /* 0x000a */ tint_array<int8_t, 2> tint_pad;
+};
+
+struct S {
+  /* 0x0000 */ float scalar_f32;
+  /* 0x0004 */ int scalar_i32;
+  /* 0x0008 */ uint scalar_u32;
+  /* 0x000c */ half scalar_f16;
+  /* 0x000e */ tint_array<int8_t, 2> tint_pad_1;
+  /* 0x0010 */ float2 vec2_f32;
+  /* 0x0018 */ int2 vec2_i32;
+  /* 0x0020 */ uint2 vec2_u32;
+  /* 0x0028 */ half2 vec2_f16;
+  /* 0x002c */ tint_array<int8_t, 4> tint_pad_2;
+  /* 0x0030 */ packed_float3 vec3_f32;
+  /* 0x003c */ tint_array<int8_t, 4> tint_pad_3;
+  /* 0x0040 */ packed_int3 vec3_i32;
+  /* 0x004c */ tint_array<int8_t, 4> tint_pad_4;
+  /* 0x0050 */ packed_uint3 vec3_u32;
+  /* 0x005c */ tint_array<int8_t, 4> tint_pad_5;
+  /* 0x0060 */ packed_half3 vec3_f16;
+  /* 0x0066 */ tint_array<int8_t, 10> tint_pad_6;
+  /* 0x0070 */ float4 vec4_f32;
+  /* 0x0080 */ int4 vec4_i32;
+  /* 0x0090 */ uint4 vec4_u32;
+  /* 0x00a0 */ half4 vec4_f16;
+  /* 0x00a8 */ float2x2 mat2x2_f32;
+  /* 0x00b8 */ tint_array<int8_t, 8> tint_pad_7;
+  /* 0x00c0 */ float2x3 mat2x3_f32;
+  /* 0x00e0 */ float2x4 mat2x4_f32;
+  /* 0x0100 */ float3x2 mat3x2_f32;
+  /* 0x0118 */ tint_array<int8_t, 8> tint_pad_8;
+  /* 0x0120 */ float3x3 mat3x3_f32;
+  /* 0x0150 */ float3x4 mat3x4_f32;
+  /* 0x0180 */ float4x2 mat4x2_f32;
+  /* 0x01a0 */ float4x3 mat4x3_f32;
+  /* 0x01e0 */ float4x4 mat4x4_f32;
+  /* 0x0220 */ half2x2 mat2x2_f16;
+  /* 0x0228 */ half2x3 mat2x3_f16;
+  /* 0x0238 */ half2x4 mat2x4_f16;
+  /* 0x0248 */ half3x2 mat3x2_f16;
+  /* 0x0254 */ tint_array<int8_t, 4> tint_pad_9;
+  /* 0x0258 */ half3x3 mat3x3_f16;
+  /* 0x0270 */ half3x4 mat3x4_f16;
+  /* 0x0288 */ half4x2 mat4x2_f16;
+  /* 0x0298 */ half4x3 mat4x3_f16;
+  /* 0x02b8 */ half4x4 mat4x4_f16;
+  /* 0x02d8 */ tint_array<int8_t, 8> tint_pad_10;
+  /* 0x02e0 */ tint_array<float3, 2> arr2_vec3_f32;
+  /* 0x0300 */ tint_array<half4x2, 2> arr2_mat4x2_f16;
+  /* 0x0320 */ Inner struct_inner;
+  /* 0x032c */ tint_array<Inner, 4> array_struct_inner;
+  /* 0x035c */ tint_array<int8_t, 4> tint_pad_11;
+};
+
+kernel void tint_symbol(const device S* tint_symbol_1 [[buffer(0)]]) {
+  float const scalar_f32 = (*(tint_symbol_1)).scalar_f32;
+  int const scalar_i32 = (*(tint_symbol_1)).scalar_i32;
+  uint const scalar_u32 = (*(tint_symbol_1)).scalar_u32;
+  half const scalar_f16 = (*(tint_symbol_1)).scalar_f16;
+  float2 const vec2_f32 = (*(tint_symbol_1)).vec2_f32;
+  int2 const vec2_i32 = (*(tint_symbol_1)).vec2_i32;
+  uint2 const vec2_u32 = (*(tint_symbol_1)).vec2_u32;
+  half2 const vec2_f16 = (*(tint_symbol_1)).vec2_f16;
+  float3 const vec3_f32 = float3((*(tint_symbol_1)).vec3_f32);
+  int3 const vec3_i32 = int3((*(tint_symbol_1)).vec3_i32);
+  uint3 const vec3_u32 = uint3((*(tint_symbol_1)).vec3_u32);
+  half3 const vec3_f16 = half3((*(tint_symbol_1)).vec3_f16);
+  float4 const vec4_f32 = (*(tint_symbol_1)).vec4_f32;
+  int4 const vec4_i32 = (*(tint_symbol_1)).vec4_i32;
+  uint4 const vec4_u32 = (*(tint_symbol_1)).vec4_u32;
+  half4 const vec4_f16 = (*(tint_symbol_1)).vec4_f16;
+  float2x2 const mat2x2_f32 = (*(tint_symbol_1)).mat2x2_f32;
+  float2x3 const mat2x3_f32 = (*(tint_symbol_1)).mat2x3_f32;
+  float2x4 const mat2x4_f32 = (*(tint_symbol_1)).mat2x4_f32;
+  float3x2 const mat3x2_f32 = (*(tint_symbol_1)).mat3x2_f32;
+  float3x3 const mat3x3_f32 = (*(tint_symbol_1)).mat3x3_f32;
+  float3x4 const mat3x4_f32 = (*(tint_symbol_1)).mat3x4_f32;
+  float4x2 const mat4x2_f32 = (*(tint_symbol_1)).mat4x2_f32;
+  float4x3 const mat4x3_f32 = (*(tint_symbol_1)).mat4x3_f32;
+  float4x4 const mat4x4_f32 = (*(tint_symbol_1)).mat4x4_f32;
+  half2x2 const mat2x2_f16 = (*(tint_symbol_1)).mat2x2_f16;
+  half2x3 const mat2x3_f16 = (*(tint_symbol_1)).mat2x3_f16;
+  half2x4 const mat2x4_f16 = (*(tint_symbol_1)).mat2x4_f16;
+  half3x2 const mat3x2_f16 = (*(tint_symbol_1)).mat3x2_f16;
+  half3x3 const mat3x3_f16 = (*(tint_symbol_1)).mat3x3_f16;
+  half3x4 const mat3x4_f16 = (*(tint_symbol_1)).mat3x4_f16;
+  half4x2 const mat4x2_f16 = (*(tint_symbol_1)).mat4x2_f16;
+  half4x3 const mat4x3_f16 = (*(tint_symbol_1)).mat4x3_f16;
+  half4x4 const mat4x4_f16 = (*(tint_symbol_1)).mat4x4_f16;
+  tint_array<float3, 2> const arr2_vec3_f32 = (*(tint_symbol_1)).arr2_vec3_f32;
+  tint_array<half4x2, 2> const arr2_mat4x2_f16 = (*(tint_symbol_1)).arr2_mat4x2_f16;
+  Inner const struct_inner = (*(tint_symbol_1)).struct_inner;
+  tint_array<Inner, 4> const array_struct_inner = (*(tint_symbol_1)).array_struct_inner;
+  return;
+}
+
diff --git a/test/tint/buffer/storage/static_index/read_f16.wgsl.expected.spvasm b/test/tint/buffer/storage/static_index/read_f16.wgsl.expected.spvasm
new file mode 100644
index 0000000..fcaa0d9
--- /dev/null
+++ b/test/tint/buffer/storage/static_index/read_f16.wgsl.expected.spvasm
@@ -0,0 +1,347 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 199
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %sb_block "sb_block"
+               OpMemberName %sb_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "scalar_f32"
+               OpMemberName %S 1 "scalar_i32"
+               OpMemberName %S 2 "scalar_u32"
+               OpMemberName %S 3 "scalar_f16"
+               OpMemberName %S 4 "vec2_f32"
+               OpMemberName %S 5 "vec2_i32"
+               OpMemberName %S 6 "vec2_u32"
+               OpMemberName %S 7 "vec2_f16"
+               OpMemberName %S 8 "vec3_f32"
+               OpMemberName %S 9 "vec3_i32"
+               OpMemberName %S 10 "vec3_u32"
+               OpMemberName %S 11 "vec3_f16"
+               OpMemberName %S 12 "vec4_f32"
+               OpMemberName %S 13 "vec4_i32"
+               OpMemberName %S 14 "vec4_u32"
+               OpMemberName %S 15 "vec4_f16"
+               OpMemberName %S 16 "mat2x2_f32"
+               OpMemberName %S 17 "mat2x3_f32"
+               OpMemberName %S 18 "mat2x4_f32"
+               OpMemberName %S 19 "mat3x2_f32"
+               OpMemberName %S 20 "mat3x3_f32"
+               OpMemberName %S 21 "mat3x4_f32"
+               OpMemberName %S 22 "mat4x2_f32"
+               OpMemberName %S 23 "mat4x3_f32"
+               OpMemberName %S 24 "mat4x4_f32"
+               OpMemberName %S 25 "mat2x2_f16"
+               OpMemberName %S 26 "mat2x3_f16"
+               OpMemberName %S 27 "mat2x4_f16"
+               OpMemberName %S 28 "mat3x2_f16"
+               OpMemberName %S 29 "mat3x3_f16"
+               OpMemberName %S 30 "mat3x4_f16"
+               OpMemberName %S 31 "mat4x2_f16"
+               OpMemberName %S 32 "mat4x3_f16"
+               OpMemberName %S 33 "mat4x4_f16"
+               OpMemberName %S 34 "arr2_vec3_f32"
+               OpMemberName %S 35 "arr2_mat4x2_f16"
+               OpMemberName %S 36 "struct_inner"
+               OpName %Inner "Inner"
+               OpMemberName %Inner 0 "scalar_i32"
+               OpMemberName %Inner 1 "scalar_f32"
+               OpMemberName %Inner 2 "scalar_f16"
+               OpMemberName %S 37 "array_struct_inner"
+               OpName %sb "sb"
+               OpName %main "main"
+               OpDecorate %sb_block Block
+               OpMemberDecorate %sb_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 4
+               OpMemberDecorate %S 2 Offset 8
+               OpMemberDecorate %S 3 Offset 12
+               OpMemberDecorate %S 4 Offset 16
+               OpMemberDecorate %S 5 Offset 24
+               OpMemberDecorate %S 6 Offset 32
+               OpMemberDecorate %S 7 Offset 40
+               OpMemberDecorate %S 8 Offset 48
+               OpMemberDecorate %S 9 Offset 64
+               OpMemberDecorate %S 10 Offset 80
+               OpMemberDecorate %S 11 Offset 96
+               OpMemberDecorate %S 12 Offset 112
+               OpMemberDecorate %S 13 Offset 128
+               OpMemberDecorate %S 14 Offset 144
+               OpMemberDecorate %S 15 Offset 160
+               OpMemberDecorate %S 16 Offset 168
+               OpMemberDecorate %S 16 ColMajor
+               OpMemberDecorate %S 16 MatrixStride 8
+               OpMemberDecorate %S 17 Offset 192
+               OpMemberDecorate %S 17 ColMajor
+               OpMemberDecorate %S 17 MatrixStride 16
+               OpMemberDecorate %S 18 Offset 224
+               OpMemberDecorate %S 18 ColMajor
+               OpMemberDecorate %S 18 MatrixStride 16
+               OpMemberDecorate %S 19 Offset 256
+               OpMemberDecorate %S 19 ColMajor
+               OpMemberDecorate %S 19 MatrixStride 8
+               OpMemberDecorate %S 20 Offset 288
+               OpMemberDecorate %S 20 ColMajor
+               OpMemberDecorate %S 20 MatrixStride 16
+               OpMemberDecorate %S 21 Offset 336
+               OpMemberDecorate %S 21 ColMajor
+               OpMemberDecorate %S 21 MatrixStride 16
+               OpMemberDecorate %S 22 Offset 384
+               OpMemberDecorate %S 22 ColMajor
+               OpMemberDecorate %S 22 MatrixStride 8
+               OpMemberDecorate %S 23 Offset 416
+               OpMemberDecorate %S 23 ColMajor
+               OpMemberDecorate %S 23 MatrixStride 16
+               OpMemberDecorate %S 24 Offset 480
+               OpMemberDecorate %S 24 ColMajor
+               OpMemberDecorate %S 24 MatrixStride 16
+               OpMemberDecorate %S 25 Offset 544
+               OpMemberDecorate %S 25 ColMajor
+               OpMemberDecorate %S 25 MatrixStride 4
+               OpMemberDecorate %S 26 Offset 552
+               OpMemberDecorate %S 26 ColMajor
+               OpMemberDecorate %S 26 MatrixStride 8
+               OpMemberDecorate %S 27 Offset 568
+               OpMemberDecorate %S 27 ColMajor
+               OpMemberDecorate %S 27 MatrixStride 8
+               OpMemberDecorate %S 28 Offset 584
+               OpMemberDecorate %S 28 ColMajor
+               OpMemberDecorate %S 28 MatrixStride 4
+               OpMemberDecorate %S 29 Offset 600
+               OpMemberDecorate %S 29 ColMajor
+               OpMemberDecorate %S 29 MatrixStride 8
+               OpMemberDecorate %S 30 Offset 624
+               OpMemberDecorate %S 30 ColMajor
+               OpMemberDecorate %S 30 MatrixStride 8
+               OpMemberDecorate %S 31 Offset 648
+               OpMemberDecorate %S 31 ColMajor
+               OpMemberDecorate %S 31 MatrixStride 4
+               OpMemberDecorate %S 32 Offset 664
+               OpMemberDecorate %S 32 ColMajor
+               OpMemberDecorate %S 32 MatrixStride 8
+               OpMemberDecorate %S 33 Offset 696
+               OpMemberDecorate %S 33 ColMajor
+               OpMemberDecorate %S 33 MatrixStride 8
+               OpMemberDecorate %S 34 Offset 736
+               OpDecorate %_arr_v3float_uint_2 ArrayStride 16
+               OpMemberDecorate %S 35 Offset 768
+               OpMemberDecorate %S 35 ColMajor
+               OpMemberDecorate %S 35 MatrixStride 4
+               OpDecorate %_arr_mat4v2half_uint_2 ArrayStride 16
+               OpMemberDecorate %S 36 Offset 800
+               OpMemberDecorate %Inner 0 Offset 0
+               OpMemberDecorate %Inner 1 Offset 4
+               OpMemberDecorate %Inner 2 Offset 8
+               OpMemberDecorate %S 37 Offset 812
+               OpDecorate %_arr_Inner_uint_4 ArrayStride 12
+               OpDecorate %sb NonWritable
+               OpDecorate %sb Binding 0
+               OpDecorate %sb DescriptorSet 0
+      %float = OpTypeFloat 32
+        %int = OpTypeInt 32 1
+       %uint = OpTypeInt 32 0
+       %half = OpTypeFloat 16
+    %v2float = OpTypeVector %float 2
+      %v2int = OpTypeVector %int 2
+     %v2uint = OpTypeVector %uint 2
+     %v2half = OpTypeVector %half 2
+    %v3float = OpTypeVector %float 3
+      %v3int = OpTypeVector %int 3
+     %v3uint = OpTypeVector %uint 3
+     %v3half = OpTypeVector %half 3
+    %v4float = OpTypeVector %float 4
+      %v4int = OpTypeVector %int 4
+     %v4uint = OpTypeVector %uint 4
+     %v4half = OpTypeVector %half 4
+%mat2v2float = OpTypeMatrix %v2float 2
+%mat2v3float = OpTypeMatrix %v3float 2
+%mat2v4float = OpTypeMatrix %v4float 2
+%mat3v2float = OpTypeMatrix %v2float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+%mat3v4float = OpTypeMatrix %v4float 3
+%mat4v2float = OpTypeMatrix %v2float 4
+%mat4v3float = OpTypeMatrix %v3float 4
+%mat4v4float = OpTypeMatrix %v4float 4
+ %mat2v2half = OpTypeMatrix %v2half 2
+ %mat2v3half = OpTypeMatrix %v3half 2
+ %mat2v4half = OpTypeMatrix %v4half 2
+ %mat3v2half = OpTypeMatrix %v2half 3
+ %mat3v3half = OpTypeMatrix %v3half 3
+ %mat3v4half = OpTypeMatrix %v4half 3
+ %mat4v2half = OpTypeMatrix %v2half 4
+ %mat4v3half = OpTypeMatrix %v3half 4
+ %mat4v4half = OpTypeMatrix %v4half 4
+     %uint_2 = OpConstant %uint 2
+%_arr_v3float_uint_2 = OpTypeArray %v3float %uint_2
+%_arr_mat4v2half_uint_2 = OpTypeArray %mat4v2half %uint_2
+      %Inner = OpTypeStruct %int %float %half
+     %uint_4 = OpConstant %uint 4
+%_arr_Inner_uint_4 = OpTypeArray %Inner %uint_4
+          %S = OpTypeStruct %float %int %uint %half %v2float %v2int %v2uint %v2half %v3float %v3int %v3uint %v3half %v4float %v4int %v4uint %v4half %mat2v2float %mat2v3float %mat2v4float %mat3v2float %mat3v3float %mat3v4float %mat4v2float %mat4v3float %mat4v4float %mat2v2half %mat2v3half %mat2v4half %mat3v2half %mat3v3half %mat3v4half %mat4v2half %mat4v3half %mat4v4half %_arr_v3float_uint_2 %_arr_mat4v2half_uint_2 %Inner %_arr_Inner_uint_4
+   %sb_block = OpTypeStruct %S
+%_ptr_StorageBuffer_sb_block = OpTypePointer StorageBuffer %sb_block
+         %sb = OpVariable %_ptr_StorageBuffer_sb_block StorageBuffer
+       %void = OpTypeVoid
+         %45 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
+     %uint_1 = OpConstant %uint 1
+%_ptr_StorageBuffer_int = OpTypePointer StorageBuffer %int
+%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
+     %uint_3 = OpConstant %uint 3
+%_ptr_StorageBuffer_half = OpTypePointer StorageBuffer %half
+%_ptr_StorageBuffer_v2float = OpTypePointer StorageBuffer %v2float
+     %uint_5 = OpConstant %uint 5
+%_ptr_StorageBuffer_v2int = OpTypePointer StorageBuffer %v2int
+     %uint_6 = OpConstant %uint 6
+%_ptr_StorageBuffer_v2uint = OpTypePointer StorageBuffer %v2uint
+     %uint_7 = OpConstant %uint 7
+%_ptr_StorageBuffer_v2half = OpTypePointer StorageBuffer %v2half
+     %uint_8 = OpConstant %uint 8
+%_ptr_StorageBuffer_v3float = OpTypePointer StorageBuffer %v3float
+     %uint_9 = OpConstant %uint 9
+%_ptr_StorageBuffer_v3int = OpTypePointer StorageBuffer %v3int
+    %uint_10 = OpConstant %uint 10
+%_ptr_StorageBuffer_v3uint = OpTypePointer StorageBuffer %v3uint
+    %uint_11 = OpConstant %uint 11
+%_ptr_StorageBuffer_v3half = OpTypePointer StorageBuffer %v3half
+    %uint_12 = OpConstant %uint 12
+%_ptr_StorageBuffer_v4float = OpTypePointer StorageBuffer %v4float
+    %uint_13 = OpConstant %uint 13
+%_ptr_StorageBuffer_v4int = OpTypePointer StorageBuffer %v4int
+    %uint_14 = OpConstant %uint 14
+%_ptr_StorageBuffer_v4uint = OpTypePointer StorageBuffer %v4uint
+    %uint_15 = OpConstant %uint 15
+%_ptr_StorageBuffer_v4half = OpTypePointer StorageBuffer %v4half
+    %uint_16 = OpConstant %uint 16
+%_ptr_StorageBuffer_mat2v2float = OpTypePointer StorageBuffer %mat2v2float
+    %uint_17 = OpConstant %uint 17
+%_ptr_StorageBuffer_mat2v3float = OpTypePointer StorageBuffer %mat2v3float
+    %uint_18 = OpConstant %uint 18
+%_ptr_StorageBuffer_mat2v4float = OpTypePointer StorageBuffer %mat2v4float
+    %uint_19 = OpConstant %uint 19
+%_ptr_StorageBuffer_mat3v2float = OpTypePointer StorageBuffer %mat3v2float
+    %uint_20 = OpConstant %uint 20
+%_ptr_StorageBuffer_mat3v3float = OpTypePointer StorageBuffer %mat3v3float
+    %uint_21 = OpConstant %uint 21
+%_ptr_StorageBuffer_mat3v4float = OpTypePointer StorageBuffer %mat3v4float
+    %uint_22 = OpConstant %uint 22
+%_ptr_StorageBuffer_mat4v2float = OpTypePointer StorageBuffer %mat4v2float
+    %uint_23 = OpConstant %uint 23
+%_ptr_StorageBuffer_mat4v3float = OpTypePointer StorageBuffer %mat4v3float
+    %uint_24 = OpConstant %uint 24
+%_ptr_StorageBuffer_mat4v4float = OpTypePointer StorageBuffer %mat4v4float
+    %uint_25 = OpConstant %uint 25
+%_ptr_StorageBuffer_mat2v2half = OpTypePointer StorageBuffer %mat2v2half
+    %uint_26 = OpConstant %uint 26
+%_ptr_StorageBuffer_mat2v3half = OpTypePointer StorageBuffer %mat2v3half
+    %uint_27 = OpConstant %uint 27
+%_ptr_StorageBuffer_mat2v4half = OpTypePointer StorageBuffer %mat2v4half
+    %uint_28 = OpConstant %uint 28
+%_ptr_StorageBuffer_mat3v2half = OpTypePointer StorageBuffer %mat3v2half
+    %uint_29 = OpConstant %uint 29
+%_ptr_StorageBuffer_mat3v3half = OpTypePointer StorageBuffer %mat3v3half
+    %uint_30 = OpConstant %uint 30
+%_ptr_StorageBuffer_mat3v4half = OpTypePointer StorageBuffer %mat3v4half
+    %uint_31 = OpConstant %uint 31
+%_ptr_StorageBuffer_mat4v2half = OpTypePointer StorageBuffer %mat4v2half
+    %uint_32 = OpConstant %uint 32
+%_ptr_StorageBuffer_mat4v3half = OpTypePointer StorageBuffer %mat4v3half
+    %uint_33 = OpConstant %uint 33
+%_ptr_StorageBuffer_mat4v4half = OpTypePointer StorageBuffer %mat4v4half
+    %uint_34 = OpConstant %uint 34
+%_ptr_StorageBuffer__arr_v3float_uint_2 = OpTypePointer StorageBuffer %_arr_v3float_uint_2
+    %uint_35 = OpConstant %uint 35
+%_ptr_StorageBuffer__arr_mat4v2half_uint_2 = OpTypePointer StorageBuffer %_arr_mat4v2half_uint_2
+    %uint_36 = OpConstant %uint 36
+%_ptr_StorageBuffer_Inner = OpTypePointer StorageBuffer %Inner
+    %uint_37 = OpConstant %uint 37
+%_ptr_StorageBuffer__arr_Inner_uint_4 = OpTypePointer StorageBuffer %_arr_Inner_uint_4
+       %main = OpFunction %void None %45
+         %48 = OpLabel
+         %51 = OpAccessChain %_ptr_StorageBuffer_float %sb %uint_0 %uint_0
+         %52 = OpLoad %float %51
+         %55 = OpAccessChain %_ptr_StorageBuffer_int %sb %uint_0 %uint_1
+         %56 = OpLoad %int %55
+         %58 = OpAccessChain %_ptr_StorageBuffer_uint %sb %uint_0 %uint_2
+         %59 = OpLoad %uint %58
+         %62 = OpAccessChain %_ptr_StorageBuffer_half %sb %uint_0 %uint_3
+         %63 = OpLoad %half %62
+         %65 = OpAccessChain %_ptr_StorageBuffer_v2float %sb %uint_0 %uint_4
+         %66 = OpLoad %v2float %65
+         %69 = OpAccessChain %_ptr_StorageBuffer_v2int %sb %uint_0 %uint_5
+         %70 = OpLoad %v2int %69
+         %73 = OpAccessChain %_ptr_StorageBuffer_v2uint %sb %uint_0 %uint_6
+         %74 = OpLoad %v2uint %73
+         %77 = OpAccessChain %_ptr_StorageBuffer_v2half %sb %uint_0 %uint_7
+         %78 = OpLoad %v2half %77
+         %81 = OpAccessChain %_ptr_StorageBuffer_v3float %sb %uint_0 %uint_8
+         %82 = OpLoad %v3float %81
+         %85 = OpAccessChain %_ptr_StorageBuffer_v3int %sb %uint_0 %uint_9
+         %86 = OpLoad %v3int %85
+         %89 = OpAccessChain %_ptr_StorageBuffer_v3uint %sb %uint_0 %uint_10
+         %90 = OpLoad %v3uint %89
+         %93 = OpAccessChain %_ptr_StorageBuffer_v3half %sb %uint_0 %uint_11
+         %94 = OpLoad %v3half %93
+         %97 = OpAccessChain %_ptr_StorageBuffer_v4float %sb %uint_0 %uint_12
+         %98 = OpLoad %v4float %97
+        %101 = OpAccessChain %_ptr_StorageBuffer_v4int %sb %uint_0 %uint_13
+        %102 = OpLoad %v4int %101
+        %105 = OpAccessChain %_ptr_StorageBuffer_v4uint %sb %uint_0 %uint_14
+        %106 = OpLoad %v4uint %105
+        %109 = OpAccessChain %_ptr_StorageBuffer_v4half %sb %uint_0 %uint_15
+        %110 = OpLoad %v4half %109
+        %113 = OpAccessChain %_ptr_StorageBuffer_mat2v2float %sb %uint_0 %uint_16
+        %114 = OpLoad %mat2v2float %113
+        %117 = OpAccessChain %_ptr_StorageBuffer_mat2v3float %sb %uint_0 %uint_17
+        %118 = OpLoad %mat2v3float %117
+        %121 = OpAccessChain %_ptr_StorageBuffer_mat2v4float %sb %uint_0 %uint_18
+        %122 = OpLoad %mat2v4float %121
+        %125 = OpAccessChain %_ptr_StorageBuffer_mat3v2float %sb %uint_0 %uint_19
+        %126 = OpLoad %mat3v2float %125
+        %129 = OpAccessChain %_ptr_StorageBuffer_mat3v3float %sb %uint_0 %uint_20
+        %130 = OpLoad %mat3v3float %129
+        %133 = OpAccessChain %_ptr_StorageBuffer_mat3v4float %sb %uint_0 %uint_21
+        %134 = OpLoad %mat3v4float %133
+        %137 = OpAccessChain %_ptr_StorageBuffer_mat4v2float %sb %uint_0 %uint_22
+        %138 = OpLoad %mat4v2float %137
+        %141 = OpAccessChain %_ptr_StorageBuffer_mat4v3float %sb %uint_0 %uint_23
+        %142 = OpLoad %mat4v3float %141
+        %145 = OpAccessChain %_ptr_StorageBuffer_mat4v4float %sb %uint_0 %uint_24
+        %146 = OpLoad %mat4v4float %145
+        %149 = OpAccessChain %_ptr_StorageBuffer_mat2v2half %sb %uint_0 %uint_25
+        %150 = OpLoad %mat2v2half %149
+        %153 = OpAccessChain %_ptr_StorageBuffer_mat2v3half %sb %uint_0 %uint_26
+        %154 = OpLoad %mat2v3half %153
+        %157 = OpAccessChain %_ptr_StorageBuffer_mat2v4half %sb %uint_0 %uint_27
+        %158 = OpLoad %mat2v4half %157
+        %161 = OpAccessChain %_ptr_StorageBuffer_mat3v2half %sb %uint_0 %uint_28
+        %162 = OpLoad %mat3v2half %161
+        %165 = OpAccessChain %_ptr_StorageBuffer_mat3v3half %sb %uint_0 %uint_29
+        %166 = OpLoad %mat3v3half %165
+        %169 = OpAccessChain %_ptr_StorageBuffer_mat3v4half %sb %uint_0 %uint_30
+        %170 = OpLoad %mat3v4half %169
+        %173 = OpAccessChain %_ptr_StorageBuffer_mat4v2half %sb %uint_0 %uint_31
+        %174 = OpLoad %mat4v2half %173
+        %177 = OpAccessChain %_ptr_StorageBuffer_mat4v3half %sb %uint_0 %uint_32
+        %178 = OpLoad %mat4v3half %177
+        %181 = OpAccessChain %_ptr_StorageBuffer_mat4v4half %sb %uint_0 %uint_33
+        %182 = OpLoad %mat4v4half %181
+        %185 = OpAccessChain %_ptr_StorageBuffer__arr_v3float_uint_2 %sb %uint_0 %uint_34
+        %186 = OpLoad %_arr_v3float_uint_2 %185
+        %189 = OpAccessChain %_ptr_StorageBuffer__arr_mat4v2half_uint_2 %sb %uint_0 %uint_35
+        %190 = OpLoad %_arr_mat4v2half_uint_2 %189
+        %193 = OpAccessChain %_ptr_StorageBuffer_Inner %sb %uint_0 %uint_36
+        %194 = OpLoad %Inner %193
+        %197 = OpAccessChain %_ptr_StorageBuffer__arr_Inner_uint_4 %sb %uint_0 %uint_37
+        %198 = OpLoad %_arr_Inner_uint_4 %197
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/storage/static_index/read_f16.wgsl.expected.wgsl b/test/tint/buffer/storage/static_index/read_f16.wgsl.expected.wgsl
new file mode 100644
index 0000000..cb7c9e1
--- /dev/null
+++ b/test/tint/buffer/storage/static_index/read_f16.wgsl.expected.wgsl
@@ -0,0 +1,92 @@
+enable f16;
+
+struct Inner {
+  scalar_i32 : i32,
+  scalar_f32 : f32,
+  scalar_f16 : f16,
+}
+
+struct S {
+  scalar_f32 : f32,
+  scalar_i32 : i32,
+  scalar_u32 : u32,
+  scalar_f16 : f16,
+  vec2_f32 : vec2<f32>,
+  vec2_i32 : vec2<i32>,
+  vec2_u32 : vec2<u32>,
+  vec2_f16 : vec2<f16>,
+  vec3_f32 : vec3<f32>,
+  vec3_i32 : vec3<i32>,
+  vec3_u32 : vec3<u32>,
+  vec3_f16 : vec3<f16>,
+  vec4_f32 : vec4<f32>,
+  vec4_i32 : vec4<i32>,
+  vec4_u32 : vec4<u32>,
+  vec4_f16 : vec4<f16>,
+  mat2x2_f32 : mat2x2<f32>,
+  mat2x3_f32 : mat2x3<f32>,
+  mat2x4_f32 : mat2x4<f32>,
+  mat3x2_f32 : mat3x2<f32>,
+  mat3x3_f32 : mat3x3<f32>,
+  mat3x4_f32 : mat3x4<f32>,
+  mat4x2_f32 : mat4x2<f32>,
+  mat4x3_f32 : mat4x3<f32>,
+  mat4x4_f32 : mat4x4<f32>,
+  mat2x2_f16 : mat2x2<f16>,
+  mat2x3_f16 : mat2x3<f16>,
+  mat2x4_f16 : mat2x4<f16>,
+  mat3x2_f16 : mat3x2<f16>,
+  mat3x3_f16 : mat3x3<f16>,
+  mat3x4_f16 : mat3x4<f16>,
+  mat4x2_f16 : mat4x2<f16>,
+  mat4x3_f16 : mat4x3<f16>,
+  mat4x4_f16 : mat4x4<f16>,
+  arr2_vec3_f32 : array<vec3<f32>, 2>,
+  arr2_mat4x2_f16 : array<mat4x2<f16>, 2>,
+  struct_inner : Inner,
+  array_struct_inner : array<Inner, 4>,
+}
+
+@binding(0) @group(0) var<storage, read> sb : S;
+
+@compute @workgroup_size(1)
+fn main() {
+  let scalar_f32 = sb.scalar_f32;
+  let scalar_i32 = sb.scalar_i32;
+  let scalar_u32 = sb.scalar_u32;
+  let scalar_f16 = sb.scalar_f16;
+  let vec2_f32 = sb.vec2_f32;
+  let vec2_i32 = sb.vec2_i32;
+  let vec2_u32 = sb.vec2_u32;
+  let vec2_f16 = sb.vec2_f16;
+  let vec3_f32 = sb.vec3_f32;
+  let vec3_i32 = sb.vec3_i32;
+  let vec3_u32 = sb.vec3_u32;
+  let vec3_f16 = sb.vec3_f16;
+  let vec4_f32 = sb.vec4_f32;
+  let vec4_i32 = sb.vec4_i32;
+  let vec4_u32 = sb.vec4_u32;
+  let vec4_f16 = sb.vec4_f16;
+  let mat2x2_f32 = sb.mat2x2_f32;
+  let mat2x3_f32 = sb.mat2x3_f32;
+  let mat2x4_f32 = sb.mat2x4_f32;
+  let mat3x2_f32 = sb.mat3x2_f32;
+  let mat3x3_f32 = sb.mat3x3_f32;
+  let mat3x4_f32 = sb.mat3x4_f32;
+  let mat4x2_f32 = sb.mat4x2_f32;
+  let mat4x3_f32 = sb.mat4x3_f32;
+  let mat4x4_f32 = sb.mat4x4_f32;
+  let mat2x2_f16 = sb.mat2x2_f16;
+  let mat2x3_f16 = sb.mat2x3_f16;
+  let mat2x4_f16 = sb.mat2x4_f16;
+  let mat3x2_f16 = sb.mat3x2_f16;
+  let mat3x3_f16 = sb.mat3x3_f16;
+  let mat3x4_f16 = sb.mat3x4_f16;
+  let mat4x2_f16 = sb.mat4x2_f16;
+  let mat4x3_f16 = sb.mat4x3_f16;
+  let mat4x4_f16 = sb.mat4x4_f16;
+  let arr2_vec3_f32 = sb.arr2_vec3_f32;
+  let arr2_mat4x2_f16 = sb.arr2_mat4x2_f16;
+  let struct_inner = sb.struct_inner;
+  let array_struct_inner = sb.array_struct_inner;
+}
diff --git a/test/tint/buffer/storage/static_index/write.wgsl b/test/tint/buffer/storage/static_index/write.wgsl
index 5290db8..abec74e 100644
--- a/test/tint/buffer/storage/static_index/write.wgsl
+++ b/test/tint/buffer/storage/static_index/write.wgsl
@@ -1,32 +1,61 @@
 struct Inner {
-    x : i32,
+    scalar_i32 : i32,
+    scalar_f32 : f32,
 };
 
 struct S {
-    a : vec3<i32>,
-    b : i32,
-    c : vec3<u32>,
-    d : u32,
-    e : vec3<f32>,
-    f : f32,
-    g : mat2x3<f32>,
-    h : mat3x2<f32>,
-    i : Inner,
-    j : array<Inner, 4>,
+    scalar_f32 : f32,
+    scalar_i32 : i32,
+    scalar_u32 : u32,
+    vec2_f32 : vec2<f32>,
+    vec2_i32 : vec2<i32>,
+    vec2_u32 : vec2<u32>,
+    vec3_f32 : vec3<f32>,
+    vec3_i32 : vec3<i32>,
+    vec3_u32 : vec3<u32>,
+    vec4_f32 : vec4<f32>,
+    vec4_i32 : vec4<i32>,
+    vec4_u32 : vec4<u32>,
+    mat2x2_f32 : mat2x2<f32>,
+    mat2x3_f32 : mat2x3<f32>,
+    mat2x4_f32 : mat2x4<f32>,
+    mat3x2_f32 : mat3x2<f32>,
+    mat3x3_f32 : mat3x3<f32>,
+    mat3x4_f32 : mat3x4<f32>,
+    mat4x2_f32 : mat4x2<f32>,
+    mat4x3_f32 : mat4x3<f32>,
+    mat4x4_f32 : mat4x4<f32>,
+    arr2_vec3_f32 : array<vec3<f32>, 2>,
+    struct_inner : Inner,
+    array_struct_inner : array<Inner, 4>,
 };
 
-@binding(0) @group(0) var<storage, read_write> s : S;
+@binding(0) @group(0) var<storage, read_write> sb : S;
 
 @compute @workgroup_size(1)
 fn main() {
-    s.a = vec3<i32>();
-    s.b = i32();
-    s.c = vec3<u32>();
-    s.d = u32();
-    s.e = vec3<f32>();
-    s.f = f32();
-    s.g = mat2x3<f32>();
-    s.h = mat3x2<f32>();
-    s.i = Inner();
-    s.j = array<Inner, 4>();
+    sb.scalar_f32 = f32();
+    sb.scalar_i32 = i32();
+    sb.scalar_u32 = u32();
+    sb.vec2_f32 = vec2<f32>();
+    sb.vec2_i32 = vec2<i32>();
+    sb.vec2_u32 = vec2<u32>();
+    sb.vec3_f32 = vec3<f32>();
+    sb.vec3_i32 = vec3<i32>();
+    sb.vec3_u32 = vec3<u32>();
+    sb.vec4_f32 = vec4<f32>();
+    sb.vec4_i32 = vec4<i32>();
+    sb.vec4_u32 = vec4<u32>();
+    sb.mat2x2_f32 = mat2x2<f32>();
+    sb.mat2x3_f32 = mat2x3<f32>();
+    sb.mat2x4_f32 = mat2x4<f32>();
+    sb.mat3x2_f32 = mat3x2<f32>();
+    sb.mat3x3_f32 = mat3x3<f32>();
+    sb.mat3x4_f32 = mat3x4<f32>();
+    sb.mat4x2_f32 = mat4x2<f32>();
+    sb.mat4x3_f32 = mat4x3<f32>();
+    sb.mat4x4_f32 = mat4x4<f32>();
+    sb.arr2_vec3_f32 = array<vec3<f32>, 2>();
+    sb.struct_inner = Inner();
+    sb.array_struct_inner = array<Inner, 4>();
 }
diff --git a/test/tint/buffer/storage/static_index/write.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/static_index/write.wgsl.expected.dxc.hlsl
index 0717f6d..1fcb362 100644
--- a/test/tint/buffer/storage/static_index/write.wgsl.expected.dxc.hlsl
+++ b/test/tint/buffer/storage/static_index/write.wgsl.expected.dxc.hlsl
@@ -1,46 +1,115 @@
 struct Inner {
-  int x;
+  int scalar_i32;
+  float scalar_f32;
 };
 
-RWByteAddressBuffer s : register(u0, space0);
+RWByteAddressBuffer sb : register(u0, space0);
 
-void tint_symbol_6(RWByteAddressBuffer buffer, uint offset, float2x3 value) {
+void tint_symbol_12(RWByteAddressBuffer buffer, uint offset, float2x2 value) {
+  buffer.Store2((offset + 0u), asuint(value[0u]));
+  buffer.Store2((offset + 8u), asuint(value[1u]));
+}
+
+void tint_symbol_13(RWByteAddressBuffer buffer, uint offset, float2x3 value) {
   buffer.Store3((offset + 0u), asuint(value[0u]));
   buffer.Store3((offset + 16u), asuint(value[1u]));
 }
 
-void tint_symbol_7(RWByteAddressBuffer buffer, uint offset, float3x2 value) {
+void tint_symbol_14(RWByteAddressBuffer buffer, uint offset, float2x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+}
+
+void tint_symbol_15(RWByteAddressBuffer buffer, uint offset, float3x2 value) {
   buffer.Store2((offset + 0u), asuint(value[0u]));
   buffer.Store2((offset + 8u), asuint(value[1u]));
   buffer.Store2((offset + 16u), asuint(value[2u]));
 }
 
-void tint_symbol_9(RWByteAddressBuffer buffer, uint offset, Inner value) {
-  buffer.Store((offset + 0u), asuint(value.x));
+void tint_symbol_16(RWByteAddressBuffer buffer, uint offset, float3x3 value) {
+  buffer.Store3((offset + 0u), asuint(value[0u]));
+  buffer.Store3((offset + 16u), asuint(value[1u]));
+  buffer.Store3((offset + 32u), asuint(value[2u]));
 }
 
-void tint_symbol_10(RWByteAddressBuffer buffer, uint offset, Inner value[4]) {
-  Inner array[4] = value;
+void tint_symbol_17(RWByteAddressBuffer buffer, uint offset, float3x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+  buffer.Store4((offset + 32u), asuint(value[2u]));
+}
+
+void tint_symbol_18(RWByteAddressBuffer buffer, uint offset, float4x2 value) {
+  buffer.Store2((offset + 0u), asuint(value[0u]));
+  buffer.Store2((offset + 8u), asuint(value[1u]));
+  buffer.Store2((offset + 16u), asuint(value[2u]));
+  buffer.Store2((offset + 24u), asuint(value[3u]));
+}
+
+void tint_symbol_19(RWByteAddressBuffer buffer, uint offset, float4x3 value) {
+  buffer.Store3((offset + 0u), asuint(value[0u]));
+  buffer.Store3((offset + 16u), asuint(value[1u]));
+  buffer.Store3((offset + 32u), asuint(value[2u]));
+  buffer.Store3((offset + 48u), asuint(value[3u]));
+}
+
+void tint_symbol_20(RWByteAddressBuffer buffer, uint offset, float4x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+  buffer.Store4((offset + 32u), asuint(value[2u]));
+  buffer.Store4((offset + 48u), asuint(value[3u]));
+}
+
+void tint_symbol_21(RWByteAddressBuffer buffer, uint offset, float3 value[2]) {
+  float3 array[2] = value;
+  {
+    for(uint i = 0u; (i < 2u); i = (i + 1u)) {
+      buffer.Store3((offset + (i * 16u)), asuint(array[i]));
+    }
+  }
+}
+
+void tint_symbol_22(RWByteAddressBuffer buffer, uint offset, Inner value) {
+  buffer.Store((offset + 0u), asuint(value.scalar_i32));
+  buffer.Store((offset + 4u), asuint(value.scalar_f32));
+}
+
+void tint_symbol_23(RWByteAddressBuffer buffer, uint offset, Inner value[4]) {
+  Inner array_1[4] = value;
   {
     for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
-      tint_symbol_9(buffer, (offset + (i_1 * 4u)), array[i_1]);
+      tint_symbol_22(buffer, (offset + (i_1 * 8u)), array_1[i_1]);
     }
   }
 }
 
 [numthreads(1, 1, 1)]
 void main() {
-  s.Store3(0u, asuint((0).xxx));
-  s.Store(12u, asuint(0));
-  s.Store3(16u, asuint((0u).xxx));
-  s.Store(28u, asuint(0u));
-  s.Store3(32u, asuint((0.0f).xxx));
-  s.Store(44u, asuint(0.0f));
-  tint_symbol_6(s, 48u, float2x3((0.0f).xxx, (0.0f).xxx));
-  tint_symbol_7(s, 80u, float3x2((0.0f).xx, (0.0f).xx, (0.0f).xx));
-  const Inner tint_symbol_11 = (Inner)0;
-  tint_symbol_9(s, 104u, tint_symbol_11);
-  const Inner tint_symbol_12[4] = (Inner[4])0;
-  tint_symbol_10(s, 108u, tint_symbol_12);
+  sb.Store(0u, asuint(0.0f));
+  sb.Store(4u, asuint(0));
+  sb.Store(8u, asuint(0u));
+  sb.Store2(16u, asuint((0.0f).xx));
+  sb.Store2(24u, asuint((0).xx));
+  sb.Store2(32u, asuint((0u).xx));
+  sb.Store3(48u, asuint((0.0f).xxx));
+  sb.Store3(64u, asuint((0).xxx));
+  sb.Store3(80u, asuint((0u).xxx));
+  sb.Store4(96u, asuint((0.0f).xxxx));
+  sb.Store4(112u, asuint((0).xxxx));
+  sb.Store4(128u, asuint((0u).xxxx));
+  tint_symbol_12(sb, 144u, float2x2((0.0f).xx, (0.0f).xx));
+  tint_symbol_13(sb, 160u, float2x3((0.0f).xxx, (0.0f).xxx));
+  tint_symbol_14(sb, 192u, float2x4((0.0f).xxxx, (0.0f).xxxx));
+  tint_symbol_15(sb, 224u, float3x2((0.0f).xx, (0.0f).xx, (0.0f).xx));
+  tint_symbol_16(sb, 256u, float3x3((0.0f).xxx, (0.0f).xxx, (0.0f).xxx));
+  tint_symbol_17(sb, 304u, float3x4((0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx));
+  tint_symbol_18(sb, 352u, float4x2((0.0f).xx, (0.0f).xx, (0.0f).xx, (0.0f).xx));
+  tint_symbol_19(sb, 384u, float4x3((0.0f).xxx, (0.0f).xxx, (0.0f).xxx, (0.0f).xxx));
+  tint_symbol_20(sb, 448u, float4x4((0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx));
+  const float3 tint_symbol_24[2] = (float3[2])0;
+  tint_symbol_21(sb, 512u, tint_symbol_24);
+  const Inner tint_symbol_25 = (Inner)0;
+  tint_symbol_22(sb, 544u, tint_symbol_25);
+  const Inner tint_symbol_26[4] = (Inner[4])0;
+  tint_symbol_23(sb, 552u, tint_symbol_26);
   return;
 }
diff --git a/test/tint/buffer/storage/static_index/write.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/static_index/write.wgsl.expected.fxc.hlsl
index 0717f6d..1fcb362 100644
--- a/test/tint/buffer/storage/static_index/write.wgsl.expected.fxc.hlsl
+++ b/test/tint/buffer/storage/static_index/write.wgsl.expected.fxc.hlsl
@@ -1,46 +1,115 @@
 struct Inner {
-  int x;
+  int scalar_i32;
+  float scalar_f32;
 };
 
-RWByteAddressBuffer s : register(u0, space0);
+RWByteAddressBuffer sb : register(u0, space0);
 
-void tint_symbol_6(RWByteAddressBuffer buffer, uint offset, float2x3 value) {
+void tint_symbol_12(RWByteAddressBuffer buffer, uint offset, float2x2 value) {
+  buffer.Store2((offset + 0u), asuint(value[0u]));
+  buffer.Store2((offset + 8u), asuint(value[1u]));
+}
+
+void tint_symbol_13(RWByteAddressBuffer buffer, uint offset, float2x3 value) {
   buffer.Store3((offset + 0u), asuint(value[0u]));
   buffer.Store3((offset + 16u), asuint(value[1u]));
 }
 
-void tint_symbol_7(RWByteAddressBuffer buffer, uint offset, float3x2 value) {
+void tint_symbol_14(RWByteAddressBuffer buffer, uint offset, float2x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+}
+
+void tint_symbol_15(RWByteAddressBuffer buffer, uint offset, float3x2 value) {
   buffer.Store2((offset + 0u), asuint(value[0u]));
   buffer.Store2((offset + 8u), asuint(value[1u]));
   buffer.Store2((offset + 16u), asuint(value[2u]));
 }
 
-void tint_symbol_9(RWByteAddressBuffer buffer, uint offset, Inner value) {
-  buffer.Store((offset + 0u), asuint(value.x));
+void tint_symbol_16(RWByteAddressBuffer buffer, uint offset, float3x3 value) {
+  buffer.Store3((offset + 0u), asuint(value[0u]));
+  buffer.Store3((offset + 16u), asuint(value[1u]));
+  buffer.Store3((offset + 32u), asuint(value[2u]));
 }
 
-void tint_symbol_10(RWByteAddressBuffer buffer, uint offset, Inner value[4]) {
-  Inner array[4] = value;
+void tint_symbol_17(RWByteAddressBuffer buffer, uint offset, float3x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+  buffer.Store4((offset + 32u), asuint(value[2u]));
+}
+
+void tint_symbol_18(RWByteAddressBuffer buffer, uint offset, float4x2 value) {
+  buffer.Store2((offset + 0u), asuint(value[0u]));
+  buffer.Store2((offset + 8u), asuint(value[1u]));
+  buffer.Store2((offset + 16u), asuint(value[2u]));
+  buffer.Store2((offset + 24u), asuint(value[3u]));
+}
+
+void tint_symbol_19(RWByteAddressBuffer buffer, uint offset, float4x3 value) {
+  buffer.Store3((offset + 0u), asuint(value[0u]));
+  buffer.Store3((offset + 16u), asuint(value[1u]));
+  buffer.Store3((offset + 32u), asuint(value[2u]));
+  buffer.Store3((offset + 48u), asuint(value[3u]));
+}
+
+void tint_symbol_20(RWByteAddressBuffer buffer, uint offset, float4x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+  buffer.Store4((offset + 32u), asuint(value[2u]));
+  buffer.Store4((offset + 48u), asuint(value[3u]));
+}
+
+void tint_symbol_21(RWByteAddressBuffer buffer, uint offset, float3 value[2]) {
+  float3 array[2] = value;
+  {
+    for(uint i = 0u; (i < 2u); i = (i + 1u)) {
+      buffer.Store3((offset + (i * 16u)), asuint(array[i]));
+    }
+  }
+}
+
+void tint_symbol_22(RWByteAddressBuffer buffer, uint offset, Inner value) {
+  buffer.Store((offset + 0u), asuint(value.scalar_i32));
+  buffer.Store((offset + 4u), asuint(value.scalar_f32));
+}
+
+void tint_symbol_23(RWByteAddressBuffer buffer, uint offset, Inner value[4]) {
+  Inner array_1[4] = value;
   {
     for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
-      tint_symbol_9(buffer, (offset + (i_1 * 4u)), array[i_1]);
+      tint_symbol_22(buffer, (offset + (i_1 * 8u)), array_1[i_1]);
     }
   }
 }
 
 [numthreads(1, 1, 1)]
 void main() {
-  s.Store3(0u, asuint((0).xxx));
-  s.Store(12u, asuint(0));
-  s.Store3(16u, asuint((0u).xxx));
-  s.Store(28u, asuint(0u));
-  s.Store3(32u, asuint((0.0f).xxx));
-  s.Store(44u, asuint(0.0f));
-  tint_symbol_6(s, 48u, float2x3((0.0f).xxx, (0.0f).xxx));
-  tint_symbol_7(s, 80u, float3x2((0.0f).xx, (0.0f).xx, (0.0f).xx));
-  const Inner tint_symbol_11 = (Inner)0;
-  tint_symbol_9(s, 104u, tint_symbol_11);
-  const Inner tint_symbol_12[4] = (Inner[4])0;
-  tint_symbol_10(s, 108u, tint_symbol_12);
+  sb.Store(0u, asuint(0.0f));
+  sb.Store(4u, asuint(0));
+  sb.Store(8u, asuint(0u));
+  sb.Store2(16u, asuint((0.0f).xx));
+  sb.Store2(24u, asuint((0).xx));
+  sb.Store2(32u, asuint((0u).xx));
+  sb.Store3(48u, asuint((0.0f).xxx));
+  sb.Store3(64u, asuint((0).xxx));
+  sb.Store3(80u, asuint((0u).xxx));
+  sb.Store4(96u, asuint((0.0f).xxxx));
+  sb.Store4(112u, asuint((0).xxxx));
+  sb.Store4(128u, asuint((0u).xxxx));
+  tint_symbol_12(sb, 144u, float2x2((0.0f).xx, (0.0f).xx));
+  tint_symbol_13(sb, 160u, float2x3((0.0f).xxx, (0.0f).xxx));
+  tint_symbol_14(sb, 192u, float2x4((0.0f).xxxx, (0.0f).xxxx));
+  tint_symbol_15(sb, 224u, float3x2((0.0f).xx, (0.0f).xx, (0.0f).xx));
+  tint_symbol_16(sb, 256u, float3x3((0.0f).xxx, (0.0f).xxx, (0.0f).xxx));
+  tint_symbol_17(sb, 304u, float3x4((0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx));
+  tint_symbol_18(sb, 352u, float4x2((0.0f).xx, (0.0f).xx, (0.0f).xx, (0.0f).xx));
+  tint_symbol_19(sb, 384u, float4x3((0.0f).xxx, (0.0f).xxx, (0.0f).xxx, (0.0f).xxx));
+  tint_symbol_20(sb, 448u, float4x4((0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx));
+  const float3 tint_symbol_24[2] = (float3[2])0;
+  tint_symbol_21(sb, 512u, tint_symbol_24);
+  const Inner tint_symbol_25 = (Inner)0;
+  tint_symbol_22(sb, 544u, tint_symbol_25);
+  const Inner tint_symbol_26[4] = (Inner[4])0;
+  tint_symbol_23(sb, 552u, tint_symbol_26);
   return;
 }
diff --git a/test/tint/buffer/storage/static_index/write.wgsl.expected.glsl b/test/tint/buffer/storage/static_index/write.wgsl.expected.glsl
index d6b3a38..636c5c3 100644
--- a/test/tint/buffer/storage/static_index/write.wgsl.expected.glsl
+++ b/test/tint/buffer/storage/static_index/write.wgsl.expected.glsl
@@ -1,40 +1,79 @@
 #version 310 es
 
 struct Inner {
-  int x;
+  int scalar_i32;
+  float scalar_f32;
 };
 
 struct S {
-  ivec3 a;
-  int b;
-  uvec3 c;
-  uint d;
-  vec3 e;
-  float f;
-  mat2x3 g;
-  mat3x2 h;
-  Inner i;
-  Inner j[4];
+  float scalar_f32;
+  int scalar_i32;
+  uint scalar_u32;
   uint pad;
+  vec2 vec2_f32;
+  ivec2 vec2_i32;
+  uvec2 vec2_u32;
+  uint pad_1;
+  uint pad_2;
+  vec3 vec3_f32;
+  uint pad_3;
+  ivec3 vec3_i32;
+  uint pad_4;
+  uvec3 vec3_u32;
+  uint pad_5;
+  vec4 vec4_f32;
+  ivec4 vec4_i32;
+  uvec4 vec4_u32;
+  mat2 mat2x2_f32;
+  mat2x3 mat2x3_f32;
+  mat2x4 mat2x4_f32;
+  mat3x2 mat3x2_f32;
+  uint pad_6;
+  uint pad_7;
+  mat3 mat3x3_f32;
+  mat3x4 mat3x4_f32;
+  mat4x2 mat4x2_f32;
+  mat4x3 mat4x3_f32;
+  mat4 mat4x4_f32;
+  vec3 arr2_vec3_f32[2];
+  Inner struct_inner;
+  Inner array_struct_inner[4];
+  uint pad_8;
+  uint pad_9;
 };
 
-layout(binding = 0, std430) buffer s_block_ssbo {
+layout(binding = 0, std430) buffer sb_block_ssbo {
   S inner;
-} s;
+} sb;
 
 void tint_symbol() {
-  s.inner.a = ivec3(0);
-  s.inner.b = 0;
-  s.inner.c = uvec3(0u);
-  s.inner.d = 0u;
-  s.inner.e = vec3(0.0f);
-  s.inner.f = 0.0f;
-  s.inner.g = mat2x3(vec3(0.0f), vec3(0.0f));
-  s.inner.h = mat3x2(vec2(0.0f), vec2(0.0f), vec2(0.0f));
-  Inner tint_symbol_1 = Inner(0);
-  s.inner.i = tint_symbol_1;
-  Inner tint_symbol_2[4] = Inner[4](Inner(0), Inner(0), Inner(0), Inner(0));
-  s.inner.j = tint_symbol_2;
+  sb.inner.scalar_f32 = 0.0f;
+  sb.inner.scalar_i32 = 0;
+  sb.inner.scalar_u32 = 0u;
+  sb.inner.vec2_f32 = vec2(0.0f);
+  sb.inner.vec2_i32 = ivec2(0);
+  sb.inner.vec2_u32 = uvec2(0u);
+  sb.inner.vec3_f32 = vec3(0.0f);
+  sb.inner.vec3_i32 = ivec3(0);
+  sb.inner.vec3_u32 = uvec3(0u);
+  sb.inner.vec4_f32 = vec4(0.0f);
+  sb.inner.vec4_i32 = ivec4(0);
+  sb.inner.vec4_u32 = uvec4(0u);
+  sb.inner.mat2x2_f32 = mat2(vec2(0.0f), vec2(0.0f));
+  sb.inner.mat2x3_f32 = mat2x3(vec3(0.0f), vec3(0.0f));
+  sb.inner.mat2x4_f32 = mat2x4(vec4(0.0f), vec4(0.0f));
+  sb.inner.mat3x2_f32 = mat3x2(vec2(0.0f), vec2(0.0f), vec2(0.0f));
+  sb.inner.mat3x3_f32 = mat3(vec3(0.0f), vec3(0.0f), vec3(0.0f));
+  sb.inner.mat3x4_f32 = mat3x4(vec4(0.0f), vec4(0.0f), vec4(0.0f));
+  sb.inner.mat4x2_f32 = mat4x2(vec2(0.0f), vec2(0.0f), vec2(0.0f), vec2(0.0f));
+  sb.inner.mat4x3_f32 = mat4x3(vec3(0.0f), vec3(0.0f), vec3(0.0f), vec3(0.0f));
+  sb.inner.mat4x4_f32 = mat4(vec4(0.0f), vec4(0.0f), vec4(0.0f), vec4(0.0f));
+  vec3 tint_symbol_1[2] = vec3[2](vec3(0.0f), vec3(0.0f));
+  sb.inner.arr2_vec3_f32 = tint_symbol_1;
+  Inner tint_symbol_2 = Inner(0, 0.0f);
+  sb.inner.struct_inner = tint_symbol_2;
+  Inner tint_symbol_3[4] = Inner[4](Inner(0, 0.0f), Inner(0, 0.0f), Inner(0, 0.0f), Inner(0, 0.0f));
+  sb.inner.array_struct_inner = tint_symbol_3;
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/buffer/storage/static_index/write.wgsl.expected.msl b/test/tint/buffer/storage/static_index/write.wgsl.expected.msl
index 1b21710..838c6a8 100644
--- a/test/tint/buffer/storage/static_index/write.wgsl.expected.msl
+++ b/test/tint/buffer/storage/static_index/write.wgsl.expected.msl
@@ -15,36 +15,72 @@
 };
 
 struct Inner {
-  /* 0x0000 */ int x;
+  /* 0x0000 */ int scalar_i32;
+  /* 0x0004 */ float scalar_f32;
 };
 
 struct S {
-  /* 0x0000 */ packed_int3 a;
-  /* 0x000c */ int b;
-  /* 0x0010 */ packed_uint3 c;
-  /* 0x001c */ uint d;
-  /* 0x0020 */ packed_float3 e;
-  /* 0x002c */ float f;
-  /* 0x0030 */ float2x3 g;
-  /* 0x0050 */ float3x2 h;
-  /* 0x0068 */ Inner i;
-  /* 0x006c */ tint_array<Inner, 4> j;
-  /* 0x007c */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0000 */ float scalar_f32;
+  /* 0x0004 */ int scalar_i32;
+  /* 0x0008 */ uint scalar_u32;
+  /* 0x000c */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0010 */ float2 vec2_f32;
+  /* 0x0018 */ int2 vec2_i32;
+  /* 0x0020 */ uint2 vec2_u32;
+  /* 0x0028 */ tint_array<int8_t, 8> tint_pad_1;
+  /* 0x0030 */ packed_float3 vec3_f32;
+  /* 0x003c */ tint_array<int8_t, 4> tint_pad_2;
+  /* 0x0040 */ packed_int3 vec3_i32;
+  /* 0x004c */ tint_array<int8_t, 4> tint_pad_3;
+  /* 0x0050 */ packed_uint3 vec3_u32;
+  /* 0x005c */ tint_array<int8_t, 4> tint_pad_4;
+  /* 0x0060 */ float4 vec4_f32;
+  /* 0x0070 */ int4 vec4_i32;
+  /* 0x0080 */ uint4 vec4_u32;
+  /* 0x0090 */ float2x2 mat2x2_f32;
+  /* 0x00a0 */ float2x3 mat2x3_f32;
+  /* 0x00c0 */ float2x4 mat2x4_f32;
+  /* 0x00e0 */ float3x2 mat3x2_f32;
+  /* 0x00f8 */ tint_array<int8_t, 8> tint_pad_5;
+  /* 0x0100 */ float3x3 mat3x3_f32;
+  /* 0x0130 */ float3x4 mat3x4_f32;
+  /* 0x0160 */ float4x2 mat4x2_f32;
+  /* 0x0180 */ float4x3 mat4x3_f32;
+  /* 0x01c0 */ float4x4 mat4x4_f32;
+  /* 0x0200 */ tint_array<float3, 2> arr2_vec3_f32;
+  /* 0x0220 */ Inner struct_inner;
+  /* 0x0228 */ tint_array<Inner, 4> array_struct_inner;
+  /* 0x0248 */ tint_array<int8_t, 8> tint_pad_6;
 };
 
-kernel void tint_symbol(device S* tint_symbol_3 [[buffer(0)]]) {
-  (*(tint_symbol_3)).a = int3(0);
-  (*(tint_symbol_3)).b = 0;
-  (*(tint_symbol_3)).c = uint3(0u);
-  (*(tint_symbol_3)).d = 0u;
-  (*(tint_symbol_3)).e = float3(0.0f);
-  (*(tint_symbol_3)).f = 0.0f;
-  (*(tint_symbol_3)).g = float2x3(float3(0.0f), float3(0.0f));
-  (*(tint_symbol_3)).h = float3x2(float2(0.0f), float2(0.0f), float2(0.0f));
-  Inner const tint_symbol_1 = Inner{};
-  (*(tint_symbol_3)).i = tint_symbol_1;
-  tint_array<Inner, 4> const tint_symbol_2 = tint_array<Inner, 4>{};
-  (*(tint_symbol_3)).j = tint_symbol_2;
+kernel void tint_symbol(device S* tint_symbol_4 [[buffer(0)]]) {
+  (*(tint_symbol_4)).scalar_f32 = 0.0f;
+  (*(tint_symbol_4)).scalar_i32 = 0;
+  (*(tint_symbol_4)).scalar_u32 = 0u;
+  (*(tint_symbol_4)).vec2_f32 = float2(0.0f);
+  (*(tint_symbol_4)).vec2_i32 = int2(0);
+  (*(tint_symbol_4)).vec2_u32 = uint2(0u);
+  (*(tint_symbol_4)).vec3_f32 = float3(0.0f);
+  (*(tint_symbol_4)).vec3_i32 = int3(0);
+  (*(tint_symbol_4)).vec3_u32 = uint3(0u);
+  (*(tint_symbol_4)).vec4_f32 = float4(0.0f);
+  (*(tint_symbol_4)).vec4_i32 = int4(0);
+  (*(tint_symbol_4)).vec4_u32 = uint4(0u);
+  (*(tint_symbol_4)).mat2x2_f32 = float2x2(float2(0.0f), float2(0.0f));
+  (*(tint_symbol_4)).mat2x3_f32 = float2x3(float3(0.0f), float3(0.0f));
+  (*(tint_symbol_4)).mat2x4_f32 = float2x4(float4(0.0f), float4(0.0f));
+  (*(tint_symbol_4)).mat3x2_f32 = float3x2(float2(0.0f), float2(0.0f), float2(0.0f));
+  (*(tint_symbol_4)).mat3x3_f32 = float3x3(float3(0.0f), float3(0.0f), float3(0.0f));
+  (*(tint_symbol_4)).mat3x4_f32 = float3x4(float4(0.0f), float4(0.0f), float4(0.0f));
+  (*(tint_symbol_4)).mat4x2_f32 = float4x2(float2(0.0f), float2(0.0f), float2(0.0f), float2(0.0f));
+  (*(tint_symbol_4)).mat4x3_f32 = float4x3(float3(0.0f), float3(0.0f), float3(0.0f), float3(0.0f));
+  (*(tint_symbol_4)).mat4x4_f32 = float4x4(float4(0.0f), float4(0.0f), float4(0.0f), float4(0.0f));
+  tint_array<float3, 2> const tint_symbol_1 = tint_array<float3, 2>{};
+  (*(tint_symbol_4)).arr2_vec3_f32 = tint_symbol_1;
+  Inner const tint_symbol_2 = Inner{};
+  (*(tint_symbol_4)).struct_inner = tint_symbol_2;
+  tint_array<Inner, 4> const tint_symbol_3 = tint_array<Inner, 4>{};
+  (*(tint_symbol_4)).array_struct_inner = tint_symbol_3;
   return;
 }
 
diff --git a/test/tint/buffer/storage/static_index/write.wgsl.expected.spvasm b/test/tint/buffer/storage/static_index/write.wgsl.expected.spvasm
index aae7630..2faa9c9 100644
--- a/test/tint/buffer/storage/static_index/write.wgsl.expected.spvasm
+++ b/test/tint/buffer/storage/static_index/write.wgsl.expected.spvasm
@@ -1,117 +1,245 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 60
+; Bound: 129
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %main "main"
                OpExecutionMode %main LocalSize 1 1 1
-               OpName %s_block "s_block"
-               OpMemberName %s_block 0 "inner"
+               OpName %sb_block "sb_block"
+               OpMemberName %sb_block 0 "inner"
                OpName %S "S"
-               OpMemberName %S 0 "a"
-               OpMemberName %S 1 "b"
-               OpMemberName %S 2 "c"
-               OpMemberName %S 3 "d"
-               OpMemberName %S 4 "e"
-               OpMemberName %S 5 "f"
-               OpMemberName %S 6 "g"
-               OpMemberName %S 7 "h"
-               OpMemberName %S 8 "i"
+               OpMemberName %S 0 "scalar_f32"
+               OpMemberName %S 1 "scalar_i32"
+               OpMemberName %S 2 "scalar_u32"
+               OpMemberName %S 3 "vec2_f32"
+               OpMemberName %S 4 "vec2_i32"
+               OpMemberName %S 5 "vec2_u32"
+               OpMemberName %S 6 "vec3_f32"
+               OpMemberName %S 7 "vec3_i32"
+               OpMemberName %S 8 "vec3_u32"
+               OpMemberName %S 9 "vec4_f32"
+               OpMemberName %S 10 "vec4_i32"
+               OpMemberName %S 11 "vec4_u32"
+               OpMemberName %S 12 "mat2x2_f32"
+               OpMemberName %S 13 "mat2x3_f32"
+               OpMemberName %S 14 "mat2x4_f32"
+               OpMemberName %S 15 "mat3x2_f32"
+               OpMemberName %S 16 "mat3x3_f32"
+               OpMemberName %S 17 "mat3x4_f32"
+               OpMemberName %S 18 "mat4x2_f32"
+               OpMemberName %S 19 "mat4x3_f32"
+               OpMemberName %S 20 "mat4x4_f32"
+               OpMemberName %S 21 "arr2_vec3_f32"
+               OpMemberName %S 22 "struct_inner"
                OpName %Inner "Inner"
-               OpMemberName %Inner 0 "x"
-               OpMemberName %S 9 "j"
-               OpName %s "s"
+               OpMemberName %Inner 0 "scalar_i32"
+               OpMemberName %Inner 1 "scalar_f32"
+               OpMemberName %S 23 "array_struct_inner"
+               OpName %sb "sb"
                OpName %main "main"
-               OpDecorate %s_block Block
-               OpMemberDecorate %s_block 0 Offset 0
+               OpDecorate %sb_block Block
+               OpMemberDecorate %sb_block 0 Offset 0
                OpMemberDecorate %S 0 Offset 0
-               OpMemberDecorate %S 1 Offset 12
-               OpMemberDecorate %S 2 Offset 16
-               OpMemberDecorate %S 3 Offset 28
-               OpMemberDecorate %S 4 Offset 32
-               OpMemberDecorate %S 5 Offset 44
+               OpMemberDecorate %S 1 Offset 4
+               OpMemberDecorate %S 2 Offset 8
+               OpMemberDecorate %S 3 Offset 16
+               OpMemberDecorate %S 4 Offset 24
+               OpMemberDecorate %S 5 Offset 32
                OpMemberDecorate %S 6 Offset 48
-               OpMemberDecorate %S 6 ColMajor
-               OpMemberDecorate %S 6 MatrixStride 16
-               OpMemberDecorate %S 7 Offset 80
-               OpMemberDecorate %S 7 ColMajor
-               OpMemberDecorate %S 7 MatrixStride 8
-               OpMemberDecorate %S 8 Offset 104
+               OpMemberDecorate %S 7 Offset 64
+               OpMemberDecorate %S 8 Offset 80
+               OpMemberDecorate %S 9 Offset 96
+               OpMemberDecorate %S 10 Offset 112
+               OpMemberDecorate %S 11 Offset 128
+               OpMemberDecorate %S 12 Offset 144
+               OpMemberDecorate %S 12 ColMajor
+               OpMemberDecorate %S 12 MatrixStride 8
+               OpMemberDecorate %S 13 Offset 160
+               OpMemberDecorate %S 13 ColMajor
+               OpMemberDecorate %S 13 MatrixStride 16
+               OpMemberDecorate %S 14 Offset 192
+               OpMemberDecorate %S 14 ColMajor
+               OpMemberDecorate %S 14 MatrixStride 16
+               OpMemberDecorate %S 15 Offset 224
+               OpMemberDecorate %S 15 ColMajor
+               OpMemberDecorate %S 15 MatrixStride 8
+               OpMemberDecorate %S 16 Offset 256
+               OpMemberDecorate %S 16 ColMajor
+               OpMemberDecorate %S 16 MatrixStride 16
+               OpMemberDecorate %S 17 Offset 304
+               OpMemberDecorate %S 17 ColMajor
+               OpMemberDecorate %S 17 MatrixStride 16
+               OpMemberDecorate %S 18 Offset 352
+               OpMemberDecorate %S 18 ColMajor
+               OpMemberDecorate %S 18 MatrixStride 8
+               OpMemberDecorate %S 19 Offset 384
+               OpMemberDecorate %S 19 ColMajor
+               OpMemberDecorate %S 19 MatrixStride 16
+               OpMemberDecorate %S 20 Offset 448
+               OpMemberDecorate %S 20 ColMajor
+               OpMemberDecorate %S 20 MatrixStride 16
+               OpMemberDecorate %S 21 Offset 512
+               OpDecorate %_arr_v3float_uint_2 ArrayStride 16
+               OpMemberDecorate %S 22 Offset 544
                OpMemberDecorate %Inner 0 Offset 0
-               OpMemberDecorate %S 9 Offset 108
-               OpDecorate %_arr_Inner_uint_4 ArrayStride 4
-               OpDecorate %s Binding 0
-               OpDecorate %s DescriptorSet 0
-        %int = OpTypeInt 32 1
-      %v3int = OpTypeVector %int 3
-       %uint = OpTypeInt 32 0
-     %v3uint = OpTypeVector %uint 3
+               OpMemberDecorate %Inner 1 Offset 4
+               OpMemberDecorate %S 23 Offset 552
+               OpDecorate %_arr_Inner_uint_4 ArrayStride 8
+               OpDecorate %sb Binding 0
+               OpDecorate %sb DescriptorSet 0
       %float = OpTypeFloat 32
-    %v3float = OpTypeVector %float 3
-%mat2v3float = OpTypeMatrix %v3float 2
+        %int = OpTypeInt 32 1
+       %uint = OpTypeInt 32 0
     %v2float = OpTypeVector %float 2
+      %v2int = OpTypeVector %int 2
+     %v2uint = OpTypeVector %uint 2
+    %v3float = OpTypeVector %float 3
+      %v3int = OpTypeVector %int 3
+     %v3uint = OpTypeVector %uint 3
+    %v4float = OpTypeVector %float 4
+      %v4int = OpTypeVector %int 4
+     %v4uint = OpTypeVector %uint 4
+%mat2v2float = OpTypeMatrix %v2float 2
+%mat2v3float = OpTypeMatrix %v3float 2
+%mat2v4float = OpTypeMatrix %v4float 2
 %mat3v2float = OpTypeMatrix %v2float 3
-      %Inner = OpTypeStruct %int
+%mat3v3float = OpTypeMatrix %v3float 3
+%mat3v4float = OpTypeMatrix %v4float 3
+%mat4v2float = OpTypeMatrix %v2float 4
+%mat4v3float = OpTypeMatrix %v3float 4
+%mat4v4float = OpTypeMatrix %v4float 4
+     %uint_2 = OpConstant %uint 2
+%_arr_v3float_uint_2 = OpTypeArray %v3float %uint_2
+      %Inner = OpTypeStruct %int %float
      %uint_4 = OpConstant %uint 4
 %_arr_Inner_uint_4 = OpTypeArray %Inner %uint_4
-          %S = OpTypeStruct %v3int %int %v3uint %uint %v3float %float %mat2v3float %mat3v2float %Inner %_arr_Inner_uint_4
-    %s_block = OpTypeStruct %S
-%_ptr_StorageBuffer_s_block = OpTypePointer StorageBuffer %s_block
-          %s = OpVariable %_ptr_StorageBuffer_s_block StorageBuffer
+          %S = OpTypeStruct %float %int %uint %v2float %v2int %v2uint %v3float %v3int %v3uint %v4float %v4int %v4uint %mat2v2float %mat2v3float %mat2v4float %mat3v2float %mat3v3float %mat3v4float %mat4v2float %mat4v3float %mat4v4float %_arr_v3float_uint_2 %Inner %_arr_Inner_uint_4
+   %sb_block = OpTypeStruct %S
+%_ptr_StorageBuffer_sb_block = OpTypePointer StorageBuffer %sb_block
+         %sb = OpVariable %_ptr_StorageBuffer_sb_block StorageBuffer
        %void = OpTypeVoid
-         %17 = OpTypeFunction %void
+         %31 = OpTypeFunction %void
      %uint_0 = OpConstant %uint 0
-%_ptr_StorageBuffer_v3int = OpTypePointer StorageBuffer %v3int
-         %24 = OpConstantNull %v3int
+%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
+         %38 = OpConstantNull %float
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_int = OpTypePointer StorageBuffer %int
-         %28 = OpConstantNull %int
-     %uint_2 = OpConstant %uint 2
-%_ptr_StorageBuffer_v3uint = OpTypePointer StorageBuffer %v3uint
-         %32 = OpConstantNull %v3uint
-     %uint_3 = OpConstant %uint 3
+         %42 = OpConstantNull %int
 %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
-         %36 = OpConstantNull %uint
-%_ptr_StorageBuffer_v3float = OpTypePointer StorageBuffer %v3float
-         %39 = OpConstantNull %v3float
+         %45 = OpConstantNull %uint
+     %uint_3 = OpConstant %uint 3
+%_ptr_StorageBuffer_v2float = OpTypePointer StorageBuffer %v2float
+         %49 = OpConstantNull %v2float
+%_ptr_StorageBuffer_v2int = OpTypePointer StorageBuffer %v2int
+         %52 = OpConstantNull %v2int
      %uint_5 = OpConstant %uint 5
-%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
-         %43 = OpConstantNull %float
+%_ptr_StorageBuffer_v2uint = OpTypePointer StorageBuffer %v2uint
+         %56 = OpConstantNull %v2uint
      %uint_6 = OpConstant %uint 6
-%_ptr_StorageBuffer_mat2v3float = OpTypePointer StorageBuffer %mat2v3float
-         %47 = OpConstantNull %mat2v3float
+%_ptr_StorageBuffer_v3float = OpTypePointer StorageBuffer %v3float
+         %60 = OpConstantNull %v3float
      %uint_7 = OpConstant %uint 7
-%_ptr_StorageBuffer_mat3v2float = OpTypePointer StorageBuffer %mat3v2float
-         %51 = OpConstantNull %mat3v2float
+%_ptr_StorageBuffer_v3int = OpTypePointer StorageBuffer %v3int
+         %64 = OpConstantNull %v3int
      %uint_8 = OpConstant %uint 8
-%_ptr_StorageBuffer_Inner = OpTypePointer StorageBuffer %Inner
-         %55 = OpConstantNull %Inner
+%_ptr_StorageBuffer_v3uint = OpTypePointer StorageBuffer %v3uint
+         %68 = OpConstantNull %v3uint
      %uint_9 = OpConstant %uint 9
+%_ptr_StorageBuffer_v4float = OpTypePointer StorageBuffer %v4float
+         %72 = OpConstantNull %v4float
+    %uint_10 = OpConstant %uint 10
+%_ptr_StorageBuffer_v4int = OpTypePointer StorageBuffer %v4int
+         %76 = OpConstantNull %v4int
+    %uint_11 = OpConstant %uint 11
+%_ptr_StorageBuffer_v4uint = OpTypePointer StorageBuffer %v4uint
+         %80 = OpConstantNull %v4uint
+    %uint_12 = OpConstant %uint 12
+%_ptr_StorageBuffer_mat2v2float = OpTypePointer StorageBuffer %mat2v2float
+         %84 = OpConstantNull %mat2v2float
+    %uint_13 = OpConstant %uint 13
+%_ptr_StorageBuffer_mat2v3float = OpTypePointer StorageBuffer %mat2v3float
+         %88 = OpConstantNull %mat2v3float
+    %uint_14 = OpConstant %uint 14
+%_ptr_StorageBuffer_mat2v4float = OpTypePointer StorageBuffer %mat2v4float
+         %92 = OpConstantNull %mat2v4float
+    %uint_15 = OpConstant %uint 15
+%_ptr_StorageBuffer_mat3v2float = OpTypePointer StorageBuffer %mat3v2float
+         %96 = OpConstantNull %mat3v2float
+    %uint_16 = OpConstant %uint 16
+%_ptr_StorageBuffer_mat3v3float = OpTypePointer StorageBuffer %mat3v3float
+        %100 = OpConstantNull %mat3v3float
+    %uint_17 = OpConstant %uint 17
+%_ptr_StorageBuffer_mat3v4float = OpTypePointer StorageBuffer %mat3v4float
+        %104 = OpConstantNull %mat3v4float
+    %uint_18 = OpConstant %uint 18
+%_ptr_StorageBuffer_mat4v2float = OpTypePointer StorageBuffer %mat4v2float
+        %108 = OpConstantNull %mat4v2float
+    %uint_19 = OpConstant %uint 19
+%_ptr_StorageBuffer_mat4v3float = OpTypePointer StorageBuffer %mat4v3float
+        %112 = OpConstantNull %mat4v3float
+    %uint_20 = OpConstant %uint 20
+%_ptr_StorageBuffer_mat4v4float = OpTypePointer StorageBuffer %mat4v4float
+        %116 = OpConstantNull %mat4v4float
+    %uint_21 = OpConstant %uint 21
+%_ptr_StorageBuffer__arr_v3float_uint_2 = OpTypePointer StorageBuffer %_arr_v3float_uint_2
+        %120 = OpConstantNull %_arr_v3float_uint_2
+    %uint_22 = OpConstant %uint 22
+%_ptr_StorageBuffer_Inner = OpTypePointer StorageBuffer %Inner
+        %124 = OpConstantNull %Inner
+    %uint_23 = OpConstant %uint 23
 %_ptr_StorageBuffer__arr_Inner_uint_4 = OpTypePointer StorageBuffer %_arr_Inner_uint_4
-         %59 = OpConstantNull %_arr_Inner_uint_4
-       %main = OpFunction %void None %17
-         %20 = OpLabel
-         %23 = OpAccessChain %_ptr_StorageBuffer_v3int %s %uint_0 %uint_0
-               OpStore %23 %24
-         %27 = OpAccessChain %_ptr_StorageBuffer_int %s %uint_0 %uint_1
-               OpStore %27 %28
-         %31 = OpAccessChain %_ptr_StorageBuffer_v3uint %s %uint_0 %uint_2
-               OpStore %31 %32
-         %35 = OpAccessChain %_ptr_StorageBuffer_uint %s %uint_0 %uint_3
-               OpStore %35 %36
-         %38 = OpAccessChain %_ptr_StorageBuffer_v3float %s %uint_0 %uint_4
-               OpStore %38 %39
-         %42 = OpAccessChain %_ptr_StorageBuffer_float %s %uint_0 %uint_5
-               OpStore %42 %43
-         %46 = OpAccessChain %_ptr_StorageBuffer_mat2v3float %s %uint_0 %uint_6
-               OpStore %46 %47
-         %50 = OpAccessChain %_ptr_StorageBuffer_mat3v2float %s %uint_0 %uint_7
-               OpStore %50 %51
-         %54 = OpAccessChain %_ptr_StorageBuffer_Inner %s %uint_0 %uint_8
-               OpStore %54 %55
-         %58 = OpAccessChain %_ptr_StorageBuffer__arr_Inner_uint_4 %s %uint_0 %uint_9
-               OpStore %58 %59
+        %128 = OpConstantNull %_arr_Inner_uint_4
+       %main = OpFunction %void None %31
+         %34 = OpLabel
+         %37 = OpAccessChain %_ptr_StorageBuffer_float %sb %uint_0 %uint_0
+               OpStore %37 %38
+         %41 = OpAccessChain %_ptr_StorageBuffer_int %sb %uint_0 %uint_1
+               OpStore %41 %42
+         %44 = OpAccessChain %_ptr_StorageBuffer_uint %sb %uint_0 %uint_2
+               OpStore %44 %45
+         %48 = OpAccessChain %_ptr_StorageBuffer_v2float %sb %uint_0 %uint_3
+               OpStore %48 %49
+         %51 = OpAccessChain %_ptr_StorageBuffer_v2int %sb %uint_0 %uint_4
+               OpStore %51 %52
+         %55 = OpAccessChain %_ptr_StorageBuffer_v2uint %sb %uint_0 %uint_5
+               OpStore %55 %56
+         %59 = OpAccessChain %_ptr_StorageBuffer_v3float %sb %uint_0 %uint_6
+               OpStore %59 %60
+         %63 = OpAccessChain %_ptr_StorageBuffer_v3int %sb %uint_0 %uint_7
+               OpStore %63 %64
+         %67 = OpAccessChain %_ptr_StorageBuffer_v3uint %sb %uint_0 %uint_8
+               OpStore %67 %68
+         %71 = OpAccessChain %_ptr_StorageBuffer_v4float %sb %uint_0 %uint_9
+               OpStore %71 %72
+         %75 = OpAccessChain %_ptr_StorageBuffer_v4int %sb %uint_0 %uint_10
+               OpStore %75 %76
+         %79 = OpAccessChain %_ptr_StorageBuffer_v4uint %sb %uint_0 %uint_11
+               OpStore %79 %80
+         %83 = OpAccessChain %_ptr_StorageBuffer_mat2v2float %sb %uint_0 %uint_12
+               OpStore %83 %84
+         %87 = OpAccessChain %_ptr_StorageBuffer_mat2v3float %sb %uint_0 %uint_13
+               OpStore %87 %88
+         %91 = OpAccessChain %_ptr_StorageBuffer_mat2v4float %sb %uint_0 %uint_14
+               OpStore %91 %92
+         %95 = OpAccessChain %_ptr_StorageBuffer_mat3v2float %sb %uint_0 %uint_15
+               OpStore %95 %96
+         %99 = OpAccessChain %_ptr_StorageBuffer_mat3v3float %sb %uint_0 %uint_16
+               OpStore %99 %100
+        %103 = OpAccessChain %_ptr_StorageBuffer_mat3v4float %sb %uint_0 %uint_17
+               OpStore %103 %104
+        %107 = OpAccessChain %_ptr_StorageBuffer_mat4v2float %sb %uint_0 %uint_18
+               OpStore %107 %108
+        %111 = OpAccessChain %_ptr_StorageBuffer_mat4v3float %sb %uint_0 %uint_19
+               OpStore %111 %112
+        %115 = OpAccessChain %_ptr_StorageBuffer_mat4v4float %sb %uint_0 %uint_20
+               OpStore %115 %116
+        %119 = OpAccessChain %_ptr_StorageBuffer__arr_v3float_uint_2 %sb %uint_0 %uint_21
+               OpStore %119 %120
+        %123 = OpAccessChain %_ptr_StorageBuffer_Inner %sb %uint_0 %uint_22
+               OpStore %123 %124
+        %127 = OpAccessChain %_ptr_StorageBuffer__arr_Inner_uint_4 %sb %uint_0 %uint_23
+               OpStore %127 %128
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/buffer/storage/static_index/write.wgsl.expected.wgsl b/test/tint/buffer/storage/static_index/write.wgsl.expected.wgsl
index af8c2de..448df1f 100644
--- a/test/tint/buffer/storage/static_index/write.wgsl.expected.wgsl
+++ b/test/tint/buffer/storage/static_index/write.wgsl.expected.wgsl
@@ -1,32 +1,61 @@
 struct Inner {
-  x : i32,
+  scalar_i32 : i32,
+  scalar_f32 : f32,
 }
 
 struct S {
-  a : vec3<i32>,
-  b : i32,
-  c : vec3<u32>,
-  d : u32,
-  e : vec3<f32>,
-  f : f32,
-  g : mat2x3<f32>,
-  h : mat3x2<f32>,
-  i : Inner,
-  j : array<Inner, 4>,
+  scalar_f32 : f32,
+  scalar_i32 : i32,
+  scalar_u32 : u32,
+  vec2_f32 : vec2<f32>,
+  vec2_i32 : vec2<i32>,
+  vec2_u32 : vec2<u32>,
+  vec3_f32 : vec3<f32>,
+  vec3_i32 : vec3<i32>,
+  vec3_u32 : vec3<u32>,
+  vec4_f32 : vec4<f32>,
+  vec4_i32 : vec4<i32>,
+  vec4_u32 : vec4<u32>,
+  mat2x2_f32 : mat2x2<f32>,
+  mat2x3_f32 : mat2x3<f32>,
+  mat2x4_f32 : mat2x4<f32>,
+  mat3x2_f32 : mat3x2<f32>,
+  mat3x3_f32 : mat3x3<f32>,
+  mat3x4_f32 : mat3x4<f32>,
+  mat4x2_f32 : mat4x2<f32>,
+  mat4x3_f32 : mat4x3<f32>,
+  mat4x4_f32 : mat4x4<f32>,
+  arr2_vec3_f32 : array<vec3<f32>, 2>,
+  struct_inner : Inner,
+  array_struct_inner : array<Inner, 4>,
 }
 
-@binding(0) @group(0) var<storage, read_write> s : S;
+@binding(0) @group(0) var<storage, read_write> sb : S;
 
 @compute @workgroup_size(1)
 fn main() {
-  s.a = vec3<i32>();
-  s.b = i32();
-  s.c = vec3<u32>();
-  s.d = u32();
-  s.e = vec3<f32>();
-  s.f = f32();
-  s.g = mat2x3<f32>();
-  s.h = mat3x2<f32>();
-  s.i = Inner();
-  s.j = array<Inner, 4>();
+  sb.scalar_f32 = f32();
+  sb.scalar_i32 = i32();
+  sb.scalar_u32 = u32();
+  sb.vec2_f32 = vec2<f32>();
+  sb.vec2_i32 = vec2<i32>();
+  sb.vec2_u32 = vec2<u32>();
+  sb.vec3_f32 = vec3<f32>();
+  sb.vec3_i32 = vec3<i32>();
+  sb.vec3_u32 = vec3<u32>();
+  sb.vec4_f32 = vec4<f32>();
+  sb.vec4_i32 = vec4<i32>();
+  sb.vec4_u32 = vec4<u32>();
+  sb.mat2x2_f32 = mat2x2<f32>();
+  sb.mat2x3_f32 = mat2x3<f32>();
+  sb.mat2x4_f32 = mat2x4<f32>();
+  sb.mat3x2_f32 = mat3x2<f32>();
+  sb.mat3x3_f32 = mat3x3<f32>();
+  sb.mat3x4_f32 = mat3x4<f32>();
+  sb.mat4x2_f32 = mat4x2<f32>();
+  sb.mat4x3_f32 = mat4x3<f32>();
+  sb.mat4x4_f32 = mat4x4<f32>();
+  sb.arr2_vec3_f32 = array<vec3<f32>, 2>();
+  sb.struct_inner = Inner();
+  sb.array_struct_inner = array<Inner, 4>();
 }
diff --git a/test/tint/buffer/storage/static_index/write_f16.wgsl b/test/tint/buffer/storage/static_index/write_f16.wgsl
new file mode 100644
index 0000000..5e1d551
--- /dev/null
+++ b/test/tint/buffer/storage/static_index/write_f16.wgsl
@@ -0,0 +1,92 @@
+enable f16;
+
+struct Inner {
+    scalar_i32 : i32,
+    scalar_f32 : f32,
+    scalar_f16 : f16,
+};
+
+struct S {
+    scalar_f32 : f32,
+    scalar_i32 : i32,
+    scalar_u32 : u32,
+    scalar_f16 : f16,
+    vec2_f32 : vec2<f32>,
+    vec2_i32 : vec2<i32>,
+    vec2_u32 : vec2<u32>,
+    vec2_f16 : vec2<f16>,
+    vec3_f32 : vec3<f32>,
+    vec3_i32 : vec3<i32>,
+    vec3_u32 : vec3<u32>,
+    vec3_f16 : vec3<f16>,
+    vec4_f32 : vec4<f32>,
+    vec4_i32 : vec4<i32>,
+    vec4_u32 : vec4<u32>,
+    vec4_f16 : vec4<f16>,
+    mat2x2_f32 : mat2x2<f32>,
+    mat2x3_f32 : mat2x3<f32>,
+    mat2x4_f32 : mat2x4<f32>,
+    mat3x2_f32 : mat3x2<f32>,
+    mat3x3_f32 : mat3x3<f32>,
+    mat3x4_f32 : mat3x4<f32>,
+    mat4x2_f32 : mat4x2<f32>,
+    mat4x3_f32 : mat4x3<f32>,
+    mat4x4_f32 : mat4x4<f32>,
+    mat2x2_f16 : mat2x2<f16>,
+    mat2x3_f16 : mat2x3<f16>,
+    mat2x4_f16 : mat2x4<f16>,
+    mat3x2_f16 : mat3x2<f16>,
+    mat3x3_f16 : mat3x3<f16>,
+    mat3x4_f16 : mat3x4<f16>,
+    mat4x2_f16 : mat4x2<f16>,
+    mat4x3_f16 : mat4x3<f16>,
+    mat4x4_f16 : mat4x4<f16>,
+    arr2_vec3_f32 : array<vec3<f32>, 2>,
+    arr2_mat4x2_f16 : array<mat4x2<f16>, 2>,
+    struct_inner : Inner,
+    array_struct_inner : array<Inner, 4>,
+};
+
+@binding(0) @group(0) var<storage, read_write> sb : S;
+
+@compute @workgroup_size(1)
+fn main() {
+    sb.scalar_f32 = f32();
+    sb.scalar_i32 = i32();
+    sb.scalar_u32 = u32();
+    sb.scalar_f16 = f16();
+    sb.vec2_f32 = vec2<f32>();
+    sb.vec2_i32 = vec2<i32>();
+    sb.vec2_u32 = vec2<u32>();
+    sb.vec2_f16 = vec2<f16>();
+    sb.vec3_f32 = vec3<f32>();
+    sb.vec3_i32 = vec3<i32>();
+    sb.vec3_u32 = vec3<u32>();
+    sb.vec3_f16 = vec3<f16>();
+    sb.vec4_f32 = vec4<f32>();
+    sb.vec4_i32 = vec4<i32>();
+    sb.vec4_u32 = vec4<u32>();
+    sb.vec4_f16 = vec4<f16>();
+    sb.mat2x2_f32 = mat2x2<f32>();
+    sb.mat2x3_f32 = mat2x3<f32>();
+    sb.mat2x4_f32 = mat2x4<f32>();
+    sb.mat3x2_f32 = mat3x2<f32>();
+    sb.mat3x3_f32 = mat3x3<f32>();
+    sb.mat3x4_f32 = mat3x4<f32>();
+    sb.mat4x2_f32 = mat4x2<f32>();
+    sb.mat4x3_f32 = mat4x3<f32>();
+    sb.mat4x4_f32 = mat4x4<f32>();
+    sb.mat2x2_f16 = mat2x2<f16>();
+    sb.mat2x3_f16 = mat2x3<f16>();
+    sb.mat2x4_f16 = mat2x4<f16>();
+    sb.mat3x2_f16 = mat3x2<f16>();
+    sb.mat3x3_f16 = mat3x3<f16>();
+    sb.mat3x4_f16 = mat3x4<f16>();
+    sb.mat4x2_f16 = mat4x2<f16>();
+    sb.mat4x3_f16 = mat4x3<f16>();
+    sb.mat4x4_f16 = mat4x4<f16>();
+    sb.arr2_vec3_f32 = array<vec3<f32>, 2>();
+    sb.arr2_mat4x2_f16 = array<mat4x2<f16>, 2>();
+    sb.struct_inner = Inner();
+    sb.array_struct_inner = array<Inner, 4>();
+}
diff --git a/test/tint/buffer/storage/static_index/write_f16.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/static_index/write_f16.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..526b6f5
--- /dev/null
+++ b/test/tint/buffer/storage/static_index/write_f16.wgsl.expected.dxc.hlsl
@@ -0,0 +1,195 @@
+struct Inner {
+  int scalar_i32;
+  float scalar_f32;
+  float16_t scalar_f16;
+};
+
+RWByteAddressBuffer sb : register(u0, space0);
+
+void tint_symbol_16(RWByteAddressBuffer buffer, uint offset, float2x2 value) {
+  buffer.Store2((offset + 0u), asuint(value[0u]));
+  buffer.Store2((offset + 8u), asuint(value[1u]));
+}
+
+void tint_symbol_17(RWByteAddressBuffer buffer, uint offset, float2x3 value) {
+  buffer.Store3((offset + 0u), asuint(value[0u]));
+  buffer.Store3((offset + 16u), asuint(value[1u]));
+}
+
+void tint_symbol_18(RWByteAddressBuffer buffer, uint offset, float2x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+}
+
+void tint_symbol_19(RWByteAddressBuffer buffer, uint offset, float3x2 value) {
+  buffer.Store2((offset + 0u), asuint(value[0u]));
+  buffer.Store2((offset + 8u), asuint(value[1u]));
+  buffer.Store2((offset + 16u), asuint(value[2u]));
+}
+
+void tint_symbol_20(RWByteAddressBuffer buffer, uint offset, float3x3 value) {
+  buffer.Store3((offset + 0u), asuint(value[0u]));
+  buffer.Store3((offset + 16u), asuint(value[1u]));
+  buffer.Store3((offset + 32u), asuint(value[2u]));
+}
+
+void tint_symbol_21(RWByteAddressBuffer buffer, uint offset, float3x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+  buffer.Store4((offset + 32u), asuint(value[2u]));
+}
+
+void tint_symbol_22(RWByteAddressBuffer buffer, uint offset, float4x2 value) {
+  buffer.Store2((offset + 0u), asuint(value[0u]));
+  buffer.Store2((offset + 8u), asuint(value[1u]));
+  buffer.Store2((offset + 16u), asuint(value[2u]));
+  buffer.Store2((offset + 24u), asuint(value[3u]));
+}
+
+void tint_symbol_23(RWByteAddressBuffer buffer, uint offset, float4x3 value) {
+  buffer.Store3((offset + 0u), asuint(value[0u]));
+  buffer.Store3((offset + 16u), asuint(value[1u]));
+  buffer.Store3((offset + 32u), asuint(value[2u]));
+  buffer.Store3((offset + 48u), asuint(value[3u]));
+}
+
+void tint_symbol_24(RWByteAddressBuffer buffer, uint offset, float4x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+  buffer.Store4((offset + 32u), asuint(value[2u]));
+  buffer.Store4((offset + 48u), asuint(value[3u]));
+}
+
+void tint_symbol_25(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 2, 2> value) {
+  buffer.Store<vector<float16_t, 2> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 4u), value[1u]);
+}
+
+void tint_symbol_26(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 2, 3> value) {
+  buffer.Store<vector<float16_t, 3> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 8u), value[1u]);
+}
+
+void tint_symbol_27(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 2, 4> value) {
+  buffer.Store<vector<float16_t, 4> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 8u), value[1u]);
+}
+
+void tint_symbol_28(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 3, 2> value) {
+  buffer.Store<vector<float16_t, 2> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 4u), value[1u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 8u), value[2u]);
+}
+
+void tint_symbol_29(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 3, 3> value) {
+  buffer.Store<vector<float16_t, 3> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 8u), value[1u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 16u), value[2u]);
+}
+
+void tint_symbol_30(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 3, 4> value) {
+  buffer.Store<vector<float16_t, 4> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 8u), value[1u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 16u), value[2u]);
+}
+
+void tint_symbol_31(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 2> value) {
+  buffer.Store<vector<float16_t, 2> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 4u), value[1u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 8u), value[2u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 12u), value[3u]);
+}
+
+void tint_symbol_32(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 3> value) {
+  buffer.Store<vector<float16_t, 3> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 8u), value[1u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 16u), value[2u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 24u), value[3u]);
+}
+
+void tint_symbol_33(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 4> value) {
+  buffer.Store<vector<float16_t, 4> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 8u), value[1u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 16u), value[2u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 24u), value[3u]);
+}
+
+void tint_symbol_34(RWByteAddressBuffer buffer, uint offset, float3 value[2]) {
+  float3 array[2] = value;
+  {
+    for(uint i = 0u; (i < 2u); i = (i + 1u)) {
+      buffer.Store3((offset + (i * 16u)), asuint(array[i]));
+    }
+  }
+}
+
+void tint_symbol_35(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 2> value[2]) {
+  matrix<float16_t, 4, 2> array_1[2] = value;
+  {
+    for(uint i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
+      tint_symbol_31(buffer, (offset + (i_1 * 16u)), array_1[i_1]);
+    }
+  }
+}
+
+void tint_symbol_36(RWByteAddressBuffer buffer, uint offset, Inner value) {
+  buffer.Store((offset + 0u), asuint(value.scalar_i32));
+  buffer.Store((offset + 4u), asuint(value.scalar_f32));
+  buffer.Store<float16_t>((offset + 8u), value.scalar_f16);
+}
+
+void tint_symbol_37(RWByteAddressBuffer buffer, uint offset, Inner value[4]) {
+  Inner array_2[4] = value;
+  {
+    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
+      tint_symbol_36(buffer, (offset + (i_2 * 12u)), array_2[i_2]);
+    }
+  }
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  sb.Store(0u, asuint(0.0f));
+  sb.Store(4u, asuint(0));
+  sb.Store(8u, asuint(0u));
+  sb.Store<float16_t>(12u, float16_t(0.0h));
+  sb.Store2(16u, asuint((0.0f).xx));
+  sb.Store2(24u, asuint((0).xx));
+  sb.Store2(32u, asuint((0u).xx));
+  sb.Store<vector<float16_t, 2> >(40u, (float16_t(0.0h)).xx);
+  sb.Store3(48u, asuint((0.0f).xxx));
+  sb.Store3(64u, asuint((0).xxx));
+  sb.Store3(80u, asuint((0u).xxx));
+  sb.Store<vector<float16_t, 3> >(96u, (float16_t(0.0h)).xxx);
+  sb.Store4(112u, asuint((0.0f).xxxx));
+  sb.Store4(128u, asuint((0).xxxx));
+  sb.Store4(144u, asuint((0u).xxxx));
+  sb.Store<vector<float16_t, 4> >(160u, (float16_t(0.0h)).xxxx);
+  tint_symbol_16(sb, 168u, float2x2((0.0f).xx, (0.0f).xx));
+  tint_symbol_17(sb, 192u, float2x3((0.0f).xxx, (0.0f).xxx));
+  tint_symbol_18(sb, 224u, float2x4((0.0f).xxxx, (0.0f).xxxx));
+  tint_symbol_19(sb, 256u, float3x2((0.0f).xx, (0.0f).xx, (0.0f).xx));
+  tint_symbol_20(sb, 288u, float3x3((0.0f).xxx, (0.0f).xxx, (0.0f).xxx));
+  tint_symbol_21(sb, 336u, float3x4((0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx));
+  tint_symbol_22(sb, 384u, float4x2((0.0f).xx, (0.0f).xx, (0.0f).xx, (0.0f).xx));
+  tint_symbol_23(sb, 416u, float4x3((0.0f).xxx, (0.0f).xxx, (0.0f).xxx, (0.0f).xxx));
+  tint_symbol_24(sb, 480u, float4x4((0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx));
+  tint_symbol_25(sb, 544u, matrix<float16_t, 2, 2>((float16_t(0.0h)).xx, (float16_t(0.0h)).xx));
+  tint_symbol_26(sb, 552u, matrix<float16_t, 2, 3>((float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx));
+  tint_symbol_27(sb, 568u, matrix<float16_t, 2, 4>((float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx));
+  tint_symbol_28(sb, 584u, matrix<float16_t, 3, 2>((float16_t(0.0h)).xx, (float16_t(0.0h)).xx, (float16_t(0.0h)).xx));
+  tint_symbol_29(sb, 600u, matrix<float16_t, 3, 3>((float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx));
+  tint_symbol_30(sb, 624u, matrix<float16_t, 3, 4>((float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx));
+  tint_symbol_31(sb, 648u, matrix<float16_t, 4, 2>((float16_t(0.0h)).xx, (float16_t(0.0h)).xx, (float16_t(0.0h)).xx, (float16_t(0.0h)).xx));
+  tint_symbol_32(sb, 664u, matrix<float16_t, 4, 3>((float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx));
+  tint_symbol_33(sb, 696u, matrix<float16_t, 4, 4>((float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx));
+  const float3 tint_symbol_38[2] = (float3[2])0;
+  tint_symbol_34(sb, 736u, tint_symbol_38);
+  const matrix<float16_t, 4, 2> tint_symbol_39[2] = (matrix<float16_t, 4, 2>[2])0;
+  tint_symbol_35(sb, 768u, tint_symbol_39);
+  const Inner tint_symbol_40 = (Inner)0;
+  tint_symbol_36(sb, 800u, tint_symbol_40);
+  const Inner tint_symbol_41[4] = (Inner[4])0;
+  tint_symbol_37(sb, 812u, tint_symbol_41);
+  return;
+}
diff --git a/test/tint/buffer/storage/static_index/write_f16.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/static_index/write_f16.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..f54b4e4
--- /dev/null
+++ b/test/tint/buffer/storage/static_index/write_f16.wgsl.expected.fxc.hlsl
@@ -0,0 +1,200 @@
+SKIP: FAILED
+
+struct Inner {
+  int scalar_i32;
+  float scalar_f32;
+  float16_t scalar_f16;
+};
+
+RWByteAddressBuffer sb : register(u0, space0);
+
+void tint_symbol_16(RWByteAddressBuffer buffer, uint offset, float2x2 value) {
+  buffer.Store2((offset + 0u), asuint(value[0u]));
+  buffer.Store2((offset + 8u), asuint(value[1u]));
+}
+
+void tint_symbol_17(RWByteAddressBuffer buffer, uint offset, float2x3 value) {
+  buffer.Store3((offset + 0u), asuint(value[0u]));
+  buffer.Store3((offset + 16u), asuint(value[1u]));
+}
+
+void tint_symbol_18(RWByteAddressBuffer buffer, uint offset, float2x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+}
+
+void tint_symbol_19(RWByteAddressBuffer buffer, uint offset, float3x2 value) {
+  buffer.Store2((offset + 0u), asuint(value[0u]));
+  buffer.Store2((offset + 8u), asuint(value[1u]));
+  buffer.Store2((offset + 16u), asuint(value[2u]));
+}
+
+void tint_symbol_20(RWByteAddressBuffer buffer, uint offset, float3x3 value) {
+  buffer.Store3((offset + 0u), asuint(value[0u]));
+  buffer.Store3((offset + 16u), asuint(value[1u]));
+  buffer.Store3((offset + 32u), asuint(value[2u]));
+}
+
+void tint_symbol_21(RWByteAddressBuffer buffer, uint offset, float3x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+  buffer.Store4((offset + 32u), asuint(value[2u]));
+}
+
+void tint_symbol_22(RWByteAddressBuffer buffer, uint offset, float4x2 value) {
+  buffer.Store2((offset + 0u), asuint(value[0u]));
+  buffer.Store2((offset + 8u), asuint(value[1u]));
+  buffer.Store2((offset + 16u), asuint(value[2u]));
+  buffer.Store2((offset + 24u), asuint(value[3u]));
+}
+
+void tint_symbol_23(RWByteAddressBuffer buffer, uint offset, float4x3 value) {
+  buffer.Store3((offset + 0u), asuint(value[0u]));
+  buffer.Store3((offset + 16u), asuint(value[1u]));
+  buffer.Store3((offset + 32u), asuint(value[2u]));
+  buffer.Store3((offset + 48u), asuint(value[3u]));
+}
+
+void tint_symbol_24(RWByteAddressBuffer buffer, uint offset, float4x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+  buffer.Store4((offset + 32u), asuint(value[2u]));
+  buffer.Store4((offset + 48u), asuint(value[3u]));
+}
+
+void tint_symbol_25(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 2, 2> value) {
+  buffer.Store<vector<float16_t, 2> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 4u), value[1u]);
+}
+
+void tint_symbol_26(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 2, 3> value) {
+  buffer.Store<vector<float16_t, 3> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 8u), value[1u]);
+}
+
+void tint_symbol_27(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 2, 4> value) {
+  buffer.Store<vector<float16_t, 4> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 8u), value[1u]);
+}
+
+void tint_symbol_28(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 3, 2> value) {
+  buffer.Store<vector<float16_t, 2> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 4u), value[1u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 8u), value[2u]);
+}
+
+void tint_symbol_29(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 3, 3> value) {
+  buffer.Store<vector<float16_t, 3> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 8u), value[1u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 16u), value[2u]);
+}
+
+void tint_symbol_30(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 3, 4> value) {
+  buffer.Store<vector<float16_t, 4> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 8u), value[1u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 16u), value[2u]);
+}
+
+void tint_symbol_31(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 2> value) {
+  buffer.Store<vector<float16_t, 2> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 4u), value[1u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 8u), value[2u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 12u), value[3u]);
+}
+
+void tint_symbol_32(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 3> value) {
+  buffer.Store<vector<float16_t, 3> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 8u), value[1u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 16u), value[2u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 24u), value[3u]);
+}
+
+void tint_symbol_33(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 4> value) {
+  buffer.Store<vector<float16_t, 4> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 8u), value[1u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 16u), value[2u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 24u), value[3u]);
+}
+
+void tint_symbol_34(RWByteAddressBuffer buffer, uint offset, float3 value[2]) {
+  float3 array[2] = value;
+  {
+    for(uint i = 0u; (i < 2u); i = (i + 1u)) {
+      buffer.Store3((offset + (i * 16u)), asuint(array[i]));
+    }
+  }
+}
+
+void tint_symbol_35(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 2> value[2]) {
+  matrix<float16_t, 4, 2> array_1[2] = value;
+  {
+    for(uint i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
+      tint_symbol_31(buffer, (offset + (i_1 * 16u)), array_1[i_1]);
+    }
+  }
+}
+
+void tint_symbol_36(RWByteAddressBuffer buffer, uint offset, Inner value) {
+  buffer.Store((offset + 0u), asuint(value.scalar_i32));
+  buffer.Store((offset + 4u), asuint(value.scalar_f32));
+  buffer.Store<float16_t>((offset + 8u), value.scalar_f16);
+}
+
+void tint_symbol_37(RWByteAddressBuffer buffer, uint offset, Inner value[4]) {
+  Inner array_2[4] = value;
+  {
+    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
+      tint_symbol_36(buffer, (offset + (i_2 * 12u)), array_2[i_2]);
+    }
+  }
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  sb.Store(0u, asuint(0.0f));
+  sb.Store(4u, asuint(0));
+  sb.Store(8u, asuint(0u));
+  sb.Store<float16_t>(12u, float16_t(0.0h));
+  sb.Store2(16u, asuint((0.0f).xx));
+  sb.Store2(24u, asuint((0).xx));
+  sb.Store2(32u, asuint((0u).xx));
+  sb.Store<vector<float16_t, 2> >(40u, (float16_t(0.0h)).xx);
+  sb.Store3(48u, asuint((0.0f).xxx));
+  sb.Store3(64u, asuint((0).xxx));
+  sb.Store3(80u, asuint((0u).xxx));
+  sb.Store<vector<float16_t, 3> >(96u, (float16_t(0.0h)).xxx);
+  sb.Store4(112u, asuint((0.0f).xxxx));
+  sb.Store4(128u, asuint((0).xxxx));
+  sb.Store4(144u, asuint((0u).xxxx));
+  sb.Store<vector<float16_t, 4> >(160u, (float16_t(0.0h)).xxxx);
+  tint_symbol_16(sb, 168u, float2x2((0.0f).xx, (0.0f).xx));
+  tint_symbol_17(sb, 192u, float2x3((0.0f).xxx, (0.0f).xxx));
+  tint_symbol_18(sb, 224u, float2x4((0.0f).xxxx, (0.0f).xxxx));
+  tint_symbol_19(sb, 256u, float3x2((0.0f).xx, (0.0f).xx, (0.0f).xx));
+  tint_symbol_20(sb, 288u, float3x3((0.0f).xxx, (0.0f).xxx, (0.0f).xxx));
+  tint_symbol_21(sb, 336u, float3x4((0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx));
+  tint_symbol_22(sb, 384u, float4x2((0.0f).xx, (0.0f).xx, (0.0f).xx, (0.0f).xx));
+  tint_symbol_23(sb, 416u, float4x3((0.0f).xxx, (0.0f).xxx, (0.0f).xxx, (0.0f).xxx));
+  tint_symbol_24(sb, 480u, float4x4((0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx));
+  tint_symbol_25(sb, 544u, matrix<float16_t, 2, 2>((float16_t(0.0h)).xx, (float16_t(0.0h)).xx));
+  tint_symbol_26(sb, 552u, matrix<float16_t, 2, 3>((float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx));
+  tint_symbol_27(sb, 568u, matrix<float16_t, 2, 4>((float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx));
+  tint_symbol_28(sb, 584u, matrix<float16_t, 3, 2>((float16_t(0.0h)).xx, (float16_t(0.0h)).xx, (float16_t(0.0h)).xx));
+  tint_symbol_29(sb, 600u, matrix<float16_t, 3, 3>((float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx));
+  tint_symbol_30(sb, 624u, matrix<float16_t, 3, 4>((float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx));
+  tint_symbol_31(sb, 648u, matrix<float16_t, 4, 2>((float16_t(0.0h)).xx, (float16_t(0.0h)).xx, (float16_t(0.0h)).xx, (float16_t(0.0h)).xx));
+  tint_symbol_32(sb, 664u, matrix<float16_t, 4, 3>((float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx));
+  tint_symbol_33(sb, 696u, matrix<float16_t, 4, 4>((float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx));
+  const float3 tint_symbol_38[2] = (float3[2])0;
+  tint_symbol_34(sb, 736u, tint_symbol_38);
+  const matrix<float16_t, 4, 2> tint_symbol_39[2] = (matrix<float16_t, 4, 2>[2])0;
+  tint_symbol_35(sb, 768u, tint_symbol_39);
+  const Inner tint_symbol_40 = (Inner)0;
+  tint_symbol_36(sb, 800u, tint_symbol_40);
+  const Inner tint_symbol_41[4] = (Inner[4])0;
+  tint_symbol_37(sb, 812u, tint_symbol_41);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000002416606A770(4,3-11): error X3000: unrecognized identifier 'float16_t'
+
diff --git a/test/tint/buffer/storage/static_index/write_f16.wgsl.expected.glsl b/test/tint/buffer/storage/static_index/write_f16.wgsl.expected.glsl
new file mode 100644
index 0000000..6a5b7de
--- /dev/null
+++ b/test/tint/buffer/storage/static_index/write_f16.wgsl.expected.glsl
@@ -0,0 +1,118 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct Inner {
+  int scalar_i32;
+  float scalar_f32;
+  float16_t scalar_f16;
+};
+
+struct S {
+  float scalar_f32;
+  int scalar_i32;
+  uint scalar_u32;
+  float16_t scalar_f16;
+  vec2 vec2_f32;
+  ivec2 vec2_i32;
+  uvec2 vec2_u32;
+  f16vec2 vec2_f16;
+  uint pad;
+  vec3 vec3_f32;
+  uint pad_1;
+  ivec3 vec3_i32;
+  uint pad_2;
+  uvec3 vec3_u32;
+  uint pad_3;
+  f16vec3 vec3_f16;
+  uint pad_4;
+  uint pad_5;
+  vec4 vec4_f32;
+  ivec4 vec4_i32;
+  uvec4 vec4_u32;
+  f16vec4 vec4_f16;
+  mat2 mat2x2_f32;
+  uint pad_6;
+  uint pad_7;
+  mat2x3 mat2x3_f32;
+  mat2x4 mat2x4_f32;
+  mat3x2 mat3x2_f32;
+  uint pad_8;
+  uint pad_9;
+  mat3 mat3x3_f32;
+  mat3x4 mat3x4_f32;
+  mat4x2 mat4x2_f32;
+  mat4x3 mat4x3_f32;
+  mat4 mat4x4_f32;
+  f16mat2 mat2x2_f16;
+  f16mat2x3 mat2x3_f16;
+  f16mat2x4 mat2x4_f16;
+  f16mat3x2 mat3x2_f16;
+  uint pad_10;
+  f16mat3 mat3x3_f16;
+  f16mat3x4 mat3x4_f16;
+  f16mat4x2 mat4x2_f16;
+  f16mat4x3 mat4x3_f16;
+  f16mat4 mat4x4_f16;
+  uint pad_11;
+  uint pad_12;
+  vec3 arr2_vec3_f32[2];
+  f16mat4x2 arr2_mat4x2_f16[2];
+  Inner struct_inner;
+  Inner array_struct_inner[4];
+  uint pad_13;
+};
+
+layout(binding = 0, std430) buffer sb_block_ssbo {
+  S inner;
+} sb;
+
+void tint_symbol() {
+  sb.inner.scalar_f32 = 0.0f;
+  sb.inner.scalar_i32 = 0;
+  sb.inner.scalar_u32 = 0u;
+  sb.inner.scalar_f16 = 0.0hf;
+  sb.inner.vec2_f32 = vec2(0.0f);
+  sb.inner.vec2_i32 = ivec2(0);
+  sb.inner.vec2_u32 = uvec2(0u);
+  sb.inner.vec2_f16 = f16vec2(0.0hf);
+  sb.inner.vec3_f32 = vec3(0.0f);
+  sb.inner.vec3_i32 = ivec3(0);
+  sb.inner.vec3_u32 = uvec3(0u);
+  sb.inner.vec3_f16 = f16vec3(0.0hf);
+  sb.inner.vec4_f32 = vec4(0.0f);
+  sb.inner.vec4_i32 = ivec4(0);
+  sb.inner.vec4_u32 = uvec4(0u);
+  sb.inner.vec4_f16 = f16vec4(0.0hf);
+  sb.inner.mat2x2_f32 = mat2(vec2(0.0f), vec2(0.0f));
+  sb.inner.mat2x3_f32 = mat2x3(vec3(0.0f), vec3(0.0f));
+  sb.inner.mat2x4_f32 = mat2x4(vec4(0.0f), vec4(0.0f));
+  sb.inner.mat3x2_f32 = mat3x2(vec2(0.0f), vec2(0.0f), vec2(0.0f));
+  sb.inner.mat3x3_f32 = mat3(vec3(0.0f), vec3(0.0f), vec3(0.0f));
+  sb.inner.mat3x4_f32 = mat3x4(vec4(0.0f), vec4(0.0f), vec4(0.0f));
+  sb.inner.mat4x2_f32 = mat4x2(vec2(0.0f), vec2(0.0f), vec2(0.0f), vec2(0.0f));
+  sb.inner.mat4x3_f32 = mat4x3(vec3(0.0f), vec3(0.0f), vec3(0.0f), vec3(0.0f));
+  sb.inner.mat4x4_f32 = mat4(vec4(0.0f), vec4(0.0f), vec4(0.0f), vec4(0.0f));
+  sb.inner.mat2x2_f16 = f16mat2(f16vec2(0.0hf), f16vec2(0.0hf));
+  sb.inner.mat2x3_f16 = f16mat2x3(f16vec3(0.0hf), f16vec3(0.0hf));
+  sb.inner.mat2x4_f16 = f16mat2x4(f16vec4(0.0hf), f16vec4(0.0hf));
+  sb.inner.mat3x2_f16 = f16mat3x2(f16vec2(0.0hf), f16vec2(0.0hf), f16vec2(0.0hf));
+  sb.inner.mat3x3_f16 = f16mat3(f16vec3(0.0hf), f16vec3(0.0hf), f16vec3(0.0hf));
+  sb.inner.mat3x4_f16 = f16mat3x4(f16vec4(0.0hf), f16vec4(0.0hf), f16vec4(0.0hf));
+  sb.inner.mat4x2_f16 = f16mat4x2(f16vec2(0.0hf), f16vec2(0.0hf), f16vec2(0.0hf), f16vec2(0.0hf));
+  sb.inner.mat4x3_f16 = f16mat4x3(f16vec3(0.0hf), f16vec3(0.0hf), f16vec3(0.0hf), f16vec3(0.0hf));
+  sb.inner.mat4x4_f16 = f16mat4(f16vec4(0.0hf), f16vec4(0.0hf), f16vec4(0.0hf), f16vec4(0.0hf));
+  vec3 tint_symbol_1[2] = vec3[2](vec3(0.0f), vec3(0.0f));
+  sb.inner.arr2_vec3_f32 = tint_symbol_1;
+  f16mat4x2 tint_symbol_2[2] = f16mat4x2[2](f16mat4x2(f16vec2(0.0hf), f16vec2(0.0hf), f16vec2(0.0hf), f16vec2(0.0hf)), f16mat4x2(f16vec2(0.0hf), f16vec2(0.0hf), f16vec2(0.0hf), f16vec2(0.0hf)));
+  sb.inner.arr2_mat4x2_f16 = tint_symbol_2;
+  Inner tint_symbol_3 = Inner(0, 0.0f, 0.0hf);
+  sb.inner.struct_inner = tint_symbol_3;
+  Inner tint_symbol_4[4] = Inner[4](Inner(0, 0.0f, 0.0hf), Inner(0, 0.0f, 0.0hf), Inner(0, 0.0f, 0.0hf), Inner(0, 0.0f, 0.0hf));
+  sb.inner.array_struct_inner = tint_symbol_4;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol();
+  return;
+}
diff --git a/test/tint/buffer/storage/static_index/write_f16.wgsl.expected.msl b/test/tint/buffer/storage/static_index/write_f16.wgsl.expected.msl
new file mode 100644
index 0000000..f67cfc5
--- /dev/null
+++ b/test/tint/buffer/storage/static_index/write_f16.wgsl.expected.msl
@@ -0,0 +1,121 @@
+#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 Inner {
+  /* 0x0000 */ int scalar_i32;
+  /* 0x0004 */ float scalar_f32;
+  /* 0x0008 */ half scalar_f16;
+  /* 0x000a */ tint_array<int8_t, 2> tint_pad;
+};
+
+struct S {
+  /* 0x0000 */ float scalar_f32;
+  /* 0x0004 */ int scalar_i32;
+  /* 0x0008 */ uint scalar_u32;
+  /* 0x000c */ half scalar_f16;
+  /* 0x000e */ tint_array<int8_t, 2> tint_pad_1;
+  /* 0x0010 */ float2 vec2_f32;
+  /* 0x0018 */ int2 vec2_i32;
+  /* 0x0020 */ uint2 vec2_u32;
+  /* 0x0028 */ half2 vec2_f16;
+  /* 0x002c */ tint_array<int8_t, 4> tint_pad_2;
+  /* 0x0030 */ packed_float3 vec3_f32;
+  /* 0x003c */ tint_array<int8_t, 4> tint_pad_3;
+  /* 0x0040 */ packed_int3 vec3_i32;
+  /* 0x004c */ tint_array<int8_t, 4> tint_pad_4;
+  /* 0x0050 */ packed_uint3 vec3_u32;
+  /* 0x005c */ tint_array<int8_t, 4> tint_pad_5;
+  /* 0x0060 */ packed_half3 vec3_f16;
+  /* 0x0066 */ tint_array<int8_t, 10> tint_pad_6;
+  /* 0x0070 */ float4 vec4_f32;
+  /* 0x0080 */ int4 vec4_i32;
+  /* 0x0090 */ uint4 vec4_u32;
+  /* 0x00a0 */ half4 vec4_f16;
+  /* 0x00a8 */ float2x2 mat2x2_f32;
+  /* 0x00b8 */ tint_array<int8_t, 8> tint_pad_7;
+  /* 0x00c0 */ float2x3 mat2x3_f32;
+  /* 0x00e0 */ float2x4 mat2x4_f32;
+  /* 0x0100 */ float3x2 mat3x2_f32;
+  /* 0x0118 */ tint_array<int8_t, 8> tint_pad_8;
+  /* 0x0120 */ float3x3 mat3x3_f32;
+  /* 0x0150 */ float3x4 mat3x4_f32;
+  /* 0x0180 */ float4x2 mat4x2_f32;
+  /* 0x01a0 */ float4x3 mat4x3_f32;
+  /* 0x01e0 */ float4x4 mat4x4_f32;
+  /* 0x0220 */ half2x2 mat2x2_f16;
+  /* 0x0228 */ half2x3 mat2x3_f16;
+  /* 0x0238 */ half2x4 mat2x4_f16;
+  /* 0x0248 */ half3x2 mat3x2_f16;
+  /* 0x0254 */ tint_array<int8_t, 4> tint_pad_9;
+  /* 0x0258 */ half3x3 mat3x3_f16;
+  /* 0x0270 */ half3x4 mat3x4_f16;
+  /* 0x0288 */ half4x2 mat4x2_f16;
+  /* 0x0298 */ half4x3 mat4x3_f16;
+  /* 0x02b8 */ half4x4 mat4x4_f16;
+  /* 0x02d8 */ tint_array<int8_t, 8> tint_pad_10;
+  /* 0x02e0 */ tint_array<float3, 2> arr2_vec3_f32;
+  /* 0x0300 */ tint_array<half4x2, 2> arr2_mat4x2_f16;
+  /* 0x0320 */ Inner struct_inner;
+  /* 0x032c */ tint_array<Inner, 4> array_struct_inner;
+  /* 0x035c */ tint_array<int8_t, 4> tint_pad_11;
+};
+
+kernel void tint_symbol(device S* tint_symbol_5 [[buffer(0)]]) {
+  (*(tint_symbol_5)).scalar_f32 = 0.0f;
+  (*(tint_symbol_5)).scalar_i32 = 0;
+  (*(tint_symbol_5)).scalar_u32 = 0u;
+  (*(tint_symbol_5)).scalar_f16 = 0.0h;
+  (*(tint_symbol_5)).vec2_f32 = float2(0.0f);
+  (*(tint_symbol_5)).vec2_i32 = int2(0);
+  (*(tint_symbol_5)).vec2_u32 = uint2(0u);
+  (*(tint_symbol_5)).vec2_f16 = half2(0.0h);
+  (*(tint_symbol_5)).vec3_f32 = float3(0.0f);
+  (*(tint_symbol_5)).vec3_i32 = int3(0);
+  (*(tint_symbol_5)).vec3_u32 = uint3(0u);
+  (*(tint_symbol_5)).vec3_f16 = half3(0.0h);
+  (*(tint_symbol_5)).vec4_f32 = float4(0.0f);
+  (*(tint_symbol_5)).vec4_i32 = int4(0);
+  (*(tint_symbol_5)).vec4_u32 = uint4(0u);
+  (*(tint_symbol_5)).vec4_f16 = half4(0.0h);
+  (*(tint_symbol_5)).mat2x2_f32 = float2x2(float2(0.0f), float2(0.0f));
+  (*(tint_symbol_5)).mat2x3_f32 = float2x3(float3(0.0f), float3(0.0f));
+  (*(tint_symbol_5)).mat2x4_f32 = float2x4(float4(0.0f), float4(0.0f));
+  (*(tint_symbol_5)).mat3x2_f32 = float3x2(float2(0.0f), float2(0.0f), float2(0.0f));
+  (*(tint_symbol_5)).mat3x3_f32 = float3x3(float3(0.0f), float3(0.0f), float3(0.0f));
+  (*(tint_symbol_5)).mat3x4_f32 = float3x4(float4(0.0f), float4(0.0f), float4(0.0f));
+  (*(tint_symbol_5)).mat4x2_f32 = float4x2(float2(0.0f), float2(0.0f), float2(0.0f), float2(0.0f));
+  (*(tint_symbol_5)).mat4x3_f32 = float4x3(float3(0.0f), float3(0.0f), float3(0.0f), float3(0.0f));
+  (*(tint_symbol_5)).mat4x4_f32 = float4x4(float4(0.0f), float4(0.0f), float4(0.0f), float4(0.0f));
+  (*(tint_symbol_5)).mat2x2_f16 = half2x2(half2(0.0h), half2(0.0h));
+  (*(tint_symbol_5)).mat2x3_f16 = half2x3(half3(0.0h), half3(0.0h));
+  (*(tint_symbol_5)).mat2x4_f16 = half2x4(half4(0.0h), half4(0.0h));
+  (*(tint_symbol_5)).mat3x2_f16 = half3x2(half2(0.0h), half2(0.0h), half2(0.0h));
+  (*(tint_symbol_5)).mat3x3_f16 = half3x3(half3(0.0h), half3(0.0h), half3(0.0h));
+  (*(tint_symbol_5)).mat3x4_f16 = half3x4(half4(0.0h), half4(0.0h), half4(0.0h));
+  (*(tint_symbol_5)).mat4x2_f16 = half4x2(half2(0.0h), half2(0.0h), half2(0.0h), half2(0.0h));
+  (*(tint_symbol_5)).mat4x3_f16 = half4x3(half3(0.0h), half3(0.0h), half3(0.0h), half3(0.0h));
+  (*(tint_symbol_5)).mat4x4_f16 = half4x4(half4(0.0h), half4(0.0h), half4(0.0h), half4(0.0h));
+  tint_array<float3, 2> const tint_symbol_1 = tint_array<float3, 2>{};
+  (*(tint_symbol_5)).arr2_vec3_f32 = tint_symbol_1;
+  tint_array<half4x2, 2> const tint_symbol_2 = tint_array<half4x2, 2>{};
+  (*(tint_symbol_5)).arr2_mat4x2_f16 = tint_symbol_2;
+  Inner const tint_symbol_3 = Inner{};
+  (*(tint_symbol_5)).struct_inner = tint_symbol_3;
+  tint_array<Inner, 4> const tint_symbol_4 = tint_array<Inner, 4>{};
+  (*(tint_symbol_5)).array_struct_inner = tint_symbol_4;
+  return;
+}
+
diff --git a/test/tint/buffer/storage/static_index/write_f16.wgsl.expected.spvasm b/test/tint/buffer/storage/static_index/write_f16.wgsl.expected.spvasm
new file mode 100644
index 0000000..16da863
--- /dev/null
+++ b/test/tint/buffer/storage/static_index/write_f16.wgsl.expected.spvasm
@@ -0,0 +1,384 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 199
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %sb_block "sb_block"
+               OpMemberName %sb_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "scalar_f32"
+               OpMemberName %S 1 "scalar_i32"
+               OpMemberName %S 2 "scalar_u32"
+               OpMemberName %S 3 "scalar_f16"
+               OpMemberName %S 4 "vec2_f32"
+               OpMemberName %S 5 "vec2_i32"
+               OpMemberName %S 6 "vec2_u32"
+               OpMemberName %S 7 "vec2_f16"
+               OpMemberName %S 8 "vec3_f32"
+               OpMemberName %S 9 "vec3_i32"
+               OpMemberName %S 10 "vec3_u32"
+               OpMemberName %S 11 "vec3_f16"
+               OpMemberName %S 12 "vec4_f32"
+               OpMemberName %S 13 "vec4_i32"
+               OpMemberName %S 14 "vec4_u32"
+               OpMemberName %S 15 "vec4_f16"
+               OpMemberName %S 16 "mat2x2_f32"
+               OpMemberName %S 17 "mat2x3_f32"
+               OpMemberName %S 18 "mat2x4_f32"
+               OpMemberName %S 19 "mat3x2_f32"
+               OpMemberName %S 20 "mat3x3_f32"
+               OpMemberName %S 21 "mat3x4_f32"
+               OpMemberName %S 22 "mat4x2_f32"
+               OpMemberName %S 23 "mat4x3_f32"
+               OpMemberName %S 24 "mat4x4_f32"
+               OpMemberName %S 25 "mat2x2_f16"
+               OpMemberName %S 26 "mat2x3_f16"
+               OpMemberName %S 27 "mat2x4_f16"
+               OpMemberName %S 28 "mat3x2_f16"
+               OpMemberName %S 29 "mat3x3_f16"
+               OpMemberName %S 30 "mat3x4_f16"
+               OpMemberName %S 31 "mat4x2_f16"
+               OpMemberName %S 32 "mat4x3_f16"
+               OpMemberName %S 33 "mat4x4_f16"
+               OpMemberName %S 34 "arr2_vec3_f32"
+               OpMemberName %S 35 "arr2_mat4x2_f16"
+               OpMemberName %S 36 "struct_inner"
+               OpName %Inner "Inner"
+               OpMemberName %Inner 0 "scalar_i32"
+               OpMemberName %Inner 1 "scalar_f32"
+               OpMemberName %Inner 2 "scalar_f16"
+               OpMemberName %S 37 "array_struct_inner"
+               OpName %sb "sb"
+               OpName %main "main"
+               OpDecorate %sb_block Block
+               OpMemberDecorate %sb_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 4
+               OpMemberDecorate %S 2 Offset 8
+               OpMemberDecorate %S 3 Offset 12
+               OpMemberDecorate %S 4 Offset 16
+               OpMemberDecorate %S 5 Offset 24
+               OpMemberDecorate %S 6 Offset 32
+               OpMemberDecorate %S 7 Offset 40
+               OpMemberDecorate %S 8 Offset 48
+               OpMemberDecorate %S 9 Offset 64
+               OpMemberDecorate %S 10 Offset 80
+               OpMemberDecorate %S 11 Offset 96
+               OpMemberDecorate %S 12 Offset 112
+               OpMemberDecorate %S 13 Offset 128
+               OpMemberDecorate %S 14 Offset 144
+               OpMemberDecorate %S 15 Offset 160
+               OpMemberDecorate %S 16 Offset 168
+               OpMemberDecorate %S 16 ColMajor
+               OpMemberDecorate %S 16 MatrixStride 8
+               OpMemberDecorate %S 17 Offset 192
+               OpMemberDecorate %S 17 ColMajor
+               OpMemberDecorate %S 17 MatrixStride 16
+               OpMemberDecorate %S 18 Offset 224
+               OpMemberDecorate %S 18 ColMajor
+               OpMemberDecorate %S 18 MatrixStride 16
+               OpMemberDecorate %S 19 Offset 256
+               OpMemberDecorate %S 19 ColMajor
+               OpMemberDecorate %S 19 MatrixStride 8
+               OpMemberDecorate %S 20 Offset 288
+               OpMemberDecorate %S 20 ColMajor
+               OpMemberDecorate %S 20 MatrixStride 16
+               OpMemberDecorate %S 21 Offset 336
+               OpMemberDecorate %S 21 ColMajor
+               OpMemberDecorate %S 21 MatrixStride 16
+               OpMemberDecorate %S 22 Offset 384
+               OpMemberDecorate %S 22 ColMajor
+               OpMemberDecorate %S 22 MatrixStride 8
+               OpMemberDecorate %S 23 Offset 416
+               OpMemberDecorate %S 23 ColMajor
+               OpMemberDecorate %S 23 MatrixStride 16
+               OpMemberDecorate %S 24 Offset 480
+               OpMemberDecorate %S 24 ColMajor
+               OpMemberDecorate %S 24 MatrixStride 16
+               OpMemberDecorate %S 25 Offset 544
+               OpMemberDecorate %S 25 ColMajor
+               OpMemberDecorate %S 25 MatrixStride 4
+               OpMemberDecorate %S 26 Offset 552
+               OpMemberDecorate %S 26 ColMajor
+               OpMemberDecorate %S 26 MatrixStride 8
+               OpMemberDecorate %S 27 Offset 568
+               OpMemberDecorate %S 27 ColMajor
+               OpMemberDecorate %S 27 MatrixStride 8
+               OpMemberDecorate %S 28 Offset 584
+               OpMemberDecorate %S 28 ColMajor
+               OpMemberDecorate %S 28 MatrixStride 4
+               OpMemberDecorate %S 29 Offset 600
+               OpMemberDecorate %S 29 ColMajor
+               OpMemberDecorate %S 29 MatrixStride 8
+               OpMemberDecorate %S 30 Offset 624
+               OpMemberDecorate %S 30 ColMajor
+               OpMemberDecorate %S 30 MatrixStride 8
+               OpMemberDecorate %S 31 Offset 648
+               OpMemberDecorate %S 31 ColMajor
+               OpMemberDecorate %S 31 MatrixStride 4
+               OpMemberDecorate %S 32 Offset 664
+               OpMemberDecorate %S 32 ColMajor
+               OpMemberDecorate %S 32 MatrixStride 8
+               OpMemberDecorate %S 33 Offset 696
+               OpMemberDecorate %S 33 ColMajor
+               OpMemberDecorate %S 33 MatrixStride 8
+               OpMemberDecorate %S 34 Offset 736
+               OpDecorate %_arr_v3float_uint_2 ArrayStride 16
+               OpMemberDecorate %S 35 Offset 768
+               OpMemberDecorate %S 35 ColMajor
+               OpMemberDecorate %S 35 MatrixStride 4
+               OpDecorate %_arr_mat4v2half_uint_2 ArrayStride 16
+               OpMemberDecorate %S 36 Offset 800
+               OpMemberDecorate %Inner 0 Offset 0
+               OpMemberDecorate %Inner 1 Offset 4
+               OpMemberDecorate %Inner 2 Offset 8
+               OpMemberDecorate %S 37 Offset 812
+               OpDecorate %_arr_Inner_uint_4 ArrayStride 12
+               OpDecorate %sb Binding 0
+               OpDecorate %sb DescriptorSet 0
+      %float = OpTypeFloat 32
+        %int = OpTypeInt 32 1
+       %uint = OpTypeInt 32 0
+       %half = OpTypeFloat 16
+    %v2float = OpTypeVector %float 2
+      %v2int = OpTypeVector %int 2
+     %v2uint = OpTypeVector %uint 2
+     %v2half = OpTypeVector %half 2
+    %v3float = OpTypeVector %float 3
+      %v3int = OpTypeVector %int 3
+     %v3uint = OpTypeVector %uint 3
+     %v3half = OpTypeVector %half 3
+    %v4float = OpTypeVector %float 4
+      %v4int = OpTypeVector %int 4
+     %v4uint = OpTypeVector %uint 4
+     %v4half = OpTypeVector %half 4
+%mat2v2float = OpTypeMatrix %v2float 2
+%mat2v3float = OpTypeMatrix %v3float 2
+%mat2v4float = OpTypeMatrix %v4float 2
+%mat3v2float = OpTypeMatrix %v2float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+%mat3v4float = OpTypeMatrix %v4float 3
+%mat4v2float = OpTypeMatrix %v2float 4
+%mat4v3float = OpTypeMatrix %v3float 4
+%mat4v4float = OpTypeMatrix %v4float 4
+ %mat2v2half = OpTypeMatrix %v2half 2
+ %mat2v3half = OpTypeMatrix %v3half 2
+ %mat2v4half = OpTypeMatrix %v4half 2
+ %mat3v2half = OpTypeMatrix %v2half 3
+ %mat3v3half = OpTypeMatrix %v3half 3
+ %mat3v4half = OpTypeMatrix %v4half 3
+ %mat4v2half = OpTypeMatrix %v2half 4
+ %mat4v3half = OpTypeMatrix %v3half 4
+ %mat4v4half = OpTypeMatrix %v4half 4
+     %uint_2 = OpConstant %uint 2
+%_arr_v3float_uint_2 = OpTypeArray %v3float %uint_2
+%_arr_mat4v2half_uint_2 = OpTypeArray %mat4v2half %uint_2
+      %Inner = OpTypeStruct %int %float %half
+     %uint_4 = OpConstant %uint 4
+%_arr_Inner_uint_4 = OpTypeArray %Inner %uint_4
+          %S = OpTypeStruct %float %int %uint %half %v2float %v2int %v2uint %v2half %v3float %v3int %v3uint %v3half %v4float %v4int %v4uint %v4half %mat2v2float %mat2v3float %mat2v4float %mat3v2float %mat3v3float %mat3v4float %mat4v2float %mat4v3float %mat4v4float %mat2v2half %mat2v3half %mat2v4half %mat3v2half %mat3v3half %mat3v4half %mat4v2half %mat4v3half %mat4v4half %_arr_v3float_uint_2 %_arr_mat4v2half_uint_2 %Inner %_arr_Inner_uint_4
+   %sb_block = OpTypeStruct %S
+%_ptr_StorageBuffer_sb_block = OpTypePointer StorageBuffer %sb_block
+         %sb = OpVariable %_ptr_StorageBuffer_sb_block StorageBuffer
+       %void = OpTypeVoid
+         %45 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
+         %52 = OpConstantNull %float
+     %uint_1 = OpConstant %uint 1
+%_ptr_StorageBuffer_int = OpTypePointer StorageBuffer %int
+         %56 = OpConstantNull %int
+%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
+         %59 = OpConstantNull %uint
+     %uint_3 = OpConstant %uint 3
+%_ptr_StorageBuffer_half = OpTypePointer StorageBuffer %half
+         %63 = OpConstantNull %half
+%_ptr_StorageBuffer_v2float = OpTypePointer StorageBuffer %v2float
+         %66 = OpConstantNull %v2float
+     %uint_5 = OpConstant %uint 5
+%_ptr_StorageBuffer_v2int = OpTypePointer StorageBuffer %v2int
+         %70 = OpConstantNull %v2int
+     %uint_6 = OpConstant %uint 6
+%_ptr_StorageBuffer_v2uint = OpTypePointer StorageBuffer %v2uint
+         %74 = OpConstantNull %v2uint
+     %uint_7 = OpConstant %uint 7
+%_ptr_StorageBuffer_v2half = OpTypePointer StorageBuffer %v2half
+         %78 = OpConstantNull %v2half
+     %uint_8 = OpConstant %uint 8
+%_ptr_StorageBuffer_v3float = OpTypePointer StorageBuffer %v3float
+         %82 = OpConstantNull %v3float
+     %uint_9 = OpConstant %uint 9
+%_ptr_StorageBuffer_v3int = OpTypePointer StorageBuffer %v3int
+         %86 = OpConstantNull %v3int
+    %uint_10 = OpConstant %uint 10
+%_ptr_StorageBuffer_v3uint = OpTypePointer StorageBuffer %v3uint
+         %90 = OpConstantNull %v3uint
+    %uint_11 = OpConstant %uint 11
+%_ptr_StorageBuffer_v3half = OpTypePointer StorageBuffer %v3half
+         %94 = OpConstantNull %v3half
+    %uint_12 = OpConstant %uint 12
+%_ptr_StorageBuffer_v4float = OpTypePointer StorageBuffer %v4float
+         %98 = OpConstantNull %v4float
+    %uint_13 = OpConstant %uint 13
+%_ptr_StorageBuffer_v4int = OpTypePointer StorageBuffer %v4int
+        %102 = OpConstantNull %v4int
+    %uint_14 = OpConstant %uint 14
+%_ptr_StorageBuffer_v4uint = OpTypePointer StorageBuffer %v4uint
+        %106 = OpConstantNull %v4uint
+    %uint_15 = OpConstant %uint 15
+%_ptr_StorageBuffer_v4half = OpTypePointer StorageBuffer %v4half
+        %110 = OpConstantNull %v4half
+    %uint_16 = OpConstant %uint 16
+%_ptr_StorageBuffer_mat2v2float = OpTypePointer StorageBuffer %mat2v2float
+        %114 = OpConstantNull %mat2v2float
+    %uint_17 = OpConstant %uint 17
+%_ptr_StorageBuffer_mat2v3float = OpTypePointer StorageBuffer %mat2v3float
+        %118 = OpConstantNull %mat2v3float
+    %uint_18 = OpConstant %uint 18
+%_ptr_StorageBuffer_mat2v4float = OpTypePointer StorageBuffer %mat2v4float
+        %122 = OpConstantNull %mat2v4float
+    %uint_19 = OpConstant %uint 19
+%_ptr_StorageBuffer_mat3v2float = OpTypePointer StorageBuffer %mat3v2float
+        %126 = OpConstantNull %mat3v2float
+    %uint_20 = OpConstant %uint 20
+%_ptr_StorageBuffer_mat3v3float = OpTypePointer StorageBuffer %mat3v3float
+        %130 = OpConstantNull %mat3v3float
+    %uint_21 = OpConstant %uint 21
+%_ptr_StorageBuffer_mat3v4float = OpTypePointer StorageBuffer %mat3v4float
+        %134 = OpConstantNull %mat3v4float
+    %uint_22 = OpConstant %uint 22
+%_ptr_StorageBuffer_mat4v2float = OpTypePointer StorageBuffer %mat4v2float
+        %138 = OpConstantNull %mat4v2float
+    %uint_23 = OpConstant %uint 23
+%_ptr_StorageBuffer_mat4v3float = OpTypePointer StorageBuffer %mat4v3float
+        %142 = OpConstantNull %mat4v3float
+    %uint_24 = OpConstant %uint 24
+%_ptr_StorageBuffer_mat4v4float = OpTypePointer StorageBuffer %mat4v4float
+        %146 = OpConstantNull %mat4v4float
+    %uint_25 = OpConstant %uint 25
+%_ptr_StorageBuffer_mat2v2half = OpTypePointer StorageBuffer %mat2v2half
+        %150 = OpConstantNull %mat2v2half
+    %uint_26 = OpConstant %uint 26
+%_ptr_StorageBuffer_mat2v3half = OpTypePointer StorageBuffer %mat2v3half
+        %154 = OpConstantNull %mat2v3half
+    %uint_27 = OpConstant %uint 27
+%_ptr_StorageBuffer_mat2v4half = OpTypePointer StorageBuffer %mat2v4half
+        %158 = OpConstantNull %mat2v4half
+    %uint_28 = OpConstant %uint 28
+%_ptr_StorageBuffer_mat3v2half = OpTypePointer StorageBuffer %mat3v2half
+        %162 = OpConstantNull %mat3v2half
+    %uint_29 = OpConstant %uint 29
+%_ptr_StorageBuffer_mat3v3half = OpTypePointer StorageBuffer %mat3v3half
+        %166 = OpConstantNull %mat3v3half
+    %uint_30 = OpConstant %uint 30
+%_ptr_StorageBuffer_mat3v4half = OpTypePointer StorageBuffer %mat3v4half
+        %170 = OpConstantNull %mat3v4half
+    %uint_31 = OpConstant %uint 31
+%_ptr_StorageBuffer_mat4v2half = OpTypePointer StorageBuffer %mat4v2half
+        %174 = OpConstantNull %mat4v2half
+    %uint_32 = OpConstant %uint 32
+%_ptr_StorageBuffer_mat4v3half = OpTypePointer StorageBuffer %mat4v3half
+        %178 = OpConstantNull %mat4v3half
+    %uint_33 = OpConstant %uint 33
+%_ptr_StorageBuffer_mat4v4half = OpTypePointer StorageBuffer %mat4v4half
+        %182 = OpConstantNull %mat4v4half
+    %uint_34 = OpConstant %uint 34
+%_ptr_StorageBuffer__arr_v3float_uint_2 = OpTypePointer StorageBuffer %_arr_v3float_uint_2
+        %186 = OpConstantNull %_arr_v3float_uint_2
+    %uint_35 = OpConstant %uint 35
+%_ptr_StorageBuffer__arr_mat4v2half_uint_2 = OpTypePointer StorageBuffer %_arr_mat4v2half_uint_2
+        %190 = OpConstantNull %_arr_mat4v2half_uint_2
+    %uint_36 = OpConstant %uint 36
+%_ptr_StorageBuffer_Inner = OpTypePointer StorageBuffer %Inner
+        %194 = OpConstantNull %Inner
+    %uint_37 = OpConstant %uint 37
+%_ptr_StorageBuffer__arr_Inner_uint_4 = OpTypePointer StorageBuffer %_arr_Inner_uint_4
+        %198 = OpConstantNull %_arr_Inner_uint_4
+       %main = OpFunction %void None %45
+         %48 = OpLabel
+         %51 = OpAccessChain %_ptr_StorageBuffer_float %sb %uint_0 %uint_0
+               OpStore %51 %52
+         %55 = OpAccessChain %_ptr_StorageBuffer_int %sb %uint_0 %uint_1
+               OpStore %55 %56
+         %58 = OpAccessChain %_ptr_StorageBuffer_uint %sb %uint_0 %uint_2
+               OpStore %58 %59
+         %62 = OpAccessChain %_ptr_StorageBuffer_half %sb %uint_0 %uint_3
+               OpStore %62 %63
+         %65 = OpAccessChain %_ptr_StorageBuffer_v2float %sb %uint_0 %uint_4
+               OpStore %65 %66
+         %69 = OpAccessChain %_ptr_StorageBuffer_v2int %sb %uint_0 %uint_5
+               OpStore %69 %70
+         %73 = OpAccessChain %_ptr_StorageBuffer_v2uint %sb %uint_0 %uint_6
+               OpStore %73 %74
+         %77 = OpAccessChain %_ptr_StorageBuffer_v2half %sb %uint_0 %uint_7
+               OpStore %77 %78
+         %81 = OpAccessChain %_ptr_StorageBuffer_v3float %sb %uint_0 %uint_8
+               OpStore %81 %82
+         %85 = OpAccessChain %_ptr_StorageBuffer_v3int %sb %uint_0 %uint_9
+               OpStore %85 %86
+         %89 = OpAccessChain %_ptr_StorageBuffer_v3uint %sb %uint_0 %uint_10
+               OpStore %89 %90
+         %93 = OpAccessChain %_ptr_StorageBuffer_v3half %sb %uint_0 %uint_11
+               OpStore %93 %94
+         %97 = OpAccessChain %_ptr_StorageBuffer_v4float %sb %uint_0 %uint_12
+               OpStore %97 %98
+        %101 = OpAccessChain %_ptr_StorageBuffer_v4int %sb %uint_0 %uint_13
+               OpStore %101 %102
+        %105 = OpAccessChain %_ptr_StorageBuffer_v4uint %sb %uint_0 %uint_14
+               OpStore %105 %106
+        %109 = OpAccessChain %_ptr_StorageBuffer_v4half %sb %uint_0 %uint_15
+               OpStore %109 %110
+        %113 = OpAccessChain %_ptr_StorageBuffer_mat2v2float %sb %uint_0 %uint_16
+               OpStore %113 %114
+        %117 = OpAccessChain %_ptr_StorageBuffer_mat2v3float %sb %uint_0 %uint_17
+               OpStore %117 %118
+        %121 = OpAccessChain %_ptr_StorageBuffer_mat2v4float %sb %uint_0 %uint_18
+               OpStore %121 %122
+        %125 = OpAccessChain %_ptr_StorageBuffer_mat3v2float %sb %uint_0 %uint_19
+               OpStore %125 %126
+        %129 = OpAccessChain %_ptr_StorageBuffer_mat3v3float %sb %uint_0 %uint_20
+               OpStore %129 %130
+        %133 = OpAccessChain %_ptr_StorageBuffer_mat3v4float %sb %uint_0 %uint_21
+               OpStore %133 %134
+        %137 = OpAccessChain %_ptr_StorageBuffer_mat4v2float %sb %uint_0 %uint_22
+               OpStore %137 %138
+        %141 = OpAccessChain %_ptr_StorageBuffer_mat4v3float %sb %uint_0 %uint_23
+               OpStore %141 %142
+        %145 = OpAccessChain %_ptr_StorageBuffer_mat4v4float %sb %uint_0 %uint_24
+               OpStore %145 %146
+        %149 = OpAccessChain %_ptr_StorageBuffer_mat2v2half %sb %uint_0 %uint_25
+               OpStore %149 %150
+        %153 = OpAccessChain %_ptr_StorageBuffer_mat2v3half %sb %uint_0 %uint_26
+               OpStore %153 %154
+        %157 = OpAccessChain %_ptr_StorageBuffer_mat2v4half %sb %uint_0 %uint_27
+               OpStore %157 %158
+        %161 = OpAccessChain %_ptr_StorageBuffer_mat3v2half %sb %uint_0 %uint_28
+               OpStore %161 %162
+        %165 = OpAccessChain %_ptr_StorageBuffer_mat3v3half %sb %uint_0 %uint_29
+               OpStore %165 %166
+        %169 = OpAccessChain %_ptr_StorageBuffer_mat3v4half %sb %uint_0 %uint_30
+               OpStore %169 %170
+        %173 = OpAccessChain %_ptr_StorageBuffer_mat4v2half %sb %uint_0 %uint_31
+               OpStore %173 %174
+        %177 = OpAccessChain %_ptr_StorageBuffer_mat4v3half %sb %uint_0 %uint_32
+               OpStore %177 %178
+        %181 = OpAccessChain %_ptr_StorageBuffer_mat4v4half %sb %uint_0 %uint_33
+               OpStore %181 %182
+        %185 = OpAccessChain %_ptr_StorageBuffer__arr_v3float_uint_2 %sb %uint_0 %uint_34
+               OpStore %185 %186
+        %189 = OpAccessChain %_ptr_StorageBuffer__arr_mat4v2half_uint_2 %sb %uint_0 %uint_35
+               OpStore %189 %190
+        %193 = OpAccessChain %_ptr_StorageBuffer_Inner %sb %uint_0 %uint_36
+               OpStore %193 %194
+        %197 = OpAccessChain %_ptr_StorageBuffer__arr_Inner_uint_4 %sb %uint_0 %uint_37
+               OpStore %197 %198
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/storage/static_index/write_f16.wgsl.expected.wgsl b/test/tint/buffer/storage/static_index/write_f16.wgsl.expected.wgsl
new file mode 100644
index 0000000..d2f699a
--- /dev/null
+++ b/test/tint/buffer/storage/static_index/write_f16.wgsl.expected.wgsl
@@ -0,0 +1,92 @@
+enable f16;
+
+struct Inner {
+  scalar_i32 : i32,
+  scalar_f32 : f32,
+  scalar_f16 : f16,
+}
+
+struct S {
+  scalar_f32 : f32,
+  scalar_i32 : i32,
+  scalar_u32 : u32,
+  scalar_f16 : f16,
+  vec2_f32 : vec2<f32>,
+  vec2_i32 : vec2<i32>,
+  vec2_u32 : vec2<u32>,
+  vec2_f16 : vec2<f16>,
+  vec3_f32 : vec3<f32>,
+  vec3_i32 : vec3<i32>,
+  vec3_u32 : vec3<u32>,
+  vec3_f16 : vec3<f16>,
+  vec4_f32 : vec4<f32>,
+  vec4_i32 : vec4<i32>,
+  vec4_u32 : vec4<u32>,
+  vec4_f16 : vec4<f16>,
+  mat2x2_f32 : mat2x2<f32>,
+  mat2x3_f32 : mat2x3<f32>,
+  mat2x4_f32 : mat2x4<f32>,
+  mat3x2_f32 : mat3x2<f32>,
+  mat3x3_f32 : mat3x3<f32>,
+  mat3x4_f32 : mat3x4<f32>,
+  mat4x2_f32 : mat4x2<f32>,
+  mat4x3_f32 : mat4x3<f32>,
+  mat4x4_f32 : mat4x4<f32>,
+  mat2x2_f16 : mat2x2<f16>,
+  mat2x3_f16 : mat2x3<f16>,
+  mat2x4_f16 : mat2x4<f16>,
+  mat3x2_f16 : mat3x2<f16>,
+  mat3x3_f16 : mat3x3<f16>,
+  mat3x4_f16 : mat3x4<f16>,
+  mat4x2_f16 : mat4x2<f16>,
+  mat4x3_f16 : mat4x3<f16>,
+  mat4x4_f16 : mat4x4<f16>,
+  arr2_vec3_f32 : array<vec3<f32>, 2>,
+  arr2_mat4x2_f16 : array<mat4x2<f16>, 2>,
+  struct_inner : Inner,
+  array_struct_inner : array<Inner, 4>,
+}
+
+@binding(0) @group(0) var<storage, read_write> sb : S;
+
+@compute @workgroup_size(1)
+fn main() {
+  sb.scalar_f32 = f32();
+  sb.scalar_i32 = i32();
+  sb.scalar_u32 = u32();
+  sb.scalar_f16 = f16();
+  sb.vec2_f32 = vec2<f32>();
+  sb.vec2_i32 = vec2<i32>();
+  sb.vec2_u32 = vec2<u32>();
+  sb.vec2_f16 = vec2<f16>();
+  sb.vec3_f32 = vec3<f32>();
+  sb.vec3_i32 = vec3<i32>();
+  sb.vec3_u32 = vec3<u32>();
+  sb.vec3_f16 = vec3<f16>();
+  sb.vec4_f32 = vec4<f32>();
+  sb.vec4_i32 = vec4<i32>();
+  sb.vec4_u32 = vec4<u32>();
+  sb.vec4_f16 = vec4<f16>();
+  sb.mat2x2_f32 = mat2x2<f32>();
+  sb.mat2x3_f32 = mat2x3<f32>();
+  sb.mat2x4_f32 = mat2x4<f32>();
+  sb.mat3x2_f32 = mat3x2<f32>();
+  sb.mat3x3_f32 = mat3x3<f32>();
+  sb.mat3x4_f32 = mat3x4<f32>();
+  sb.mat4x2_f32 = mat4x2<f32>();
+  sb.mat4x3_f32 = mat4x3<f32>();
+  sb.mat4x4_f32 = mat4x4<f32>();
+  sb.mat2x2_f16 = mat2x2<f16>();
+  sb.mat2x3_f16 = mat2x3<f16>();
+  sb.mat2x4_f16 = mat2x4<f16>();
+  sb.mat3x2_f16 = mat3x2<f16>();
+  sb.mat3x3_f16 = mat3x3<f16>();
+  sb.mat3x4_f16 = mat3x4<f16>();
+  sb.mat4x2_f16 = mat4x2<f16>();
+  sb.mat4x3_f16 = mat4x3<f16>();
+  sb.mat4x4_f16 = mat4x4<f16>();
+  sb.arr2_vec3_f32 = array<vec3<f32>, 2>();
+  sb.arr2_mat4x2_f16 = array<mat4x2<f16>, 2>();
+  sb.struct_inner = Inner();
+  sb.array_struct_inner = array<Inner, 4>();
+}
diff --git a/test/tint/buffer/storage/types/array4_f16.wgsl b/test/tint/buffer/storage/types/array4_f16.wgsl
new file mode 100644
index 0000000..adc6067
--- /dev/null
+++ b/test/tint/buffer/storage/types/array4_f16.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0)
+var<storage, read> in : array<f16, 4>;
+
+@group(0) @binding(1)
+var<storage, read_write> out : array<f16, 4>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/array4_f16.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/types/array4_f16.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..15fa0ab
--- /dev/null
+++ b/test/tint/buffer/storage/types/array4_f16.wgsl.expected.dxc.hlsl
@@ -0,0 +1,28 @@
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+void tint_symbol_2(RWByteAddressBuffer buffer, uint offset, float16_t value[4]) {
+  float16_t array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      buffer.Store<float16_t>((offset + (i * 2u)), array[i]);
+    }
+  }
+}
+
+typedef float16_t tint_symbol_4_ret[4];
+tint_symbol_4_ret tint_symbol_4(ByteAddressBuffer buffer, uint offset) {
+  float16_t arr[4] = (float16_t[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = buffer.Load<float16_t>((offset + (i_1 * 2u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_2(tint_symbol_1, 0u, tint_symbol_4(tint_symbol, 0u));
+  return;
+}
diff --git a/test/tint/buffer/storage/types/array4_f16.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/types/array4_f16.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..68566c9
--- /dev/null
+++ b/test/tint/buffer/storage/types/array4_f16.wgsl.expected.fxc.hlsl
@@ -0,0 +1,33 @@
+SKIP: FAILED
+
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+void tint_symbol_2(RWByteAddressBuffer buffer, uint offset, float16_t value[4]) {
+  float16_t array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      buffer.Store<float16_t>((offset + (i * 2u)), array[i]);
+    }
+  }
+}
+
+typedef float16_t tint_symbol_4_ret[4];
+tint_symbol_4_ret tint_symbol_4(ByteAddressBuffer buffer, uint offset) {
+  float16_t arr[4] = (float16_t[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = buffer.Load<float16_t>((offset + (i_1 * 2u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_2(tint_symbol_1, 0u, tint_symbol_4(tint_symbol, 0u));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000026D14358AA0(4,61-69): error X3000: unrecognized identifier 'float16_t'
+
diff --git a/test/tint/buffer/storage/types/array4_f16.wgsl.expected.glsl b/test/tint/buffer/storage/types/array4_f16.wgsl.expected.glsl
new file mode 100644
index 0000000..ea5353e
--- /dev/null
+++ b/test/tint/buffer/storage/types/array4_f16.wgsl.expected.glsl
@@ -0,0 +1,20 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std430) buffer tint_symbol_block_ssbo {
+  float16_t inner[4];
+} tint_symbol;
+
+layout(binding = 1, std430) buffer tint_symbol_block_ssbo_1 {
+  float16_t inner[4];
+} tint_symbol_1;
+
+void tint_symbol_2() {
+  tint_symbol_1.inner = tint_symbol.inner;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol_2();
+  return;
+}
diff --git a/test/tint/buffer/storage/types/array4_f16.wgsl.expected.msl b/test/tint/buffer/storage/types/array4_f16.wgsl.expected.msl
new file mode 100644
index 0000000..78f6acf
--- /dev/null
+++ b/test/tint/buffer/storage/types/array4_f16.wgsl.expected.msl
@@ -0,0 +1,21 @@
+#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];
+};
+
+kernel void tint_symbol(device tint_array<half, 4>* tint_symbol_1 [[buffer(0)]], const device tint_array<half, 4>* tint_symbol_2 [[buffer(1)]]) {
+  *(tint_symbol_1) = *(tint_symbol_2);
+  return;
+}
+
diff --git a/test/tint/buffer/storage/types/array4_f16.wgsl.expected.spvasm b/test/tint/buffer/storage/types/array4_f16.wgsl.expected.spvasm
new file mode 100644
index 0000000..64da920
--- /dev/null
+++ b/test/tint/buffer/storage/types/array4_f16.wgsl.expected.spvasm
@@ -0,0 +1,46 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 18
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %in_block "in_block"
+               OpMemberName %in_block 0 "inner"
+               OpName %in "in"
+               OpName %out "out"
+               OpName %main "main"
+               OpDecorate %in_block Block
+               OpMemberDecorate %in_block 0 Offset 0
+               OpDecorate %_arr_half_uint_4 ArrayStride 2
+               OpDecorate %in NonWritable
+               OpDecorate %in DescriptorSet 0
+               OpDecorate %in Binding 0
+               OpDecorate %out DescriptorSet 0
+               OpDecorate %out Binding 1
+       %half = OpTypeFloat 16
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_half_uint_4 = OpTypeArray %half %uint_4
+   %in_block = OpTypeStruct %_arr_half_uint_4
+%_ptr_StorageBuffer_in_block = OpTypePointer StorageBuffer %in_block
+         %in = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+        %out = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+       %void = OpTypeVoid
+          %9 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer__arr_half_uint_4 = OpTypePointer StorageBuffer %_arr_half_uint_4
+       %main = OpFunction %void None %9
+         %12 = OpLabel
+         %15 = OpAccessChain %_ptr_StorageBuffer__arr_half_uint_4 %out %uint_0
+         %16 = OpAccessChain %_ptr_StorageBuffer__arr_half_uint_4 %in %uint_0
+         %17 = OpLoad %_arr_half_uint_4 %16
+               OpStore %15 %17
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/storage/types/array4_f16.wgsl.expected.wgsl b/test/tint/buffer/storage/types/array4_f16.wgsl.expected.wgsl
new file mode 100644
index 0000000..69b786c
--- /dev/null
+++ b/test/tint/buffer/storage/types/array4_f16.wgsl.expected.wgsl
@@ -0,0 +1,10 @@
+enable f16;
+
+@group(0) @binding(0) var<storage, read> in : array<f16, 4>;
+
+@group(0) @binding(1) var<storage, read_write> out : array<f16, 4>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/array.wgsl b/test/tint/buffer/storage/types/array4_f32.wgsl
similarity index 100%
rename from test/tint/buffer/storage/types/array.wgsl
rename to test/tint/buffer/storage/types/array4_f32.wgsl
diff --git a/test/tint/buffer/storage/types/array.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/types/array4_f32.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/storage/types/array.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/storage/types/array4_f32.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/storage/types/array.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/types/array4_f32.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/storage/types/array.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/storage/types/array4_f32.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/storage/types/array.wgsl.expected.glsl b/test/tint/buffer/storage/types/array4_f32.wgsl.expected.glsl
similarity index 100%
rename from test/tint/buffer/storage/types/array.wgsl.expected.glsl
rename to test/tint/buffer/storage/types/array4_f32.wgsl.expected.glsl
diff --git a/test/tint/buffer/storage/types/array.wgsl.expected.msl b/test/tint/buffer/storage/types/array4_f32.wgsl.expected.msl
similarity index 100%
rename from test/tint/buffer/storage/types/array.wgsl.expected.msl
rename to test/tint/buffer/storage/types/array4_f32.wgsl.expected.msl
diff --git a/test/tint/buffer/storage/types/array.wgsl.expected.spvasm b/test/tint/buffer/storage/types/array4_f32.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/storage/types/array.wgsl.expected.spvasm
rename to test/tint/buffer/storage/types/array4_f32.wgsl.expected.spvasm
diff --git a/test/tint/buffer/storage/types/array.wgsl.expected.wgsl b/test/tint/buffer/storage/types/array4_f32.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/buffer/storage/types/array.wgsl.expected.wgsl
rename to test/tint/buffer/storage/types/array4_f32.wgsl.expected.wgsl
diff --git a/test/tint/buffer/storage/types/f16.wgsl b/test/tint/buffer/storage/types/f16.wgsl
new file mode 100644
index 0000000..4cc239e
--- /dev/null
+++ b/test/tint/buffer/storage/types/f16.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0)
+var<storage, read> in : f16;
+
+@group(0) @binding(1)
+var<storage, read_write> out : f16;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/f16.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/types/f16.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..bfdede4
--- /dev/null
+++ b/test/tint/buffer/storage/types/f16.wgsl.expected.dxc.hlsl
@@ -0,0 +1,8 @@
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_1.Store<float16_t>(0u, tint_symbol.Load<float16_t>(0u));
+  return;
+}
diff --git a/test/tint/buffer/storage/types/f16.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/types/f16.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..b9b25bf
--- /dev/null
+++ b/test/tint/buffer/storage/types/f16.wgsl.expected.fxc.hlsl
@@ -0,0 +1,13 @@
+SKIP: FAILED
+
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_1.Store<float16_t>(0u, tint_symbol.Load<float16_t>(0u));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000020E4EF78E80(6,3-21): error X3018: invalid subscript 'Store'
+
diff --git a/test/tint/buffer/storage/types/f16.wgsl.expected.glsl b/test/tint/buffer/storage/types/f16.wgsl.expected.glsl
new file mode 100644
index 0000000..7f3dfad
--- /dev/null
+++ b/test/tint/buffer/storage/types/f16.wgsl.expected.glsl
@@ -0,0 +1,20 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std430) buffer tint_symbol_block_ssbo {
+  float16_t inner;
+} tint_symbol;
+
+layout(binding = 1, std430) buffer tint_symbol_block_ssbo_1 {
+  float16_t inner;
+} tint_symbol_1;
+
+void tint_symbol_2() {
+  tint_symbol_1.inner = tint_symbol.inner;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol_2();
+  return;
+}
diff --git a/test/tint/buffer/storage/types/f16.wgsl.expected.msl b/test/tint/buffer/storage/types/f16.wgsl.expected.msl
new file mode 100644
index 0000000..5991f9e
--- /dev/null
+++ b/test/tint/buffer/storage/types/f16.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(device half* tint_symbol_1 [[buffer(0)]], const device half* tint_symbol_2 [[buffer(1)]]) {
+  *(tint_symbol_1) = *(tint_symbol_2);
+  return;
+}
+
diff --git a/test/tint/buffer/storage/types/f16.wgsl.expected.spvasm b/test/tint/buffer/storage/types/f16.wgsl.expected.spvasm
new file mode 100644
index 0000000..18f45d8
--- /dev/null
+++ b/test/tint/buffer/storage/types/f16.wgsl.expected.spvasm
@@ -0,0 +1,43 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 16
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %in_block "in_block"
+               OpMemberName %in_block 0 "inner"
+               OpName %in "in"
+               OpName %out "out"
+               OpName %main "main"
+               OpDecorate %in_block Block
+               OpMemberDecorate %in_block 0 Offset 0
+               OpDecorate %in NonWritable
+               OpDecorate %in DescriptorSet 0
+               OpDecorate %in Binding 0
+               OpDecorate %out DescriptorSet 0
+               OpDecorate %out Binding 1
+       %half = OpTypeFloat 16
+   %in_block = OpTypeStruct %half
+%_ptr_StorageBuffer_in_block = OpTypePointer StorageBuffer %in_block
+         %in = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+        %out = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+       %void = OpTypeVoid
+          %6 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_half = OpTypePointer StorageBuffer %half
+       %main = OpFunction %void None %6
+          %9 = OpLabel
+         %13 = OpAccessChain %_ptr_StorageBuffer_half %out %uint_0
+         %14 = OpAccessChain %_ptr_StorageBuffer_half %in %uint_0
+         %15 = OpLoad %half %14
+               OpStore %13 %15
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/storage/types/f16.wgsl.expected.wgsl b/test/tint/buffer/storage/types/f16.wgsl.expected.wgsl
new file mode 100644
index 0000000..69bde46
--- /dev/null
+++ b/test/tint/buffer/storage/types/f16.wgsl.expected.wgsl
@@ -0,0 +1,10 @@
+enable f16;
+
+@group(0) @binding(0) var<storage, read> in : f16;
+
+@group(0) @binding(1) var<storage, read_write> out : f16;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/mat2x2_f16.wgsl b/test/tint/buffer/storage/types/mat2x2_f16.wgsl
new file mode 100644
index 0000000..cf89bf3
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat2x2_f16.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0)
+var<storage, read> in : mat2x2<f16>;
+
+@group(0) @binding(1)
+var<storage, read_write> out : mat2x2<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/mat2x2_f16.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/types/mat2x2_f16.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..3730b98
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat2x2_f16.wgsl.expected.dxc.hlsl
@@ -0,0 +1,17 @@
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+void tint_symbol_2(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 2, 2> value) {
+  buffer.Store<vector<float16_t, 2> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 4u), value[1u]);
+}
+
+matrix<float16_t, 2, 2> tint_symbol_4(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 2, 2>(buffer.Load<vector<float16_t, 2> >((offset + 0u)), buffer.Load<vector<float16_t, 2> >((offset + 4u)));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_2(tint_symbol_1, 0u, tint_symbol_4(tint_symbol, 0u));
+  return;
+}
diff --git a/test/tint/buffer/storage/types/mat2x2_f16.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/types/mat2x2_f16.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..ac54fc4
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat2x2_f16.wgsl.expected.fxc.hlsl
@@ -0,0 +1,23 @@
+SKIP: FAILED
+
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+void tint_symbol_2(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 2, 2> value) {
+  buffer.Store<vector<float16_t, 2> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 4u), value[1u]);
+}
+
+matrix<float16_t, 2, 2> tint_symbol_4(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 2, 2>(buffer.Load<vector<float16_t, 2> >((offset + 0u)), buffer.Load<vector<float16_t, 2> >((offset + 4u)));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_2(tint_symbol_1, 0u, tint_symbol_4(tint_symbol, 0u));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001C807B6A460(4,68-76): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001C807B6A460(5,3-14): error X3018: invalid subscript 'Store'
+
diff --git a/test/tint/buffer/storage/types/mat2x2_f16.wgsl.expected.glsl b/test/tint/buffer/storage/types/mat2x2_f16.wgsl.expected.glsl
new file mode 100644
index 0000000..7c9f01a
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat2x2_f16.wgsl.expected.glsl
@@ -0,0 +1,20 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std430) buffer tint_symbol_block_ssbo {
+  f16mat2 inner;
+} tint_symbol;
+
+layout(binding = 1, std430) buffer tint_symbol_block_ssbo_1 {
+  f16mat2 inner;
+} tint_symbol_1;
+
+void tint_symbol_2() {
+  tint_symbol_1.inner = tint_symbol.inner;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol_2();
+  return;
+}
diff --git a/test/tint/buffer/storage/types/mat2x2_f16.wgsl.expected.msl b/test/tint/buffer/storage/types/mat2x2_f16.wgsl.expected.msl
new file mode 100644
index 0000000..9c048c5
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat2x2_f16.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(device half2x2* tint_symbol_1 [[buffer(0)]], const device half2x2* tint_symbol_2 [[buffer(1)]]) {
+  *(tint_symbol_1) = *(tint_symbol_2);
+  return;
+}
+
diff --git a/test/tint/buffer/storage/types/mat2x2_f16.wgsl.expected.spvasm b/test/tint/buffer/storage/types/mat2x2_f16.wgsl.expected.spvasm
new file mode 100644
index 0000000..8bd8c4b
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat2x2_f16.wgsl.expected.spvasm
@@ -0,0 +1,47 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 18
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %in_block "in_block"
+               OpMemberName %in_block 0 "inner"
+               OpName %in "in"
+               OpName %out "out"
+               OpName %main "main"
+               OpDecorate %in_block Block
+               OpMemberDecorate %in_block 0 Offset 0
+               OpMemberDecorate %in_block 0 ColMajor
+               OpMemberDecorate %in_block 0 MatrixStride 4
+               OpDecorate %in NonWritable
+               OpDecorate %in DescriptorSet 0
+               OpDecorate %in Binding 0
+               OpDecorate %out DescriptorSet 0
+               OpDecorate %out Binding 1
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+ %mat2v2half = OpTypeMatrix %v2half 2
+   %in_block = OpTypeStruct %mat2v2half
+%_ptr_StorageBuffer_in_block = OpTypePointer StorageBuffer %in_block
+         %in = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+        %out = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+       %void = OpTypeVoid
+          %8 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_mat2v2half = OpTypePointer StorageBuffer %mat2v2half
+       %main = OpFunction %void None %8
+         %11 = OpLabel
+         %15 = OpAccessChain %_ptr_StorageBuffer_mat2v2half %out %uint_0
+         %16 = OpAccessChain %_ptr_StorageBuffer_mat2v2half %in %uint_0
+         %17 = OpLoad %mat2v2half %16
+               OpStore %15 %17
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/storage/types/mat2x2_f16.wgsl.expected.wgsl b/test/tint/buffer/storage/types/mat2x2_f16.wgsl.expected.wgsl
new file mode 100644
index 0000000..4beb63d
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat2x2_f16.wgsl.expected.wgsl
@@ -0,0 +1,10 @@
+enable f16;
+
+@group(0) @binding(0) var<storage, read> in : mat2x2<f16>;
+
+@group(0) @binding(1) var<storage, read_write> out : mat2x2<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/mat2x2.wgsl b/test/tint/buffer/storage/types/mat2x2_f32.wgsl
similarity index 100%
rename from test/tint/buffer/storage/types/mat2x2.wgsl
rename to test/tint/buffer/storage/types/mat2x2_f32.wgsl
diff --git a/test/tint/buffer/storage/types/mat2x2.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/types/mat2x2_f32.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/storage/types/mat2x2.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/storage/types/mat2x2_f32.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/storage/types/mat2x2.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/types/mat2x2_f32.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/storage/types/mat2x2.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/storage/types/mat2x2_f32.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/storage/types/mat2x2.wgsl.expected.glsl b/test/tint/buffer/storage/types/mat2x2_f32.wgsl.expected.glsl
similarity index 100%
rename from test/tint/buffer/storage/types/mat2x2.wgsl.expected.glsl
rename to test/tint/buffer/storage/types/mat2x2_f32.wgsl.expected.glsl
diff --git a/test/tint/buffer/storage/types/mat2x2.wgsl.expected.msl b/test/tint/buffer/storage/types/mat2x2_f32.wgsl.expected.msl
similarity index 100%
rename from test/tint/buffer/storage/types/mat2x2.wgsl.expected.msl
rename to test/tint/buffer/storage/types/mat2x2_f32.wgsl.expected.msl
diff --git a/test/tint/buffer/storage/types/mat2x2.wgsl.expected.spvasm b/test/tint/buffer/storage/types/mat2x2_f32.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/storage/types/mat2x2.wgsl.expected.spvasm
rename to test/tint/buffer/storage/types/mat2x2_f32.wgsl.expected.spvasm
diff --git a/test/tint/buffer/storage/types/mat2x2.wgsl.expected.wgsl b/test/tint/buffer/storage/types/mat2x2_f32.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/buffer/storage/types/mat2x2.wgsl.expected.wgsl
rename to test/tint/buffer/storage/types/mat2x2_f32.wgsl.expected.wgsl
diff --git a/test/tint/buffer/storage/types/mat2x3_f16.wgsl b/test/tint/buffer/storage/types/mat2x3_f16.wgsl
new file mode 100644
index 0000000..dba9a50
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat2x3_f16.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0)
+var<storage, read> in : mat2x3<f16>;
+
+@group(0) @binding(1)
+var<storage, read_write> out : mat2x3<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/mat2x3_f16.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/types/mat2x3_f16.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..0411bf3
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat2x3_f16.wgsl.expected.dxc.hlsl
@@ -0,0 +1,17 @@
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+void tint_symbol_2(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 2, 3> value) {
+  buffer.Store<vector<float16_t, 3> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 8u), value[1u]);
+}
+
+matrix<float16_t, 2, 3> tint_symbol_4(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 2, 3>(buffer.Load<vector<float16_t, 3> >((offset + 0u)), buffer.Load<vector<float16_t, 3> >((offset + 8u)));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_2(tint_symbol_1, 0u, tint_symbol_4(tint_symbol, 0u));
+  return;
+}
diff --git a/test/tint/buffer/storage/types/mat2x3_f16.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/types/mat2x3_f16.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..3eb59f8
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat2x3_f16.wgsl.expected.fxc.hlsl
@@ -0,0 +1,23 @@
+SKIP: FAILED
+
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+void tint_symbol_2(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 2, 3> value) {
+  buffer.Store<vector<float16_t, 3> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 8u), value[1u]);
+}
+
+matrix<float16_t, 2, 3> tint_symbol_4(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 2, 3>(buffer.Load<vector<float16_t, 3> >((offset + 0u)), buffer.Load<vector<float16_t, 3> >((offset + 8u)));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_2(tint_symbol_1, 0u, tint_symbol_4(tint_symbol, 0u));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000020545EDA130(4,68-76): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000020545EDA130(5,3-14): error X3018: invalid subscript 'Store'
+
diff --git a/test/tint/buffer/storage/types/mat2x3_f16.wgsl.expected.glsl b/test/tint/buffer/storage/types/mat2x3_f16.wgsl.expected.glsl
new file mode 100644
index 0000000..6bed36f
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat2x3_f16.wgsl.expected.glsl
@@ -0,0 +1,20 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std430) buffer tint_symbol_block_ssbo {
+  f16mat2x3 inner;
+} tint_symbol;
+
+layout(binding = 1, std430) buffer tint_symbol_block_ssbo_1 {
+  f16mat2x3 inner;
+} tint_symbol_1;
+
+void tint_symbol_2() {
+  tint_symbol_1.inner = tint_symbol.inner;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol_2();
+  return;
+}
diff --git a/test/tint/buffer/storage/types/mat2x3_f16.wgsl.expected.msl b/test/tint/buffer/storage/types/mat2x3_f16.wgsl.expected.msl
new file mode 100644
index 0000000..81af92d
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat2x3_f16.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(device half2x3* tint_symbol_1 [[buffer(0)]], const device half2x3* tint_symbol_2 [[buffer(1)]]) {
+  *(tint_symbol_1) = *(tint_symbol_2);
+  return;
+}
+
diff --git a/test/tint/buffer/storage/types/mat2x3_f16.wgsl.expected.spvasm b/test/tint/buffer/storage/types/mat2x3_f16.wgsl.expected.spvasm
new file mode 100644
index 0000000..5ddb847
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat2x3_f16.wgsl.expected.spvasm
@@ -0,0 +1,47 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 18
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %in_block "in_block"
+               OpMemberName %in_block 0 "inner"
+               OpName %in "in"
+               OpName %out "out"
+               OpName %main "main"
+               OpDecorate %in_block Block
+               OpMemberDecorate %in_block 0 Offset 0
+               OpMemberDecorate %in_block 0 ColMajor
+               OpMemberDecorate %in_block 0 MatrixStride 8
+               OpDecorate %in NonWritable
+               OpDecorate %in DescriptorSet 0
+               OpDecorate %in Binding 0
+               OpDecorate %out DescriptorSet 0
+               OpDecorate %out Binding 1
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+ %mat2v3half = OpTypeMatrix %v3half 2
+   %in_block = OpTypeStruct %mat2v3half
+%_ptr_StorageBuffer_in_block = OpTypePointer StorageBuffer %in_block
+         %in = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+        %out = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+       %void = OpTypeVoid
+          %8 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_mat2v3half = OpTypePointer StorageBuffer %mat2v3half
+       %main = OpFunction %void None %8
+         %11 = OpLabel
+         %15 = OpAccessChain %_ptr_StorageBuffer_mat2v3half %out %uint_0
+         %16 = OpAccessChain %_ptr_StorageBuffer_mat2v3half %in %uint_0
+         %17 = OpLoad %mat2v3half %16
+               OpStore %15 %17
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/storage/types/mat2x3_f16.wgsl.expected.wgsl b/test/tint/buffer/storage/types/mat2x3_f16.wgsl.expected.wgsl
new file mode 100644
index 0000000..b60f8d1
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat2x3_f16.wgsl.expected.wgsl
@@ -0,0 +1,10 @@
+enable f16;
+
+@group(0) @binding(0) var<storage, read> in : mat2x3<f16>;
+
+@group(0) @binding(1) var<storage, read_write> out : mat2x3<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/mat2x3.wgsl b/test/tint/buffer/storage/types/mat2x3_f32.wgsl
similarity index 100%
rename from test/tint/buffer/storage/types/mat2x3.wgsl
rename to test/tint/buffer/storage/types/mat2x3_f32.wgsl
diff --git a/test/tint/buffer/storage/types/mat2x3.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/types/mat2x3_f32.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/storage/types/mat2x3.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/storage/types/mat2x3_f32.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/storage/types/mat2x3.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/types/mat2x3_f32.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/storage/types/mat2x3.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/storage/types/mat2x3_f32.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/storage/types/mat2x3.wgsl.expected.glsl b/test/tint/buffer/storage/types/mat2x3_f32.wgsl.expected.glsl
similarity index 100%
rename from test/tint/buffer/storage/types/mat2x3.wgsl.expected.glsl
rename to test/tint/buffer/storage/types/mat2x3_f32.wgsl.expected.glsl
diff --git a/test/tint/buffer/storage/types/mat2x3.wgsl.expected.msl b/test/tint/buffer/storage/types/mat2x3_f32.wgsl.expected.msl
similarity index 100%
rename from test/tint/buffer/storage/types/mat2x3.wgsl.expected.msl
rename to test/tint/buffer/storage/types/mat2x3_f32.wgsl.expected.msl
diff --git a/test/tint/buffer/storage/types/mat2x3.wgsl.expected.spvasm b/test/tint/buffer/storage/types/mat2x3_f32.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/storage/types/mat2x3.wgsl.expected.spvasm
rename to test/tint/buffer/storage/types/mat2x3_f32.wgsl.expected.spvasm
diff --git a/test/tint/buffer/storage/types/mat2x3.wgsl.expected.wgsl b/test/tint/buffer/storage/types/mat2x3_f32.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/buffer/storage/types/mat2x3.wgsl.expected.wgsl
rename to test/tint/buffer/storage/types/mat2x3_f32.wgsl.expected.wgsl
diff --git a/test/tint/buffer/storage/types/mat2x4_f16.wgsl b/test/tint/buffer/storage/types/mat2x4_f16.wgsl
new file mode 100644
index 0000000..75b62f4
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat2x4_f16.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0)
+var<storage, read> in : mat2x4<f16>;
+
+@group(0) @binding(1)
+var<storage, read_write> out : mat2x4<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/mat2x4_f16.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/types/mat2x4_f16.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..ac4058f
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat2x4_f16.wgsl.expected.dxc.hlsl
@@ -0,0 +1,17 @@
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+void tint_symbol_2(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 2, 4> value) {
+  buffer.Store<vector<float16_t, 4> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 8u), value[1u]);
+}
+
+matrix<float16_t, 2, 4> tint_symbol_4(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 2, 4>(buffer.Load<vector<float16_t, 4> >((offset + 0u)), buffer.Load<vector<float16_t, 4> >((offset + 8u)));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_2(tint_symbol_1, 0u, tint_symbol_4(tint_symbol, 0u));
+  return;
+}
diff --git a/test/tint/buffer/storage/types/mat2x4_f16.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/types/mat2x4_f16.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..d823c51
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat2x4_f16.wgsl.expected.fxc.hlsl
@@ -0,0 +1,23 @@
+SKIP: FAILED
+
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+void tint_symbol_2(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 2, 4> value) {
+  buffer.Store<vector<float16_t, 4> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 8u), value[1u]);
+}
+
+matrix<float16_t, 2, 4> tint_symbol_4(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 2, 4>(buffer.Load<vector<float16_t, 4> >((offset + 0u)), buffer.Load<vector<float16_t, 4> >((offset + 8u)));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_2(tint_symbol_1, 0u, tint_symbol_4(tint_symbol, 0u));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001A3CD399A80(4,68-76): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001A3CD399A80(5,3-14): error X3018: invalid subscript 'Store'
+
diff --git a/test/tint/buffer/storage/types/mat2x4_f16.wgsl.expected.glsl b/test/tint/buffer/storage/types/mat2x4_f16.wgsl.expected.glsl
new file mode 100644
index 0000000..47b484c
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat2x4_f16.wgsl.expected.glsl
@@ -0,0 +1,20 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std430) buffer tint_symbol_block_ssbo {
+  f16mat2x4 inner;
+} tint_symbol;
+
+layout(binding = 1, std430) buffer tint_symbol_block_ssbo_1 {
+  f16mat2x4 inner;
+} tint_symbol_1;
+
+void tint_symbol_2() {
+  tint_symbol_1.inner = tint_symbol.inner;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol_2();
+  return;
+}
diff --git a/test/tint/buffer/storage/types/mat2x4_f16.wgsl.expected.msl b/test/tint/buffer/storage/types/mat2x4_f16.wgsl.expected.msl
new file mode 100644
index 0000000..7901bcb
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat2x4_f16.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(device half2x4* tint_symbol_1 [[buffer(0)]], const device half2x4* tint_symbol_2 [[buffer(1)]]) {
+  *(tint_symbol_1) = *(tint_symbol_2);
+  return;
+}
+
diff --git a/test/tint/buffer/storage/types/mat2x4_f16.wgsl.expected.spvasm b/test/tint/buffer/storage/types/mat2x4_f16.wgsl.expected.spvasm
new file mode 100644
index 0000000..529e93f
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat2x4_f16.wgsl.expected.spvasm
@@ -0,0 +1,47 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 18
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %in_block "in_block"
+               OpMemberName %in_block 0 "inner"
+               OpName %in "in"
+               OpName %out "out"
+               OpName %main "main"
+               OpDecorate %in_block Block
+               OpMemberDecorate %in_block 0 Offset 0
+               OpMemberDecorate %in_block 0 ColMajor
+               OpMemberDecorate %in_block 0 MatrixStride 8
+               OpDecorate %in NonWritable
+               OpDecorate %in DescriptorSet 0
+               OpDecorate %in Binding 0
+               OpDecorate %out DescriptorSet 0
+               OpDecorate %out Binding 1
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+ %mat2v4half = OpTypeMatrix %v4half 2
+   %in_block = OpTypeStruct %mat2v4half
+%_ptr_StorageBuffer_in_block = OpTypePointer StorageBuffer %in_block
+         %in = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+        %out = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+       %void = OpTypeVoid
+          %8 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_mat2v4half = OpTypePointer StorageBuffer %mat2v4half
+       %main = OpFunction %void None %8
+         %11 = OpLabel
+         %15 = OpAccessChain %_ptr_StorageBuffer_mat2v4half %out %uint_0
+         %16 = OpAccessChain %_ptr_StorageBuffer_mat2v4half %in %uint_0
+         %17 = OpLoad %mat2v4half %16
+               OpStore %15 %17
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/storage/types/mat2x4_f16.wgsl.expected.wgsl b/test/tint/buffer/storage/types/mat2x4_f16.wgsl.expected.wgsl
new file mode 100644
index 0000000..29a329e
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat2x4_f16.wgsl.expected.wgsl
@@ -0,0 +1,10 @@
+enable f16;
+
+@group(0) @binding(0) var<storage, read> in : mat2x4<f16>;
+
+@group(0) @binding(1) var<storage, read_write> out : mat2x4<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/mat2x4_f32.wgsl b/test/tint/buffer/storage/types/mat2x4_f32.wgsl
new file mode 100644
index 0000000..148be1a
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat2x4_f32.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0)
+var<storage, read> in : mat2x4<f32>;
+
+@group(0) @binding(1)
+var<storage, read_write> out : mat2x4<f32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/mat2x4_f32.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/types/mat2x4_f32.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..2776e89
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat2x4_f32.wgsl.expected.dxc.hlsl
@@ -0,0 +1,17 @@
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+void tint_symbol_2(RWByteAddressBuffer buffer, uint offset, float2x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+}
+
+float2x4 tint_symbol_4(ByteAddressBuffer buffer, uint offset) {
+  return float2x4(asfloat(buffer.Load4((offset + 0u))), asfloat(buffer.Load4((offset + 16u))));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_2(tint_symbol_1, 0u, tint_symbol_4(tint_symbol, 0u));
+  return;
+}
diff --git a/test/tint/buffer/storage/types/mat2x4_f32.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/types/mat2x4_f32.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..2776e89
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat2x4_f32.wgsl.expected.fxc.hlsl
@@ -0,0 +1,17 @@
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+void tint_symbol_2(RWByteAddressBuffer buffer, uint offset, float2x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+}
+
+float2x4 tint_symbol_4(ByteAddressBuffer buffer, uint offset) {
+  return float2x4(asfloat(buffer.Load4((offset + 0u))), asfloat(buffer.Load4((offset + 16u))));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_2(tint_symbol_1, 0u, tint_symbol_4(tint_symbol, 0u));
+  return;
+}
diff --git a/test/tint/buffer/storage/types/mat2x4_f32.wgsl.expected.glsl b/test/tint/buffer/storage/types/mat2x4_f32.wgsl.expected.glsl
new file mode 100644
index 0000000..d1da44b
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat2x4_f32.wgsl.expected.glsl
@@ -0,0 +1,19 @@
+#version 310 es
+
+layout(binding = 0, std430) buffer tint_symbol_block_ssbo {
+  mat2x4 inner;
+} tint_symbol;
+
+layout(binding = 1, std430) buffer tint_symbol_block_ssbo_1 {
+  mat2x4 inner;
+} tint_symbol_1;
+
+void tint_symbol_2() {
+  tint_symbol_1.inner = tint_symbol.inner;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol_2();
+  return;
+}
diff --git a/test/tint/buffer/storage/types/mat2x4_f32.wgsl.expected.msl b/test/tint/buffer/storage/types/mat2x4_f32.wgsl.expected.msl
new file mode 100644
index 0000000..4672889
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat2x4_f32.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(device float2x4* tint_symbol_1 [[buffer(0)]], const device float2x4* tint_symbol_2 [[buffer(1)]]) {
+  *(tint_symbol_1) = *(tint_symbol_2);
+  return;
+}
+
diff --git a/test/tint/buffer/storage/types/mat2x4_f32.wgsl.expected.spvasm b/test/tint/buffer/storage/types/mat2x4_f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..be3b863
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat2x4_f32.wgsl.expected.spvasm
@@ -0,0 +1,43 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 18
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %in_block "in_block"
+               OpMemberName %in_block 0 "inner"
+               OpName %in "in"
+               OpName %out "out"
+               OpName %main "main"
+               OpDecorate %in_block Block
+               OpMemberDecorate %in_block 0 Offset 0
+               OpMemberDecorate %in_block 0 ColMajor
+               OpMemberDecorate %in_block 0 MatrixStride 16
+               OpDecorate %in NonWritable
+               OpDecorate %in DescriptorSet 0
+               OpDecorate %in Binding 0
+               OpDecorate %out DescriptorSet 0
+               OpDecorate %out Binding 1
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat2v4float = OpTypeMatrix %v4float 2
+   %in_block = OpTypeStruct %mat2v4float
+%_ptr_StorageBuffer_in_block = OpTypePointer StorageBuffer %in_block
+         %in = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+        %out = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+       %void = OpTypeVoid
+          %8 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_mat2v4float = OpTypePointer StorageBuffer %mat2v4float
+       %main = OpFunction %void None %8
+         %11 = OpLabel
+         %15 = OpAccessChain %_ptr_StorageBuffer_mat2v4float %out %uint_0
+         %16 = OpAccessChain %_ptr_StorageBuffer_mat2v4float %in %uint_0
+         %17 = OpLoad %mat2v4float %16
+               OpStore %15 %17
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/storage/types/mat2x4_f32.wgsl.expected.wgsl b/test/tint/buffer/storage/types/mat2x4_f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..2a476a7
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat2x4_f32.wgsl.expected.wgsl
@@ -0,0 +1,8 @@
+@group(0) @binding(0) var<storage, read> in : mat2x4<f32>;
+
+@group(0) @binding(1) var<storage, read_write> out : mat2x4<f32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/mat3x2_f16.wgsl b/test/tint/buffer/storage/types/mat3x2_f16.wgsl
new file mode 100644
index 0000000..1274f1d
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat3x2_f16.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0)
+var<storage, read> in : mat3x2<f16>;
+
+@group(0) @binding(1)
+var<storage, read_write> out : mat3x2<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/mat3x2_f16.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/types/mat3x2_f16.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..f5984ae
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat3x2_f16.wgsl.expected.dxc.hlsl
@@ -0,0 +1,18 @@
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+void tint_symbol_2(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 3, 2> value) {
+  buffer.Store<vector<float16_t, 2> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 4u), value[1u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 8u), value[2u]);
+}
+
+matrix<float16_t, 3, 2> tint_symbol_4(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 3, 2>(buffer.Load<vector<float16_t, 2> >((offset + 0u)), buffer.Load<vector<float16_t, 2> >((offset + 4u)), buffer.Load<vector<float16_t, 2> >((offset + 8u)));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_2(tint_symbol_1, 0u, tint_symbol_4(tint_symbol, 0u));
+  return;
+}
diff --git a/test/tint/buffer/storage/types/mat3x2_f16.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/types/mat3x2_f16.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..b48f684
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat3x2_f16.wgsl.expected.fxc.hlsl
@@ -0,0 +1,24 @@
+SKIP: FAILED
+
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+void tint_symbol_2(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 3, 2> value) {
+  buffer.Store<vector<float16_t, 2> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 4u), value[1u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 8u), value[2u]);
+}
+
+matrix<float16_t, 3, 2> tint_symbol_4(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 3, 2>(buffer.Load<vector<float16_t, 2> >((offset + 0u)), buffer.Load<vector<float16_t, 2> >((offset + 4u)), buffer.Load<vector<float16_t, 2> >((offset + 8u)));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_2(tint_symbol_1, 0u, tint_symbol_4(tint_symbol, 0u));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001A3687DC740(4,68-76): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001A3687DC740(5,3-14): error X3018: invalid subscript 'Store'
+
diff --git a/test/tint/buffer/storage/types/mat3x2_f16.wgsl.expected.glsl b/test/tint/buffer/storage/types/mat3x2_f16.wgsl.expected.glsl
new file mode 100644
index 0000000..e48dbc4
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat3x2_f16.wgsl.expected.glsl
@@ -0,0 +1,20 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std430) buffer tint_symbol_block_ssbo {
+  f16mat3x2 inner;
+} tint_symbol;
+
+layout(binding = 1, std430) buffer tint_symbol_block_ssbo_1 {
+  f16mat3x2 inner;
+} tint_symbol_1;
+
+void tint_symbol_2() {
+  tint_symbol_1.inner = tint_symbol.inner;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol_2();
+  return;
+}
diff --git a/test/tint/buffer/storage/types/mat3x2_f16.wgsl.expected.msl b/test/tint/buffer/storage/types/mat3x2_f16.wgsl.expected.msl
new file mode 100644
index 0000000..c71e0e4
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat3x2_f16.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(device half3x2* tint_symbol_1 [[buffer(0)]], const device half3x2* tint_symbol_2 [[buffer(1)]]) {
+  *(tint_symbol_1) = *(tint_symbol_2);
+  return;
+}
+
diff --git a/test/tint/buffer/storage/types/mat3x2_f16.wgsl.expected.spvasm b/test/tint/buffer/storage/types/mat3x2_f16.wgsl.expected.spvasm
new file mode 100644
index 0000000..f39c243
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat3x2_f16.wgsl.expected.spvasm
@@ -0,0 +1,47 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 18
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %in_block "in_block"
+               OpMemberName %in_block 0 "inner"
+               OpName %in "in"
+               OpName %out "out"
+               OpName %main "main"
+               OpDecorate %in_block Block
+               OpMemberDecorate %in_block 0 Offset 0
+               OpMemberDecorate %in_block 0 ColMajor
+               OpMemberDecorate %in_block 0 MatrixStride 4
+               OpDecorate %in NonWritable
+               OpDecorate %in DescriptorSet 0
+               OpDecorate %in Binding 0
+               OpDecorate %out DescriptorSet 0
+               OpDecorate %out Binding 1
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+ %mat3v2half = OpTypeMatrix %v2half 3
+   %in_block = OpTypeStruct %mat3v2half
+%_ptr_StorageBuffer_in_block = OpTypePointer StorageBuffer %in_block
+         %in = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+        %out = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+       %void = OpTypeVoid
+          %8 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_mat3v2half = OpTypePointer StorageBuffer %mat3v2half
+       %main = OpFunction %void None %8
+         %11 = OpLabel
+         %15 = OpAccessChain %_ptr_StorageBuffer_mat3v2half %out %uint_0
+         %16 = OpAccessChain %_ptr_StorageBuffer_mat3v2half %in %uint_0
+         %17 = OpLoad %mat3v2half %16
+               OpStore %15 %17
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/storage/types/mat3x2_f16.wgsl.expected.wgsl b/test/tint/buffer/storage/types/mat3x2_f16.wgsl.expected.wgsl
new file mode 100644
index 0000000..d50b848
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat3x2_f16.wgsl.expected.wgsl
@@ -0,0 +1,10 @@
+enable f16;
+
+@group(0) @binding(0) var<storage, read> in : mat3x2<f16>;
+
+@group(0) @binding(1) var<storage, read_write> out : mat3x2<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/mat3x2.wgsl b/test/tint/buffer/storage/types/mat3x2_f32.wgsl
similarity index 100%
rename from test/tint/buffer/storage/types/mat3x2.wgsl
rename to test/tint/buffer/storage/types/mat3x2_f32.wgsl
diff --git a/test/tint/buffer/storage/types/mat3x2.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/types/mat3x2_f32.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/storage/types/mat3x2.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/storage/types/mat3x2_f32.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/storage/types/mat3x2.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/types/mat3x2_f32.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/storage/types/mat3x2.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/storage/types/mat3x2_f32.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/storage/types/mat3x2.wgsl.expected.glsl b/test/tint/buffer/storage/types/mat3x2_f32.wgsl.expected.glsl
similarity index 100%
rename from test/tint/buffer/storage/types/mat3x2.wgsl.expected.glsl
rename to test/tint/buffer/storage/types/mat3x2_f32.wgsl.expected.glsl
diff --git a/test/tint/buffer/storage/types/mat3x2.wgsl.expected.msl b/test/tint/buffer/storage/types/mat3x2_f32.wgsl.expected.msl
similarity index 100%
rename from test/tint/buffer/storage/types/mat3x2.wgsl.expected.msl
rename to test/tint/buffer/storage/types/mat3x2_f32.wgsl.expected.msl
diff --git a/test/tint/buffer/storage/types/mat3x2.wgsl.expected.spvasm b/test/tint/buffer/storage/types/mat3x2_f32.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/storage/types/mat3x2.wgsl.expected.spvasm
rename to test/tint/buffer/storage/types/mat3x2_f32.wgsl.expected.spvasm
diff --git a/test/tint/buffer/storage/types/mat3x2.wgsl.expected.wgsl b/test/tint/buffer/storage/types/mat3x2_f32.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/buffer/storage/types/mat3x2.wgsl.expected.wgsl
rename to test/tint/buffer/storage/types/mat3x2_f32.wgsl.expected.wgsl
diff --git a/test/tint/buffer/storage/types/mat3x3_f16.wgsl b/test/tint/buffer/storage/types/mat3x3_f16.wgsl
new file mode 100644
index 0000000..4b961bd
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat3x3_f16.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0)
+var<storage, read> in : mat3x3<f16>;
+
+@group(0) @binding(1)
+var<storage, read_write> out : mat3x3<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/mat3x3_f16.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/types/mat3x3_f16.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..01aa7ad
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat3x3_f16.wgsl.expected.dxc.hlsl
@@ -0,0 +1,18 @@
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+void tint_symbol_2(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 3, 3> value) {
+  buffer.Store<vector<float16_t, 3> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 8u), value[1u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 16u), value[2u]);
+}
+
+matrix<float16_t, 3, 3> tint_symbol_4(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 3, 3>(buffer.Load<vector<float16_t, 3> >((offset + 0u)), buffer.Load<vector<float16_t, 3> >((offset + 8u)), buffer.Load<vector<float16_t, 3> >((offset + 16u)));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_2(tint_symbol_1, 0u, tint_symbol_4(tint_symbol, 0u));
+  return;
+}
diff --git a/test/tint/buffer/storage/types/mat3x3_f16.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/types/mat3x3_f16.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..a5d9c58
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat3x3_f16.wgsl.expected.fxc.hlsl
@@ -0,0 +1,24 @@
+SKIP: FAILED
+
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+void tint_symbol_2(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 3, 3> value) {
+  buffer.Store<vector<float16_t, 3> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 8u), value[1u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 16u), value[2u]);
+}
+
+matrix<float16_t, 3, 3> tint_symbol_4(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 3, 3>(buffer.Load<vector<float16_t, 3> >((offset + 0u)), buffer.Load<vector<float16_t, 3> >((offset + 8u)), buffer.Load<vector<float16_t, 3> >((offset + 16u)));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_2(tint_symbol_1, 0u, tint_symbol_4(tint_symbol, 0u));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000002722B6D74E0(4,68-76): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000002722B6D74E0(5,3-14): error X3018: invalid subscript 'Store'
+
diff --git a/test/tint/buffer/storage/types/mat3x3_f16.wgsl.expected.glsl b/test/tint/buffer/storage/types/mat3x3_f16.wgsl.expected.glsl
new file mode 100644
index 0000000..00509e6
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat3x3_f16.wgsl.expected.glsl
@@ -0,0 +1,20 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std430) buffer tint_symbol_block_ssbo {
+  f16mat3 inner;
+} tint_symbol;
+
+layout(binding = 1, std430) buffer tint_symbol_block_ssbo_1 {
+  f16mat3 inner;
+} tint_symbol_1;
+
+void tint_symbol_2() {
+  tint_symbol_1.inner = tint_symbol.inner;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol_2();
+  return;
+}
diff --git a/test/tint/buffer/storage/types/mat3x3_f16.wgsl.expected.msl b/test/tint/buffer/storage/types/mat3x3_f16.wgsl.expected.msl
new file mode 100644
index 0000000..e22bd15
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat3x3_f16.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(device half3x3* tint_symbol_1 [[buffer(0)]], const device half3x3* tint_symbol_2 [[buffer(1)]]) {
+  *(tint_symbol_1) = *(tint_symbol_2);
+  return;
+}
+
diff --git a/test/tint/buffer/storage/types/mat3x3_f16.wgsl.expected.spvasm b/test/tint/buffer/storage/types/mat3x3_f16.wgsl.expected.spvasm
new file mode 100644
index 0000000..ad8eff5
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat3x3_f16.wgsl.expected.spvasm
@@ -0,0 +1,47 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 18
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %in_block "in_block"
+               OpMemberName %in_block 0 "inner"
+               OpName %in "in"
+               OpName %out "out"
+               OpName %main "main"
+               OpDecorate %in_block Block
+               OpMemberDecorate %in_block 0 Offset 0
+               OpMemberDecorate %in_block 0 ColMajor
+               OpMemberDecorate %in_block 0 MatrixStride 8
+               OpDecorate %in NonWritable
+               OpDecorate %in DescriptorSet 0
+               OpDecorate %in Binding 0
+               OpDecorate %out DescriptorSet 0
+               OpDecorate %out Binding 1
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+ %mat3v3half = OpTypeMatrix %v3half 3
+   %in_block = OpTypeStruct %mat3v3half
+%_ptr_StorageBuffer_in_block = OpTypePointer StorageBuffer %in_block
+         %in = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+        %out = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+       %void = OpTypeVoid
+          %8 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_mat3v3half = OpTypePointer StorageBuffer %mat3v3half
+       %main = OpFunction %void None %8
+         %11 = OpLabel
+         %15 = OpAccessChain %_ptr_StorageBuffer_mat3v3half %out %uint_0
+         %16 = OpAccessChain %_ptr_StorageBuffer_mat3v3half %in %uint_0
+         %17 = OpLoad %mat3v3half %16
+               OpStore %15 %17
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/storage/types/mat3x3_f16.wgsl.expected.wgsl b/test/tint/buffer/storage/types/mat3x3_f16.wgsl.expected.wgsl
new file mode 100644
index 0000000..acb6b84
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat3x3_f16.wgsl.expected.wgsl
@@ -0,0 +1,10 @@
+enable f16;
+
+@group(0) @binding(0) var<storage, read> in : mat3x3<f16>;
+
+@group(0) @binding(1) var<storage, read_write> out : mat3x3<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/mat3x3_f32.wgsl b/test/tint/buffer/storage/types/mat3x3_f32.wgsl
new file mode 100644
index 0000000..e5ae1a5
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat3x3_f32.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0)
+var<storage, read> in : mat3x3<f32>;
+
+@group(0) @binding(1)
+var<storage, read_write> out : mat3x3<f32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/mat3x3_f32.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/types/mat3x3_f32.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..086d35a
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat3x3_f32.wgsl.expected.dxc.hlsl
@@ -0,0 +1,18 @@
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+void tint_symbol_2(RWByteAddressBuffer buffer, uint offset, float3x3 value) {
+  buffer.Store3((offset + 0u), asuint(value[0u]));
+  buffer.Store3((offset + 16u), asuint(value[1u]));
+  buffer.Store3((offset + 32u), asuint(value[2u]));
+}
+
+float3x3 tint_symbol_4(ByteAddressBuffer buffer, uint offset) {
+  return float3x3(asfloat(buffer.Load3((offset + 0u))), asfloat(buffer.Load3((offset + 16u))), asfloat(buffer.Load3((offset + 32u))));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_2(tint_symbol_1, 0u, tint_symbol_4(tint_symbol, 0u));
+  return;
+}
diff --git a/test/tint/buffer/storage/types/mat3x3_f32.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/types/mat3x3_f32.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..086d35a
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat3x3_f32.wgsl.expected.fxc.hlsl
@@ -0,0 +1,18 @@
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+void tint_symbol_2(RWByteAddressBuffer buffer, uint offset, float3x3 value) {
+  buffer.Store3((offset + 0u), asuint(value[0u]));
+  buffer.Store3((offset + 16u), asuint(value[1u]));
+  buffer.Store3((offset + 32u), asuint(value[2u]));
+}
+
+float3x3 tint_symbol_4(ByteAddressBuffer buffer, uint offset) {
+  return float3x3(asfloat(buffer.Load3((offset + 0u))), asfloat(buffer.Load3((offset + 16u))), asfloat(buffer.Load3((offset + 32u))));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_2(tint_symbol_1, 0u, tint_symbol_4(tint_symbol, 0u));
+  return;
+}
diff --git a/test/tint/buffer/storage/types/mat3x3_f32.wgsl.expected.glsl b/test/tint/buffer/storage/types/mat3x3_f32.wgsl.expected.glsl
new file mode 100644
index 0000000..b6e12e5
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat3x3_f32.wgsl.expected.glsl
@@ -0,0 +1,19 @@
+#version 310 es
+
+layout(binding = 0, std430) buffer tint_symbol_block_ssbo {
+  mat3 inner;
+} tint_symbol;
+
+layout(binding = 1, std430) buffer tint_symbol_block_ssbo_1 {
+  mat3 inner;
+} tint_symbol_1;
+
+void tint_symbol_2() {
+  tint_symbol_1.inner = tint_symbol.inner;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol_2();
+  return;
+}
diff --git a/test/tint/buffer/storage/types/mat3x3_f32.wgsl.expected.msl b/test/tint/buffer/storage/types/mat3x3_f32.wgsl.expected.msl
new file mode 100644
index 0000000..c8db576
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat3x3_f32.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(device float3x3* tint_symbol_1 [[buffer(0)]], const device float3x3* tint_symbol_2 [[buffer(1)]]) {
+  *(tint_symbol_1) = *(tint_symbol_2);
+  return;
+}
+
diff --git a/test/tint/buffer/storage/types/mat3x3_f32.wgsl.expected.spvasm b/test/tint/buffer/storage/types/mat3x3_f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..278850e
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat3x3_f32.wgsl.expected.spvasm
@@ -0,0 +1,43 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 18
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %in_block "in_block"
+               OpMemberName %in_block 0 "inner"
+               OpName %in "in"
+               OpName %out "out"
+               OpName %main "main"
+               OpDecorate %in_block Block
+               OpMemberDecorate %in_block 0 Offset 0
+               OpMemberDecorate %in_block 0 ColMajor
+               OpMemberDecorate %in_block 0 MatrixStride 16
+               OpDecorate %in NonWritable
+               OpDecorate %in DescriptorSet 0
+               OpDecorate %in Binding 0
+               OpDecorate %out DescriptorSet 0
+               OpDecorate %out Binding 1
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+   %in_block = OpTypeStruct %mat3v3float
+%_ptr_StorageBuffer_in_block = OpTypePointer StorageBuffer %in_block
+         %in = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+        %out = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+       %void = OpTypeVoid
+          %8 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_mat3v3float = OpTypePointer StorageBuffer %mat3v3float
+       %main = OpFunction %void None %8
+         %11 = OpLabel
+         %15 = OpAccessChain %_ptr_StorageBuffer_mat3v3float %out %uint_0
+         %16 = OpAccessChain %_ptr_StorageBuffer_mat3v3float %in %uint_0
+         %17 = OpLoad %mat3v3float %16
+               OpStore %15 %17
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/storage/types/mat3x3_f32.wgsl.expected.wgsl b/test/tint/buffer/storage/types/mat3x3_f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..eec45bd
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat3x3_f32.wgsl.expected.wgsl
@@ -0,0 +1,8 @@
+@group(0) @binding(0) var<storage, read> in : mat3x3<f32>;
+
+@group(0) @binding(1) var<storage, read_write> out : mat3x3<f32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/mat3x4_f16.wgsl b/test/tint/buffer/storage/types/mat3x4_f16.wgsl
new file mode 100644
index 0000000..3dea88d
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat3x4_f16.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0)
+var<storage, read> in : mat3x4<f16>;
+
+@group(0) @binding(1)
+var<storage, read_write> out : mat3x4<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/mat3x4_f16.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/types/mat3x4_f16.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..c788def
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat3x4_f16.wgsl.expected.dxc.hlsl
@@ -0,0 +1,18 @@
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+void tint_symbol_2(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 3, 4> value) {
+  buffer.Store<vector<float16_t, 4> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 8u), value[1u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 16u), value[2u]);
+}
+
+matrix<float16_t, 3, 4> tint_symbol_4(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 3, 4>(buffer.Load<vector<float16_t, 4> >((offset + 0u)), buffer.Load<vector<float16_t, 4> >((offset + 8u)), buffer.Load<vector<float16_t, 4> >((offset + 16u)));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_2(tint_symbol_1, 0u, tint_symbol_4(tint_symbol, 0u));
+  return;
+}
diff --git a/test/tint/buffer/storage/types/mat3x4_f16.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/types/mat3x4_f16.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..56c3651
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat3x4_f16.wgsl.expected.fxc.hlsl
@@ -0,0 +1,24 @@
+SKIP: FAILED
+
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+void tint_symbol_2(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 3, 4> value) {
+  buffer.Store<vector<float16_t, 4> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 8u), value[1u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 16u), value[2u]);
+}
+
+matrix<float16_t, 3, 4> tint_symbol_4(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 3, 4>(buffer.Load<vector<float16_t, 4> >((offset + 0u)), buffer.Load<vector<float16_t, 4> >((offset + 8u)), buffer.Load<vector<float16_t, 4> >((offset + 16u)));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_2(tint_symbol_1, 0u, tint_symbol_4(tint_symbol, 0u));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001F969F77390(4,68-76): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001F969F77390(5,3-14): error X3018: invalid subscript 'Store'
+
diff --git a/test/tint/buffer/storage/types/mat3x4_f16.wgsl.expected.glsl b/test/tint/buffer/storage/types/mat3x4_f16.wgsl.expected.glsl
new file mode 100644
index 0000000..a09091a
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat3x4_f16.wgsl.expected.glsl
@@ -0,0 +1,20 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std430) buffer tint_symbol_block_ssbo {
+  f16mat3x4 inner;
+} tint_symbol;
+
+layout(binding = 1, std430) buffer tint_symbol_block_ssbo_1 {
+  f16mat3x4 inner;
+} tint_symbol_1;
+
+void tint_symbol_2() {
+  tint_symbol_1.inner = tint_symbol.inner;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol_2();
+  return;
+}
diff --git a/test/tint/buffer/storage/types/mat3x4_f16.wgsl.expected.msl b/test/tint/buffer/storage/types/mat3x4_f16.wgsl.expected.msl
new file mode 100644
index 0000000..0668084
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat3x4_f16.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(device half3x4* tint_symbol_1 [[buffer(0)]], const device half3x4* tint_symbol_2 [[buffer(1)]]) {
+  *(tint_symbol_1) = *(tint_symbol_2);
+  return;
+}
+
diff --git a/test/tint/buffer/storage/types/mat3x4_f16.wgsl.expected.spvasm b/test/tint/buffer/storage/types/mat3x4_f16.wgsl.expected.spvasm
new file mode 100644
index 0000000..50d9234
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat3x4_f16.wgsl.expected.spvasm
@@ -0,0 +1,47 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 18
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %in_block "in_block"
+               OpMemberName %in_block 0 "inner"
+               OpName %in "in"
+               OpName %out "out"
+               OpName %main "main"
+               OpDecorate %in_block Block
+               OpMemberDecorate %in_block 0 Offset 0
+               OpMemberDecorate %in_block 0 ColMajor
+               OpMemberDecorate %in_block 0 MatrixStride 8
+               OpDecorate %in NonWritable
+               OpDecorate %in DescriptorSet 0
+               OpDecorate %in Binding 0
+               OpDecorate %out DescriptorSet 0
+               OpDecorate %out Binding 1
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+ %mat3v4half = OpTypeMatrix %v4half 3
+   %in_block = OpTypeStruct %mat3v4half
+%_ptr_StorageBuffer_in_block = OpTypePointer StorageBuffer %in_block
+         %in = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+        %out = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+       %void = OpTypeVoid
+          %8 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_mat3v4half = OpTypePointer StorageBuffer %mat3v4half
+       %main = OpFunction %void None %8
+         %11 = OpLabel
+         %15 = OpAccessChain %_ptr_StorageBuffer_mat3v4half %out %uint_0
+         %16 = OpAccessChain %_ptr_StorageBuffer_mat3v4half %in %uint_0
+         %17 = OpLoad %mat3v4half %16
+               OpStore %15 %17
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/storage/types/mat3x4_f16.wgsl.expected.wgsl b/test/tint/buffer/storage/types/mat3x4_f16.wgsl.expected.wgsl
new file mode 100644
index 0000000..44b9a64
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat3x4_f16.wgsl.expected.wgsl
@@ -0,0 +1,10 @@
+enable f16;
+
+@group(0) @binding(0) var<storage, read> in : mat3x4<f16>;
+
+@group(0) @binding(1) var<storage, read_write> out : mat3x4<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/mat3x4_f32.wgsl b/test/tint/buffer/storage/types/mat3x4_f32.wgsl
new file mode 100644
index 0000000..3ee71ee
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat3x4_f32.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0)
+var<storage, read> in : mat3x4<f32>;
+
+@group(0) @binding(1)
+var<storage, read_write> out : mat3x4<f32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/mat3x4_f32.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/types/mat3x4_f32.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..2d8f11b
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat3x4_f32.wgsl.expected.dxc.hlsl
@@ -0,0 +1,18 @@
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+void tint_symbol_2(RWByteAddressBuffer buffer, uint offset, float3x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+  buffer.Store4((offset + 32u), asuint(value[2u]));
+}
+
+float3x4 tint_symbol_4(ByteAddressBuffer buffer, uint offset) {
+  return float3x4(asfloat(buffer.Load4((offset + 0u))), asfloat(buffer.Load4((offset + 16u))), asfloat(buffer.Load4((offset + 32u))));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_2(tint_symbol_1, 0u, tint_symbol_4(tint_symbol, 0u));
+  return;
+}
diff --git a/test/tint/buffer/storage/types/mat3x4_f32.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/types/mat3x4_f32.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..2d8f11b
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat3x4_f32.wgsl.expected.fxc.hlsl
@@ -0,0 +1,18 @@
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+void tint_symbol_2(RWByteAddressBuffer buffer, uint offset, float3x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+  buffer.Store4((offset + 32u), asuint(value[2u]));
+}
+
+float3x4 tint_symbol_4(ByteAddressBuffer buffer, uint offset) {
+  return float3x4(asfloat(buffer.Load4((offset + 0u))), asfloat(buffer.Load4((offset + 16u))), asfloat(buffer.Load4((offset + 32u))));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_2(tint_symbol_1, 0u, tint_symbol_4(tint_symbol, 0u));
+  return;
+}
diff --git a/test/tint/buffer/storage/types/mat3x4_f32.wgsl.expected.glsl b/test/tint/buffer/storage/types/mat3x4_f32.wgsl.expected.glsl
new file mode 100644
index 0000000..a32c3e0
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat3x4_f32.wgsl.expected.glsl
@@ -0,0 +1,19 @@
+#version 310 es
+
+layout(binding = 0, std430) buffer tint_symbol_block_ssbo {
+  mat3x4 inner;
+} tint_symbol;
+
+layout(binding = 1, std430) buffer tint_symbol_block_ssbo_1 {
+  mat3x4 inner;
+} tint_symbol_1;
+
+void tint_symbol_2() {
+  tint_symbol_1.inner = tint_symbol.inner;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol_2();
+  return;
+}
diff --git a/test/tint/buffer/storage/types/mat3x4_f32.wgsl.expected.msl b/test/tint/buffer/storage/types/mat3x4_f32.wgsl.expected.msl
new file mode 100644
index 0000000..d6dbe7f
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat3x4_f32.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(device float3x4* tint_symbol_1 [[buffer(0)]], const device float3x4* tint_symbol_2 [[buffer(1)]]) {
+  *(tint_symbol_1) = *(tint_symbol_2);
+  return;
+}
+
diff --git a/test/tint/buffer/storage/types/mat3x4_f32.wgsl.expected.spvasm b/test/tint/buffer/storage/types/mat3x4_f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..9f0d97c
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat3x4_f32.wgsl.expected.spvasm
@@ -0,0 +1,43 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 18
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %in_block "in_block"
+               OpMemberName %in_block 0 "inner"
+               OpName %in "in"
+               OpName %out "out"
+               OpName %main "main"
+               OpDecorate %in_block Block
+               OpMemberDecorate %in_block 0 Offset 0
+               OpMemberDecorate %in_block 0 ColMajor
+               OpMemberDecorate %in_block 0 MatrixStride 16
+               OpDecorate %in NonWritable
+               OpDecorate %in DescriptorSet 0
+               OpDecorate %in Binding 0
+               OpDecorate %out DescriptorSet 0
+               OpDecorate %out Binding 1
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat3v4float = OpTypeMatrix %v4float 3
+   %in_block = OpTypeStruct %mat3v4float
+%_ptr_StorageBuffer_in_block = OpTypePointer StorageBuffer %in_block
+         %in = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+        %out = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+       %void = OpTypeVoid
+          %8 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_mat3v4float = OpTypePointer StorageBuffer %mat3v4float
+       %main = OpFunction %void None %8
+         %11 = OpLabel
+         %15 = OpAccessChain %_ptr_StorageBuffer_mat3v4float %out %uint_0
+         %16 = OpAccessChain %_ptr_StorageBuffer_mat3v4float %in %uint_0
+         %17 = OpLoad %mat3v4float %16
+               OpStore %15 %17
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/storage/types/mat3x4_f32.wgsl.expected.wgsl b/test/tint/buffer/storage/types/mat3x4_f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..f8b8e5c
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat3x4_f32.wgsl.expected.wgsl
@@ -0,0 +1,8 @@
+@group(0) @binding(0) var<storage, read> in : mat3x4<f32>;
+
+@group(0) @binding(1) var<storage, read_write> out : mat3x4<f32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/mat4x2_f16.wgsl b/test/tint/buffer/storage/types/mat4x2_f16.wgsl
new file mode 100644
index 0000000..b56cef8
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat4x2_f16.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0)
+var<storage, read> in : mat4x2<f16>;
+
+@group(0) @binding(1)
+var<storage, read_write> out : mat4x2<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/mat4x2_f16.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/types/mat4x2_f16.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..8dce844
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat4x2_f16.wgsl.expected.dxc.hlsl
@@ -0,0 +1,19 @@
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+void tint_symbol_2(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 2> value) {
+  buffer.Store<vector<float16_t, 2> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 4u), value[1u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 8u), value[2u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 12u), value[3u]);
+}
+
+matrix<float16_t, 4, 2> tint_symbol_4(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 4, 2>(buffer.Load<vector<float16_t, 2> >((offset + 0u)), buffer.Load<vector<float16_t, 2> >((offset + 4u)), buffer.Load<vector<float16_t, 2> >((offset + 8u)), buffer.Load<vector<float16_t, 2> >((offset + 12u)));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_2(tint_symbol_1, 0u, tint_symbol_4(tint_symbol, 0u));
+  return;
+}
diff --git a/test/tint/buffer/storage/types/mat4x2_f16.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/types/mat4x2_f16.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..c3aacd6
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat4x2_f16.wgsl.expected.fxc.hlsl
@@ -0,0 +1,25 @@
+SKIP: FAILED
+
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+void tint_symbol_2(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 2> value) {
+  buffer.Store<vector<float16_t, 2> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 4u), value[1u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 8u), value[2u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 12u), value[3u]);
+}
+
+matrix<float16_t, 4, 2> tint_symbol_4(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 4, 2>(buffer.Load<vector<float16_t, 2> >((offset + 0u)), buffer.Load<vector<float16_t, 2> >((offset + 4u)), buffer.Load<vector<float16_t, 2> >((offset + 8u)), buffer.Load<vector<float16_t, 2> >((offset + 12u)));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_2(tint_symbol_1, 0u, tint_symbol_4(tint_symbol, 0u));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001A0195E7740(4,68-76): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001A0195E7740(5,3-14): error X3018: invalid subscript 'Store'
+
diff --git a/test/tint/buffer/storage/types/mat4x2_f16.wgsl.expected.glsl b/test/tint/buffer/storage/types/mat4x2_f16.wgsl.expected.glsl
new file mode 100644
index 0000000..f4c91fe
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat4x2_f16.wgsl.expected.glsl
@@ -0,0 +1,20 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std430) buffer tint_symbol_block_ssbo {
+  f16mat4x2 inner;
+} tint_symbol;
+
+layout(binding = 1, std430) buffer tint_symbol_block_ssbo_1 {
+  f16mat4x2 inner;
+} tint_symbol_1;
+
+void tint_symbol_2() {
+  tint_symbol_1.inner = tint_symbol.inner;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol_2();
+  return;
+}
diff --git a/test/tint/buffer/storage/types/mat4x2_f16.wgsl.expected.msl b/test/tint/buffer/storage/types/mat4x2_f16.wgsl.expected.msl
new file mode 100644
index 0000000..1e4191e
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat4x2_f16.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(device half4x2* tint_symbol_1 [[buffer(0)]], const device half4x2* tint_symbol_2 [[buffer(1)]]) {
+  *(tint_symbol_1) = *(tint_symbol_2);
+  return;
+}
+
diff --git a/test/tint/buffer/storage/types/mat4x2_f16.wgsl.expected.spvasm b/test/tint/buffer/storage/types/mat4x2_f16.wgsl.expected.spvasm
new file mode 100644
index 0000000..5781d8e
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat4x2_f16.wgsl.expected.spvasm
@@ -0,0 +1,47 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 18
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %in_block "in_block"
+               OpMemberName %in_block 0 "inner"
+               OpName %in "in"
+               OpName %out "out"
+               OpName %main "main"
+               OpDecorate %in_block Block
+               OpMemberDecorate %in_block 0 Offset 0
+               OpMemberDecorate %in_block 0 ColMajor
+               OpMemberDecorate %in_block 0 MatrixStride 4
+               OpDecorate %in NonWritable
+               OpDecorate %in DescriptorSet 0
+               OpDecorate %in Binding 0
+               OpDecorate %out DescriptorSet 0
+               OpDecorate %out Binding 1
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+ %mat4v2half = OpTypeMatrix %v2half 4
+   %in_block = OpTypeStruct %mat4v2half
+%_ptr_StorageBuffer_in_block = OpTypePointer StorageBuffer %in_block
+         %in = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+        %out = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+       %void = OpTypeVoid
+          %8 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_mat4v2half = OpTypePointer StorageBuffer %mat4v2half
+       %main = OpFunction %void None %8
+         %11 = OpLabel
+         %15 = OpAccessChain %_ptr_StorageBuffer_mat4v2half %out %uint_0
+         %16 = OpAccessChain %_ptr_StorageBuffer_mat4v2half %in %uint_0
+         %17 = OpLoad %mat4v2half %16
+               OpStore %15 %17
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/storage/types/mat4x2_f16.wgsl.expected.wgsl b/test/tint/buffer/storage/types/mat4x2_f16.wgsl.expected.wgsl
new file mode 100644
index 0000000..b6be63a
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat4x2_f16.wgsl.expected.wgsl
@@ -0,0 +1,10 @@
+enable f16;
+
+@group(0) @binding(0) var<storage, read> in : mat4x2<f16>;
+
+@group(0) @binding(1) var<storage, read_write> out : mat4x2<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/mat4x2_f32.wgsl b/test/tint/buffer/storage/types/mat4x2_f32.wgsl
new file mode 100644
index 0000000..60244dc
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat4x2_f32.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0)
+var<storage, read> in : mat4x2<f32>;
+
+@group(0) @binding(1)
+var<storage, read_write> out : mat4x2<f32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/mat4x2_f32.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/types/mat4x2_f32.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..a8ca4f5
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat4x2_f32.wgsl.expected.dxc.hlsl
@@ -0,0 +1,19 @@
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+void tint_symbol_2(RWByteAddressBuffer buffer, uint offset, float4x2 value) {
+  buffer.Store2((offset + 0u), asuint(value[0u]));
+  buffer.Store2((offset + 8u), asuint(value[1u]));
+  buffer.Store2((offset + 16u), asuint(value[2u]));
+  buffer.Store2((offset + 24u), asuint(value[3u]));
+}
+
+float4x2 tint_symbol_4(ByteAddressBuffer buffer, uint offset) {
+  return float4x2(asfloat(buffer.Load2((offset + 0u))), asfloat(buffer.Load2((offset + 8u))), asfloat(buffer.Load2((offset + 16u))), asfloat(buffer.Load2((offset + 24u))));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_2(tint_symbol_1, 0u, tint_symbol_4(tint_symbol, 0u));
+  return;
+}
diff --git a/test/tint/buffer/storage/types/mat4x2_f32.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/types/mat4x2_f32.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..a8ca4f5
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat4x2_f32.wgsl.expected.fxc.hlsl
@@ -0,0 +1,19 @@
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+void tint_symbol_2(RWByteAddressBuffer buffer, uint offset, float4x2 value) {
+  buffer.Store2((offset + 0u), asuint(value[0u]));
+  buffer.Store2((offset + 8u), asuint(value[1u]));
+  buffer.Store2((offset + 16u), asuint(value[2u]));
+  buffer.Store2((offset + 24u), asuint(value[3u]));
+}
+
+float4x2 tint_symbol_4(ByteAddressBuffer buffer, uint offset) {
+  return float4x2(asfloat(buffer.Load2((offset + 0u))), asfloat(buffer.Load2((offset + 8u))), asfloat(buffer.Load2((offset + 16u))), asfloat(buffer.Load2((offset + 24u))));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_2(tint_symbol_1, 0u, tint_symbol_4(tint_symbol, 0u));
+  return;
+}
diff --git a/test/tint/buffer/storage/types/mat4x2_f32.wgsl.expected.glsl b/test/tint/buffer/storage/types/mat4x2_f32.wgsl.expected.glsl
new file mode 100644
index 0000000..8d7d981
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat4x2_f32.wgsl.expected.glsl
@@ -0,0 +1,19 @@
+#version 310 es
+
+layout(binding = 0, std430) buffer tint_symbol_block_ssbo {
+  mat4x2 inner;
+} tint_symbol;
+
+layout(binding = 1, std430) buffer tint_symbol_block_ssbo_1 {
+  mat4x2 inner;
+} tint_symbol_1;
+
+void tint_symbol_2() {
+  tint_symbol_1.inner = tint_symbol.inner;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol_2();
+  return;
+}
diff --git a/test/tint/buffer/storage/types/mat4x2_f32.wgsl.expected.msl b/test/tint/buffer/storage/types/mat4x2_f32.wgsl.expected.msl
new file mode 100644
index 0000000..3ff5e73
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat4x2_f32.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(device float4x2* tint_symbol_1 [[buffer(0)]], const device float4x2* tint_symbol_2 [[buffer(1)]]) {
+  *(tint_symbol_1) = *(tint_symbol_2);
+  return;
+}
+
diff --git a/test/tint/buffer/storage/types/mat4x2_f32.wgsl.expected.spvasm b/test/tint/buffer/storage/types/mat4x2_f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..da7afd5
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat4x2_f32.wgsl.expected.spvasm
@@ -0,0 +1,43 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 18
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %in_block "in_block"
+               OpMemberName %in_block 0 "inner"
+               OpName %in "in"
+               OpName %out "out"
+               OpName %main "main"
+               OpDecorate %in_block Block
+               OpMemberDecorate %in_block 0 Offset 0
+               OpMemberDecorate %in_block 0 ColMajor
+               OpMemberDecorate %in_block 0 MatrixStride 8
+               OpDecorate %in NonWritable
+               OpDecorate %in DescriptorSet 0
+               OpDecorate %in Binding 0
+               OpDecorate %out DescriptorSet 0
+               OpDecorate %out Binding 1
+      %float = OpTypeFloat 32
+    %v2float = OpTypeVector %float 2
+%mat4v2float = OpTypeMatrix %v2float 4
+   %in_block = OpTypeStruct %mat4v2float
+%_ptr_StorageBuffer_in_block = OpTypePointer StorageBuffer %in_block
+         %in = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+        %out = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+       %void = OpTypeVoid
+          %8 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_mat4v2float = OpTypePointer StorageBuffer %mat4v2float
+       %main = OpFunction %void None %8
+         %11 = OpLabel
+         %15 = OpAccessChain %_ptr_StorageBuffer_mat4v2float %out %uint_0
+         %16 = OpAccessChain %_ptr_StorageBuffer_mat4v2float %in %uint_0
+         %17 = OpLoad %mat4v2float %16
+               OpStore %15 %17
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/storage/types/mat4x2_f32.wgsl.expected.wgsl b/test/tint/buffer/storage/types/mat4x2_f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..4027c07
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat4x2_f32.wgsl.expected.wgsl
@@ -0,0 +1,8 @@
+@group(0) @binding(0) var<storage, read> in : mat4x2<f32>;
+
+@group(0) @binding(1) var<storage, read_write> out : mat4x2<f32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/mat4x3_f16.wgsl b/test/tint/buffer/storage/types/mat4x3_f16.wgsl
new file mode 100644
index 0000000..ab4ecf7
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat4x3_f16.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0)
+var<storage, read> in : mat4x3<f16>;
+
+@group(0) @binding(1)
+var<storage, read_write> out : mat4x3<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/mat4x3_f16.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/types/mat4x3_f16.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..29a2a90
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat4x3_f16.wgsl.expected.dxc.hlsl
@@ -0,0 +1,19 @@
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+void tint_symbol_2(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 3> value) {
+  buffer.Store<vector<float16_t, 3> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 8u), value[1u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 16u), value[2u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 24u), value[3u]);
+}
+
+matrix<float16_t, 4, 3> tint_symbol_4(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 4, 3>(buffer.Load<vector<float16_t, 3> >((offset + 0u)), buffer.Load<vector<float16_t, 3> >((offset + 8u)), buffer.Load<vector<float16_t, 3> >((offset + 16u)), buffer.Load<vector<float16_t, 3> >((offset + 24u)));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_2(tint_symbol_1, 0u, tint_symbol_4(tint_symbol, 0u));
+  return;
+}
diff --git a/test/tint/buffer/storage/types/mat4x3_f16.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/types/mat4x3_f16.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..a117a65
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat4x3_f16.wgsl.expected.fxc.hlsl
@@ -0,0 +1,25 @@
+SKIP: FAILED
+
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+void tint_symbol_2(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 3> value) {
+  buffer.Store<vector<float16_t, 3> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 8u), value[1u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 16u), value[2u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 24u), value[3u]);
+}
+
+matrix<float16_t, 4, 3> tint_symbol_4(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 4, 3>(buffer.Load<vector<float16_t, 3> >((offset + 0u)), buffer.Load<vector<float16_t, 3> >((offset + 8u)), buffer.Load<vector<float16_t, 3> >((offset + 16u)), buffer.Load<vector<float16_t, 3> >((offset + 24u)));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_2(tint_symbol_1, 0u, tint_symbol_4(tint_symbol, 0u));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000027711EB7740(4,68-76): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000027711EB7740(5,3-14): error X3018: invalid subscript 'Store'
+
diff --git a/test/tint/buffer/storage/types/mat4x3_f16.wgsl.expected.glsl b/test/tint/buffer/storage/types/mat4x3_f16.wgsl.expected.glsl
new file mode 100644
index 0000000..65e8a13
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat4x3_f16.wgsl.expected.glsl
@@ -0,0 +1,20 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std430) buffer tint_symbol_block_ssbo {
+  f16mat4x3 inner;
+} tint_symbol;
+
+layout(binding = 1, std430) buffer tint_symbol_block_ssbo_1 {
+  f16mat4x3 inner;
+} tint_symbol_1;
+
+void tint_symbol_2() {
+  tint_symbol_1.inner = tint_symbol.inner;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol_2();
+  return;
+}
diff --git a/test/tint/buffer/storage/types/mat4x3_f16.wgsl.expected.msl b/test/tint/buffer/storage/types/mat4x3_f16.wgsl.expected.msl
new file mode 100644
index 0000000..57f08f6
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat4x3_f16.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(device half4x3* tint_symbol_1 [[buffer(0)]], const device half4x3* tint_symbol_2 [[buffer(1)]]) {
+  *(tint_symbol_1) = *(tint_symbol_2);
+  return;
+}
+
diff --git a/test/tint/buffer/storage/types/mat4x3_f16.wgsl.expected.spvasm b/test/tint/buffer/storage/types/mat4x3_f16.wgsl.expected.spvasm
new file mode 100644
index 0000000..5cd7565
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat4x3_f16.wgsl.expected.spvasm
@@ -0,0 +1,47 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 18
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %in_block "in_block"
+               OpMemberName %in_block 0 "inner"
+               OpName %in "in"
+               OpName %out "out"
+               OpName %main "main"
+               OpDecorate %in_block Block
+               OpMemberDecorate %in_block 0 Offset 0
+               OpMemberDecorate %in_block 0 ColMajor
+               OpMemberDecorate %in_block 0 MatrixStride 8
+               OpDecorate %in NonWritable
+               OpDecorate %in DescriptorSet 0
+               OpDecorate %in Binding 0
+               OpDecorate %out DescriptorSet 0
+               OpDecorate %out Binding 1
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+ %mat4v3half = OpTypeMatrix %v3half 4
+   %in_block = OpTypeStruct %mat4v3half
+%_ptr_StorageBuffer_in_block = OpTypePointer StorageBuffer %in_block
+         %in = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+        %out = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+       %void = OpTypeVoid
+          %8 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_mat4v3half = OpTypePointer StorageBuffer %mat4v3half
+       %main = OpFunction %void None %8
+         %11 = OpLabel
+         %15 = OpAccessChain %_ptr_StorageBuffer_mat4v3half %out %uint_0
+         %16 = OpAccessChain %_ptr_StorageBuffer_mat4v3half %in %uint_0
+         %17 = OpLoad %mat4v3half %16
+               OpStore %15 %17
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/storage/types/mat4x3_f16.wgsl.expected.wgsl b/test/tint/buffer/storage/types/mat4x3_f16.wgsl.expected.wgsl
new file mode 100644
index 0000000..3223e4f
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat4x3_f16.wgsl.expected.wgsl
@@ -0,0 +1,10 @@
+enable f16;
+
+@group(0) @binding(0) var<storage, read> in : mat4x3<f16>;
+
+@group(0) @binding(1) var<storage, read_write> out : mat4x3<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/mat4x3_f32.wgsl b/test/tint/buffer/storage/types/mat4x3_f32.wgsl
new file mode 100644
index 0000000..0900fa7
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat4x3_f32.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0)
+var<storage, read> in : mat4x3<f32>;
+
+@group(0) @binding(1)
+var<storage, read_write> out : mat4x3<f32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/mat4x3_f32.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/types/mat4x3_f32.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..44051da
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat4x3_f32.wgsl.expected.dxc.hlsl
@@ -0,0 +1,19 @@
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+void tint_symbol_2(RWByteAddressBuffer buffer, uint offset, float4x3 value) {
+  buffer.Store3((offset + 0u), asuint(value[0u]));
+  buffer.Store3((offset + 16u), asuint(value[1u]));
+  buffer.Store3((offset + 32u), asuint(value[2u]));
+  buffer.Store3((offset + 48u), asuint(value[3u]));
+}
+
+float4x3 tint_symbol_4(ByteAddressBuffer buffer, uint offset) {
+  return float4x3(asfloat(buffer.Load3((offset + 0u))), asfloat(buffer.Load3((offset + 16u))), asfloat(buffer.Load3((offset + 32u))), asfloat(buffer.Load3((offset + 48u))));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_2(tint_symbol_1, 0u, tint_symbol_4(tint_symbol, 0u));
+  return;
+}
diff --git a/test/tint/buffer/storage/types/mat4x3_f32.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/types/mat4x3_f32.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..44051da
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat4x3_f32.wgsl.expected.fxc.hlsl
@@ -0,0 +1,19 @@
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+void tint_symbol_2(RWByteAddressBuffer buffer, uint offset, float4x3 value) {
+  buffer.Store3((offset + 0u), asuint(value[0u]));
+  buffer.Store3((offset + 16u), asuint(value[1u]));
+  buffer.Store3((offset + 32u), asuint(value[2u]));
+  buffer.Store3((offset + 48u), asuint(value[3u]));
+}
+
+float4x3 tint_symbol_4(ByteAddressBuffer buffer, uint offset) {
+  return float4x3(asfloat(buffer.Load3((offset + 0u))), asfloat(buffer.Load3((offset + 16u))), asfloat(buffer.Load3((offset + 32u))), asfloat(buffer.Load3((offset + 48u))));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_2(tint_symbol_1, 0u, tint_symbol_4(tint_symbol, 0u));
+  return;
+}
diff --git a/test/tint/buffer/storage/types/mat4x3_f32.wgsl.expected.glsl b/test/tint/buffer/storage/types/mat4x3_f32.wgsl.expected.glsl
new file mode 100644
index 0000000..a4a1a8f
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat4x3_f32.wgsl.expected.glsl
@@ -0,0 +1,19 @@
+#version 310 es
+
+layout(binding = 0, std430) buffer tint_symbol_block_ssbo {
+  mat4x3 inner;
+} tint_symbol;
+
+layout(binding = 1, std430) buffer tint_symbol_block_ssbo_1 {
+  mat4x3 inner;
+} tint_symbol_1;
+
+void tint_symbol_2() {
+  tint_symbol_1.inner = tint_symbol.inner;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol_2();
+  return;
+}
diff --git a/test/tint/buffer/storage/types/mat4x3_f32.wgsl.expected.msl b/test/tint/buffer/storage/types/mat4x3_f32.wgsl.expected.msl
new file mode 100644
index 0000000..7465a1a
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat4x3_f32.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(device float4x3* tint_symbol_1 [[buffer(0)]], const device float4x3* tint_symbol_2 [[buffer(1)]]) {
+  *(tint_symbol_1) = *(tint_symbol_2);
+  return;
+}
+
diff --git a/test/tint/buffer/storage/types/mat4x3_f32.wgsl.expected.spvasm b/test/tint/buffer/storage/types/mat4x3_f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..39fafdd
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat4x3_f32.wgsl.expected.spvasm
@@ -0,0 +1,43 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 18
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %in_block "in_block"
+               OpMemberName %in_block 0 "inner"
+               OpName %in "in"
+               OpName %out "out"
+               OpName %main "main"
+               OpDecorate %in_block Block
+               OpMemberDecorate %in_block 0 Offset 0
+               OpMemberDecorate %in_block 0 ColMajor
+               OpMemberDecorate %in_block 0 MatrixStride 16
+               OpDecorate %in NonWritable
+               OpDecorate %in DescriptorSet 0
+               OpDecorate %in Binding 0
+               OpDecorate %out DescriptorSet 0
+               OpDecorate %out Binding 1
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat4v3float = OpTypeMatrix %v3float 4
+   %in_block = OpTypeStruct %mat4v3float
+%_ptr_StorageBuffer_in_block = OpTypePointer StorageBuffer %in_block
+         %in = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+        %out = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+       %void = OpTypeVoid
+          %8 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_mat4v3float = OpTypePointer StorageBuffer %mat4v3float
+       %main = OpFunction %void None %8
+         %11 = OpLabel
+         %15 = OpAccessChain %_ptr_StorageBuffer_mat4v3float %out %uint_0
+         %16 = OpAccessChain %_ptr_StorageBuffer_mat4v3float %in %uint_0
+         %17 = OpLoad %mat4v3float %16
+               OpStore %15 %17
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/storage/types/mat4x3_f32.wgsl.expected.wgsl b/test/tint/buffer/storage/types/mat4x3_f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..9bdd003
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat4x3_f32.wgsl.expected.wgsl
@@ -0,0 +1,8 @@
+@group(0) @binding(0) var<storage, read> in : mat4x3<f32>;
+
+@group(0) @binding(1) var<storage, read_write> out : mat4x3<f32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/mat4x4_f16.wgsl b/test/tint/buffer/storage/types/mat4x4_f16.wgsl
new file mode 100644
index 0000000..bddf877
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat4x4_f16.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0)
+var<storage, read> in : mat4x4<f16>;
+
+@group(0) @binding(1)
+var<storage, read_write> out : mat4x4<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/mat4x4_f16.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/types/mat4x4_f16.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..3931c45
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat4x4_f16.wgsl.expected.dxc.hlsl
@@ -0,0 +1,19 @@
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+void tint_symbol_2(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 4> value) {
+  buffer.Store<vector<float16_t, 4> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 8u), value[1u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 16u), value[2u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 24u), value[3u]);
+}
+
+matrix<float16_t, 4, 4> tint_symbol_4(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 4, 4>(buffer.Load<vector<float16_t, 4> >((offset + 0u)), buffer.Load<vector<float16_t, 4> >((offset + 8u)), buffer.Load<vector<float16_t, 4> >((offset + 16u)), buffer.Load<vector<float16_t, 4> >((offset + 24u)));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_2(tint_symbol_1, 0u, tint_symbol_4(tint_symbol, 0u));
+  return;
+}
diff --git a/test/tint/buffer/storage/types/mat4x4_f16.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/types/mat4x4_f16.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..9139ed2
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat4x4_f16.wgsl.expected.fxc.hlsl
@@ -0,0 +1,25 @@
+SKIP: FAILED
+
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+void tint_symbol_2(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 4> value) {
+  buffer.Store<vector<float16_t, 4> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 8u), value[1u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 16u), value[2u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 24u), value[3u]);
+}
+
+matrix<float16_t, 4, 4> tint_symbol_4(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 4, 4>(buffer.Load<vector<float16_t, 4> >((offset + 0u)), buffer.Load<vector<float16_t, 4> >((offset + 8u)), buffer.Load<vector<float16_t, 4> >((offset + 16u)), buffer.Load<vector<float16_t, 4> >((offset + 24u)));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_2(tint_symbol_1, 0u, tint_symbol_4(tint_symbol, 0u));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000023AE8057740(4,68-76): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000023AE8057740(5,3-14): error X3018: invalid subscript 'Store'
+
diff --git a/test/tint/buffer/storage/types/mat4x4_f16.wgsl.expected.glsl b/test/tint/buffer/storage/types/mat4x4_f16.wgsl.expected.glsl
new file mode 100644
index 0000000..1d549eb
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat4x4_f16.wgsl.expected.glsl
@@ -0,0 +1,20 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std430) buffer tint_symbol_block_ssbo {
+  f16mat4 inner;
+} tint_symbol;
+
+layout(binding = 1, std430) buffer tint_symbol_block_ssbo_1 {
+  f16mat4 inner;
+} tint_symbol_1;
+
+void tint_symbol_2() {
+  tint_symbol_1.inner = tint_symbol.inner;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol_2();
+  return;
+}
diff --git a/test/tint/buffer/storage/types/mat4x4_f16.wgsl.expected.msl b/test/tint/buffer/storage/types/mat4x4_f16.wgsl.expected.msl
new file mode 100644
index 0000000..8059f64
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat4x4_f16.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(device half4x4* tint_symbol_1 [[buffer(0)]], const device half4x4* tint_symbol_2 [[buffer(1)]]) {
+  *(tint_symbol_1) = *(tint_symbol_2);
+  return;
+}
+
diff --git a/test/tint/buffer/storage/types/mat4x4_f16.wgsl.expected.spvasm b/test/tint/buffer/storage/types/mat4x4_f16.wgsl.expected.spvasm
new file mode 100644
index 0000000..9f990fb
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat4x4_f16.wgsl.expected.spvasm
@@ -0,0 +1,47 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 18
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %in_block "in_block"
+               OpMemberName %in_block 0 "inner"
+               OpName %in "in"
+               OpName %out "out"
+               OpName %main "main"
+               OpDecorate %in_block Block
+               OpMemberDecorate %in_block 0 Offset 0
+               OpMemberDecorate %in_block 0 ColMajor
+               OpMemberDecorate %in_block 0 MatrixStride 8
+               OpDecorate %in NonWritable
+               OpDecorate %in DescriptorSet 0
+               OpDecorate %in Binding 0
+               OpDecorate %out DescriptorSet 0
+               OpDecorate %out Binding 1
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+ %mat4v4half = OpTypeMatrix %v4half 4
+   %in_block = OpTypeStruct %mat4v4half
+%_ptr_StorageBuffer_in_block = OpTypePointer StorageBuffer %in_block
+         %in = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+        %out = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+       %void = OpTypeVoid
+          %8 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_mat4v4half = OpTypePointer StorageBuffer %mat4v4half
+       %main = OpFunction %void None %8
+         %11 = OpLabel
+         %15 = OpAccessChain %_ptr_StorageBuffer_mat4v4half %out %uint_0
+         %16 = OpAccessChain %_ptr_StorageBuffer_mat4v4half %in %uint_0
+         %17 = OpLoad %mat4v4half %16
+               OpStore %15 %17
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/storage/types/mat4x4_f16.wgsl.expected.wgsl b/test/tint/buffer/storage/types/mat4x4_f16.wgsl.expected.wgsl
new file mode 100644
index 0000000..9284cf9
--- /dev/null
+++ b/test/tint/buffer/storage/types/mat4x4_f16.wgsl.expected.wgsl
@@ -0,0 +1,10 @@
+enable f16;
+
+@group(0) @binding(0) var<storage, read> in : mat4x4<f16>;
+
+@group(0) @binding(1) var<storage, read_write> out : mat4x4<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/mat4x4.wgsl b/test/tint/buffer/storage/types/mat4x4_f32.wgsl
similarity index 100%
rename from test/tint/buffer/storage/types/mat4x4.wgsl
rename to test/tint/buffer/storage/types/mat4x4_f32.wgsl
diff --git a/test/tint/buffer/storage/types/mat4x4.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/types/mat4x4_f32.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/storage/types/mat4x4.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/storage/types/mat4x4_f32.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/storage/types/mat4x4.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/types/mat4x4_f32.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/storage/types/mat4x4.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/storage/types/mat4x4_f32.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/storage/types/mat4x4.wgsl.expected.glsl b/test/tint/buffer/storage/types/mat4x4_f32.wgsl.expected.glsl
similarity index 100%
rename from test/tint/buffer/storage/types/mat4x4.wgsl.expected.glsl
rename to test/tint/buffer/storage/types/mat4x4_f32.wgsl.expected.glsl
diff --git a/test/tint/buffer/storage/types/mat4x4.wgsl.expected.msl b/test/tint/buffer/storage/types/mat4x4_f32.wgsl.expected.msl
similarity index 100%
rename from test/tint/buffer/storage/types/mat4x4.wgsl.expected.msl
rename to test/tint/buffer/storage/types/mat4x4_f32.wgsl.expected.msl
diff --git a/test/tint/buffer/storage/types/mat4x4.wgsl.expected.spvasm b/test/tint/buffer/storage/types/mat4x4_f32.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/storage/types/mat4x4.wgsl.expected.spvasm
rename to test/tint/buffer/storage/types/mat4x4_f32.wgsl.expected.spvasm
diff --git a/test/tint/buffer/storage/types/mat4x4.wgsl.expected.wgsl b/test/tint/buffer/storage/types/mat4x4_f32.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/buffer/storage/types/mat4x4.wgsl.expected.wgsl
rename to test/tint/buffer/storage/types/mat4x4_f32.wgsl.expected.wgsl
diff --git a/test/tint/buffer/storage/types/runtime_array.wgsl b/test/tint/buffer/storage/types/runtime_array.wgsl
deleted file mode 100644
index 4ecdc37..0000000
--- a/test/tint/buffer/storage/types/runtime_array.wgsl
+++ /dev/null
@@ -1,14 +0,0 @@
-struct S {
-  f : f32,
-};
-
-@group(0) @binding(0)
-var<storage, read> in : array<S>;
-
-@group(0) @binding(1)
-var<storage, read_write> out : array<S>;
-
-@compute @workgroup_size(1)
-fn main() {
-  out[0] = in[0];
-}
diff --git a/test/tint/buffer/storage/types/runtime_array.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/types/runtime_array.wgsl.expected.dxc.hlsl
deleted file mode 100644
index 0843539..0000000
--- a/test/tint/buffer/storage/types/runtime_array.wgsl.expected.dxc.hlsl
+++ /dev/null
@@ -1,21 +0,0 @@
-struct S {
-  float f;
-};
-
-ByteAddressBuffer tint_symbol : register(t0, space0);
-RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
-
-void tint_symbol_2(RWByteAddressBuffer buffer, uint offset, S value) {
-  buffer.Store((offset + 0u), asuint(value.f));
-}
-
-S tint_symbol_4(ByteAddressBuffer buffer, uint offset) {
-  const S tint_symbol_6 = {asfloat(buffer.Load((offset + 0u)))};
-  return tint_symbol_6;
-}
-
-[numthreads(1, 1, 1)]
-void main() {
-  tint_symbol_2(tint_symbol_1, 0u, tint_symbol_4(tint_symbol, 0u));
-  return;
-}
diff --git a/test/tint/buffer/storage/types/runtime_array.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/types/runtime_array.wgsl.expected.fxc.hlsl
deleted file mode 100644
index 0843539..0000000
--- a/test/tint/buffer/storage/types/runtime_array.wgsl.expected.fxc.hlsl
+++ /dev/null
@@ -1,21 +0,0 @@
-struct S {
-  float f;
-};
-
-ByteAddressBuffer tint_symbol : register(t0, space0);
-RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
-
-void tint_symbol_2(RWByteAddressBuffer buffer, uint offset, S value) {
-  buffer.Store((offset + 0u), asuint(value.f));
-}
-
-S tint_symbol_4(ByteAddressBuffer buffer, uint offset) {
-  const S tint_symbol_6 = {asfloat(buffer.Load((offset + 0u)))};
-  return tint_symbol_6;
-}
-
-[numthreads(1, 1, 1)]
-void main() {
-  tint_symbol_2(tint_symbol_1, 0u, tint_symbol_4(tint_symbol, 0u));
-  return;
-}
diff --git a/test/tint/buffer/storage/types/runtime_array.wgsl.expected.glsl b/test/tint/buffer/storage/types/runtime_array.wgsl.expected.glsl
deleted file mode 100644
index 40eb01b..0000000
--- a/test/tint/buffer/storage/types/runtime_array.wgsl.expected.glsl
+++ /dev/null
@@ -1,23 +0,0 @@
-#version 310 es
-
-struct S {
-  float f;
-};
-
-layout(binding = 0, std430) buffer tint_symbol_block_ssbo {
-  S inner[];
-} tint_symbol;
-
-layout(binding = 1, std430) buffer tint_symbol_block_ssbo_1 {
-  S inner[];
-} tint_symbol_1;
-
-void tint_symbol_2() {
-  tint_symbol_1.inner[0] = tint_symbol.inner[0];
-}
-
-layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
-void main() {
-  tint_symbol_2();
-  return;
-}
diff --git a/test/tint/buffer/storage/types/runtime_array.wgsl.expected.msl b/test/tint/buffer/storage/types/runtime_array.wgsl.expected.msl
deleted file mode 100644
index 836dba1..0000000
--- a/test/tint/buffer/storage/types/runtime_array.wgsl.expected.msl
+++ /dev/null
@@ -1,33 +0,0 @@
-#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 S {
-  /* 0x0000 */ float f;
-};
-
-struct tint_symbol_2 {
-  /* 0x0000 */ tint_array<S, 1> arr;
-};
-
-struct tint_symbol_4 {
-  /* 0x0000 */ tint_array<S, 1> arr;
-};
-
-kernel void tint_symbol(device tint_symbol_2* tint_symbol_1 [[buffer(0)]], const device tint_symbol_4* tint_symbol_3 [[buffer(1)]]) {
-  (*(tint_symbol_1)).arr[0] = (*(tint_symbol_3)).arr[0];
-  return;
-}
-
diff --git a/test/tint/buffer/storage/types/runtime_array.wgsl.expected.spvasm b/test/tint/buffer/storage/types/runtime_array.wgsl.expected.spvasm
deleted file mode 100644
index 8fbc2ca..0000000
--- a/test/tint/buffer/storage/types/runtime_array.wgsl.expected.spvasm
+++ /dev/null
@@ -1,47 +0,0 @@
-; SPIR-V
-; Version: 1.3
-; Generator: Google Tint Compiler; 0
-; Bound: 20
-; Schema: 0
-               OpCapability Shader
-               OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %main "main"
-               OpExecutionMode %main LocalSize 1 1 1
-               OpName %in_block "in_block"
-               OpMemberName %in_block 0 "inner"
-               OpName %S "S"
-               OpMemberName %S 0 "f"
-               OpName %in "in"
-               OpName %out "out"
-               OpName %main "main"
-               OpDecorate %in_block Block
-               OpMemberDecorate %in_block 0 Offset 0
-               OpMemberDecorate %S 0 Offset 0
-               OpDecorate %_runtimearr_S ArrayStride 4
-               OpDecorate %in NonWritable
-               OpDecorate %in DescriptorSet 0
-               OpDecorate %in Binding 0
-               OpDecorate %out DescriptorSet 0
-               OpDecorate %out Binding 1
-      %float = OpTypeFloat 32
-          %S = OpTypeStruct %float
-%_runtimearr_S = OpTypeRuntimeArray %S
-   %in_block = OpTypeStruct %_runtimearr_S
-%_ptr_StorageBuffer_in_block = OpTypePointer StorageBuffer %in_block
-         %in = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
-        %out = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
-       %void = OpTypeVoid
-          %8 = OpTypeFunction %void
-       %uint = OpTypeInt 32 0
-     %uint_0 = OpConstant %uint 0
-        %int = OpTypeInt 32 1
-         %15 = OpConstantNull %int
-%_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
-       %main = OpFunction %void None %8
-         %11 = OpLabel
-         %17 = OpAccessChain %_ptr_StorageBuffer_S %out %uint_0 %15
-         %18 = OpAccessChain %_ptr_StorageBuffer_S %in %uint_0 %15
-         %19 = OpLoad %S %18
-               OpStore %17 %19
-               OpReturn
-               OpFunctionEnd
diff --git a/test/tint/buffer/storage/types/runtime_array.wgsl.expected.wgsl b/test/tint/buffer/storage/types/runtime_array.wgsl.expected.wgsl
deleted file mode 100644
index 3946635..0000000
--- a/test/tint/buffer/storage/types/runtime_array.wgsl.expected.wgsl
+++ /dev/null
@@ -1,12 +0,0 @@
-struct S {
-  f : f32,
-}
-
-@group(0) @binding(0) var<storage, read> in : array<S>;
-
-@group(0) @binding(1) var<storage, read_write> out : array<S>;
-
-@compute @workgroup_size(1)
-fn main() {
-  out[0] = in[0];
-}
diff --git a/test/tint/buffer/storage/types/runtime_array_f16.wgsl b/test/tint/buffer/storage/types/runtime_array_f16.wgsl
new file mode 100644
index 0000000..0df7afa
--- /dev/null
+++ b/test/tint/buffer/storage/types/runtime_array_f16.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0)
+var<storage, read> in : array<f16>;
+
+@group(0) @binding(1)
+var<storage, read_write> out : array<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out[0] = in[0];
+}
diff --git a/test/tint/buffer/storage/types/runtime_array_f16.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/types/runtime_array_f16.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..bfdede4
--- /dev/null
+++ b/test/tint/buffer/storage/types/runtime_array_f16.wgsl.expected.dxc.hlsl
@@ -0,0 +1,8 @@
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_1.Store<float16_t>(0u, tint_symbol.Load<float16_t>(0u));
+  return;
+}
diff --git a/test/tint/buffer/storage/types/runtime_array_f16.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/types/runtime_array_f16.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..922c506
--- /dev/null
+++ b/test/tint/buffer/storage/types/runtime_array_f16.wgsl.expected.fxc.hlsl
@@ -0,0 +1,13 @@
+SKIP: FAILED
+
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_1.Store<float16_t>(0u, tint_symbol.Load<float16_t>(0u));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001A520622CB0(6,3-21): error X3018: invalid subscript 'Store'
+
diff --git a/test/tint/buffer/storage/types/runtime_array_f16.wgsl.expected.glsl b/test/tint/buffer/storage/types/runtime_array_f16.wgsl.expected.glsl
new file mode 100644
index 0000000..244510b
--- /dev/null
+++ b/test/tint/buffer/storage/types/runtime_array_f16.wgsl.expected.glsl
@@ -0,0 +1,20 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std430) buffer tint_symbol_block_ssbo {
+  float16_t inner[];
+} tint_symbol;
+
+layout(binding = 1, std430) buffer tint_symbol_block_ssbo_1 {
+  float16_t inner[];
+} tint_symbol_1;
+
+void tint_symbol_2() {
+  tint_symbol_1.inner[0] = tint_symbol.inner[0];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol_2();
+  return;
+}
diff --git a/test/tint/buffer/storage/types/runtime_array_f16.wgsl.expected.msl b/test/tint/buffer/storage/types/runtime_array_f16.wgsl.expected.msl
new file mode 100644
index 0000000..b6b4ed5
--- /dev/null
+++ b/test/tint/buffer/storage/types/runtime_array_f16.wgsl.expected.msl
@@ -0,0 +1,29 @@
+#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_symbol_2 {
+  /* 0x0000 */ tint_array<half, 1> arr;
+};
+
+struct tint_symbol_4 {
+  /* 0x0000 */ tint_array<half, 1> arr;
+};
+
+kernel void tint_symbol(device tint_symbol_2* tint_symbol_1 [[buffer(0)]], const device tint_symbol_4* tint_symbol_3 [[buffer(1)]]) {
+  (*(tint_symbol_1)).arr[0] = (*(tint_symbol_3)).arr[0];
+  return;
+}
+
diff --git a/test/tint/buffer/storage/types/runtime_array_f16.wgsl.expected.spvasm b/test/tint/buffer/storage/types/runtime_array_f16.wgsl.expected.spvasm
new file mode 100644
index 0000000..c3f1ad2
--- /dev/null
+++ b/test/tint/buffer/storage/types/runtime_array_f16.wgsl.expected.spvasm
@@ -0,0 +1,47 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 19
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %in_block "in_block"
+               OpMemberName %in_block 0 "inner"
+               OpName %in "in"
+               OpName %out "out"
+               OpName %main "main"
+               OpDecorate %in_block Block
+               OpMemberDecorate %in_block 0 Offset 0
+               OpDecorate %_runtimearr_half ArrayStride 2
+               OpDecorate %in NonWritable
+               OpDecorate %in DescriptorSet 0
+               OpDecorate %in Binding 0
+               OpDecorate %out DescriptorSet 0
+               OpDecorate %out Binding 1
+       %half = OpTypeFloat 16
+%_runtimearr_half = OpTypeRuntimeArray %half
+   %in_block = OpTypeStruct %_runtimearr_half
+%_ptr_StorageBuffer_in_block = OpTypePointer StorageBuffer %in_block
+         %in = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+        %out = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+       %void = OpTypeVoid
+          %7 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+        %int = OpTypeInt 32 1
+         %14 = OpConstantNull %int
+%_ptr_StorageBuffer_half = OpTypePointer StorageBuffer %half
+       %main = OpFunction %void None %7
+         %10 = OpLabel
+         %16 = OpAccessChain %_ptr_StorageBuffer_half %out %uint_0 %14
+         %17 = OpAccessChain %_ptr_StorageBuffer_half %in %uint_0 %14
+         %18 = OpLoad %half %17
+               OpStore %16 %18
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/storage/types/runtime_array_f16.wgsl.expected.wgsl b/test/tint/buffer/storage/types/runtime_array_f16.wgsl.expected.wgsl
new file mode 100644
index 0000000..ac40351
--- /dev/null
+++ b/test/tint/buffer/storage/types/runtime_array_f16.wgsl.expected.wgsl
@@ -0,0 +1,10 @@
+enable f16;
+
+@group(0) @binding(0) var<storage, read> in : array<f16>;
+
+@group(0) @binding(1) var<storage, read_write> out : array<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out[0] = in[0];
+}
diff --git a/test/tint/buffer/storage/types/runtime_array_f32.wgsl b/test/tint/buffer/storage/types/runtime_array_f32.wgsl
new file mode 100644
index 0000000..e32bbc5
--- /dev/null
+++ b/test/tint/buffer/storage/types/runtime_array_f32.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0)
+var<storage, read> in : array<f32>;
+
+@group(0) @binding(1)
+var<storage, read_write> out : array<f32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out[0] = in[0];
+}
diff --git a/test/tint/buffer/storage/types/runtime_array_f32.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/types/runtime_array_f32.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..e6dca9e
--- /dev/null
+++ b/test/tint/buffer/storage/types/runtime_array_f32.wgsl.expected.dxc.hlsl
@@ -0,0 +1,8 @@
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_1.Store(0u, asuint(asfloat(tint_symbol.Load(0u))));
+  return;
+}
diff --git a/test/tint/buffer/storage/types/runtime_array_f32.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/types/runtime_array_f32.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..e6dca9e
--- /dev/null
+++ b/test/tint/buffer/storage/types/runtime_array_f32.wgsl.expected.fxc.hlsl
@@ -0,0 +1,8 @@
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_1.Store(0u, asuint(asfloat(tint_symbol.Load(0u))));
+  return;
+}
diff --git a/test/tint/buffer/storage/types/runtime_array_f32.wgsl.expected.glsl b/test/tint/buffer/storage/types/runtime_array_f32.wgsl.expected.glsl
new file mode 100644
index 0000000..2355b88
--- /dev/null
+++ b/test/tint/buffer/storage/types/runtime_array_f32.wgsl.expected.glsl
@@ -0,0 +1,19 @@
+#version 310 es
+
+layout(binding = 0, std430) buffer tint_symbol_block_ssbo {
+  float inner[];
+} tint_symbol;
+
+layout(binding = 1, std430) buffer tint_symbol_block_ssbo_1 {
+  float inner[];
+} tint_symbol_1;
+
+void tint_symbol_2() {
+  tint_symbol_1.inner[0] = tint_symbol.inner[0];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol_2();
+  return;
+}
diff --git a/test/tint/buffer/storage/types/runtime_array_f32.wgsl.expected.msl b/test/tint/buffer/storage/types/runtime_array_f32.wgsl.expected.msl
new file mode 100644
index 0000000..65ac123
--- /dev/null
+++ b/test/tint/buffer/storage/types/runtime_array_f32.wgsl.expected.msl
@@ -0,0 +1,29 @@
+#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_symbol_2 {
+  /* 0x0000 */ tint_array<float, 1> arr;
+};
+
+struct tint_symbol_4 {
+  /* 0x0000 */ tint_array<float, 1> arr;
+};
+
+kernel void tint_symbol(device tint_symbol_2* tint_symbol_1 [[buffer(0)]], const device tint_symbol_4* tint_symbol_3 [[buffer(1)]]) {
+  (*(tint_symbol_1)).arr[0] = (*(tint_symbol_3)).arr[0];
+  return;
+}
+
diff --git a/test/tint/buffer/storage/types/runtime_array_f32.wgsl.expected.spvasm b/test/tint/buffer/storage/types/runtime_array_f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..25e734c
--- /dev/null
+++ b/test/tint/buffer/storage/types/runtime_array_f32.wgsl.expected.spvasm
@@ -0,0 +1,43 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 19
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %in_block "in_block"
+               OpMemberName %in_block 0 "inner"
+               OpName %in "in"
+               OpName %out "out"
+               OpName %main "main"
+               OpDecorate %in_block Block
+               OpMemberDecorate %in_block 0 Offset 0
+               OpDecorate %_runtimearr_float ArrayStride 4
+               OpDecorate %in NonWritable
+               OpDecorate %in DescriptorSet 0
+               OpDecorate %in Binding 0
+               OpDecorate %out DescriptorSet 0
+               OpDecorate %out Binding 1
+      %float = OpTypeFloat 32
+%_runtimearr_float = OpTypeRuntimeArray %float
+   %in_block = OpTypeStruct %_runtimearr_float
+%_ptr_StorageBuffer_in_block = OpTypePointer StorageBuffer %in_block
+         %in = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+        %out = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+       %void = OpTypeVoid
+          %7 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+        %int = OpTypeInt 32 1
+         %14 = OpConstantNull %int
+%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
+       %main = OpFunction %void None %7
+         %10 = OpLabel
+         %16 = OpAccessChain %_ptr_StorageBuffer_float %out %uint_0 %14
+         %17 = OpAccessChain %_ptr_StorageBuffer_float %in %uint_0 %14
+         %18 = OpLoad %float %17
+               OpStore %16 %18
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/storage/types/runtime_array_f32.wgsl.expected.wgsl b/test/tint/buffer/storage/types/runtime_array_f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..bfa5487
--- /dev/null
+++ b/test/tint/buffer/storage/types/runtime_array_f32.wgsl.expected.wgsl
@@ -0,0 +1,8 @@
+@group(0) @binding(0) var<storage, read> in : array<f32>;
+
+@group(0) @binding(1) var<storage, read_write> out : array<f32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out[0] = in[0];
+}
diff --git a/test/tint/buffer/storage/types/struct.wgsl b/test/tint/buffer/storage/types/struct.wgsl
deleted file mode 100644
index ad75a94..0000000
--- a/test/tint/buffer/storage/types/struct.wgsl
+++ /dev/null
@@ -1,17 +0,0 @@
-struct Inner {
-  f : f32,
-};
-struct S {
-  inner : Inner,
-};
-
-@group(0) @binding(0)
-var<storage, read> in : S;
-
-@group(0) @binding(1)
-var<storage, read_write> out : S;
-
-@compute @workgroup_size(1)
-fn main() {
-  out = in;
-}
diff --git a/test/tint/buffer/storage/types/struct.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/types/struct.wgsl.expected.dxc.hlsl
deleted file mode 100644
index 05be600..0000000
--- a/test/tint/buffer/storage/types/struct.wgsl.expected.dxc.hlsl
+++ /dev/null
@@ -1,33 +0,0 @@
-struct Inner {
-  float f;
-};
-struct S {
-  Inner inner;
-};
-
-ByteAddressBuffer tint_symbol : register(t0, space0);
-RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
-
-void tint_symbol_3(RWByteAddressBuffer buffer, uint offset, Inner value) {
-  buffer.Store((offset + 0u), asuint(value.f));
-}
-
-void tint_symbol_2(RWByteAddressBuffer buffer, uint offset, S value) {
-  tint_symbol_3(buffer, (offset + 0u), value.inner);
-}
-
-Inner tint_symbol_6(ByteAddressBuffer buffer, uint offset) {
-  const Inner tint_symbol_8 = {asfloat(buffer.Load((offset + 0u)))};
-  return tint_symbol_8;
-}
-
-S tint_symbol_5(ByteAddressBuffer buffer, uint offset) {
-  const S tint_symbol_9 = {tint_symbol_6(buffer, (offset + 0u))};
-  return tint_symbol_9;
-}
-
-[numthreads(1, 1, 1)]
-void main() {
-  tint_symbol_2(tint_symbol_1, 0u, tint_symbol_5(tint_symbol, 0u));
-  return;
-}
diff --git a/test/tint/buffer/storage/types/struct.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/types/struct.wgsl.expected.fxc.hlsl
deleted file mode 100644
index 05be600..0000000
--- a/test/tint/buffer/storage/types/struct.wgsl.expected.fxc.hlsl
+++ /dev/null
@@ -1,33 +0,0 @@
-struct Inner {
-  float f;
-};
-struct S {
-  Inner inner;
-};
-
-ByteAddressBuffer tint_symbol : register(t0, space0);
-RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
-
-void tint_symbol_3(RWByteAddressBuffer buffer, uint offset, Inner value) {
-  buffer.Store((offset + 0u), asuint(value.f));
-}
-
-void tint_symbol_2(RWByteAddressBuffer buffer, uint offset, S value) {
-  tint_symbol_3(buffer, (offset + 0u), value.inner);
-}
-
-Inner tint_symbol_6(ByteAddressBuffer buffer, uint offset) {
-  const Inner tint_symbol_8 = {asfloat(buffer.Load((offset + 0u)))};
-  return tint_symbol_8;
-}
-
-S tint_symbol_5(ByteAddressBuffer buffer, uint offset) {
-  const S tint_symbol_9 = {tint_symbol_6(buffer, (offset + 0u))};
-  return tint_symbol_9;
-}
-
-[numthreads(1, 1, 1)]
-void main() {
-  tint_symbol_2(tint_symbol_1, 0u, tint_symbol_5(tint_symbol, 0u));
-  return;
-}
diff --git a/test/tint/buffer/storage/types/struct.wgsl.expected.msl b/test/tint/buffer/storage/types/struct.wgsl.expected.msl
deleted file mode 100644
index 7f042b2..0000000
--- a/test/tint/buffer/storage/types/struct.wgsl.expected.msl
+++ /dev/null
@@ -1,16 +0,0 @@
-#include <metal_stdlib>
-
-using namespace metal;
-struct Inner {
-  /* 0x0000 */ float f;
-};
-
-struct S {
-  /* 0x0000 */ Inner inner;
-};
-
-kernel void tint_symbol(device S* tint_symbol_1 [[buffer(0)]], const device S* tint_symbol_2 [[buffer(1)]]) {
-  *(tint_symbol_1) = *(tint_symbol_2);
-  return;
-}
-
diff --git a/test/tint/buffer/storage/types/struct.wgsl.expected.wgsl b/test/tint/buffer/storage/types/struct.wgsl.expected.wgsl
deleted file mode 100644
index ad3cde3..0000000
--- a/test/tint/buffer/storage/types/struct.wgsl.expected.wgsl
+++ /dev/null
@@ -1,16 +0,0 @@
-struct Inner {
-  f : f32,
-}
-
-struct S {
-  inner : Inner,
-}
-
-@group(0) @binding(0) var<storage, read> in : S;
-
-@group(0) @binding(1) var<storage, read_write> out : S;
-
-@compute @workgroup_size(1)
-fn main() {
-  out = in;
-}
diff --git a/test/tint/buffer/storage/types/struct_f16.wgsl b/test/tint/buffer/storage/types/struct_f16.wgsl
new file mode 100644
index 0000000..4e91562
--- /dev/null
+++ b/test/tint/buffer/storage/types/struct_f16.wgsl
@@ -0,0 +1,22 @@
+enable f16;
+
+struct Inner {
+  scalar_f16 : f16,
+  vec3_f16 : vec3<f16>,
+  mat2x4_f16 : mat2x4<f16>,
+};
+struct S {
+  inner : Inner,
+};
+
+@group(0) @binding(0)
+var<storage, read> in : S;
+
+@group(0) @binding(1)
+var<storage, read_write> out : S;
+
+@compute @workgroup_size(1)
+fn main() {
+  let t = in;
+  out = t;
+}
diff --git a/test/tint/buffer/storage/types/struct_f16.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/types/struct_f16.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..9a48940
--- /dev/null
+++ b/test/tint/buffer/storage/types/struct_f16.wgsl.expected.dxc.hlsl
@@ -0,0 +1,47 @@
+struct Inner {
+  float16_t scalar_f16;
+  vector<float16_t, 3> vec3_f16;
+  matrix<float16_t, 2, 4> mat2x4_f16;
+};
+struct S {
+  Inner inner;
+};
+
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+matrix<float16_t, 2, 4> tint_symbol_6(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 2, 4>(buffer.Load<vector<float16_t, 4> >((offset + 0u)), buffer.Load<vector<float16_t, 4> >((offset + 8u)));
+}
+
+Inner tint_symbol_3(ByteAddressBuffer buffer, uint offset) {
+  const Inner tint_symbol_14 = {buffer.Load<float16_t>((offset + 0u)), buffer.Load<vector<float16_t, 3> >((offset + 8u)), tint_symbol_6(buffer, (offset + 16u))};
+  return tint_symbol_14;
+}
+
+S tint_symbol_2(ByteAddressBuffer buffer, uint offset) {
+  const S tint_symbol_15 = {tint_symbol_3(buffer, (offset + 0u))};
+  return tint_symbol_15;
+}
+
+void tint_symbol_12(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 2, 4> value) {
+  buffer.Store<vector<float16_t, 4> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 8u), value[1u]);
+}
+
+void tint_symbol_9(RWByteAddressBuffer buffer, uint offset, Inner value) {
+  buffer.Store<float16_t>((offset + 0u), value.scalar_f16);
+  buffer.Store<vector<float16_t, 3> >((offset + 8u), value.vec3_f16);
+  tint_symbol_12(buffer, (offset + 16u), value.mat2x4_f16);
+}
+
+void tint_symbol_8(RWByteAddressBuffer buffer, uint offset, S value) {
+  tint_symbol_9(buffer, (offset + 0u), value.inner);
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  const S t = tint_symbol_2(tint_symbol, 0u);
+  tint_symbol_8(tint_symbol_1, 0u, t);
+  return;
+}
diff --git a/test/tint/buffer/storage/types/struct_f16.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/types/struct_f16.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..c4b0487
--- /dev/null
+++ b/test/tint/buffer/storage/types/struct_f16.wgsl.expected.fxc.hlsl
@@ -0,0 +1,52 @@
+SKIP: FAILED
+
+struct Inner {
+  float16_t scalar_f16;
+  vector<float16_t, 3> vec3_f16;
+  matrix<float16_t, 2, 4> mat2x4_f16;
+};
+struct S {
+  Inner inner;
+};
+
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+matrix<float16_t, 2, 4> tint_symbol_6(ByteAddressBuffer buffer, uint offset) {
+  return matrix<float16_t, 2, 4>(buffer.Load<vector<float16_t, 4> >((offset + 0u)), buffer.Load<vector<float16_t, 4> >((offset + 8u)));
+}
+
+Inner tint_symbol_3(ByteAddressBuffer buffer, uint offset) {
+  const Inner tint_symbol_14 = {buffer.Load<float16_t>((offset + 0u)), buffer.Load<vector<float16_t, 3> >((offset + 8u)), tint_symbol_6(buffer, (offset + 16u))};
+  return tint_symbol_14;
+}
+
+S tint_symbol_2(ByteAddressBuffer buffer, uint offset) {
+  const S tint_symbol_15 = {tint_symbol_3(buffer, (offset + 0u))};
+  return tint_symbol_15;
+}
+
+void tint_symbol_12(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 2, 4> value) {
+  buffer.Store<vector<float16_t, 4> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 8u), value[1u]);
+}
+
+void tint_symbol_9(RWByteAddressBuffer buffer, uint offset, Inner value) {
+  buffer.Store<float16_t>((offset + 0u), value.scalar_f16);
+  buffer.Store<vector<float16_t, 3> >((offset + 8u), value.vec3_f16);
+  tint_symbol_12(buffer, (offset + 16u), value.mat2x4_f16);
+}
+
+void tint_symbol_8(RWByteAddressBuffer buffer, uint offset, S value) {
+  tint_symbol_9(buffer, (offset + 0u), value.inner);
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  const S t = tint_symbol_2(tint_symbol, 0u);
+  tint_symbol_8(tint_symbol_1, 0u, t);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001A50B947690(2,3-11): error X3000: unrecognized identifier 'float16_t'
+
diff --git a/test/tint/buffer/storage/types/struct_f16.wgsl.expected.glsl b/test/tint/buffer/storage/types/struct_f16.wgsl.expected.glsl
new file mode 100644
index 0000000..341d140
--- /dev/null
+++ b/test/tint/buffer/storage/types/struct_f16.wgsl.expected.glsl
@@ -0,0 +1,32 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct Inner {
+  float16_t scalar_f16;
+  uint pad;
+  f16vec3 vec3_f16;
+  f16mat2x4 mat2x4_f16;
+};
+
+struct S {
+  Inner inner;
+};
+
+layout(binding = 0, std430) buffer tint_symbol_block_ssbo {
+  S inner;
+} tint_symbol;
+
+layout(binding = 1, std430) buffer tint_symbol_block_ssbo_1 {
+  S inner;
+} tint_symbol_1;
+
+void tint_symbol_2() {
+  S t = tint_symbol.inner;
+  tint_symbol_1.inner = t;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol_2();
+  return;
+}
diff --git a/test/tint/buffer/storage/types/struct_f16.wgsl.expected.msl b/test/tint/buffer/storage/types/struct_f16.wgsl.expected.msl
new file mode 100644
index 0000000..ffb7311
--- /dev/null
+++ b/test/tint/buffer/storage/types/struct_f16.wgsl.expected.msl
@@ -0,0 +1,34 @@
+#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 Inner {
+  /* 0x0000 */ half scalar_f16;
+  /* 0x0002 */ tint_array<int8_t, 6> tint_pad;
+  /* 0x0008 */ packed_half3 vec3_f16;
+  /* 0x000e */ tint_array<int8_t, 2> tint_pad_1;
+  /* 0x0010 */ half2x4 mat2x4_f16;
+};
+
+struct S {
+  /* 0x0000 */ Inner inner;
+};
+
+kernel void tint_symbol(const device S* tint_symbol_1 [[buffer(1)]], device S* tint_symbol_2 [[buffer(0)]]) {
+  S const t = *(tint_symbol_1);
+  *(tint_symbol_2) = t;
+  return;
+}
+
diff --git a/test/tint/buffer/storage/types/struct_f16.wgsl.expected.spvasm b/test/tint/buffer/storage/types/struct_f16.wgsl.expected.spvasm
new file mode 100644
index 0000000..d981f5e
--- /dev/null
+++ b/test/tint/buffer/storage/types/struct_f16.wgsl.expected.spvasm
@@ -0,0 +1,60 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 21
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %in_block "in_block"
+               OpMemberName %in_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "inner"
+               OpName %Inner "Inner"
+               OpMemberName %Inner 0 "scalar_f16"
+               OpMemberName %Inner 1 "vec3_f16"
+               OpMemberName %Inner 2 "mat2x4_f16"
+               OpName %in "in"
+               OpName %out "out"
+               OpName %main "main"
+               OpDecorate %in_block Block
+               OpMemberDecorate %in_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %Inner 0 Offset 0
+               OpMemberDecorate %Inner 1 Offset 8
+               OpMemberDecorate %Inner 2 Offset 16
+               OpMemberDecorate %Inner 2 ColMajor
+               OpMemberDecorate %Inner 2 MatrixStride 8
+               OpDecorate %in NonWritable
+               OpDecorate %in DescriptorSet 0
+               OpDecorate %in Binding 0
+               OpDecorate %out DescriptorSet 0
+               OpDecorate %out Binding 1
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+     %v4half = OpTypeVector %half 4
+ %mat2v4half = OpTypeMatrix %v4half 2
+      %Inner = OpTypeStruct %half %v3half %mat2v4half
+          %S = OpTypeStruct %Inner
+   %in_block = OpTypeStruct %S
+%_ptr_StorageBuffer_in_block = OpTypePointer StorageBuffer %in_block
+         %in = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+        %out = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+       %void = OpTypeVoid
+         %11 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
+       %main = OpFunction %void None %11
+         %14 = OpLabel
+         %18 = OpAccessChain %_ptr_StorageBuffer_S %in %uint_0
+         %19 = OpLoad %S %18
+         %20 = OpAccessChain %_ptr_StorageBuffer_S %out %uint_0
+               OpStore %20 %19
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/storage/types/struct_f16.wgsl.expected.wgsl b/test/tint/buffer/storage/types/struct_f16.wgsl.expected.wgsl
new file mode 100644
index 0000000..72cd847
--- /dev/null
+++ b/test/tint/buffer/storage/types/struct_f16.wgsl.expected.wgsl
@@ -0,0 +1,21 @@
+enable f16;
+
+struct Inner {
+  scalar_f16 : f16,
+  vec3_f16 : vec3<f16>,
+  mat2x4_f16 : mat2x4<f16>,
+}
+
+struct S {
+  inner : Inner,
+}
+
+@group(0) @binding(0) var<storage, read> in : S;
+
+@group(0) @binding(1) var<storage, read_write> out : S;
+
+@compute @workgroup_size(1)
+fn main() {
+  let t = in;
+  out = t;
+}
diff --git a/test/tint/buffer/storage/types/struct_f32.wgsl b/test/tint/buffer/storage/types/struct_f32.wgsl
new file mode 100644
index 0000000..2c5ba50
--- /dev/null
+++ b/test/tint/buffer/storage/types/struct_f32.wgsl
@@ -0,0 +1,20 @@
+struct Inner {
+  scalar_f32 : f32,
+  vec3_f32 : vec3<f32>,
+  mat2x4_f32 : mat2x4<f32>,
+};
+struct S {
+  inner : Inner,
+};
+
+@group(0) @binding(0)
+var<storage, read> in : S;
+
+@group(0) @binding(1)
+var<storage, read_write> out : S;
+
+@compute @workgroup_size(1)
+fn main() {
+  let t = in;
+  out = t;
+}
diff --git a/test/tint/buffer/storage/types/struct_f32.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/types/struct_f32.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..b32317f
--- /dev/null
+++ b/test/tint/buffer/storage/types/struct_f32.wgsl.expected.dxc.hlsl
@@ -0,0 +1,47 @@
+struct Inner {
+  float scalar_f32;
+  float3 vec3_f32;
+  float2x4 mat2x4_f32;
+};
+struct S {
+  Inner inner;
+};
+
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+float2x4 tint_symbol_6(ByteAddressBuffer buffer, uint offset) {
+  return float2x4(asfloat(buffer.Load4((offset + 0u))), asfloat(buffer.Load4((offset + 16u))));
+}
+
+Inner tint_symbol_3(ByteAddressBuffer buffer, uint offset) {
+  const Inner tint_symbol_14 = {asfloat(buffer.Load((offset + 0u))), asfloat(buffer.Load3((offset + 16u))), tint_symbol_6(buffer, (offset + 32u))};
+  return tint_symbol_14;
+}
+
+S tint_symbol_2(ByteAddressBuffer buffer, uint offset) {
+  const S tint_symbol_15 = {tint_symbol_3(buffer, (offset + 0u))};
+  return tint_symbol_15;
+}
+
+void tint_symbol_12(RWByteAddressBuffer buffer, uint offset, float2x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+}
+
+void tint_symbol_9(RWByteAddressBuffer buffer, uint offset, Inner value) {
+  buffer.Store((offset + 0u), asuint(value.scalar_f32));
+  buffer.Store3((offset + 16u), asuint(value.vec3_f32));
+  tint_symbol_12(buffer, (offset + 32u), value.mat2x4_f32);
+}
+
+void tint_symbol_8(RWByteAddressBuffer buffer, uint offset, S value) {
+  tint_symbol_9(buffer, (offset + 0u), value.inner);
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  const S t = tint_symbol_2(tint_symbol, 0u);
+  tint_symbol_8(tint_symbol_1, 0u, t);
+  return;
+}
diff --git a/test/tint/buffer/storage/types/struct_f32.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/types/struct_f32.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..b32317f
--- /dev/null
+++ b/test/tint/buffer/storage/types/struct_f32.wgsl.expected.fxc.hlsl
@@ -0,0 +1,47 @@
+struct Inner {
+  float scalar_f32;
+  float3 vec3_f32;
+  float2x4 mat2x4_f32;
+};
+struct S {
+  Inner inner;
+};
+
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+float2x4 tint_symbol_6(ByteAddressBuffer buffer, uint offset) {
+  return float2x4(asfloat(buffer.Load4((offset + 0u))), asfloat(buffer.Load4((offset + 16u))));
+}
+
+Inner tint_symbol_3(ByteAddressBuffer buffer, uint offset) {
+  const Inner tint_symbol_14 = {asfloat(buffer.Load((offset + 0u))), asfloat(buffer.Load3((offset + 16u))), tint_symbol_6(buffer, (offset + 32u))};
+  return tint_symbol_14;
+}
+
+S tint_symbol_2(ByteAddressBuffer buffer, uint offset) {
+  const S tint_symbol_15 = {tint_symbol_3(buffer, (offset + 0u))};
+  return tint_symbol_15;
+}
+
+void tint_symbol_12(RWByteAddressBuffer buffer, uint offset, float2x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+}
+
+void tint_symbol_9(RWByteAddressBuffer buffer, uint offset, Inner value) {
+  buffer.Store((offset + 0u), asuint(value.scalar_f32));
+  buffer.Store3((offset + 16u), asuint(value.vec3_f32));
+  tint_symbol_12(buffer, (offset + 32u), value.mat2x4_f32);
+}
+
+void tint_symbol_8(RWByteAddressBuffer buffer, uint offset, S value) {
+  tint_symbol_9(buffer, (offset + 0u), value.inner);
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  const S t = tint_symbol_2(tint_symbol, 0u);
+  tint_symbol_8(tint_symbol_1, 0u, t);
+  return;
+}
diff --git a/test/tint/buffer/storage/types/struct_f32.wgsl.expected.glsl b/test/tint/buffer/storage/types/struct_f32.wgsl.expected.glsl
new file mode 100644
index 0000000..cd535d3
--- /dev/null
+++ b/test/tint/buffer/storage/types/struct_f32.wgsl.expected.glsl
@@ -0,0 +1,34 @@
+#version 310 es
+
+struct Inner {
+  float scalar_f32;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  vec3 vec3_f32;
+  uint pad_3;
+  mat2x4 mat2x4_f32;
+};
+
+struct S {
+  Inner inner;
+};
+
+layout(binding = 0, std430) buffer tint_symbol_block_ssbo {
+  S inner;
+} tint_symbol;
+
+layout(binding = 1, std430) buffer tint_symbol_block_ssbo_1 {
+  S inner;
+} tint_symbol_1;
+
+void tint_symbol_2() {
+  S t = tint_symbol.inner;
+  tint_symbol_1.inner = t;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol_2();
+  return;
+}
diff --git a/test/tint/buffer/storage/types/struct_f32.wgsl.expected.msl b/test/tint/buffer/storage/types/struct_f32.wgsl.expected.msl
new file mode 100644
index 0000000..0df3bc4
--- /dev/null
+++ b/test/tint/buffer/storage/types/struct_f32.wgsl.expected.msl
@@ -0,0 +1,34 @@
+#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 Inner {
+  /* 0x0000 */ float scalar_f32;
+  /* 0x0004 */ tint_array<int8_t, 12> tint_pad;
+  /* 0x0010 */ packed_float3 vec3_f32;
+  /* 0x001c */ tint_array<int8_t, 4> tint_pad_1;
+  /* 0x0020 */ float2x4 mat2x4_f32;
+};
+
+struct S {
+  /* 0x0000 */ Inner inner;
+};
+
+kernel void tint_symbol(const device S* tint_symbol_1 [[buffer(1)]], device S* tint_symbol_2 [[buffer(0)]]) {
+  S const t = *(tint_symbol_1);
+  *(tint_symbol_2) = t;
+  return;
+}
+
diff --git a/test/tint/buffer/storage/types/struct_f32.wgsl.expected.spvasm b/test/tint/buffer/storage/types/struct_f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..0da5cf1
--- /dev/null
+++ b/test/tint/buffer/storage/types/struct_f32.wgsl.expected.spvasm
@@ -0,0 +1,56 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 21
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %in_block "in_block"
+               OpMemberName %in_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "inner"
+               OpName %Inner "Inner"
+               OpMemberName %Inner 0 "scalar_f32"
+               OpMemberName %Inner 1 "vec3_f32"
+               OpMemberName %Inner 2 "mat2x4_f32"
+               OpName %in "in"
+               OpName %out "out"
+               OpName %main "main"
+               OpDecorate %in_block Block
+               OpMemberDecorate %in_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %Inner 0 Offset 0
+               OpMemberDecorate %Inner 1 Offset 16
+               OpMemberDecorate %Inner 2 Offset 32
+               OpMemberDecorate %Inner 2 ColMajor
+               OpMemberDecorate %Inner 2 MatrixStride 16
+               OpDecorate %in NonWritable
+               OpDecorate %in DescriptorSet 0
+               OpDecorate %in Binding 0
+               OpDecorate %out DescriptorSet 0
+               OpDecorate %out Binding 1
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+    %v4float = OpTypeVector %float 4
+%mat2v4float = OpTypeMatrix %v4float 2
+      %Inner = OpTypeStruct %float %v3float %mat2v4float
+          %S = OpTypeStruct %Inner
+   %in_block = OpTypeStruct %S
+%_ptr_StorageBuffer_in_block = OpTypePointer StorageBuffer %in_block
+         %in = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+        %out = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+       %void = OpTypeVoid
+         %11 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
+       %main = OpFunction %void None %11
+         %14 = OpLabel
+         %18 = OpAccessChain %_ptr_StorageBuffer_S %in %uint_0
+         %19 = OpLoad %S %18
+         %20 = OpAccessChain %_ptr_StorageBuffer_S %out %uint_0
+               OpStore %20 %19
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/storage/types/struct_f32.wgsl.expected.wgsl b/test/tint/buffer/storage/types/struct_f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..dde254b
--- /dev/null
+++ b/test/tint/buffer/storage/types/struct_f32.wgsl.expected.wgsl
@@ -0,0 +1,19 @@
+struct Inner {
+  scalar_f32 : f32,
+  vec3_f32 : vec3<f32>,
+  mat2x4_f32 : mat2x4<f32>,
+}
+
+struct S {
+  inner : Inner,
+}
+
+@group(0) @binding(0) var<storage, read> in : S;
+
+@group(0) @binding(1) var<storage, read_write> out : S;
+
+@compute @workgroup_size(1)
+fn main() {
+  let t = in;
+  out = t;
+}
diff --git a/test/tint/buffer/storage/types/vec2_f16.wgsl b/test/tint/buffer/storage/types/vec2_f16.wgsl
new file mode 100644
index 0000000..74e5f4b
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec2_f16.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0)
+var<storage, read> in : vec2<f16>;
+
+@group(0) @binding(1)
+var<storage, read_write> out : vec2<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/vec2_f16.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/types/vec2_f16.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..109befb
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec2_f16.wgsl.expected.dxc.hlsl
@@ -0,0 +1,8 @@
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_1.Store<vector<float16_t, 2> >(0u, tint_symbol.Load<vector<float16_t, 2> >(0u));
+  return;
+}
diff --git a/test/tint/buffer/storage/types/vec2_f16.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/types/vec2_f16.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..7756784
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec2_f16.wgsl.expected.fxc.hlsl
@@ -0,0 +1,13 @@
+SKIP: FAILED
+
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_1.Store<vector<float16_t, 2> >(0u, tint_symbol.Load<vector<float16_t, 2> >(0u));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000017510013100(6,3-21): error X3018: invalid subscript 'Store'
+
diff --git a/test/tint/buffer/storage/types/vec2_f16.wgsl.expected.glsl b/test/tint/buffer/storage/types/vec2_f16.wgsl.expected.glsl
new file mode 100644
index 0000000..1ff8c34
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec2_f16.wgsl.expected.glsl
@@ -0,0 +1,20 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std430) buffer tint_symbol_block_ssbo {
+  f16vec2 inner;
+} tint_symbol;
+
+layout(binding = 1, std430) buffer tint_symbol_block_ssbo_1 {
+  f16vec2 inner;
+} tint_symbol_1;
+
+void tint_symbol_2() {
+  tint_symbol_1.inner = tint_symbol.inner;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol_2();
+  return;
+}
diff --git a/test/tint/buffer/storage/types/vec2_f16.wgsl.expected.msl b/test/tint/buffer/storage/types/vec2_f16.wgsl.expected.msl
new file mode 100644
index 0000000..420e73b
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec2_f16.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(device half2* tint_symbol_1 [[buffer(0)]], const device half2* tint_symbol_2 [[buffer(1)]]) {
+  *(tint_symbol_1) = *(tint_symbol_2);
+  return;
+}
+
diff --git a/test/tint/buffer/storage/types/vec2_f16.wgsl.expected.spvasm b/test/tint/buffer/storage/types/vec2_f16.wgsl.expected.spvasm
new file mode 100644
index 0000000..3ecc71d
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec2_f16.wgsl.expected.spvasm
@@ -0,0 +1,44 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 17
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %in_block "in_block"
+               OpMemberName %in_block 0 "inner"
+               OpName %in "in"
+               OpName %out "out"
+               OpName %main "main"
+               OpDecorate %in_block Block
+               OpMemberDecorate %in_block 0 Offset 0
+               OpDecorate %in NonWritable
+               OpDecorate %in DescriptorSet 0
+               OpDecorate %in Binding 0
+               OpDecorate %out DescriptorSet 0
+               OpDecorate %out Binding 1
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+   %in_block = OpTypeStruct %v2half
+%_ptr_StorageBuffer_in_block = OpTypePointer StorageBuffer %in_block
+         %in = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+        %out = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+       %void = OpTypeVoid
+          %7 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_v2half = OpTypePointer StorageBuffer %v2half
+       %main = OpFunction %void None %7
+         %10 = OpLabel
+         %14 = OpAccessChain %_ptr_StorageBuffer_v2half %out %uint_0
+         %15 = OpAccessChain %_ptr_StorageBuffer_v2half %in %uint_0
+         %16 = OpLoad %v2half %15
+               OpStore %14 %16
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/storage/types/vec2_f16.wgsl.expected.wgsl b/test/tint/buffer/storage/types/vec2_f16.wgsl.expected.wgsl
new file mode 100644
index 0000000..197d6c1
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec2_f16.wgsl.expected.wgsl
@@ -0,0 +1,10 @@
+enable f16;
+
+@group(0) @binding(0) var<storage, read> in : vec2<f16>;
+
+@group(0) @binding(1) var<storage, read_write> out : vec2<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/vec2_f32.wgsl b/test/tint/buffer/storage/types/vec2_f32.wgsl
new file mode 100644
index 0000000..b274bfd
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec2_f32.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0)
+var<storage, read> in : vec2<f32>;
+
+@group(0) @binding(1)
+var<storage, read_write> out : vec2<f32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/vec2_f32.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/types/vec2_f32.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..0b35cb3
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec2_f32.wgsl.expected.dxc.hlsl
@@ -0,0 +1,8 @@
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_1.Store2(0u, asuint(asfloat(tint_symbol.Load2(0u))));
+  return;
+}
diff --git a/test/tint/buffer/storage/types/vec2_f32.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/types/vec2_f32.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..0b35cb3
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec2_f32.wgsl.expected.fxc.hlsl
@@ -0,0 +1,8 @@
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_1.Store2(0u, asuint(asfloat(tint_symbol.Load2(0u))));
+  return;
+}
diff --git a/test/tint/buffer/storage/types/vec2_f32.wgsl.expected.glsl b/test/tint/buffer/storage/types/vec2_f32.wgsl.expected.glsl
new file mode 100644
index 0000000..ffdfc2b
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec2_f32.wgsl.expected.glsl
@@ -0,0 +1,19 @@
+#version 310 es
+
+layout(binding = 0, std430) buffer tint_symbol_block_ssbo {
+  vec2 inner;
+} tint_symbol;
+
+layout(binding = 1, std430) buffer tint_symbol_block_ssbo_1 {
+  vec2 inner;
+} tint_symbol_1;
+
+void tint_symbol_2() {
+  tint_symbol_1.inner = tint_symbol.inner;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol_2();
+  return;
+}
diff --git a/test/tint/buffer/storage/types/vec2_f32.wgsl.expected.msl b/test/tint/buffer/storage/types/vec2_f32.wgsl.expected.msl
new file mode 100644
index 0000000..a0396b3
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec2_f32.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(device float2* tint_symbol_1 [[buffer(0)]], const device float2* tint_symbol_2 [[buffer(1)]]) {
+  *(tint_symbol_1) = *(tint_symbol_2);
+  return;
+}
+
diff --git a/test/tint/buffer/storage/types/vec2_f32.wgsl.expected.spvasm b/test/tint/buffer/storage/types/vec2_f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..95447ff
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec2_f32.wgsl.expected.spvasm
@@ -0,0 +1,40 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 17
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %in_block "in_block"
+               OpMemberName %in_block 0 "inner"
+               OpName %in "in"
+               OpName %out "out"
+               OpName %main "main"
+               OpDecorate %in_block Block
+               OpMemberDecorate %in_block 0 Offset 0
+               OpDecorate %in NonWritable
+               OpDecorate %in DescriptorSet 0
+               OpDecorate %in Binding 0
+               OpDecorate %out DescriptorSet 0
+               OpDecorate %out Binding 1
+      %float = OpTypeFloat 32
+    %v2float = OpTypeVector %float 2
+   %in_block = OpTypeStruct %v2float
+%_ptr_StorageBuffer_in_block = OpTypePointer StorageBuffer %in_block
+         %in = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+        %out = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+       %void = OpTypeVoid
+          %7 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_v2float = OpTypePointer StorageBuffer %v2float
+       %main = OpFunction %void None %7
+         %10 = OpLabel
+         %14 = OpAccessChain %_ptr_StorageBuffer_v2float %out %uint_0
+         %15 = OpAccessChain %_ptr_StorageBuffer_v2float %in %uint_0
+         %16 = OpLoad %v2float %15
+               OpStore %14 %16
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/storage/types/vec2_f32.wgsl.expected.wgsl b/test/tint/buffer/storage/types/vec2_f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..36117da
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec2_f32.wgsl.expected.wgsl
@@ -0,0 +1,8 @@
+@group(0) @binding(0) var<storage, read> in : vec2<f32>;
+
+@group(0) @binding(1) var<storage, read_write> out : vec2<f32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/vec2.wgsl b/test/tint/buffer/storage/types/vec2_i32.wgsl
similarity index 100%
rename from test/tint/buffer/storage/types/vec2.wgsl
rename to test/tint/buffer/storage/types/vec2_i32.wgsl
diff --git a/test/tint/buffer/storage/types/vec2.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/types/vec2_i32.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/storage/types/vec2.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/storage/types/vec2_i32.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/storage/types/vec2.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/types/vec2_i32.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/storage/types/vec2.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/storage/types/vec2_i32.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/storage/types/vec2.wgsl.expected.glsl b/test/tint/buffer/storage/types/vec2_i32.wgsl.expected.glsl
similarity index 100%
rename from test/tint/buffer/storage/types/vec2.wgsl.expected.glsl
rename to test/tint/buffer/storage/types/vec2_i32.wgsl.expected.glsl
diff --git a/test/tint/buffer/storage/types/vec2.wgsl.expected.msl b/test/tint/buffer/storage/types/vec2_i32.wgsl.expected.msl
similarity index 100%
rename from test/tint/buffer/storage/types/vec2.wgsl.expected.msl
rename to test/tint/buffer/storage/types/vec2_i32.wgsl.expected.msl
diff --git a/test/tint/buffer/storage/types/vec2.wgsl.expected.spvasm b/test/tint/buffer/storage/types/vec2_i32.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/storage/types/vec2.wgsl.expected.spvasm
rename to test/tint/buffer/storage/types/vec2_i32.wgsl.expected.spvasm
diff --git a/test/tint/buffer/storage/types/vec2.wgsl.expected.wgsl b/test/tint/buffer/storage/types/vec2_i32.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/buffer/storage/types/vec2.wgsl.expected.wgsl
rename to test/tint/buffer/storage/types/vec2_i32.wgsl.expected.wgsl
diff --git a/test/tint/buffer/storage/types/vec2_u32.wgsl b/test/tint/buffer/storage/types/vec2_u32.wgsl
new file mode 100644
index 0000000..345cbe7
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec2_u32.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0)
+var<storage, read> in : vec2<u32>;
+
+@group(0) @binding(1)
+var<storage, read_write> out : vec2<u32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/vec2_u32.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/types/vec2_u32.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..7acc823
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec2_u32.wgsl.expected.dxc.hlsl
@@ -0,0 +1,8 @@
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_1.Store2(0u, asuint(tint_symbol.Load2(0u)));
+  return;
+}
diff --git a/test/tint/buffer/storage/types/vec2_u32.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/types/vec2_u32.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..7acc823
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec2_u32.wgsl.expected.fxc.hlsl
@@ -0,0 +1,8 @@
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_1.Store2(0u, asuint(tint_symbol.Load2(0u)));
+  return;
+}
diff --git a/test/tint/buffer/storage/types/vec2_u32.wgsl.expected.glsl b/test/tint/buffer/storage/types/vec2_u32.wgsl.expected.glsl
new file mode 100644
index 0000000..269bd1f
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec2_u32.wgsl.expected.glsl
@@ -0,0 +1,19 @@
+#version 310 es
+
+layout(binding = 0, std430) buffer tint_symbol_block_ssbo {
+  uvec2 inner;
+} tint_symbol;
+
+layout(binding = 1, std430) buffer tint_symbol_block_ssbo_1 {
+  uvec2 inner;
+} tint_symbol_1;
+
+void tint_symbol_2() {
+  tint_symbol_1.inner = tint_symbol.inner;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol_2();
+  return;
+}
diff --git a/test/tint/buffer/storage/types/vec2_u32.wgsl.expected.msl b/test/tint/buffer/storage/types/vec2_u32.wgsl.expected.msl
new file mode 100644
index 0000000..412fcd1
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec2_u32.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(device uint2* tint_symbol_1 [[buffer(0)]], const device uint2* tint_symbol_2 [[buffer(1)]]) {
+  *(tint_symbol_1) = *(tint_symbol_2);
+  return;
+}
+
diff --git a/test/tint/buffer/storage/types/vec2_u32.wgsl.expected.spvasm b/test/tint/buffer/storage/types/vec2_u32.wgsl.expected.spvasm
new file mode 100644
index 0000000..f79e277
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec2_u32.wgsl.expected.spvasm
@@ -0,0 +1,39 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 16
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %in_block "in_block"
+               OpMemberName %in_block 0 "inner"
+               OpName %in "in"
+               OpName %out "out"
+               OpName %main "main"
+               OpDecorate %in_block Block
+               OpMemberDecorate %in_block 0 Offset 0
+               OpDecorate %in NonWritable
+               OpDecorate %in DescriptorSet 0
+               OpDecorate %in Binding 0
+               OpDecorate %out DescriptorSet 0
+               OpDecorate %out Binding 1
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+   %in_block = OpTypeStruct %v2uint
+%_ptr_StorageBuffer_in_block = OpTypePointer StorageBuffer %in_block
+         %in = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+        %out = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+       %void = OpTypeVoid
+          %7 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_v2uint = OpTypePointer StorageBuffer %v2uint
+       %main = OpFunction %void None %7
+         %10 = OpLabel
+         %13 = OpAccessChain %_ptr_StorageBuffer_v2uint %out %uint_0
+         %14 = OpAccessChain %_ptr_StorageBuffer_v2uint %in %uint_0
+         %15 = OpLoad %v2uint %14
+               OpStore %13 %15
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/storage/types/vec2_u32.wgsl.expected.wgsl b/test/tint/buffer/storage/types/vec2_u32.wgsl.expected.wgsl
new file mode 100644
index 0000000..cfe55fb
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec2_u32.wgsl.expected.wgsl
@@ -0,0 +1,8 @@
+@group(0) @binding(0) var<storage, read> in : vec2<u32>;
+
+@group(0) @binding(1) var<storage, read_write> out : vec2<u32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/vec3_f16.wgsl b/test/tint/buffer/storage/types/vec3_f16.wgsl
new file mode 100644
index 0000000..ec8914a
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec3_f16.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0)
+var<storage, read> in : vec3<f16>;
+
+@group(0) @binding(1)
+var<storage, read_write> out : vec3<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/vec3_f16.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/types/vec3_f16.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..9bb54e8
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec3_f16.wgsl.expected.dxc.hlsl
@@ -0,0 +1,8 @@
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_1.Store<vector<float16_t, 3> >(0u, tint_symbol.Load<vector<float16_t, 3> >(0u));
+  return;
+}
diff --git a/test/tint/buffer/storage/types/vec3_f16.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/types/vec3_f16.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..8354072
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec3_f16.wgsl.expected.fxc.hlsl
@@ -0,0 +1,13 @@
+SKIP: FAILED
+
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_1.Store<vector<float16_t, 3> >(0u, tint_symbol.Load<vector<float16_t, 3> >(0u));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x00000207E7334340(6,3-21): error X3018: invalid subscript 'Store'
+
diff --git a/test/tint/buffer/storage/types/vec3_f16.wgsl.expected.glsl b/test/tint/buffer/storage/types/vec3_f16.wgsl.expected.glsl
new file mode 100644
index 0000000..ce9061f
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec3_f16.wgsl.expected.glsl
@@ -0,0 +1,20 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std430) buffer tint_symbol_block_ssbo {
+  f16vec3 inner;
+} tint_symbol;
+
+layout(binding = 1, std430) buffer tint_symbol_block_ssbo_1 {
+  f16vec3 inner;
+} tint_symbol_1;
+
+void tint_symbol_2() {
+  tint_symbol_1.inner = tint_symbol.inner;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol_2();
+  return;
+}
diff --git a/test/tint/buffer/storage/types/vec3_f16.wgsl.expected.msl b/test/tint/buffer/storage/types/vec3_f16.wgsl.expected.msl
new file mode 100644
index 0000000..d5bfb88
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec3_f16.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(device half3* tint_symbol_1 [[buffer(0)]], const device half3* tint_symbol_2 [[buffer(1)]]) {
+  *(tint_symbol_1) = *(tint_symbol_2);
+  return;
+}
+
diff --git a/test/tint/buffer/storage/types/vec3_f16.wgsl.expected.spvasm b/test/tint/buffer/storage/types/vec3_f16.wgsl.expected.spvasm
new file mode 100644
index 0000000..21de92d
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec3_f16.wgsl.expected.spvasm
@@ -0,0 +1,44 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 17
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %in_block "in_block"
+               OpMemberName %in_block 0 "inner"
+               OpName %in "in"
+               OpName %out "out"
+               OpName %main "main"
+               OpDecorate %in_block Block
+               OpMemberDecorate %in_block 0 Offset 0
+               OpDecorate %in NonWritable
+               OpDecorate %in DescriptorSet 0
+               OpDecorate %in Binding 0
+               OpDecorate %out DescriptorSet 0
+               OpDecorate %out Binding 1
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+   %in_block = OpTypeStruct %v3half
+%_ptr_StorageBuffer_in_block = OpTypePointer StorageBuffer %in_block
+         %in = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+        %out = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+       %void = OpTypeVoid
+          %7 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_v3half = OpTypePointer StorageBuffer %v3half
+       %main = OpFunction %void None %7
+         %10 = OpLabel
+         %14 = OpAccessChain %_ptr_StorageBuffer_v3half %out %uint_0
+         %15 = OpAccessChain %_ptr_StorageBuffer_v3half %in %uint_0
+         %16 = OpLoad %v3half %15
+               OpStore %14 %16
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/storage/types/vec3_f16.wgsl.expected.wgsl b/test/tint/buffer/storage/types/vec3_f16.wgsl.expected.wgsl
new file mode 100644
index 0000000..b49d6f3
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec3_f16.wgsl.expected.wgsl
@@ -0,0 +1,10 @@
+enable f16;
+
+@group(0) @binding(0) var<storage, read> in : vec3<f16>;
+
+@group(0) @binding(1) var<storage, read_write> out : vec3<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/vec3_f32.wgsl b/test/tint/buffer/storage/types/vec3_f32.wgsl
new file mode 100644
index 0000000..b0bd77a
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec3_f32.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0)
+var<storage, read> in : vec3<f32>;
+
+@group(0) @binding(1)
+var<storage, read_write> out : vec3<f32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/vec3_f32.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/types/vec3_f32.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..fa40436
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec3_f32.wgsl.expected.dxc.hlsl
@@ -0,0 +1,8 @@
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_1.Store3(0u, asuint(asfloat(tint_symbol.Load3(0u))));
+  return;
+}
diff --git a/test/tint/buffer/storage/types/vec3_f32.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/types/vec3_f32.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..fa40436
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec3_f32.wgsl.expected.fxc.hlsl
@@ -0,0 +1,8 @@
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_1.Store3(0u, asuint(asfloat(tint_symbol.Load3(0u))));
+  return;
+}
diff --git a/test/tint/buffer/storage/types/vec3_f32.wgsl.expected.glsl b/test/tint/buffer/storage/types/vec3_f32.wgsl.expected.glsl
new file mode 100644
index 0000000..fc44035
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec3_f32.wgsl.expected.glsl
@@ -0,0 +1,19 @@
+#version 310 es
+
+layout(binding = 0, std430) buffer tint_symbol_block_ssbo {
+  vec3 inner;
+} tint_symbol;
+
+layout(binding = 1, std430) buffer tint_symbol_block_ssbo_1 {
+  vec3 inner;
+} tint_symbol_1;
+
+void tint_symbol_2() {
+  tint_symbol_1.inner = tint_symbol.inner;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol_2();
+  return;
+}
diff --git a/test/tint/buffer/storage/types/vec3_f32.wgsl.expected.msl b/test/tint/buffer/storage/types/vec3_f32.wgsl.expected.msl
new file mode 100644
index 0000000..800b609
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec3_f32.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(device float3* tint_symbol_1 [[buffer(0)]], const device float3* tint_symbol_2 [[buffer(1)]]) {
+  *(tint_symbol_1) = *(tint_symbol_2);
+  return;
+}
+
diff --git a/test/tint/buffer/storage/types/vec3_f32.wgsl.expected.spvasm b/test/tint/buffer/storage/types/vec3_f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..f6c29a4
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec3_f32.wgsl.expected.spvasm
@@ -0,0 +1,40 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 17
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %in_block "in_block"
+               OpMemberName %in_block 0 "inner"
+               OpName %in "in"
+               OpName %out "out"
+               OpName %main "main"
+               OpDecorate %in_block Block
+               OpMemberDecorate %in_block 0 Offset 0
+               OpDecorate %in NonWritable
+               OpDecorate %in DescriptorSet 0
+               OpDecorate %in Binding 0
+               OpDecorate %out DescriptorSet 0
+               OpDecorate %out Binding 1
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+   %in_block = OpTypeStruct %v3float
+%_ptr_StorageBuffer_in_block = OpTypePointer StorageBuffer %in_block
+         %in = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+        %out = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+       %void = OpTypeVoid
+          %7 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_v3float = OpTypePointer StorageBuffer %v3float
+       %main = OpFunction %void None %7
+         %10 = OpLabel
+         %14 = OpAccessChain %_ptr_StorageBuffer_v3float %out %uint_0
+         %15 = OpAccessChain %_ptr_StorageBuffer_v3float %in %uint_0
+         %16 = OpLoad %v3float %15
+               OpStore %14 %16
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/storage/types/vec3_f32.wgsl.expected.wgsl b/test/tint/buffer/storage/types/vec3_f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..5e4581e
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec3_f32.wgsl.expected.wgsl
@@ -0,0 +1,8 @@
+@group(0) @binding(0) var<storage, read> in : vec3<f32>;
+
+@group(0) @binding(1) var<storage, read_write> out : vec3<f32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/vec3_i32.wgsl b/test/tint/buffer/storage/types/vec3_i32.wgsl
new file mode 100644
index 0000000..2d123ab
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec3_i32.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0)
+var<storage, read> in : vec3<i32>;
+
+@group(0) @binding(1)
+var<storage, read_write> out : vec3<i32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/vec3_i32.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/types/vec3_i32.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..66af38f
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec3_i32.wgsl.expected.dxc.hlsl
@@ -0,0 +1,8 @@
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_1.Store3(0u, asuint(asint(tint_symbol.Load3(0u))));
+  return;
+}
diff --git a/test/tint/buffer/storage/types/vec3_i32.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/types/vec3_i32.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..66af38f
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec3_i32.wgsl.expected.fxc.hlsl
@@ -0,0 +1,8 @@
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_1.Store3(0u, asuint(asint(tint_symbol.Load3(0u))));
+  return;
+}
diff --git a/test/tint/buffer/storage/types/vec3_i32.wgsl.expected.glsl b/test/tint/buffer/storage/types/vec3_i32.wgsl.expected.glsl
new file mode 100644
index 0000000..2e4649d
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec3_i32.wgsl.expected.glsl
@@ -0,0 +1,19 @@
+#version 310 es
+
+layout(binding = 0, std430) buffer tint_symbol_block_ssbo {
+  ivec3 inner;
+} tint_symbol;
+
+layout(binding = 1, std430) buffer tint_symbol_block_ssbo_1 {
+  ivec3 inner;
+} tint_symbol_1;
+
+void tint_symbol_2() {
+  tint_symbol_1.inner = tint_symbol.inner;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol_2();
+  return;
+}
diff --git a/test/tint/buffer/storage/types/vec3_i32.wgsl.expected.msl b/test/tint/buffer/storage/types/vec3_i32.wgsl.expected.msl
new file mode 100644
index 0000000..d056869
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec3_i32.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(device int3* tint_symbol_1 [[buffer(0)]], const device int3* tint_symbol_2 [[buffer(1)]]) {
+  *(tint_symbol_1) = *(tint_symbol_2);
+  return;
+}
+
diff --git a/test/tint/buffer/storage/types/vec3_i32.wgsl.expected.spvasm b/test/tint/buffer/storage/types/vec3_i32.wgsl.expected.spvasm
new file mode 100644
index 0000000..aaebcf5
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec3_i32.wgsl.expected.spvasm
@@ -0,0 +1,40 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 17
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %in_block "in_block"
+               OpMemberName %in_block 0 "inner"
+               OpName %in "in"
+               OpName %out "out"
+               OpName %main "main"
+               OpDecorate %in_block Block
+               OpMemberDecorate %in_block 0 Offset 0
+               OpDecorate %in NonWritable
+               OpDecorate %in DescriptorSet 0
+               OpDecorate %in Binding 0
+               OpDecorate %out DescriptorSet 0
+               OpDecorate %out Binding 1
+        %int = OpTypeInt 32 1
+      %v3int = OpTypeVector %int 3
+   %in_block = OpTypeStruct %v3int
+%_ptr_StorageBuffer_in_block = OpTypePointer StorageBuffer %in_block
+         %in = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+        %out = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+       %void = OpTypeVoid
+          %7 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_v3int = OpTypePointer StorageBuffer %v3int
+       %main = OpFunction %void None %7
+         %10 = OpLabel
+         %14 = OpAccessChain %_ptr_StorageBuffer_v3int %out %uint_0
+         %15 = OpAccessChain %_ptr_StorageBuffer_v3int %in %uint_0
+         %16 = OpLoad %v3int %15
+               OpStore %14 %16
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/storage/types/vec3_i32.wgsl.expected.wgsl b/test/tint/buffer/storage/types/vec3_i32.wgsl.expected.wgsl
new file mode 100644
index 0000000..89bfe47
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec3_i32.wgsl.expected.wgsl
@@ -0,0 +1,8 @@
+@group(0) @binding(0) var<storage, read> in : vec3<i32>;
+
+@group(0) @binding(1) var<storage, read_write> out : vec3<i32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/vec3.wgsl b/test/tint/buffer/storage/types/vec3_u32.wgsl
similarity index 100%
rename from test/tint/buffer/storage/types/vec3.wgsl
rename to test/tint/buffer/storage/types/vec3_u32.wgsl
diff --git a/test/tint/buffer/storage/types/vec3.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/types/vec3_u32.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/storage/types/vec3.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/storage/types/vec3_u32.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/storage/types/vec3.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/types/vec3_u32.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/storage/types/vec3.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/storage/types/vec3_u32.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/storage/types/vec3.wgsl.expected.glsl b/test/tint/buffer/storage/types/vec3_u32.wgsl.expected.glsl
similarity index 100%
rename from test/tint/buffer/storage/types/vec3.wgsl.expected.glsl
rename to test/tint/buffer/storage/types/vec3_u32.wgsl.expected.glsl
diff --git a/test/tint/buffer/storage/types/vec3.wgsl.expected.msl b/test/tint/buffer/storage/types/vec3_u32.wgsl.expected.msl
similarity index 100%
rename from test/tint/buffer/storage/types/vec3.wgsl.expected.msl
rename to test/tint/buffer/storage/types/vec3_u32.wgsl.expected.msl
diff --git a/test/tint/buffer/storage/types/vec3.wgsl.expected.spvasm b/test/tint/buffer/storage/types/vec3_u32.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/storage/types/vec3.wgsl.expected.spvasm
rename to test/tint/buffer/storage/types/vec3_u32.wgsl.expected.spvasm
diff --git a/test/tint/buffer/storage/types/vec3.wgsl.expected.wgsl b/test/tint/buffer/storage/types/vec3_u32.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/buffer/storage/types/vec3.wgsl.expected.wgsl
rename to test/tint/buffer/storage/types/vec3_u32.wgsl.expected.wgsl
diff --git a/test/tint/buffer/storage/types/vec4_f16.wgsl b/test/tint/buffer/storage/types/vec4_f16.wgsl
new file mode 100644
index 0000000..8afe29f
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec4_f16.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0)
+var<storage, read> in : vec4<f16>;
+
+@group(0) @binding(1)
+var<storage, read_write> out : vec4<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/vec4_f16.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/types/vec4_f16.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..0fea94d
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec4_f16.wgsl.expected.dxc.hlsl
@@ -0,0 +1,8 @@
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_1.Store<vector<float16_t, 4> >(0u, tint_symbol.Load<vector<float16_t, 4> >(0u));
+  return;
+}
diff --git a/test/tint/buffer/storage/types/vec4_f16.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/types/vec4_f16.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..5910328
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec4_f16.wgsl.expected.fxc.hlsl
@@ -0,0 +1,13 @@
+SKIP: FAILED
+
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_1.Store<vector<float16_t, 4> >(0u, tint_symbol.Load<vector<float16_t, 4> >(0u));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001D5DD394680(6,3-21): error X3018: invalid subscript 'Store'
+
diff --git a/test/tint/buffer/storage/types/vec4_f16.wgsl.expected.glsl b/test/tint/buffer/storage/types/vec4_f16.wgsl.expected.glsl
new file mode 100644
index 0000000..e8e1dde
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec4_f16.wgsl.expected.glsl
@@ -0,0 +1,20 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std430) buffer tint_symbol_block_ssbo {
+  f16vec4 inner;
+} tint_symbol;
+
+layout(binding = 1, std430) buffer tint_symbol_block_ssbo_1 {
+  f16vec4 inner;
+} tint_symbol_1;
+
+void tint_symbol_2() {
+  tint_symbol_1.inner = tint_symbol.inner;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol_2();
+  return;
+}
diff --git a/test/tint/buffer/storage/types/vec4_f16.wgsl.expected.msl b/test/tint/buffer/storage/types/vec4_f16.wgsl.expected.msl
new file mode 100644
index 0000000..fb77d9b
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec4_f16.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(device half4* tint_symbol_1 [[buffer(0)]], const device half4* tint_symbol_2 [[buffer(1)]]) {
+  *(tint_symbol_1) = *(tint_symbol_2);
+  return;
+}
+
diff --git a/test/tint/buffer/storage/types/vec4_f16.wgsl.expected.spvasm b/test/tint/buffer/storage/types/vec4_f16.wgsl.expected.spvasm
new file mode 100644
index 0000000..1054de34c
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec4_f16.wgsl.expected.spvasm
@@ -0,0 +1,44 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 17
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %in_block "in_block"
+               OpMemberName %in_block 0 "inner"
+               OpName %in "in"
+               OpName %out "out"
+               OpName %main "main"
+               OpDecorate %in_block Block
+               OpMemberDecorate %in_block 0 Offset 0
+               OpDecorate %in NonWritable
+               OpDecorate %in DescriptorSet 0
+               OpDecorate %in Binding 0
+               OpDecorate %out DescriptorSet 0
+               OpDecorate %out Binding 1
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+   %in_block = OpTypeStruct %v4half
+%_ptr_StorageBuffer_in_block = OpTypePointer StorageBuffer %in_block
+         %in = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+        %out = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+       %void = OpTypeVoid
+          %7 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_v4half = OpTypePointer StorageBuffer %v4half
+       %main = OpFunction %void None %7
+         %10 = OpLabel
+         %14 = OpAccessChain %_ptr_StorageBuffer_v4half %out %uint_0
+         %15 = OpAccessChain %_ptr_StorageBuffer_v4half %in %uint_0
+         %16 = OpLoad %v4half %15
+               OpStore %14 %16
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/storage/types/vec4_f16.wgsl.expected.wgsl b/test/tint/buffer/storage/types/vec4_f16.wgsl.expected.wgsl
new file mode 100644
index 0000000..7c54506
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec4_f16.wgsl.expected.wgsl
@@ -0,0 +1,10 @@
+enable f16;
+
+@group(0) @binding(0) var<storage, read> in : vec4<f16>;
+
+@group(0) @binding(1) var<storage, read_write> out : vec4<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/vec4.wgsl b/test/tint/buffer/storage/types/vec4_f32.wgsl
similarity index 100%
rename from test/tint/buffer/storage/types/vec4.wgsl
rename to test/tint/buffer/storage/types/vec4_f32.wgsl
diff --git a/test/tint/buffer/storage/types/vec4.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/types/vec4_f32.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/storage/types/vec4.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/storage/types/vec4_f32.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/storage/types/vec4.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/types/vec4_f32.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/storage/types/vec4.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/storage/types/vec4_f32.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/storage/types/vec4.wgsl.expected.glsl b/test/tint/buffer/storage/types/vec4_f32.wgsl.expected.glsl
similarity index 100%
rename from test/tint/buffer/storage/types/vec4.wgsl.expected.glsl
rename to test/tint/buffer/storage/types/vec4_f32.wgsl.expected.glsl
diff --git a/test/tint/buffer/storage/types/vec4.wgsl.expected.msl b/test/tint/buffer/storage/types/vec4_f32.wgsl.expected.msl
similarity index 100%
rename from test/tint/buffer/storage/types/vec4.wgsl.expected.msl
rename to test/tint/buffer/storage/types/vec4_f32.wgsl.expected.msl
diff --git a/test/tint/buffer/storage/types/vec4.wgsl.expected.spvasm b/test/tint/buffer/storage/types/vec4_f32.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/storage/types/vec4.wgsl.expected.spvasm
rename to test/tint/buffer/storage/types/vec4_f32.wgsl.expected.spvasm
diff --git a/test/tint/buffer/storage/types/vec4.wgsl.expected.wgsl b/test/tint/buffer/storage/types/vec4_f32.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/buffer/storage/types/vec4.wgsl.expected.wgsl
rename to test/tint/buffer/storage/types/vec4_f32.wgsl.expected.wgsl
diff --git a/test/tint/buffer/storage/types/vec4_i32.wgsl b/test/tint/buffer/storage/types/vec4_i32.wgsl
new file mode 100644
index 0000000..8f5f825
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec4_i32.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0)
+var<storage, read> in : vec4<i32>;
+
+@group(0) @binding(1)
+var<storage, read_write> out : vec4<i32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/vec4_i32.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/types/vec4_i32.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..3e5b3f6
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec4_i32.wgsl.expected.dxc.hlsl
@@ -0,0 +1,8 @@
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_1.Store4(0u, asuint(asint(tint_symbol.Load4(0u))));
+  return;
+}
diff --git a/test/tint/buffer/storage/types/vec4_i32.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/types/vec4_i32.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..3e5b3f6
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec4_i32.wgsl.expected.fxc.hlsl
@@ -0,0 +1,8 @@
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_1.Store4(0u, asuint(asint(tint_symbol.Load4(0u))));
+  return;
+}
diff --git a/test/tint/buffer/storage/types/vec4_i32.wgsl.expected.glsl b/test/tint/buffer/storage/types/vec4_i32.wgsl.expected.glsl
new file mode 100644
index 0000000..5c3c067
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec4_i32.wgsl.expected.glsl
@@ -0,0 +1,19 @@
+#version 310 es
+
+layout(binding = 0, std430) buffer tint_symbol_block_ssbo {
+  ivec4 inner;
+} tint_symbol;
+
+layout(binding = 1, std430) buffer tint_symbol_block_ssbo_1 {
+  ivec4 inner;
+} tint_symbol_1;
+
+void tint_symbol_2() {
+  tint_symbol_1.inner = tint_symbol.inner;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol_2();
+  return;
+}
diff --git a/test/tint/buffer/storage/types/vec4_i32.wgsl.expected.msl b/test/tint/buffer/storage/types/vec4_i32.wgsl.expected.msl
new file mode 100644
index 0000000..56e60b0
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec4_i32.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(device int4* tint_symbol_1 [[buffer(0)]], const device int4* tint_symbol_2 [[buffer(1)]]) {
+  *(tint_symbol_1) = *(tint_symbol_2);
+  return;
+}
+
diff --git a/test/tint/buffer/storage/types/vec4_i32.wgsl.expected.spvasm b/test/tint/buffer/storage/types/vec4_i32.wgsl.expected.spvasm
new file mode 100644
index 0000000..e7ec0df
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec4_i32.wgsl.expected.spvasm
@@ -0,0 +1,40 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 17
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %in_block "in_block"
+               OpMemberName %in_block 0 "inner"
+               OpName %in "in"
+               OpName %out "out"
+               OpName %main "main"
+               OpDecorate %in_block Block
+               OpMemberDecorate %in_block 0 Offset 0
+               OpDecorate %in NonWritable
+               OpDecorate %in DescriptorSet 0
+               OpDecorate %in Binding 0
+               OpDecorate %out DescriptorSet 0
+               OpDecorate %out Binding 1
+        %int = OpTypeInt 32 1
+      %v4int = OpTypeVector %int 4
+   %in_block = OpTypeStruct %v4int
+%_ptr_StorageBuffer_in_block = OpTypePointer StorageBuffer %in_block
+         %in = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+        %out = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+       %void = OpTypeVoid
+          %7 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_v4int = OpTypePointer StorageBuffer %v4int
+       %main = OpFunction %void None %7
+         %10 = OpLabel
+         %14 = OpAccessChain %_ptr_StorageBuffer_v4int %out %uint_0
+         %15 = OpAccessChain %_ptr_StorageBuffer_v4int %in %uint_0
+         %16 = OpLoad %v4int %15
+               OpStore %14 %16
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/storage/types/vec4_i32.wgsl.expected.wgsl b/test/tint/buffer/storage/types/vec4_i32.wgsl.expected.wgsl
new file mode 100644
index 0000000..c9774fb
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec4_i32.wgsl.expected.wgsl
@@ -0,0 +1,8 @@
+@group(0) @binding(0) var<storage, read> in : vec4<i32>;
+
+@group(0) @binding(1) var<storage, read_write> out : vec4<i32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/vec4_u32.wgsl b/test/tint/buffer/storage/types/vec4_u32.wgsl
new file mode 100644
index 0000000..9542278
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec4_u32.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0)
+var<storage, read> in : vec4<u32>;
+
+@group(0) @binding(1)
+var<storage, read_write> out : vec4<u32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/storage/types/vec4_u32.wgsl.expected.dxc.hlsl b/test/tint/buffer/storage/types/vec4_u32.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..59665d7
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec4_u32.wgsl.expected.dxc.hlsl
@@ -0,0 +1,8 @@
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_1.Store4(0u, asuint(tint_symbol.Load4(0u)));
+  return;
+}
diff --git a/test/tint/buffer/storage/types/vec4_u32.wgsl.expected.fxc.hlsl b/test/tint/buffer/storage/types/vec4_u32.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..59665d7
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec4_u32.wgsl.expected.fxc.hlsl
@@ -0,0 +1,8 @@
+ByteAddressBuffer tint_symbol : register(t0, space0);
+RWByteAddressBuffer tint_symbol_1 : register(u1, space0);
+
+[numthreads(1, 1, 1)]
+void main() {
+  tint_symbol_1.Store4(0u, asuint(tint_symbol.Load4(0u)));
+  return;
+}
diff --git a/test/tint/buffer/storage/types/vec4_u32.wgsl.expected.glsl b/test/tint/buffer/storage/types/vec4_u32.wgsl.expected.glsl
new file mode 100644
index 0000000..ff88441
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec4_u32.wgsl.expected.glsl
@@ -0,0 +1,19 @@
+#version 310 es
+
+layout(binding = 0, std430) buffer tint_symbol_block_ssbo {
+  uvec4 inner;
+} tint_symbol;
+
+layout(binding = 1, std430) buffer tint_symbol_block_ssbo_1 {
+  uvec4 inner;
+} tint_symbol_1;
+
+void tint_symbol_2() {
+  tint_symbol_1.inner = tint_symbol.inner;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol_2();
+  return;
+}
diff --git a/test/tint/buffer/storage/types/vec4_u32.wgsl.expected.msl b/test/tint/buffer/storage/types/vec4_u32.wgsl.expected.msl
new file mode 100644
index 0000000..d6bce0a
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec4_u32.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(device uint4* tint_symbol_1 [[buffer(0)]], const device uint4* tint_symbol_2 [[buffer(1)]]) {
+  *(tint_symbol_1) = *(tint_symbol_2);
+  return;
+}
+
diff --git a/test/tint/buffer/storage/types/vec4_u32.wgsl.expected.spvasm b/test/tint/buffer/storage/types/vec4_u32.wgsl.expected.spvasm
new file mode 100644
index 0000000..c779b48
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec4_u32.wgsl.expected.spvasm
@@ -0,0 +1,39 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 16
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %in_block "in_block"
+               OpMemberName %in_block 0 "inner"
+               OpName %in "in"
+               OpName %out "out"
+               OpName %main "main"
+               OpDecorate %in_block Block
+               OpMemberDecorate %in_block 0 Offset 0
+               OpDecorate %in NonWritable
+               OpDecorate %in DescriptorSet 0
+               OpDecorate %in Binding 0
+               OpDecorate %out DescriptorSet 0
+               OpDecorate %out Binding 1
+       %uint = OpTypeInt 32 0
+     %v4uint = OpTypeVector %uint 4
+   %in_block = OpTypeStruct %v4uint
+%_ptr_StorageBuffer_in_block = OpTypePointer StorageBuffer %in_block
+         %in = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+        %out = OpVariable %_ptr_StorageBuffer_in_block StorageBuffer
+       %void = OpTypeVoid
+          %7 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_v4uint = OpTypePointer StorageBuffer %v4uint
+       %main = OpFunction %void None %7
+         %10 = OpLabel
+         %13 = OpAccessChain %_ptr_StorageBuffer_v4uint %out %uint_0
+         %14 = OpAccessChain %_ptr_StorageBuffer_v4uint %in %uint_0
+         %15 = OpLoad %v4uint %14
+               OpStore %13 %15
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/storage/types/vec4_u32.wgsl.expected.wgsl b/test/tint/buffer/storage/types/vec4_u32.wgsl.expected.wgsl
new file mode 100644
index 0000000..7d349db
--- /dev/null
+++ b/test/tint/buffer/storage/types/vec4_u32.wgsl.expected.wgsl
@@ -0,0 +1,8 @@
+@group(0) @binding(0) var<storage, read> in : vec4<u32>;
+
+@group(0) @binding(1) var<storage, read_write> out : vec4<u32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  out = in;
+}
diff --git a/test/tint/buffer/uniform/dynamic_index/read.wgsl b/test/tint/buffer/uniform/dynamic_index/read.wgsl
index 05d1083..730ba80 100644
--- a/test/tint/buffer/uniform/dynamic_index/read.wgsl
+++ b/test/tint/buffer/uniform/dynamic_index/read.wgsl
@@ -1,34 +1,56 @@
 struct Inner {
-    a : vec3<i32>,
-    b : i32,
-    c : vec3<u32>,
-    d : u32,
-    e : vec3<f32>,
-    f : f32,
-    g : vec2<i32>,
-    h : vec2<i32>,
-    i : mat2x3<f32>,
-    @align(16) j : mat3x2<f32>,
-    @align(16) k : array<vec4<i32>, 4>,
+    scalar_f32 : f32,
+    scalar_i32 : i32,
+    scalar_u32 : u32,
+    vec2_f32 : vec2<f32>,
+    vec2_i32 : vec2<i32>,
+    vec2_u32 : vec2<u32>,
+    vec3_f32 : vec3<f32>,
+    vec3_i32 : vec3<i32>,
+    vec3_u32 : vec3<u32>,
+    vec4_f32 : vec4<f32>,
+    vec4_i32 : vec4<i32>,
+    vec4_u32 : vec4<u32>,
+    mat2x2_f32 : mat2x2<f32>,
+    mat2x3_f32 : mat2x3<f32>,
+    mat2x4_f32 : mat2x4<f32>,
+    mat3x2_f32 : mat3x2<f32>,
+    mat3x3_f32 : mat3x3<f32>,
+    mat3x4_f32 : mat3x4<f32>,
+    mat4x2_f32 : mat4x2<f32>,
+    mat4x3_f32 : mat4x3<f32>,
+    mat4x4_f32 : mat4x4<f32>,
+    @align(16) arr2_vec3_f32 : array<vec3<f32>, 2>,
 };
 
 struct S {
     arr : array<Inner, 8>,
 };
 
-@binding(0) @group(0) var<uniform> s : S;
+@binding(0) @group(0) var<uniform> ub : S;
 
 @compute @workgroup_size(1)
 fn main(@builtin(local_invocation_index) idx : u32) {
-    let a = s.arr[idx].a;
-    let b = s.arr[idx].b;
-    let c = s.arr[idx].c;
-    let d = s.arr[idx].d;
-    let e = s.arr[idx].e;
-    let f = s.arr[idx].f;
-    let g = s.arr[idx].g;
-    let h = s.arr[idx].h;
-    let i = s.arr[idx].i;
-    let j = s.arr[idx].j;
-    let k = s.arr[idx].k;
-}
+    let scalar_f32 : f32 = ub.arr[idx].scalar_f32;
+    let scalar_i32 : i32 = ub.arr[idx].scalar_i32;
+    let scalar_u32 : u32 = ub.arr[idx].scalar_u32;
+    let vec2_f32 : vec2<f32> = ub.arr[idx].vec2_f32;
+    let vec2_i32 : vec2<i32> = ub.arr[idx].vec2_i32;
+    let vec2_u32 : vec2<u32> = ub.arr[idx].vec2_u32;
+    let vec3_f32 : vec3<f32> = ub.arr[idx].vec3_f32;
+    let vec3_i32 : vec3<i32> = ub.arr[idx].vec3_i32;
+    let vec3_u32 : vec3<u32> = ub.arr[idx].vec3_u32;
+    let vec4_f32 : vec4<f32> = ub.arr[idx].vec4_f32;
+    let vec4_i32 : vec4<i32> = ub.arr[idx].vec4_i32;
+    let vec4_u32 : vec4<u32> = ub.arr[idx].vec4_u32;
+    let mat2x2_f32 : mat2x2<f32> = ub.arr[idx].mat2x2_f32;
+    let mat2x3_f32 : mat2x3<f32> = ub.arr[idx].mat2x3_f32;
+    let mat2x4_f32 : mat2x4<f32> = ub.arr[idx].mat2x4_f32;
+    let mat3x2_f32 : mat3x2<f32> = ub.arr[idx].mat3x2_f32;
+    let mat3x3_f32 : mat3x3<f32> = ub.arr[idx].mat3x3_f32;
+    let mat3x4_f32 : mat3x4<f32> = ub.arr[idx].mat3x4_f32;
+    let mat4x2_f32 : mat4x2<f32> = ub.arr[idx].mat4x2_f32;
+    let mat4x3_f32 : mat4x3<f32> = ub.arr[idx].mat4x3_f32;
+    let mat4x4_f32 : mat4x4<f32> = ub.arr[idx].mat4x4_f32;
+    let arr2_vec3_f32 : array<vec3<f32>, 2> = ub.arr[idx].arr2_vec3_f32;
+}
\ No newline at end of file
diff --git a/test/tint/buffer/uniform/dynamic_index/read.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/dynamic_index/read.wgsl.expected.dxc.hlsl
index b110fb7..4e80c66 100644
--- a/test/tint/buffer/uniform/dynamic_index/read.wgsl.expected.dxc.hlsl
+++ b/test/tint/buffer/uniform/dynamic_index/read.wgsl.expected.dxc.hlsl
@@ -1,61 +1,133 @@
-cbuffer cbuffer_s : register(b0, space0) {
-  uint4 s[96];
+cbuffer cbuffer_ub : register(b0, space0) {
+  uint4 ub[272];
 };
 
 struct tint_symbol_1 {
   uint idx : SV_GroupIndex;
 };
 
-float2x3 tint_symbol_9(uint4 buffer[96], uint offset) {
+float2x2 tint_symbol_14(uint4 buffer[272], uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
-  const uint scalar_offset_1 = ((offset + 16u)) / 4;
-  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  return float2x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)));
 }
 
-float3x2 tint_symbol_10(uint4 buffer[96], uint offset) {
+float2x3 tint_symbol_15(uint4 buffer[272], uint offset) {
   const uint scalar_offset_2 = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset_2 / 4];
-  const uint scalar_offset_3 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_3 / 4];
-  const uint scalar_offset_4 = ((offset + 16u)) / 4;
-  uint4 ubo_load_2 = buffer[scalar_offset_4 / 4];
-  return float3x2(asfloat(((scalar_offset_2 & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_3 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_4 & 2) ? ubo_load_2.zw : ubo_load_2.xy)));
+  const uint scalar_offset_3 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
 }
 
-typedef int4 tint_symbol_12_ret[4];
-tint_symbol_12_ret tint_symbol_12(uint4 buffer[96], uint offset) {
-  int4 arr_1[4] = (int4[4])0;
+float2x4 tint_symbol_16(uint4 buffer[272], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset_4 / 4]), asfloat(buffer[scalar_offset_5 / 4]));
+}
+
+float3x2 tint_symbol_17(uint4 buffer[272], uint offset) {
+  const uint scalar_offset_6 = ((offset + 0u)) / 4;
+  uint4 ubo_load_2 = buffer[scalar_offset_6 / 4];
+  const uint scalar_offset_7 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_7 / 4];
+  const uint scalar_offset_8 = ((offset + 16u)) / 4;
+  uint4 ubo_load_4 = buffer[scalar_offset_8 / 4];
+  return float3x2(asfloat(((scalar_offset_6 & 2) ? ubo_load_2.zw : ubo_load_2.xy)), asfloat(((scalar_offset_7 & 2) ? ubo_load_3.zw : ubo_load_3.xy)), asfloat(((scalar_offset_8 & 2) ? ubo_load_4.zw : ubo_load_4.xy)));
+}
+
+float3x3 tint_symbol_18(uint4 buffer[272], uint offset) {
+  const uint scalar_offset_9 = ((offset + 0u)) / 4;
+  const uint scalar_offset_10 = ((offset + 16u)) / 4;
+  const uint scalar_offset_11 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset_9 / 4].xyz), asfloat(buffer[scalar_offset_10 / 4].xyz), asfloat(buffer[scalar_offset_11 / 4].xyz));
+}
+
+float3x4 tint_symbol_19(uint4 buffer[272], uint offset) {
+  const uint scalar_offset_12 = ((offset + 0u)) / 4;
+  const uint scalar_offset_13 = ((offset + 16u)) / 4;
+  const uint scalar_offset_14 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset_12 / 4]), asfloat(buffer[scalar_offset_13 / 4]), asfloat(buffer[scalar_offset_14 / 4]));
+}
+
+float4x2 tint_symbol_20(uint4 buffer[272], uint offset) {
+  const uint scalar_offset_15 = ((offset + 0u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_15 / 4];
+  const uint scalar_offset_16 = ((offset + 8u)) / 4;
+  uint4 ubo_load_6 = buffer[scalar_offset_16 / 4];
+  const uint scalar_offset_17 = ((offset + 16u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_17 / 4];
+  const uint scalar_offset_18 = ((offset + 24u)) / 4;
+  uint4 ubo_load_8 = buffer[scalar_offset_18 / 4];
+  return float4x2(asfloat(((scalar_offset_15 & 2) ? ubo_load_5.zw : ubo_load_5.xy)), asfloat(((scalar_offset_16 & 2) ? ubo_load_6.zw : ubo_load_6.xy)), asfloat(((scalar_offset_17 & 2) ? ubo_load_7.zw : ubo_load_7.xy)), asfloat(((scalar_offset_18 & 2) ? ubo_load_8.zw : ubo_load_8.xy)));
+}
+
+float4x3 tint_symbol_21(uint4 buffer[272], uint offset) {
+  const uint scalar_offset_19 = ((offset + 0u)) / 4;
+  const uint scalar_offset_20 = ((offset + 16u)) / 4;
+  const uint scalar_offset_21 = ((offset + 32u)) / 4;
+  const uint scalar_offset_22 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset_19 / 4].xyz), asfloat(buffer[scalar_offset_20 / 4].xyz), asfloat(buffer[scalar_offset_21 / 4].xyz), asfloat(buffer[scalar_offset_22 / 4].xyz));
+}
+
+float4x4 tint_symbol_22(uint4 buffer[272], uint offset) {
+  const uint scalar_offset_23 = ((offset + 0u)) / 4;
+  const uint scalar_offset_24 = ((offset + 16u)) / 4;
+  const uint scalar_offset_25 = ((offset + 32u)) / 4;
+  const uint scalar_offset_26 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset_23 / 4]), asfloat(buffer[scalar_offset_24 / 4]), asfloat(buffer[scalar_offset_25 / 4]), asfloat(buffer[scalar_offset_26 / 4]));
+}
+
+typedef float3 tint_symbol_23_ret[2];
+tint_symbol_23_ret tint_symbol_23(uint4 buffer[272], uint offset) {
+  float3 arr_1[2] = (float3[2])0;
   {
-    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
-      const uint scalar_offset_5 = ((offset + (i_1 * 16u))) / 4;
-      arr_1[i_1] = asint(buffer[scalar_offset_5 / 4]);
+    for(uint i = 0u; (i < 2u); i = (i + 1u)) {
+      const uint scalar_offset_27 = ((offset + (i * 16u))) / 4;
+      arr_1[i] = asfloat(buffer[scalar_offset_27 / 4].xyz);
     }
   }
   return arr_1;
 }
 
 void main_inner(uint idx) {
-  const uint scalar_offset_6 = ((192u * idx)) / 4;
-  const int3 a = asint(s[scalar_offset_6 / 4].xyz);
-  const uint scalar_offset_7 = (((192u * idx) + 12u)) / 4;
-  const int b = asint(s[scalar_offset_7 / 4][scalar_offset_7 % 4]);
-  const uint scalar_offset_8 = (((192u * idx) + 16u)) / 4;
-  const uint3 c = s[scalar_offset_8 / 4].xyz;
-  const uint scalar_offset_9 = (((192u * idx) + 28u)) / 4;
-  const uint d = s[scalar_offset_9 / 4][scalar_offset_9 % 4];
-  const uint scalar_offset_10 = (((192u * idx) + 32u)) / 4;
-  const float3 e = asfloat(s[scalar_offset_10 / 4].xyz);
-  const uint scalar_offset_11 = (((192u * idx) + 44u)) / 4;
-  const float f = asfloat(s[scalar_offset_11 / 4][scalar_offset_11 % 4]);
-  const uint scalar_offset_12 = (((192u * idx) + 48u)) / 4;
-  uint4 ubo_load_3 = s[scalar_offset_12 / 4];
-  const int2 g = asint(((scalar_offset_12 & 2) ? ubo_load_3.zw : ubo_load_3.xy));
-  const uint scalar_offset_13 = (((192u * idx) + 56u)) / 4;
-  uint4 ubo_load_4 = s[scalar_offset_13 / 4];
-  const int2 h = asint(((scalar_offset_13 & 2) ? ubo_load_4.zw : ubo_load_4.xy));
-  const float2x3 i = tint_symbol_9(s, ((192u * idx) + 64u));
-  const float3x2 j = tint_symbol_10(s, ((192u * idx) + 96u));
-  const int4 k[4] = tint_symbol_12(s, ((192u * idx) + 128u));
+  const uint scalar_offset_28 = ((544u * idx)) / 4;
+  const float scalar_f32 = asfloat(ub[scalar_offset_28 / 4][scalar_offset_28 % 4]);
+  const uint scalar_offset_29 = (((544u * idx) + 4u)) / 4;
+  const int scalar_i32 = asint(ub[scalar_offset_29 / 4][scalar_offset_29 % 4]);
+  const uint scalar_offset_30 = (((544u * idx) + 8u)) / 4;
+  const uint scalar_u32 = ub[scalar_offset_30 / 4][scalar_offset_30 % 4];
+  const uint scalar_offset_31 = (((544u * idx) + 16u)) / 4;
+  uint4 ubo_load_9 = ub[scalar_offset_31 / 4];
+  const float2 vec2_f32 = asfloat(((scalar_offset_31 & 2) ? ubo_load_9.zw : ubo_load_9.xy));
+  const uint scalar_offset_32 = (((544u * idx) + 24u)) / 4;
+  uint4 ubo_load_10 = ub[scalar_offset_32 / 4];
+  const int2 vec2_i32 = asint(((scalar_offset_32 & 2) ? ubo_load_10.zw : ubo_load_10.xy));
+  const uint scalar_offset_33 = (((544u * idx) + 32u)) / 4;
+  uint4 ubo_load_11 = ub[scalar_offset_33 / 4];
+  const uint2 vec2_u32 = ((scalar_offset_33 & 2) ? ubo_load_11.zw : ubo_load_11.xy);
+  const uint scalar_offset_34 = (((544u * idx) + 48u)) / 4;
+  const float3 vec3_f32 = asfloat(ub[scalar_offset_34 / 4].xyz);
+  const uint scalar_offset_35 = (((544u * idx) + 64u)) / 4;
+  const int3 vec3_i32 = asint(ub[scalar_offset_35 / 4].xyz);
+  const uint scalar_offset_36 = (((544u * idx) + 80u)) / 4;
+  const uint3 vec3_u32 = ub[scalar_offset_36 / 4].xyz;
+  const uint scalar_offset_37 = (((544u * idx) + 96u)) / 4;
+  const float4 vec4_f32 = asfloat(ub[scalar_offset_37 / 4]);
+  const uint scalar_offset_38 = (((544u * idx) + 112u)) / 4;
+  const int4 vec4_i32 = asint(ub[scalar_offset_38 / 4]);
+  const uint scalar_offset_39 = (((544u * idx) + 128u)) / 4;
+  const uint4 vec4_u32 = ub[scalar_offset_39 / 4];
+  const float2x2 mat2x2_f32 = tint_symbol_14(ub, ((544u * idx) + 144u));
+  const float2x3 mat2x3_f32 = tint_symbol_15(ub, ((544u * idx) + 160u));
+  const float2x4 mat2x4_f32 = tint_symbol_16(ub, ((544u * idx) + 192u));
+  const float3x2 mat3x2_f32 = tint_symbol_17(ub, ((544u * idx) + 224u));
+  const float3x3 mat3x3_f32 = tint_symbol_18(ub, ((544u * idx) + 256u));
+  const float3x4 mat3x4_f32 = tint_symbol_19(ub, ((544u * idx) + 304u));
+  const float4x2 mat4x2_f32 = tint_symbol_20(ub, ((544u * idx) + 352u));
+  const float4x3 mat4x3_f32 = tint_symbol_21(ub, ((544u * idx) + 384u));
+  const float4x4 mat4x4_f32 = tint_symbol_22(ub, ((544u * idx) + 448u));
+  const float3 arr2_vec3_f32[2] = tint_symbol_23(ub, ((544u * idx) + 512u));
 }
 
 [numthreads(1, 1, 1)]
diff --git a/test/tint/buffer/uniform/dynamic_index/read.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/dynamic_index/read.wgsl.expected.fxc.hlsl
index b110fb7..4e80c66 100644
--- a/test/tint/buffer/uniform/dynamic_index/read.wgsl.expected.fxc.hlsl
+++ b/test/tint/buffer/uniform/dynamic_index/read.wgsl.expected.fxc.hlsl
@@ -1,61 +1,133 @@
-cbuffer cbuffer_s : register(b0, space0) {
-  uint4 s[96];
+cbuffer cbuffer_ub : register(b0, space0) {
+  uint4 ub[272];
 };
 
 struct tint_symbol_1 {
   uint idx : SV_GroupIndex;
 };
 
-float2x3 tint_symbol_9(uint4 buffer[96], uint offset) {
+float2x2 tint_symbol_14(uint4 buffer[272], uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
-  const uint scalar_offset_1 = ((offset + 16u)) / 4;
-  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  return float2x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)));
 }
 
-float3x2 tint_symbol_10(uint4 buffer[96], uint offset) {
+float2x3 tint_symbol_15(uint4 buffer[272], uint offset) {
   const uint scalar_offset_2 = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset_2 / 4];
-  const uint scalar_offset_3 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_3 / 4];
-  const uint scalar_offset_4 = ((offset + 16u)) / 4;
-  uint4 ubo_load_2 = buffer[scalar_offset_4 / 4];
-  return float3x2(asfloat(((scalar_offset_2 & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_3 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_4 & 2) ? ubo_load_2.zw : ubo_load_2.xy)));
+  const uint scalar_offset_3 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
 }
 
-typedef int4 tint_symbol_12_ret[4];
-tint_symbol_12_ret tint_symbol_12(uint4 buffer[96], uint offset) {
-  int4 arr_1[4] = (int4[4])0;
+float2x4 tint_symbol_16(uint4 buffer[272], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset_4 / 4]), asfloat(buffer[scalar_offset_5 / 4]));
+}
+
+float3x2 tint_symbol_17(uint4 buffer[272], uint offset) {
+  const uint scalar_offset_6 = ((offset + 0u)) / 4;
+  uint4 ubo_load_2 = buffer[scalar_offset_6 / 4];
+  const uint scalar_offset_7 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_7 / 4];
+  const uint scalar_offset_8 = ((offset + 16u)) / 4;
+  uint4 ubo_load_4 = buffer[scalar_offset_8 / 4];
+  return float3x2(asfloat(((scalar_offset_6 & 2) ? ubo_load_2.zw : ubo_load_2.xy)), asfloat(((scalar_offset_7 & 2) ? ubo_load_3.zw : ubo_load_3.xy)), asfloat(((scalar_offset_8 & 2) ? ubo_load_4.zw : ubo_load_4.xy)));
+}
+
+float3x3 tint_symbol_18(uint4 buffer[272], uint offset) {
+  const uint scalar_offset_9 = ((offset + 0u)) / 4;
+  const uint scalar_offset_10 = ((offset + 16u)) / 4;
+  const uint scalar_offset_11 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset_9 / 4].xyz), asfloat(buffer[scalar_offset_10 / 4].xyz), asfloat(buffer[scalar_offset_11 / 4].xyz));
+}
+
+float3x4 tint_symbol_19(uint4 buffer[272], uint offset) {
+  const uint scalar_offset_12 = ((offset + 0u)) / 4;
+  const uint scalar_offset_13 = ((offset + 16u)) / 4;
+  const uint scalar_offset_14 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset_12 / 4]), asfloat(buffer[scalar_offset_13 / 4]), asfloat(buffer[scalar_offset_14 / 4]));
+}
+
+float4x2 tint_symbol_20(uint4 buffer[272], uint offset) {
+  const uint scalar_offset_15 = ((offset + 0u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_15 / 4];
+  const uint scalar_offset_16 = ((offset + 8u)) / 4;
+  uint4 ubo_load_6 = buffer[scalar_offset_16 / 4];
+  const uint scalar_offset_17 = ((offset + 16u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_17 / 4];
+  const uint scalar_offset_18 = ((offset + 24u)) / 4;
+  uint4 ubo_load_8 = buffer[scalar_offset_18 / 4];
+  return float4x2(asfloat(((scalar_offset_15 & 2) ? ubo_load_5.zw : ubo_load_5.xy)), asfloat(((scalar_offset_16 & 2) ? ubo_load_6.zw : ubo_load_6.xy)), asfloat(((scalar_offset_17 & 2) ? ubo_load_7.zw : ubo_load_7.xy)), asfloat(((scalar_offset_18 & 2) ? ubo_load_8.zw : ubo_load_8.xy)));
+}
+
+float4x3 tint_symbol_21(uint4 buffer[272], uint offset) {
+  const uint scalar_offset_19 = ((offset + 0u)) / 4;
+  const uint scalar_offset_20 = ((offset + 16u)) / 4;
+  const uint scalar_offset_21 = ((offset + 32u)) / 4;
+  const uint scalar_offset_22 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset_19 / 4].xyz), asfloat(buffer[scalar_offset_20 / 4].xyz), asfloat(buffer[scalar_offset_21 / 4].xyz), asfloat(buffer[scalar_offset_22 / 4].xyz));
+}
+
+float4x4 tint_symbol_22(uint4 buffer[272], uint offset) {
+  const uint scalar_offset_23 = ((offset + 0u)) / 4;
+  const uint scalar_offset_24 = ((offset + 16u)) / 4;
+  const uint scalar_offset_25 = ((offset + 32u)) / 4;
+  const uint scalar_offset_26 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset_23 / 4]), asfloat(buffer[scalar_offset_24 / 4]), asfloat(buffer[scalar_offset_25 / 4]), asfloat(buffer[scalar_offset_26 / 4]));
+}
+
+typedef float3 tint_symbol_23_ret[2];
+tint_symbol_23_ret tint_symbol_23(uint4 buffer[272], uint offset) {
+  float3 arr_1[2] = (float3[2])0;
   {
-    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
-      const uint scalar_offset_5 = ((offset + (i_1 * 16u))) / 4;
-      arr_1[i_1] = asint(buffer[scalar_offset_5 / 4]);
+    for(uint i = 0u; (i < 2u); i = (i + 1u)) {
+      const uint scalar_offset_27 = ((offset + (i * 16u))) / 4;
+      arr_1[i] = asfloat(buffer[scalar_offset_27 / 4].xyz);
     }
   }
   return arr_1;
 }
 
 void main_inner(uint idx) {
-  const uint scalar_offset_6 = ((192u * idx)) / 4;
-  const int3 a = asint(s[scalar_offset_6 / 4].xyz);
-  const uint scalar_offset_7 = (((192u * idx) + 12u)) / 4;
-  const int b = asint(s[scalar_offset_7 / 4][scalar_offset_7 % 4]);
-  const uint scalar_offset_8 = (((192u * idx) + 16u)) / 4;
-  const uint3 c = s[scalar_offset_8 / 4].xyz;
-  const uint scalar_offset_9 = (((192u * idx) + 28u)) / 4;
-  const uint d = s[scalar_offset_9 / 4][scalar_offset_9 % 4];
-  const uint scalar_offset_10 = (((192u * idx) + 32u)) / 4;
-  const float3 e = asfloat(s[scalar_offset_10 / 4].xyz);
-  const uint scalar_offset_11 = (((192u * idx) + 44u)) / 4;
-  const float f = asfloat(s[scalar_offset_11 / 4][scalar_offset_11 % 4]);
-  const uint scalar_offset_12 = (((192u * idx) + 48u)) / 4;
-  uint4 ubo_load_3 = s[scalar_offset_12 / 4];
-  const int2 g = asint(((scalar_offset_12 & 2) ? ubo_load_3.zw : ubo_load_3.xy));
-  const uint scalar_offset_13 = (((192u * idx) + 56u)) / 4;
-  uint4 ubo_load_4 = s[scalar_offset_13 / 4];
-  const int2 h = asint(((scalar_offset_13 & 2) ? ubo_load_4.zw : ubo_load_4.xy));
-  const float2x3 i = tint_symbol_9(s, ((192u * idx) + 64u));
-  const float3x2 j = tint_symbol_10(s, ((192u * idx) + 96u));
-  const int4 k[4] = tint_symbol_12(s, ((192u * idx) + 128u));
+  const uint scalar_offset_28 = ((544u * idx)) / 4;
+  const float scalar_f32 = asfloat(ub[scalar_offset_28 / 4][scalar_offset_28 % 4]);
+  const uint scalar_offset_29 = (((544u * idx) + 4u)) / 4;
+  const int scalar_i32 = asint(ub[scalar_offset_29 / 4][scalar_offset_29 % 4]);
+  const uint scalar_offset_30 = (((544u * idx) + 8u)) / 4;
+  const uint scalar_u32 = ub[scalar_offset_30 / 4][scalar_offset_30 % 4];
+  const uint scalar_offset_31 = (((544u * idx) + 16u)) / 4;
+  uint4 ubo_load_9 = ub[scalar_offset_31 / 4];
+  const float2 vec2_f32 = asfloat(((scalar_offset_31 & 2) ? ubo_load_9.zw : ubo_load_9.xy));
+  const uint scalar_offset_32 = (((544u * idx) + 24u)) / 4;
+  uint4 ubo_load_10 = ub[scalar_offset_32 / 4];
+  const int2 vec2_i32 = asint(((scalar_offset_32 & 2) ? ubo_load_10.zw : ubo_load_10.xy));
+  const uint scalar_offset_33 = (((544u * idx) + 32u)) / 4;
+  uint4 ubo_load_11 = ub[scalar_offset_33 / 4];
+  const uint2 vec2_u32 = ((scalar_offset_33 & 2) ? ubo_load_11.zw : ubo_load_11.xy);
+  const uint scalar_offset_34 = (((544u * idx) + 48u)) / 4;
+  const float3 vec3_f32 = asfloat(ub[scalar_offset_34 / 4].xyz);
+  const uint scalar_offset_35 = (((544u * idx) + 64u)) / 4;
+  const int3 vec3_i32 = asint(ub[scalar_offset_35 / 4].xyz);
+  const uint scalar_offset_36 = (((544u * idx) + 80u)) / 4;
+  const uint3 vec3_u32 = ub[scalar_offset_36 / 4].xyz;
+  const uint scalar_offset_37 = (((544u * idx) + 96u)) / 4;
+  const float4 vec4_f32 = asfloat(ub[scalar_offset_37 / 4]);
+  const uint scalar_offset_38 = (((544u * idx) + 112u)) / 4;
+  const int4 vec4_i32 = asint(ub[scalar_offset_38 / 4]);
+  const uint scalar_offset_39 = (((544u * idx) + 128u)) / 4;
+  const uint4 vec4_u32 = ub[scalar_offset_39 / 4];
+  const float2x2 mat2x2_f32 = tint_symbol_14(ub, ((544u * idx) + 144u));
+  const float2x3 mat2x3_f32 = tint_symbol_15(ub, ((544u * idx) + 160u));
+  const float2x4 mat2x4_f32 = tint_symbol_16(ub, ((544u * idx) + 192u));
+  const float3x2 mat3x2_f32 = tint_symbol_17(ub, ((544u * idx) + 224u));
+  const float3x3 mat3x3_f32 = tint_symbol_18(ub, ((544u * idx) + 256u));
+  const float3x4 mat3x4_f32 = tint_symbol_19(ub, ((544u * idx) + 304u));
+  const float4x2 mat4x2_f32 = tint_symbol_20(ub, ((544u * idx) + 352u));
+  const float4x3 mat4x3_f32 = tint_symbol_21(ub, ((544u * idx) + 384u));
+  const float4x4 mat4x4_f32 = tint_symbol_22(ub, ((544u * idx) + 448u));
+  const float3 arr2_vec3_f32[2] = tint_symbol_23(ub, ((544u * idx) + 512u));
 }
 
 [numthreads(1, 1, 1)]
diff --git a/test/tint/buffer/uniform/dynamic_index/read.wgsl.expected.glsl b/test/tint/buffer/uniform/dynamic_index/read.wgsl.expected.glsl
index 7c900f4..521d84e 100644
--- a/test/tint/buffer/uniform/dynamic_index/read.wgsl.expected.glsl
+++ b/test/tint/buffer/uniform/dynamic_index/read.wgsl.expected.glsl
@@ -1,37 +1,75 @@
 #version 310 es
 
 struct Inner {
-  ivec3 a;
-  int b;
-  uvec3 c;
-  uint d;
-  vec3 e;
-  float f;
-  ivec2 g;
-  ivec2 h;
-  mat2x3 i;
-  mat3x2 j;
+  float scalar_f32;
+  int scalar_i32;
+  uint scalar_u32;
   uint pad;
+  vec2 vec2_f32;
+  ivec2 vec2_i32;
+  uvec2 vec2_u32;
   uint pad_1;
-  ivec4 k[4];
+  uint pad_2;
+  vec3 vec3_f32;
+  uint pad_3;
+  ivec3 vec3_i32;
+  uint pad_4;
+  uvec3 vec3_u32;
+  uint pad_5;
+  vec4 vec4_f32;
+  ivec4 vec4_i32;
+  uvec4 vec4_u32;
+  mat2 mat2x2_f32;
+  mat2x3 mat2x3_f32;
+  mat2x4 mat2x4_f32;
+  mat3x2 mat3x2_f32;
+  uint pad_6;
+  uint pad_7;
+  mat3 mat3x3_f32;
+  mat3x4 mat3x4_f32;
+  mat4x2 mat4x2_f32;
+  mat4x3 mat4x3_f32;
+  mat4 mat4x4_f32;
+  vec3 arr2_vec3_f32[2];
 };
 
 struct Inner_std140 {
-  ivec3 a;
-  int b;
-  uvec3 c;
-  uint d;
-  vec3 e;
-  float f;
-  ivec2 g;
-  ivec2 h;
-  mat2x3 i;
-  vec2 j_0;
-  vec2 j_1;
-  vec2 j_2;
+  float scalar_f32;
+  int scalar_i32;
+  uint scalar_u32;
   uint pad;
+  vec2 vec2_f32;
+  ivec2 vec2_i32;
+  uvec2 vec2_u32;
   uint pad_1;
-  ivec4 k[4];
+  uint pad_2;
+  vec3 vec3_f32;
+  uint pad_3;
+  ivec3 vec3_i32;
+  uint pad_4;
+  uvec3 vec3_u32;
+  uint pad_5;
+  vec4 vec4_f32;
+  ivec4 vec4_i32;
+  uvec4 vec4_u32;
+  vec2 mat2x2_f32_0;
+  vec2 mat2x2_f32_1;
+  mat2x3 mat2x3_f32;
+  mat2x4 mat2x4_f32;
+  vec2 mat3x2_f32_0;
+  vec2 mat3x2_f32_1;
+  vec2 mat3x2_f32_2;
+  uint pad_6;
+  uint pad_7;
+  mat3 mat3x3_f32;
+  mat3x4 mat3x4_f32;
+  vec2 mat4x2_f32_0;
+  vec2 mat4x2_f32_1;
+  vec2 mat4x2_f32_2;
+  vec2 mat4x2_f32_3;
+  mat4x3 mat4x3_f32;
+  mat4 mat4x4_f32;
+  vec3 arr2_vec3_f32[2];
 };
 
 struct S {
@@ -42,27 +80,48 @@
   Inner_std140 arr[8];
 };
 
-layout(binding = 0, std140) uniform s_block_std140_ubo {
+layout(binding = 0, std140) uniform ub_block_std140_ubo {
   S_std140 inner;
-} s;
+} ub;
 
-mat3x2 load_s_inner_arr_p0_j(uint p0) {
+mat2 load_ub_inner_arr_p0_mat2x2_f32(uint p0) {
   uint s_save = p0;
-  return mat3x2(s.inner.arr[s_save].j_0, s.inner.arr[s_save].j_1, s.inner.arr[s_save].j_2);
+  return mat2(ub.inner.arr[s_save].mat2x2_f32_0, ub.inner.arr[s_save].mat2x2_f32_1);
+}
+
+mat3x2 load_ub_inner_arr_p0_mat3x2_f32(uint p0) {
+  uint s_save_1 = p0;
+  return mat3x2(ub.inner.arr[s_save_1].mat3x2_f32_0, ub.inner.arr[s_save_1].mat3x2_f32_1, ub.inner.arr[s_save_1].mat3x2_f32_2);
+}
+
+mat4x2 load_ub_inner_arr_p0_mat4x2_f32(uint p0) {
+  uint s_save_2 = p0;
+  return mat4x2(ub.inner.arr[s_save_2].mat4x2_f32_0, ub.inner.arr[s_save_2].mat4x2_f32_1, ub.inner.arr[s_save_2].mat4x2_f32_2, ub.inner.arr[s_save_2].mat4x2_f32_3);
 }
 
 void tint_symbol(uint idx) {
-  ivec3 a = s.inner.arr[idx].a;
-  int b = s.inner.arr[idx].b;
-  uvec3 c = s.inner.arr[idx].c;
-  uint d = s.inner.arr[idx].d;
-  vec3 e = s.inner.arr[idx].e;
-  float f = s.inner.arr[idx].f;
-  ivec2 g = s.inner.arr[idx].g;
-  ivec2 h = s.inner.arr[idx].h;
-  mat2x3 i = s.inner.arr[idx].i;
-  mat3x2 j = load_s_inner_arr_p0_j(uint(idx));
-  ivec4 k[4] = s.inner.arr[idx].k;
+  float scalar_f32 = ub.inner.arr[idx].scalar_f32;
+  int scalar_i32 = ub.inner.arr[idx].scalar_i32;
+  uint scalar_u32 = ub.inner.arr[idx].scalar_u32;
+  vec2 vec2_f32 = ub.inner.arr[idx].vec2_f32;
+  ivec2 vec2_i32 = ub.inner.arr[idx].vec2_i32;
+  uvec2 vec2_u32 = ub.inner.arr[idx].vec2_u32;
+  vec3 vec3_f32 = ub.inner.arr[idx].vec3_f32;
+  ivec3 vec3_i32 = ub.inner.arr[idx].vec3_i32;
+  uvec3 vec3_u32 = ub.inner.arr[idx].vec3_u32;
+  vec4 vec4_f32 = ub.inner.arr[idx].vec4_f32;
+  ivec4 vec4_i32 = ub.inner.arr[idx].vec4_i32;
+  uvec4 vec4_u32 = ub.inner.arr[idx].vec4_u32;
+  mat2 mat2x2_f32 = load_ub_inner_arr_p0_mat2x2_f32(uint(idx));
+  mat2x3 mat2x3_f32 = ub.inner.arr[idx].mat2x3_f32;
+  mat2x4 mat2x4_f32 = ub.inner.arr[idx].mat2x4_f32;
+  mat3x2 mat3x2_f32 = load_ub_inner_arr_p0_mat3x2_f32(uint(idx));
+  mat3 mat3x3_f32 = ub.inner.arr[idx].mat3x3_f32;
+  mat3x4 mat3x4_f32 = ub.inner.arr[idx].mat3x4_f32;
+  mat4x2 mat4x2_f32 = load_ub_inner_arr_p0_mat4x2_f32(uint(idx));
+  mat4x3 mat4x3_f32 = ub.inner.arr[idx].mat4x3_f32;
+  mat4 mat4x4_f32 = ub.inner.arr[idx].mat4x4_f32;
+  vec3 arr2_vec3_f32[2] = ub.inner.arr[idx].arr2_vec3_f32;
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/buffer/uniform/dynamic_index/read.wgsl.expected.msl b/test/tint/buffer/uniform/dynamic_index/read.wgsl.expected.msl
index 37817c3..f976bd1 100644
--- a/test/tint/buffer/uniform/dynamic_index/read.wgsl.expected.msl
+++ b/test/tint/buffer/uniform/dynamic_index/read.wgsl.expected.msl
@@ -15,18 +15,34 @@
 };
 
 struct Inner {
-  /* 0x0000 */ packed_int3 a;
-  /* 0x000c */ int b;
-  /* 0x0010 */ packed_uint3 c;
-  /* 0x001c */ uint d;
-  /* 0x0020 */ packed_float3 e;
-  /* 0x002c */ float f;
-  /* 0x0030 */ int2 g;
-  /* 0x0038 */ int2 h;
-  /* 0x0040 */ float2x3 i;
-  /* 0x0060 */ float3x2 j;
-  /* 0x0078 */ tint_array<int8_t, 8> tint_pad;
-  /* 0x0080 */ tint_array<int4, 4> k;
+  /* 0x0000 */ float scalar_f32;
+  /* 0x0004 */ int scalar_i32;
+  /* 0x0008 */ uint scalar_u32;
+  /* 0x000c */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0010 */ float2 vec2_f32;
+  /* 0x0018 */ int2 vec2_i32;
+  /* 0x0020 */ uint2 vec2_u32;
+  /* 0x0028 */ tint_array<int8_t, 8> tint_pad_1;
+  /* 0x0030 */ packed_float3 vec3_f32;
+  /* 0x003c */ tint_array<int8_t, 4> tint_pad_2;
+  /* 0x0040 */ packed_int3 vec3_i32;
+  /* 0x004c */ tint_array<int8_t, 4> tint_pad_3;
+  /* 0x0050 */ packed_uint3 vec3_u32;
+  /* 0x005c */ tint_array<int8_t, 4> tint_pad_4;
+  /* 0x0060 */ float4 vec4_f32;
+  /* 0x0070 */ int4 vec4_i32;
+  /* 0x0080 */ uint4 vec4_u32;
+  /* 0x0090 */ float2x2 mat2x2_f32;
+  /* 0x00a0 */ float2x3 mat2x3_f32;
+  /* 0x00c0 */ float2x4 mat2x4_f32;
+  /* 0x00e0 */ float3x2 mat3x2_f32;
+  /* 0x00f8 */ tint_array<int8_t, 8> tint_pad_5;
+  /* 0x0100 */ float3x3 mat3x3_f32;
+  /* 0x0130 */ float3x4 mat3x4_f32;
+  /* 0x0160 */ float4x2 mat4x2_f32;
+  /* 0x0180 */ float4x3 mat4x3_f32;
+  /* 0x01c0 */ float4x4 mat4x4_f32;
+  /* 0x0200 */ tint_array<float3, 2> arr2_vec3_f32;
 };
 
 struct S {
@@ -34,17 +50,28 @@
 };
 
 void tint_symbol_inner(uint idx, const constant S* const tint_symbol_1) {
-  int3 const a = int3((*(tint_symbol_1)).arr[idx].a);
-  int const b = (*(tint_symbol_1)).arr[idx].b;
-  uint3 const c = uint3((*(tint_symbol_1)).arr[idx].c);
-  uint const d = (*(tint_symbol_1)).arr[idx].d;
-  float3 const e = float3((*(tint_symbol_1)).arr[idx].e);
-  float const f = (*(tint_symbol_1)).arr[idx].f;
-  int2 const g = (*(tint_symbol_1)).arr[idx].g;
-  int2 const h = (*(tint_symbol_1)).arr[idx].h;
-  float2x3 const i = (*(tint_symbol_1)).arr[idx].i;
-  float3x2 const j = (*(tint_symbol_1)).arr[idx].j;
-  tint_array<int4, 4> const k = (*(tint_symbol_1)).arr[idx].k;
+  float const scalar_f32 = (*(tint_symbol_1)).arr[idx].scalar_f32;
+  int const scalar_i32 = (*(tint_symbol_1)).arr[idx].scalar_i32;
+  uint const scalar_u32 = (*(tint_symbol_1)).arr[idx].scalar_u32;
+  float2 const vec2_f32 = (*(tint_symbol_1)).arr[idx].vec2_f32;
+  int2 const vec2_i32 = (*(tint_symbol_1)).arr[idx].vec2_i32;
+  uint2 const vec2_u32 = (*(tint_symbol_1)).arr[idx].vec2_u32;
+  float3 const vec3_f32 = float3((*(tint_symbol_1)).arr[idx].vec3_f32);
+  int3 const vec3_i32 = int3((*(tint_symbol_1)).arr[idx].vec3_i32);
+  uint3 const vec3_u32 = uint3((*(tint_symbol_1)).arr[idx].vec3_u32);
+  float4 const vec4_f32 = (*(tint_symbol_1)).arr[idx].vec4_f32;
+  int4 const vec4_i32 = (*(tint_symbol_1)).arr[idx].vec4_i32;
+  uint4 const vec4_u32 = (*(tint_symbol_1)).arr[idx].vec4_u32;
+  float2x2 const mat2x2_f32 = (*(tint_symbol_1)).arr[idx].mat2x2_f32;
+  float2x3 const mat2x3_f32 = (*(tint_symbol_1)).arr[idx].mat2x3_f32;
+  float2x4 const mat2x4_f32 = (*(tint_symbol_1)).arr[idx].mat2x4_f32;
+  float3x2 const mat3x2_f32 = (*(tint_symbol_1)).arr[idx].mat3x2_f32;
+  float3x3 const mat3x3_f32 = (*(tint_symbol_1)).arr[idx].mat3x3_f32;
+  float3x4 const mat3x4_f32 = (*(tint_symbol_1)).arr[idx].mat3x4_f32;
+  float4x2 const mat4x2_f32 = (*(tint_symbol_1)).arr[idx].mat4x2_f32;
+  float4x3 const mat4x3_f32 = (*(tint_symbol_1)).arr[idx].mat4x3_f32;
+  float4x4 const mat4x4_f32 = (*(tint_symbol_1)).arr[idx].mat4x4_f32;
+  tint_array<float3, 2> const arr2_vec3_f32 = (*(tint_symbol_1)).arr[idx].arr2_vec3_f32;
 }
 
 kernel void tint_symbol(const constant S* tint_symbol_2 [[buffer(0)]], uint idx [[thread_index_in_threadgroup]]) {
diff --git a/test/tint/buffer/uniform/dynamic_index/read.wgsl.expected.spvasm b/test/tint/buffer/uniform/dynamic_index/read.wgsl.expected.spvasm
index e8c067c..1781177 100644
--- a/test/tint/buffer/uniform/dynamic_index/read.wgsl.expected.spvasm
+++ b/test/tint/buffer/uniform/dynamic_index/read.wgsl.expected.spvasm
@@ -1,151 +1,277 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 93
+; Bound: 181
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %main "main" %idx_1
                OpExecutionMode %main LocalSize 1 1 1
                OpName %idx_1 "idx_1"
-               OpName %s_block_std140 "s_block_std140"
-               OpMemberName %s_block_std140 0 "inner"
+               OpName %ub_block_std140 "ub_block_std140"
+               OpMemberName %ub_block_std140 0 "inner"
                OpName %S_std140 "S_std140"
                OpMemberName %S_std140 0 "arr"
                OpName %Inner_std140 "Inner_std140"
-               OpMemberName %Inner_std140 0 "a"
-               OpMemberName %Inner_std140 1 "b"
-               OpMemberName %Inner_std140 2 "c"
-               OpMemberName %Inner_std140 3 "d"
-               OpMemberName %Inner_std140 4 "e"
-               OpMemberName %Inner_std140 5 "f"
-               OpMemberName %Inner_std140 6 "g"
-               OpMemberName %Inner_std140 7 "h"
-               OpMemberName %Inner_std140 8 "i"
-               OpMemberName %Inner_std140 9 "j_0"
-               OpMemberName %Inner_std140 10 "j_1"
-               OpMemberName %Inner_std140 11 "j_2"
-               OpMemberName %Inner_std140 12 "k"
-               OpName %s "s"
-               OpName %load_s_inner_arr_p0_j "load_s_inner_arr_p0_j"
+               OpMemberName %Inner_std140 0 "scalar_f32"
+               OpMemberName %Inner_std140 1 "scalar_i32"
+               OpMemberName %Inner_std140 2 "scalar_u32"
+               OpMemberName %Inner_std140 3 "vec2_f32"
+               OpMemberName %Inner_std140 4 "vec2_i32"
+               OpMemberName %Inner_std140 5 "vec2_u32"
+               OpMemberName %Inner_std140 6 "vec3_f32"
+               OpMemberName %Inner_std140 7 "vec3_i32"
+               OpMemberName %Inner_std140 8 "vec3_u32"
+               OpMemberName %Inner_std140 9 "vec4_f32"
+               OpMemberName %Inner_std140 10 "vec4_i32"
+               OpMemberName %Inner_std140 11 "vec4_u32"
+               OpMemberName %Inner_std140 12 "mat2x2_f32_0"
+               OpMemberName %Inner_std140 13 "mat2x2_f32_1"
+               OpMemberName %Inner_std140 14 "mat2x3_f32"
+               OpMemberName %Inner_std140 15 "mat2x4_f32"
+               OpMemberName %Inner_std140 16 "mat3x2_f32_0"
+               OpMemberName %Inner_std140 17 "mat3x2_f32_1"
+               OpMemberName %Inner_std140 18 "mat3x2_f32_2"
+               OpMemberName %Inner_std140 19 "mat3x3_f32"
+               OpMemberName %Inner_std140 20 "mat3x4_f32"
+               OpMemberName %Inner_std140 21 "mat4x2_f32_0"
+               OpMemberName %Inner_std140 22 "mat4x2_f32_1"
+               OpMemberName %Inner_std140 23 "mat4x2_f32_2"
+               OpMemberName %Inner_std140 24 "mat4x2_f32_3"
+               OpMemberName %Inner_std140 25 "mat4x3_f32"
+               OpMemberName %Inner_std140 26 "mat4x4_f32"
+               OpMemberName %Inner_std140 27 "arr2_vec3_f32"
+               OpName %ub "ub"
+               OpName %load_ub_inner_arr_p0_mat2x2_f32 "load_ub_inner_arr_p0_mat2x2_f32"
                OpName %p0 "p0"
+               OpName %load_ub_inner_arr_p0_mat3x2_f32 "load_ub_inner_arr_p0_mat3x2_f32"
+               OpName %p0_0 "p0"
+               OpName %load_ub_inner_arr_p0_mat4x2_f32 "load_ub_inner_arr_p0_mat4x2_f32"
+               OpName %p0_1 "p0"
                OpName %main_inner "main_inner"
                OpName %idx "idx"
                OpName %main "main"
                OpDecorate %idx_1 BuiltIn LocalInvocationIndex
-               OpDecorate %s_block_std140 Block
-               OpMemberDecorate %s_block_std140 0 Offset 0
+               OpDecorate %ub_block_std140 Block
+               OpMemberDecorate %ub_block_std140 0 Offset 0
                OpMemberDecorate %S_std140 0 Offset 0
                OpMemberDecorate %Inner_std140 0 Offset 0
-               OpMemberDecorate %Inner_std140 1 Offset 12
-               OpMemberDecorate %Inner_std140 2 Offset 16
-               OpMemberDecorate %Inner_std140 3 Offset 28
-               OpMemberDecorate %Inner_std140 4 Offset 32
-               OpMemberDecorate %Inner_std140 5 Offset 44
+               OpMemberDecorate %Inner_std140 1 Offset 4
+               OpMemberDecorate %Inner_std140 2 Offset 8
+               OpMemberDecorate %Inner_std140 3 Offset 16
+               OpMemberDecorate %Inner_std140 4 Offset 24
+               OpMemberDecorate %Inner_std140 5 Offset 32
                OpMemberDecorate %Inner_std140 6 Offset 48
-               OpMemberDecorate %Inner_std140 7 Offset 56
-               OpMemberDecorate %Inner_std140 8 Offset 64
-               OpMemberDecorate %Inner_std140 8 ColMajor
-               OpMemberDecorate %Inner_std140 8 MatrixStride 16
+               OpMemberDecorate %Inner_std140 7 Offset 64
+               OpMemberDecorate %Inner_std140 8 Offset 80
                OpMemberDecorate %Inner_std140 9 Offset 96
-               OpMemberDecorate %Inner_std140 10 Offset 104
-               OpMemberDecorate %Inner_std140 11 Offset 112
-               OpMemberDecorate %Inner_std140 12 Offset 128
-               OpDecorate %_arr_v4int_uint_4 ArrayStride 16
-               OpDecorate %_arr_Inner_std140_uint_8 ArrayStride 192
-               OpDecorate %s NonWritable
-               OpDecorate %s Binding 0
-               OpDecorate %s DescriptorSet 0
+               OpMemberDecorate %Inner_std140 10 Offset 112
+               OpMemberDecorate %Inner_std140 11 Offset 128
+               OpMemberDecorate %Inner_std140 12 Offset 144
+               OpMemberDecorate %Inner_std140 13 Offset 152
+               OpMemberDecorate %Inner_std140 14 Offset 160
+               OpMemberDecorate %Inner_std140 14 ColMajor
+               OpMemberDecorate %Inner_std140 14 MatrixStride 16
+               OpMemberDecorate %Inner_std140 15 Offset 192
+               OpMemberDecorate %Inner_std140 15 ColMajor
+               OpMemberDecorate %Inner_std140 15 MatrixStride 16
+               OpMemberDecorate %Inner_std140 16 Offset 224
+               OpMemberDecorate %Inner_std140 17 Offset 232
+               OpMemberDecorate %Inner_std140 18 Offset 240
+               OpMemberDecorate %Inner_std140 19 Offset 256
+               OpMemberDecorate %Inner_std140 19 ColMajor
+               OpMemberDecorate %Inner_std140 19 MatrixStride 16
+               OpMemberDecorate %Inner_std140 20 Offset 304
+               OpMemberDecorate %Inner_std140 20 ColMajor
+               OpMemberDecorate %Inner_std140 20 MatrixStride 16
+               OpMemberDecorate %Inner_std140 21 Offset 352
+               OpMemberDecorate %Inner_std140 22 Offset 360
+               OpMemberDecorate %Inner_std140 23 Offset 368
+               OpMemberDecorate %Inner_std140 24 Offset 376
+               OpMemberDecorate %Inner_std140 25 Offset 384
+               OpMemberDecorate %Inner_std140 25 ColMajor
+               OpMemberDecorate %Inner_std140 25 MatrixStride 16
+               OpMemberDecorate %Inner_std140 26 Offset 448
+               OpMemberDecorate %Inner_std140 26 ColMajor
+               OpMemberDecorate %Inner_std140 26 MatrixStride 16
+               OpMemberDecorate %Inner_std140 27 Offset 512
+               OpDecorate %_arr_v3float_uint_2 ArrayStride 16
+               OpDecorate %_arr_Inner_std140_uint_8 ArrayStride 544
+               OpDecorate %ub NonWritable
+               OpDecorate %ub Binding 0
+               OpDecorate %ub DescriptorSet 0
        %uint = OpTypeInt 32 0
 %_ptr_Input_uint = OpTypePointer Input %uint
       %idx_1 = OpVariable %_ptr_Input_uint Input
+      %float = OpTypeFloat 32
         %int = OpTypeInt 32 1
+    %v2float = OpTypeVector %float 2
+      %v2int = OpTypeVector %int 2
+     %v2uint = OpTypeVector %uint 2
+    %v3float = OpTypeVector %float 3
       %v3int = OpTypeVector %int 3
      %v3uint = OpTypeVector %uint 3
-      %float = OpTypeFloat 32
-    %v3float = OpTypeVector %float 3
-      %v2int = OpTypeVector %int 2
-%mat2v3float = OpTypeMatrix %v3float 2
-    %v2float = OpTypeVector %float 2
+    %v4float = OpTypeVector %float 4
       %v4int = OpTypeVector %int 4
-     %uint_4 = OpConstant %uint 4
-%_arr_v4int_uint_4 = OpTypeArray %v4int %uint_4
-%Inner_std140 = OpTypeStruct %v3int %int %v3uint %uint %v3float %float %v2int %v2int %mat2v3float %v2float %v2float %v2float %_arr_v4int_uint_4
+     %v4uint = OpTypeVector %uint 4
+%mat2v3float = OpTypeMatrix %v3float 2
+%mat2v4float = OpTypeMatrix %v4float 2
+%mat3v3float = OpTypeMatrix %v3float 3
+%mat3v4float = OpTypeMatrix %v4float 3
+%mat4v3float = OpTypeMatrix %v3float 4
+%mat4v4float = OpTypeMatrix %v4float 4
+     %uint_2 = OpConstant %uint 2
+%_arr_v3float_uint_2 = OpTypeArray %v3float %uint_2
+%Inner_std140 = OpTypeStruct %float %int %uint %v2float %v2int %v2uint %v3float %v3int %v3uint %v4float %v4int %v4uint %v2float %v2float %mat2v3float %mat2v4float %v2float %v2float %v2float %mat3v3float %mat3v4float %v2float %v2float %v2float %v2float %mat4v3float %mat4v4float %_arr_v3float_uint_2
      %uint_8 = OpConstant %uint 8
 %_arr_Inner_std140_uint_8 = OpTypeArray %Inner_std140 %uint_8
    %S_std140 = OpTypeStruct %_arr_Inner_std140_uint_8
-%s_block_std140 = OpTypeStruct %S_std140
-%_ptr_Uniform_s_block_std140 = OpTypePointer Uniform %s_block_std140
-          %s = OpVariable %_ptr_Uniform_s_block_std140 Uniform
-%mat3v2float = OpTypeMatrix %v2float 3
-         %22 = OpTypeFunction %mat3v2float %uint
+%ub_block_std140 = OpTypeStruct %S_std140
+%_ptr_Uniform_ub_block_std140 = OpTypePointer Uniform %ub_block_std140
+         %ub = OpVariable %_ptr_Uniform_ub_block_std140 Uniform
+%mat2v2float = OpTypeMatrix %v2float 2
+         %30 = OpTypeFunction %mat2v2float %uint
      %uint_0 = OpConstant %uint 0
 %_ptr_Uniform_Inner_std140 = OpTypePointer Uniform %Inner_std140
-     %uint_9 = OpConstant %uint 9
+    %uint_12 = OpConstant %uint 12
 %_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
-    %uint_10 = OpConstant %uint 10
-    %uint_11 = OpConstant %uint 11
+    %uint_13 = OpConstant %uint 13
+%mat3v2float = OpTypeMatrix %v2float 3
+         %49 = OpTypeFunction %mat3v2float %uint
+    %uint_16 = OpConstant %uint 16
+    %uint_17 = OpConstant %uint 17
+    %uint_18 = OpConstant %uint 18
+%mat4v2float = OpTypeMatrix %v2float 4
+         %69 = OpTypeFunction %mat4v2float %uint
+    %uint_21 = OpConstant %uint 21
+    %uint_22 = OpConstant %uint 22
+    %uint_23 = OpConstant %uint 23
+    %uint_24 = OpConstant %uint 24
        %void = OpTypeVoid
-         %45 = OpTypeFunction %void %uint
-%_ptr_Uniform_v3int = OpTypePointer Uniform %v3int
+         %93 = OpTypeFunction %void %uint
+%_ptr_Uniform_float = OpTypePointer Uniform %float
      %uint_1 = OpConstant %uint 1
 %_ptr_Uniform_int = OpTypePointer Uniform %int
-     %uint_2 = OpConstant %uint 2
-%_ptr_Uniform_v3uint = OpTypePointer Uniform %v3uint
-     %uint_3 = OpConstant %uint 3
 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
-%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
-     %uint_5 = OpConstant %uint 5
-%_ptr_Uniform_float = OpTypePointer Uniform %float
-     %uint_6 = OpConstant %uint 6
+     %uint_3 = OpConstant %uint 3
+     %uint_4 = OpConstant %uint 4
 %_ptr_Uniform_v2int = OpTypePointer Uniform %v2int
+     %uint_5 = OpConstant %uint 5
+%_ptr_Uniform_v2uint = OpTypePointer Uniform %v2uint
+     %uint_6 = OpConstant %uint 6
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
      %uint_7 = OpConstant %uint 7
+%_ptr_Uniform_v3int = OpTypePointer Uniform %v3int
+%_ptr_Uniform_v3uint = OpTypePointer Uniform %v3uint
+     %uint_9 = OpConstant %uint 9
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+    %uint_10 = OpConstant %uint 10
+%_ptr_Uniform_v4int = OpTypePointer Uniform %v4int
+    %uint_11 = OpConstant %uint 11
+%_ptr_Uniform_v4uint = OpTypePointer Uniform %v4uint
+    %uint_14 = OpConstant %uint 14
 %_ptr_Uniform_mat2v3float = OpTypePointer Uniform %mat2v3float
-    %uint_12 = OpConstant %uint 12
-%_ptr_Uniform__arr_v4int_uint_4 = OpTypePointer Uniform %_arr_v4int_uint_4
-         %88 = OpTypeFunction %void
-%load_s_inner_arr_p0_j = OpFunction %mat3v2float None %22
+    %uint_15 = OpConstant %uint 15
+%_ptr_Uniform_mat2v4float = OpTypePointer Uniform %mat2v4float
+    %uint_19 = OpConstant %uint 19
+%_ptr_Uniform_mat3v3float = OpTypePointer Uniform %mat3v3float
+    %uint_20 = OpConstant %uint 20
+%_ptr_Uniform_mat3v4float = OpTypePointer Uniform %mat3v4float
+    %uint_25 = OpConstant %uint 25
+%_ptr_Uniform_mat4v3float = OpTypePointer Uniform %mat4v3float
+    %uint_26 = OpConstant %uint 26
+%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float
+    %uint_27 = OpConstant %uint 27
+%_ptr_Uniform__arr_v3float_uint_2 = OpTypePointer Uniform %_arr_v3float_uint_2
+        %176 = OpTypeFunction %void
+%load_ub_inner_arr_p0_mat2x2_f32 = OpFunction %mat2v2float None %30
          %p0 = OpFunctionParameter %uint
-         %26 = OpLabel
-         %30 = OpAccessChain %_ptr_Uniform_Inner_std140 %s %uint_0 %uint_0 %p0
-         %34 = OpAccessChain %_ptr_Uniform_v2float %30 %uint_9
-         %35 = OpLoad %v2float %34
-         %38 = OpAccessChain %_ptr_Uniform_v2float %30 %uint_10
-         %39 = OpLoad %v2float %38
-         %42 = OpAccessChain %_ptr_Uniform_v2float %30 %uint_11
+         %34 = OpLabel
+         %38 = OpAccessChain %_ptr_Uniform_Inner_std140 %ub %uint_0 %uint_0 %p0
+         %42 = OpAccessChain %_ptr_Uniform_v2float %38 %uint_12
          %43 = OpLoad %v2float %42
-         %44 = OpCompositeConstruct %mat3v2float %35 %39 %43
-               OpReturnValue %44
+         %46 = OpAccessChain %_ptr_Uniform_v2float %38 %uint_13
+         %47 = OpLoad %v2float %46
+         %48 = OpCompositeConstruct %mat2v2float %43 %47
+               OpReturnValue %48
                OpFunctionEnd
- %main_inner = OpFunction %void None %45
+%load_ub_inner_arr_p0_mat3x2_f32 = OpFunction %mat3v2float None %49
+       %p0_0 = OpFunctionParameter %uint
+         %53 = OpLabel
+         %55 = OpAccessChain %_ptr_Uniform_Inner_std140 %ub %uint_0 %uint_0 %p0_0
+         %58 = OpAccessChain %_ptr_Uniform_v2float %55 %uint_16
+         %59 = OpLoad %v2float %58
+         %62 = OpAccessChain %_ptr_Uniform_v2float %55 %uint_17
+         %63 = OpLoad %v2float %62
+         %66 = OpAccessChain %_ptr_Uniform_v2float %55 %uint_18
+         %67 = OpLoad %v2float %66
+         %68 = OpCompositeConstruct %mat3v2float %59 %63 %67
+               OpReturnValue %68
+               OpFunctionEnd
+%load_ub_inner_arr_p0_mat4x2_f32 = OpFunction %mat4v2float None %69
+       %p0_1 = OpFunctionParameter %uint
+         %73 = OpLabel
+         %75 = OpAccessChain %_ptr_Uniform_Inner_std140 %ub %uint_0 %uint_0 %p0_1
+         %78 = OpAccessChain %_ptr_Uniform_v2float %75 %uint_21
+         %79 = OpLoad %v2float %78
+         %82 = OpAccessChain %_ptr_Uniform_v2float %75 %uint_22
+         %83 = OpLoad %v2float %82
+         %86 = OpAccessChain %_ptr_Uniform_v2float %75 %uint_23
+         %87 = OpLoad %v2float %86
+         %90 = OpAccessChain %_ptr_Uniform_v2float %75 %uint_24
+         %91 = OpLoad %v2float %90
+         %92 = OpCompositeConstruct %mat4v2float %79 %83 %87 %91
+               OpReturnValue %92
+               OpFunctionEnd
+ %main_inner = OpFunction %void None %93
         %idx = OpFunctionParameter %uint
-         %49 = OpLabel
-         %51 = OpAccessChain %_ptr_Uniform_v3int %s %uint_0 %uint_0 %idx %uint_0
-         %52 = OpLoad %v3int %51
-         %55 = OpAccessChain %_ptr_Uniform_int %s %uint_0 %uint_0 %idx %uint_1
-         %56 = OpLoad %int %55
-         %59 = OpAccessChain %_ptr_Uniform_v3uint %s %uint_0 %uint_0 %idx %uint_2
-         %60 = OpLoad %v3uint %59
-         %63 = OpAccessChain %_ptr_Uniform_uint %s %uint_0 %uint_0 %idx %uint_3
-         %64 = OpLoad %uint %63
-         %66 = OpAccessChain %_ptr_Uniform_v3float %s %uint_0 %uint_0 %idx %uint_4
-         %67 = OpLoad %v3float %66
-         %70 = OpAccessChain %_ptr_Uniform_float %s %uint_0 %uint_0 %idx %uint_5
-         %71 = OpLoad %float %70
-         %74 = OpAccessChain %_ptr_Uniform_v2int %s %uint_0 %uint_0 %idx %uint_6
-         %75 = OpLoad %v2int %74
-         %77 = OpAccessChain %_ptr_Uniform_v2int %s %uint_0 %uint_0 %idx %uint_7
-         %78 = OpLoad %v2int %77
-         %80 = OpAccessChain %_ptr_Uniform_mat2v3float %s %uint_0 %uint_0 %idx %uint_8
-         %81 = OpLoad %mat2v3float %80
-         %82 = OpFunctionCall %mat3v2float %load_s_inner_arr_p0_j %idx
-         %86 = OpAccessChain %_ptr_Uniform__arr_v4int_uint_4 %s %uint_0 %uint_0 %idx %uint_12
-         %87 = OpLoad %_arr_v4int_uint_4 %86
+         %97 = OpLabel
+         %99 = OpAccessChain %_ptr_Uniform_float %ub %uint_0 %uint_0 %idx %uint_0
+        %100 = OpLoad %float %99
+        %103 = OpAccessChain %_ptr_Uniform_int %ub %uint_0 %uint_0 %idx %uint_1
+        %104 = OpLoad %int %103
+        %106 = OpAccessChain %_ptr_Uniform_uint %ub %uint_0 %uint_0 %idx %uint_2
+        %107 = OpLoad %uint %106
+        %109 = OpAccessChain %_ptr_Uniform_v2float %ub %uint_0 %uint_0 %idx %uint_3
+        %110 = OpLoad %v2float %109
+        %113 = OpAccessChain %_ptr_Uniform_v2int %ub %uint_0 %uint_0 %idx %uint_4
+        %114 = OpLoad %v2int %113
+        %117 = OpAccessChain %_ptr_Uniform_v2uint %ub %uint_0 %uint_0 %idx %uint_5
+        %118 = OpLoad %v2uint %117
+        %121 = OpAccessChain %_ptr_Uniform_v3float %ub %uint_0 %uint_0 %idx %uint_6
+        %122 = OpLoad %v3float %121
+        %125 = OpAccessChain %_ptr_Uniform_v3int %ub %uint_0 %uint_0 %idx %uint_7
+        %126 = OpLoad %v3int %125
+        %128 = OpAccessChain %_ptr_Uniform_v3uint %ub %uint_0 %uint_0 %idx %uint_8
+        %129 = OpLoad %v3uint %128
+        %132 = OpAccessChain %_ptr_Uniform_v4float %ub %uint_0 %uint_0 %idx %uint_9
+        %133 = OpLoad %v4float %132
+        %136 = OpAccessChain %_ptr_Uniform_v4int %ub %uint_0 %uint_0 %idx %uint_10
+        %137 = OpLoad %v4int %136
+        %140 = OpAccessChain %_ptr_Uniform_v4uint %ub %uint_0 %uint_0 %idx %uint_11
+        %141 = OpLoad %v4uint %140
+        %142 = OpFunctionCall %mat2v2float %load_ub_inner_arr_p0_mat2x2_f32 %idx
+        %146 = OpAccessChain %_ptr_Uniform_mat2v3float %ub %uint_0 %uint_0 %idx %uint_14
+        %147 = OpLoad %mat2v3float %146
+        %150 = OpAccessChain %_ptr_Uniform_mat2v4float %ub %uint_0 %uint_0 %idx %uint_15
+        %151 = OpLoad %mat2v4float %150
+        %152 = OpFunctionCall %mat3v2float %load_ub_inner_arr_p0_mat3x2_f32 %idx
+        %156 = OpAccessChain %_ptr_Uniform_mat3v3float %ub %uint_0 %uint_0 %idx %uint_19
+        %157 = OpLoad %mat3v3float %156
+        %160 = OpAccessChain %_ptr_Uniform_mat3v4float %ub %uint_0 %uint_0 %idx %uint_20
+        %161 = OpLoad %mat3v4float %160
+        %162 = OpFunctionCall %mat4v2float %load_ub_inner_arr_p0_mat4x2_f32 %idx
+        %166 = OpAccessChain %_ptr_Uniform_mat4v3float %ub %uint_0 %uint_0 %idx %uint_25
+        %167 = OpLoad %mat4v3float %166
+        %170 = OpAccessChain %_ptr_Uniform_mat4v4float %ub %uint_0 %uint_0 %idx %uint_26
+        %171 = OpLoad %mat4v4float %170
+        %174 = OpAccessChain %_ptr_Uniform__arr_v3float_uint_2 %ub %uint_0 %uint_0 %idx %uint_27
+        %175 = OpLoad %_arr_v3float_uint_2 %174
                OpReturn
                OpFunctionEnd
-       %main = OpFunction %void None %88
-         %90 = OpLabel
-         %92 = OpLoad %uint %idx_1
-         %91 = OpFunctionCall %void %main_inner %92
+       %main = OpFunction %void None %176
+        %178 = OpLabel
+        %180 = OpLoad %uint %idx_1
+        %179 = OpFunctionCall %void %main_inner %180
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/buffer/uniform/dynamic_index/read.wgsl.expected.wgsl b/test/tint/buffer/uniform/dynamic_index/read.wgsl.expected.wgsl
index 8c8e684..80d5296 100644
--- a/test/tint/buffer/uniform/dynamic_index/read.wgsl.expected.wgsl
+++ b/test/tint/buffer/uniform/dynamic_index/read.wgsl.expected.wgsl
@@ -1,36 +1,57 @@
 struct Inner {
-  a : vec3<i32>,
-  b : i32,
-  c : vec3<u32>,
-  d : u32,
-  e : vec3<f32>,
-  f : f32,
-  g : vec2<i32>,
-  h : vec2<i32>,
-  i : mat2x3<f32>,
+  scalar_f32 : f32,
+  scalar_i32 : i32,
+  scalar_u32 : u32,
+  vec2_f32 : vec2<f32>,
+  vec2_i32 : vec2<i32>,
+  vec2_u32 : vec2<u32>,
+  vec3_f32 : vec3<f32>,
+  vec3_i32 : vec3<i32>,
+  vec3_u32 : vec3<u32>,
+  vec4_f32 : vec4<f32>,
+  vec4_i32 : vec4<i32>,
+  vec4_u32 : vec4<u32>,
+  mat2x2_f32 : mat2x2<f32>,
+  mat2x3_f32 : mat2x3<f32>,
+  mat2x4_f32 : mat2x4<f32>,
+  mat3x2_f32 : mat3x2<f32>,
+  mat3x3_f32 : mat3x3<f32>,
+  mat3x4_f32 : mat3x4<f32>,
+  mat4x2_f32 : mat4x2<f32>,
+  mat4x3_f32 : mat4x3<f32>,
+  mat4x4_f32 : mat4x4<f32>,
   @align(16)
-  j : mat3x2<f32>,
-  @align(16)
-  k : array<vec4<i32>, 4>,
+  arr2_vec3_f32 : array<vec3<f32>, 2>,
 }
 
 struct S {
   arr : array<Inner, 8>,
 }
 
-@binding(0) @group(0) var<uniform> s : S;
+@binding(0) @group(0) var<uniform> ub : S;
 
 @compute @workgroup_size(1)
 fn main(@builtin(local_invocation_index) idx : u32) {
-  let a = s.arr[idx].a;
-  let b = s.arr[idx].b;
-  let c = s.arr[idx].c;
-  let d = s.arr[idx].d;
-  let e = s.arr[idx].e;
-  let f = s.arr[idx].f;
-  let g = s.arr[idx].g;
-  let h = s.arr[idx].h;
-  let i = s.arr[idx].i;
-  let j = s.arr[idx].j;
-  let k = s.arr[idx].k;
+  let scalar_f32 : f32 = ub.arr[idx].scalar_f32;
+  let scalar_i32 : i32 = ub.arr[idx].scalar_i32;
+  let scalar_u32 : u32 = ub.arr[idx].scalar_u32;
+  let vec2_f32 : vec2<f32> = ub.arr[idx].vec2_f32;
+  let vec2_i32 : vec2<i32> = ub.arr[idx].vec2_i32;
+  let vec2_u32 : vec2<u32> = ub.arr[idx].vec2_u32;
+  let vec3_f32 : vec3<f32> = ub.arr[idx].vec3_f32;
+  let vec3_i32 : vec3<i32> = ub.arr[idx].vec3_i32;
+  let vec3_u32 : vec3<u32> = ub.arr[idx].vec3_u32;
+  let vec4_f32 : vec4<f32> = ub.arr[idx].vec4_f32;
+  let vec4_i32 : vec4<i32> = ub.arr[idx].vec4_i32;
+  let vec4_u32 : vec4<u32> = ub.arr[idx].vec4_u32;
+  let mat2x2_f32 : mat2x2<f32> = ub.arr[idx].mat2x2_f32;
+  let mat2x3_f32 : mat2x3<f32> = ub.arr[idx].mat2x3_f32;
+  let mat2x4_f32 : mat2x4<f32> = ub.arr[idx].mat2x4_f32;
+  let mat3x2_f32 : mat3x2<f32> = ub.arr[idx].mat3x2_f32;
+  let mat3x3_f32 : mat3x3<f32> = ub.arr[idx].mat3x3_f32;
+  let mat3x4_f32 : mat3x4<f32> = ub.arr[idx].mat3x4_f32;
+  let mat4x2_f32 : mat4x2<f32> = ub.arr[idx].mat4x2_f32;
+  let mat4x3_f32 : mat4x3<f32> = ub.arr[idx].mat4x3_f32;
+  let mat4x4_f32 : mat4x4<f32> = ub.arr[idx].mat4x4_f32;
+  let arr2_vec3_f32 : array<vec3<f32>, 2> = ub.arr[idx].arr2_vec3_f32;
 }
diff --git a/test/tint/buffer/uniform/dynamic_index/read_f16.wgsl b/test/tint/buffer/uniform/dynamic_index/read_f16.wgsl
new file mode 100644
index 0000000..707e982
--- /dev/null
+++ b/test/tint/buffer/uniform/dynamic_index/read_f16.wgsl
@@ -0,0 +1,86 @@
+enable f16;
+
+struct Inner {
+    scalar_f32 : f32,
+    scalar_i32 : i32,
+    scalar_u32 : u32,
+    scalar_f16 : f16,
+    vec2_f32 : vec2<f32>,
+    vec2_i32 : vec2<i32>,
+    vec2_u32 : vec2<u32>,
+    vec2_f16 : vec2<f16>,
+    vec3_f32 : vec3<f32>,
+    vec3_i32 : vec3<i32>,
+    vec3_u32 : vec3<u32>,
+    vec3_f16 : vec3<f16>,
+    vec4_f32 : vec4<f32>,
+    vec4_i32 : vec4<i32>,
+    vec4_u32 : vec4<u32>,
+    vec4_f16 : vec4<f16>,
+    mat2x2_f32 : mat2x2<f32>,
+    mat2x3_f32 : mat2x3<f32>,
+    mat2x4_f32 : mat2x4<f32>,
+    mat3x2_f32 : mat3x2<f32>,
+    mat3x3_f32 : mat3x3<f32>,
+    mat3x4_f32 : mat3x4<f32>,
+    mat4x2_f32 : mat4x2<f32>,
+    mat4x3_f32 : mat4x3<f32>,
+    mat4x4_f32 : mat4x4<f32>,
+    mat2x2_f16 : mat2x2<f16>,
+    mat2x3_f16 : mat2x3<f16>,
+    mat2x4_f16 : mat2x4<f16>,
+    mat3x2_f16 : mat3x2<f16>,
+    mat3x3_f16 : mat3x3<f16>,
+    mat3x4_f16 : mat3x4<f16>,
+    mat4x2_f16 : mat4x2<f16>,
+    mat4x3_f16 : mat4x3<f16>,
+    mat4x4_f16 : mat4x4<f16>,
+    @align(16) arr2_vec3_f32 : array<vec3<f32>, 2>,
+    arr2_mat4x2_f16 : array<mat4x2<f16>, 2>,
+};
+
+struct S {
+    arr : array<Inner, 8>,
+};
+
+@binding(0) @group(0) var<uniform> ub : S;
+
+@compute @workgroup_size(1)
+fn main(@builtin(local_invocation_index) idx : u32) {
+    let scalar_f32 : f32 = ub.arr[idx].scalar_f32;
+    let scalar_i32 : i32 = ub.arr[idx].scalar_i32;
+    let scalar_u32 : u32 = ub.arr[idx].scalar_u32;
+    let scalar_f16 : f16 = ub.arr[idx].scalar_f16;
+    let vec2_f32 : vec2<f32> = ub.arr[idx].vec2_f32;
+    let vec2_i32 : vec2<i32> = ub.arr[idx].vec2_i32;
+    let vec2_u32 : vec2<u32> = ub.arr[idx].vec2_u32;
+    let vec2_f16 : vec2<f16> = ub.arr[idx].vec2_f16;
+    let vec3_f32 : vec3<f32> = ub.arr[idx].vec3_f32;
+    let vec3_i32 : vec3<i32> = ub.arr[idx].vec3_i32;
+    let vec3_u32 : vec3<u32> = ub.arr[idx].vec3_u32;
+    let vec3_f16 : vec3<f16> = ub.arr[idx].vec3_f16;
+    let vec4_f32 : vec4<f32> = ub.arr[idx].vec4_f32;
+    let vec4_i32 : vec4<i32> = ub.arr[idx].vec4_i32;
+    let vec4_u32 : vec4<u32> = ub.arr[idx].vec4_u32;
+    let vec4_f16 : vec4<f16> = ub.arr[idx].vec4_f16;
+    let mat2x2_f32 : mat2x2<f32> = ub.arr[idx].mat2x2_f32;
+    let mat2x3_f32 : mat2x3<f32> = ub.arr[idx].mat2x3_f32;
+    let mat2x4_f32 : mat2x4<f32> = ub.arr[idx].mat2x4_f32;
+    let mat3x2_f32 : mat3x2<f32> = ub.arr[idx].mat3x2_f32;
+    let mat3x3_f32 : mat3x3<f32> = ub.arr[idx].mat3x3_f32;
+    let mat3x4_f32 : mat3x4<f32> = ub.arr[idx].mat3x4_f32;
+    let mat4x2_f32 : mat4x2<f32> = ub.arr[idx].mat4x2_f32;
+    let mat4x3_f32 : mat4x3<f32> = ub.arr[idx].mat4x3_f32;
+    let mat4x4_f32 : mat4x4<f32> = ub.arr[idx].mat4x4_f32;
+    let mat2x2_f16 : mat2x2<f16> = ub.arr[idx].mat2x2_f16;
+    let mat2x3_f16 : mat2x3<f16> = ub.arr[idx].mat2x3_f16;
+    let mat2x4_f16 : mat2x4<f16> = ub.arr[idx].mat2x4_f16;
+    let mat3x2_f16 : mat3x2<f16> = ub.arr[idx].mat3x2_f16;
+    let mat3x3_f16 : mat3x3<f16> = ub.arr[idx].mat3x3_f16;
+    let mat3x4_f16 : mat3x4<f16> = ub.arr[idx].mat3x4_f16;
+    let mat4x2_f16 : mat4x2<f16> = ub.arr[idx].mat4x2_f16;
+    let mat4x3_f16 : mat4x3<f16> = ub.arr[idx].mat4x3_f16;
+    let mat4x4_f16 : mat4x4<f16> = ub.arr[idx].mat4x4_f16;
+    let arr2_vec3_f32 : array<vec3<f32>, 2> = ub.arr[idx].arr2_vec3_f32;
+    let arr2_mat4x2_f16 : array<mat4x2<f16>, 2> = ub.arr[idx].arr2_mat4x2_f16;
+}
\ No newline at end of file
diff --git a/test/tint/buffer/uniform/dynamic_index/read_f16.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/dynamic_index/read_f16.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..5ba1911
--- /dev/null
+++ b/test/tint/buffer/uniform/dynamic_index/read_f16.wgsl.expected.dxc.hlsl
@@ -0,0 +1,320 @@
+cbuffer cbuffer_ub : register(b0, space0) {
+  uint4 ub[400];
+};
+
+struct tint_symbol_1 {
+  uint idx : SV_GroupIndex;
+};
+
+float2x2 tint_symbol_18(uint4 buffer[400], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  return float2x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)));
+}
+
+float2x3 tint_symbol_19(uint4 buffer[400], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+float2x4 tint_symbol_20(uint4 buffer[400], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset_4 / 4]), asfloat(buffer[scalar_offset_5 / 4]));
+}
+
+float3x2 tint_symbol_21(uint4 buffer[400], uint offset) {
+  const uint scalar_offset_6 = ((offset + 0u)) / 4;
+  uint4 ubo_load_2 = buffer[scalar_offset_6 / 4];
+  const uint scalar_offset_7 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_7 / 4];
+  const uint scalar_offset_8 = ((offset + 16u)) / 4;
+  uint4 ubo_load_4 = buffer[scalar_offset_8 / 4];
+  return float3x2(asfloat(((scalar_offset_6 & 2) ? ubo_load_2.zw : ubo_load_2.xy)), asfloat(((scalar_offset_7 & 2) ? ubo_load_3.zw : ubo_load_3.xy)), asfloat(((scalar_offset_8 & 2) ? ubo_load_4.zw : ubo_load_4.xy)));
+}
+
+float3x3 tint_symbol_22(uint4 buffer[400], uint offset) {
+  const uint scalar_offset_9 = ((offset + 0u)) / 4;
+  const uint scalar_offset_10 = ((offset + 16u)) / 4;
+  const uint scalar_offset_11 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset_9 / 4].xyz), asfloat(buffer[scalar_offset_10 / 4].xyz), asfloat(buffer[scalar_offset_11 / 4].xyz));
+}
+
+float3x4 tint_symbol_23(uint4 buffer[400], uint offset) {
+  const uint scalar_offset_12 = ((offset + 0u)) / 4;
+  const uint scalar_offset_13 = ((offset + 16u)) / 4;
+  const uint scalar_offset_14 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset_12 / 4]), asfloat(buffer[scalar_offset_13 / 4]), asfloat(buffer[scalar_offset_14 / 4]));
+}
+
+float4x2 tint_symbol_24(uint4 buffer[400], uint offset) {
+  const uint scalar_offset_15 = ((offset + 0u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_15 / 4];
+  const uint scalar_offset_16 = ((offset + 8u)) / 4;
+  uint4 ubo_load_6 = buffer[scalar_offset_16 / 4];
+  const uint scalar_offset_17 = ((offset + 16u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_17 / 4];
+  const uint scalar_offset_18 = ((offset + 24u)) / 4;
+  uint4 ubo_load_8 = buffer[scalar_offset_18 / 4];
+  return float4x2(asfloat(((scalar_offset_15 & 2) ? ubo_load_5.zw : ubo_load_5.xy)), asfloat(((scalar_offset_16 & 2) ? ubo_load_6.zw : ubo_load_6.xy)), asfloat(((scalar_offset_17 & 2) ? ubo_load_7.zw : ubo_load_7.xy)), asfloat(((scalar_offset_18 & 2) ? ubo_load_8.zw : ubo_load_8.xy)));
+}
+
+float4x3 tint_symbol_25(uint4 buffer[400], uint offset) {
+  const uint scalar_offset_19 = ((offset + 0u)) / 4;
+  const uint scalar_offset_20 = ((offset + 16u)) / 4;
+  const uint scalar_offset_21 = ((offset + 32u)) / 4;
+  const uint scalar_offset_22 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset_19 / 4].xyz), asfloat(buffer[scalar_offset_20 / 4].xyz), asfloat(buffer[scalar_offset_21 / 4].xyz), asfloat(buffer[scalar_offset_22 / 4].xyz));
+}
+
+float4x4 tint_symbol_26(uint4 buffer[400], uint offset) {
+  const uint scalar_offset_23 = ((offset + 0u)) / 4;
+  const uint scalar_offset_24 = ((offset + 16u)) / 4;
+  const uint scalar_offset_25 = ((offset + 32u)) / 4;
+  const uint scalar_offset_26 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset_23 / 4]), asfloat(buffer[scalar_offset_24 / 4]), asfloat(buffer[scalar_offset_25 / 4]), asfloat(buffer[scalar_offset_26 / 4]));
+}
+
+matrix<float16_t, 2, 2> tint_symbol_27(uint4 buffer[400], uint offset) {
+  const uint scalar_offset_27 = ((offset + 0u)) / 4;
+  uint ubo_load_9 = buffer[scalar_offset_27 / 4][scalar_offset_27 % 4];
+  const uint scalar_offset_28 = ((offset + 4u)) / 4;
+  uint ubo_load_10 = buffer[scalar_offset_28 / 4][scalar_offset_28 % 4];
+  return matrix<float16_t, 2, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_9 & 0xFFFF)), float16_t(f16tof32(ubo_load_9 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_10 & 0xFFFF)), float16_t(f16tof32(ubo_load_10 >> 16))));
+}
+
+matrix<float16_t, 2, 3> tint_symbol_28(uint4 buffer[400], uint offset) {
+  const uint scalar_offset_29 = ((offset + 0u)) / 4;
+  uint4 ubo_load_12 = buffer[scalar_offset_29 / 4];
+  uint2 ubo_load_11 = ((scalar_offset_29 & 2) ? ubo_load_12.zw : ubo_load_12.xy);
+  vector<float16_t, 2> ubo_load_11_xz = vector<float16_t, 2>(f16tof32(ubo_load_11 & 0xFFFF));
+  float16_t ubo_load_11_y = f16tof32(ubo_load_11[0] >> 16);
+  const uint scalar_offset_30 = ((offset + 8u)) / 4;
+  uint4 ubo_load_14 = buffer[scalar_offset_30 / 4];
+  uint2 ubo_load_13 = ((scalar_offset_30 & 2) ? ubo_load_14.zw : ubo_load_14.xy);
+  vector<float16_t, 2> ubo_load_13_xz = vector<float16_t, 2>(f16tof32(ubo_load_13 & 0xFFFF));
+  float16_t ubo_load_13_y = f16tof32(ubo_load_13[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_11_xz[0], ubo_load_11_y, ubo_load_11_xz[1]), vector<float16_t, 3>(ubo_load_13_xz[0], ubo_load_13_y, ubo_load_13_xz[1]));
+}
+
+matrix<float16_t, 2, 4> tint_symbol_29(uint4 buffer[400], uint offset) {
+  const uint scalar_offset_31 = ((offset + 0u)) / 4;
+  uint4 ubo_load_16 = buffer[scalar_offset_31 / 4];
+  uint2 ubo_load_15 = ((scalar_offset_31 & 2) ? ubo_load_16.zw : ubo_load_16.xy);
+  vector<float16_t, 2> ubo_load_15_xz = vector<float16_t, 2>(f16tof32(ubo_load_15 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_15_yw = vector<float16_t, 2>(f16tof32(ubo_load_15 >> 16));
+  const uint scalar_offset_32 = ((offset + 8u)) / 4;
+  uint4 ubo_load_18 = buffer[scalar_offset_32 / 4];
+  uint2 ubo_load_17 = ((scalar_offset_32 & 2) ? ubo_load_18.zw : ubo_load_18.xy);
+  vector<float16_t, 2> ubo_load_17_xz = vector<float16_t, 2>(f16tof32(ubo_load_17 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_17_yw = vector<float16_t, 2>(f16tof32(ubo_load_17 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_15_xz[0], ubo_load_15_yw[0], ubo_load_15_xz[1], ubo_load_15_yw[1]), vector<float16_t, 4>(ubo_load_17_xz[0], ubo_load_17_yw[0], ubo_load_17_xz[1], ubo_load_17_yw[1]));
+}
+
+matrix<float16_t, 3, 2> tint_symbol_30(uint4 buffer[400], uint offset) {
+  const uint scalar_offset_33 = ((offset + 0u)) / 4;
+  uint ubo_load_19 = buffer[scalar_offset_33 / 4][scalar_offset_33 % 4];
+  const uint scalar_offset_34 = ((offset + 4u)) / 4;
+  uint ubo_load_20 = buffer[scalar_offset_34 / 4][scalar_offset_34 % 4];
+  const uint scalar_offset_35 = ((offset + 8u)) / 4;
+  uint ubo_load_21 = buffer[scalar_offset_35 / 4][scalar_offset_35 % 4];
+  return matrix<float16_t, 3, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_19 & 0xFFFF)), float16_t(f16tof32(ubo_load_19 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_20 & 0xFFFF)), float16_t(f16tof32(ubo_load_20 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_21 & 0xFFFF)), float16_t(f16tof32(ubo_load_21 >> 16))));
+}
+
+matrix<float16_t, 3, 3> tint_symbol_31(uint4 buffer[400], uint offset) {
+  const uint scalar_offset_36 = ((offset + 0u)) / 4;
+  uint4 ubo_load_23 = buffer[scalar_offset_36 / 4];
+  uint2 ubo_load_22 = ((scalar_offset_36 & 2) ? ubo_load_23.zw : ubo_load_23.xy);
+  vector<float16_t, 2> ubo_load_22_xz = vector<float16_t, 2>(f16tof32(ubo_load_22 & 0xFFFF));
+  float16_t ubo_load_22_y = f16tof32(ubo_load_22[0] >> 16);
+  const uint scalar_offset_37 = ((offset + 8u)) / 4;
+  uint4 ubo_load_25 = buffer[scalar_offset_37 / 4];
+  uint2 ubo_load_24 = ((scalar_offset_37 & 2) ? ubo_load_25.zw : ubo_load_25.xy);
+  vector<float16_t, 2> ubo_load_24_xz = vector<float16_t, 2>(f16tof32(ubo_load_24 & 0xFFFF));
+  float16_t ubo_load_24_y = f16tof32(ubo_load_24[0] >> 16);
+  const uint scalar_offset_38 = ((offset + 16u)) / 4;
+  uint4 ubo_load_27 = buffer[scalar_offset_38 / 4];
+  uint2 ubo_load_26 = ((scalar_offset_38 & 2) ? ubo_load_27.zw : ubo_load_27.xy);
+  vector<float16_t, 2> ubo_load_26_xz = vector<float16_t, 2>(f16tof32(ubo_load_26 & 0xFFFF));
+  float16_t ubo_load_26_y = f16tof32(ubo_load_26[0] >> 16);
+  return matrix<float16_t, 3, 3>(vector<float16_t, 3>(ubo_load_22_xz[0], ubo_load_22_y, ubo_load_22_xz[1]), vector<float16_t, 3>(ubo_load_24_xz[0], ubo_load_24_y, ubo_load_24_xz[1]), vector<float16_t, 3>(ubo_load_26_xz[0], ubo_load_26_y, ubo_load_26_xz[1]));
+}
+
+matrix<float16_t, 3, 4> tint_symbol_32(uint4 buffer[400], uint offset) {
+  const uint scalar_offset_39 = ((offset + 0u)) / 4;
+  uint4 ubo_load_29 = buffer[scalar_offset_39 / 4];
+  uint2 ubo_load_28 = ((scalar_offset_39 & 2) ? ubo_load_29.zw : ubo_load_29.xy);
+  vector<float16_t, 2> ubo_load_28_xz = vector<float16_t, 2>(f16tof32(ubo_load_28 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_28_yw = vector<float16_t, 2>(f16tof32(ubo_load_28 >> 16));
+  const uint scalar_offset_40 = ((offset + 8u)) / 4;
+  uint4 ubo_load_31 = buffer[scalar_offset_40 / 4];
+  uint2 ubo_load_30 = ((scalar_offset_40 & 2) ? ubo_load_31.zw : ubo_load_31.xy);
+  vector<float16_t, 2> ubo_load_30_xz = vector<float16_t, 2>(f16tof32(ubo_load_30 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_30_yw = vector<float16_t, 2>(f16tof32(ubo_load_30 >> 16));
+  const uint scalar_offset_41 = ((offset + 16u)) / 4;
+  uint4 ubo_load_33 = buffer[scalar_offset_41 / 4];
+  uint2 ubo_load_32 = ((scalar_offset_41 & 2) ? ubo_load_33.zw : ubo_load_33.xy);
+  vector<float16_t, 2> ubo_load_32_xz = vector<float16_t, 2>(f16tof32(ubo_load_32 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_32_yw = vector<float16_t, 2>(f16tof32(ubo_load_32 >> 16));
+  return matrix<float16_t, 3, 4>(vector<float16_t, 4>(ubo_load_28_xz[0], ubo_load_28_yw[0], ubo_load_28_xz[1], ubo_load_28_yw[1]), vector<float16_t, 4>(ubo_load_30_xz[0], ubo_load_30_yw[0], ubo_load_30_xz[1], ubo_load_30_yw[1]), vector<float16_t, 4>(ubo_load_32_xz[0], ubo_load_32_yw[0], ubo_load_32_xz[1], ubo_load_32_yw[1]));
+}
+
+matrix<float16_t, 4, 2> tint_symbol_33(uint4 buffer[400], uint offset) {
+  const uint scalar_offset_42 = ((offset + 0u)) / 4;
+  uint ubo_load_34 = buffer[scalar_offset_42 / 4][scalar_offset_42 % 4];
+  const uint scalar_offset_43 = ((offset + 4u)) / 4;
+  uint ubo_load_35 = buffer[scalar_offset_43 / 4][scalar_offset_43 % 4];
+  const uint scalar_offset_44 = ((offset + 8u)) / 4;
+  uint ubo_load_36 = buffer[scalar_offset_44 / 4][scalar_offset_44 % 4];
+  const uint scalar_offset_45 = ((offset + 12u)) / 4;
+  uint ubo_load_37 = buffer[scalar_offset_45 / 4][scalar_offset_45 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_34 & 0xFFFF)), float16_t(f16tof32(ubo_load_34 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_35 & 0xFFFF)), float16_t(f16tof32(ubo_load_35 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_36 & 0xFFFF)), float16_t(f16tof32(ubo_load_36 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_37 & 0xFFFF)), float16_t(f16tof32(ubo_load_37 >> 16))));
+}
+
+matrix<float16_t, 4, 3> tint_symbol_34(uint4 buffer[400], uint offset) {
+  const uint scalar_offset_46 = ((offset + 0u)) / 4;
+  uint4 ubo_load_39 = buffer[scalar_offset_46 / 4];
+  uint2 ubo_load_38 = ((scalar_offset_46 & 2) ? ubo_load_39.zw : ubo_load_39.xy);
+  vector<float16_t, 2> ubo_load_38_xz = vector<float16_t, 2>(f16tof32(ubo_load_38 & 0xFFFF));
+  float16_t ubo_load_38_y = f16tof32(ubo_load_38[0] >> 16);
+  const uint scalar_offset_47 = ((offset + 8u)) / 4;
+  uint4 ubo_load_41 = buffer[scalar_offset_47 / 4];
+  uint2 ubo_load_40 = ((scalar_offset_47 & 2) ? ubo_load_41.zw : ubo_load_41.xy);
+  vector<float16_t, 2> ubo_load_40_xz = vector<float16_t, 2>(f16tof32(ubo_load_40 & 0xFFFF));
+  float16_t ubo_load_40_y = f16tof32(ubo_load_40[0] >> 16);
+  const uint scalar_offset_48 = ((offset + 16u)) / 4;
+  uint4 ubo_load_43 = buffer[scalar_offset_48 / 4];
+  uint2 ubo_load_42 = ((scalar_offset_48 & 2) ? ubo_load_43.zw : ubo_load_43.xy);
+  vector<float16_t, 2> ubo_load_42_xz = vector<float16_t, 2>(f16tof32(ubo_load_42 & 0xFFFF));
+  float16_t ubo_load_42_y = f16tof32(ubo_load_42[0] >> 16);
+  const uint scalar_offset_49 = ((offset + 24u)) / 4;
+  uint4 ubo_load_45 = buffer[scalar_offset_49 / 4];
+  uint2 ubo_load_44 = ((scalar_offset_49 & 2) ? ubo_load_45.zw : ubo_load_45.xy);
+  vector<float16_t, 2> ubo_load_44_xz = vector<float16_t, 2>(f16tof32(ubo_load_44 & 0xFFFF));
+  float16_t ubo_load_44_y = f16tof32(ubo_load_44[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_38_xz[0], ubo_load_38_y, ubo_load_38_xz[1]), vector<float16_t, 3>(ubo_load_40_xz[0], ubo_load_40_y, ubo_load_40_xz[1]), vector<float16_t, 3>(ubo_load_42_xz[0], ubo_load_42_y, ubo_load_42_xz[1]), vector<float16_t, 3>(ubo_load_44_xz[0], ubo_load_44_y, ubo_load_44_xz[1]));
+}
+
+matrix<float16_t, 4, 4> tint_symbol_35(uint4 buffer[400], uint offset) {
+  const uint scalar_offset_50 = ((offset + 0u)) / 4;
+  uint4 ubo_load_47 = buffer[scalar_offset_50 / 4];
+  uint2 ubo_load_46 = ((scalar_offset_50 & 2) ? ubo_load_47.zw : ubo_load_47.xy);
+  vector<float16_t, 2> ubo_load_46_xz = vector<float16_t, 2>(f16tof32(ubo_load_46 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_46_yw = vector<float16_t, 2>(f16tof32(ubo_load_46 >> 16));
+  const uint scalar_offset_51 = ((offset + 8u)) / 4;
+  uint4 ubo_load_49 = buffer[scalar_offset_51 / 4];
+  uint2 ubo_load_48 = ((scalar_offset_51 & 2) ? ubo_load_49.zw : ubo_load_49.xy);
+  vector<float16_t, 2> ubo_load_48_xz = vector<float16_t, 2>(f16tof32(ubo_load_48 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_48_yw = vector<float16_t, 2>(f16tof32(ubo_load_48 >> 16));
+  const uint scalar_offset_52 = ((offset + 16u)) / 4;
+  uint4 ubo_load_51 = buffer[scalar_offset_52 / 4];
+  uint2 ubo_load_50 = ((scalar_offset_52 & 2) ? ubo_load_51.zw : ubo_load_51.xy);
+  vector<float16_t, 2> ubo_load_50_xz = vector<float16_t, 2>(f16tof32(ubo_load_50 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_50_yw = vector<float16_t, 2>(f16tof32(ubo_load_50 >> 16));
+  const uint scalar_offset_53 = ((offset + 24u)) / 4;
+  uint4 ubo_load_53 = buffer[scalar_offset_53 / 4];
+  uint2 ubo_load_52 = ((scalar_offset_53 & 2) ? ubo_load_53.zw : ubo_load_53.xy);
+  vector<float16_t, 2> ubo_load_52_xz = vector<float16_t, 2>(f16tof32(ubo_load_52 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_52_yw = vector<float16_t, 2>(f16tof32(ubo_load_52 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_46_xz[0], ubo_load_46_yw[0], ubo_load_46_xz[1], ubo_load_46_yw[1]), vector<float16_t, 4>(ubo_load_48_xz[0], ubo_load_48_yw[0], ubo_load_48_xz[1], ubo_load_48_yw[1]), vector<float16_t, 4>(ubo_load_50_xz[0], ubo_load_50_yw[0], ubo_load_50_xz[1], ubo_load_50_yw[1]), vector<float16_t, 4>(ubo_load_52_xz[0], ubo_load_52_yw[0], ubo_load_52_xz[1], ubo_load_52_yw[1]));
+}
+
+typedef float3 tint_symbol_36_ret[2];
+tint_symbol_36_ret tint_symbol_36(uint4 buffer[400], uint offset) {
+  float3 arr_1[2] = (float3[2])0;
+  {
+    for(uint i = 0u; (i < 2u); i = (i + 1u)) {
+      const uint scalar_offset_54 = ((offset + (i * 16u))) / 4;
+      arr_1[i] = asfloat(buffer[scalar_offset_54 / 4].xyz);
+    }
+  }
+  return arr_1;
+}
+
+typedef matrix<float16_t, 4, 2> tint_symbol_37_ret[2];
+tint_symbol_37_ret tint_symbol_37(uint4 buffer[400], uint offset) {
+  matrix<float16_t, 4, 2> arr_2[2] = (matrix<float16_t, 4, 2>[2])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
+      arr_2[i_1] = tint_symbol_33(buffer, (offset + (i_1 * 16u)));
+    }
+  }
+  return arr_2;
+}
+
+void main_inner(uint idx) {
+  const uint scalar_offset_55 = ((800u * idx)) / 4;
+  const float scalar_f32 = asfloat(ub[scalar_offset_55 / 4][scalar_offset_55 % 4]);
+  const uint scalar_offset_56 = (((800u * idx) + 4u)) / 4;
+  const int scalar_i32 = asint(ub[scalar_offset_56 / 4][scalar_offset_56 % 4]);
+  const uint scalar_offset_57 = (((800u * idx) + 8u)) / 4;
+  const uint scalar_u32 = ub[scalar_offset_57 / 4][scalar_offset_57 % 4];
+  const uint scalar_offset_bytes = (((800u * idx) + 12u));
+  const uint scalar_offset_index = scalar_offset_bytes / 4;
+  const float16_t scalar_f16 = float16_t(f16tof32(((ub[scalar_offset_index / 4][scalar_offset_index % 4] >> (scalar_offset_bytes % 4 == 0 ? 0 : 16)) & 0xFFFF)));
+  const uint scalar_offset_58 = (((800u * idx) + 16u)) / 4;
+  uint4 ubo_load_54 = ub[scalar_offset_58 / 4];
+  const float2 vec2_f32 = asfloat(((scalar_offset_58 & 2) ? ubo_load_54.zw : ubo_load_54.xy));
+  const uint scalar_offset_59 = (((800u * idx) + 24u)) / 4;
+  uint4 ubo_load_55 = ub[scalar_offset_59 / 4];
+  const int2 vec2_i32 = asint(((scalar_offset_59 & 2) ? ubo_load_55.zw : ubo_load_55.xy));
+  const uint scalar_offset_60 = (((800u * idx) + 32u)) / 4;
+  uint4 ubo_load_56 = ub[scalar_offset_60 / 4];
+  const uint2 vec2_u32 = ((scalar_offset_60 & 2) ? ubo_load_56.zw : ubo_load_56.xy);
+  const uint scalar_offset_61 = (((800u * idx) + 40u)) / 4;
+  uint ubo_load_57 = ub[scalar_offset_61 / 4][scalar_offset_61 % 4];
+  const vector<float16_t, 2> vec2_f16 = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_57 & 0xFFFF)), float16_t(f16tof32(ubo_load_57 >> 16)));
+  const uint scalar_offset_62 = (((800u * idx) + 48u)) / 4;
+  const float3 vec3_f32 = asfloat(ub[scalar_offset_62 / 4].xyz);
+  const uint scalar_offset_63 = (((800u * idx) + 64u)) / 4;
+  const int3 vec3_i32 = asint(ub[scalar_offset_63 / 4].xyz);
+  const uint scalar_offset_64 = (((800u * idx) + 80u)) / 4;
+  const uint3 vec3_u32 = ub[scalar_offset_64 / 4].xyz;
+  const uint scalar_offset_65 = (((800u * idx) + 96u)) / 4;
+  uint4 ubo_load_59 = ub[scalar_offset_65 / 4];
+  uint2 ubo_load_58 = ((scalar_offset_65 & 2) ? ubo_load_59.zw : ubo_load_59.xy);
+  vector<float16_t, 2> ubo_load_58_xz = vector<float16_t, 2>(f16tof32(ubo_load_58 & 0xFFFF));
+  float16_t ubo_load_58_y = f16tof32(ubo_load_58[0] >> 16);
+  const vector<float16_t, 3> vec3_f16 = vector<float16_t, 3>(ubo_load_58_xz[0], ubo_load_58_y, ubo_load_58_xz[1]);
+  const uint scalar_offset_66 = (((800u * idx) + 112u)) / 4;
+  const float4 vec4_f32 = asfloat(ub[scalar_offset_66 / 4]);
+  const uint scalar_offset_67 = (((800u * idx) + 128u)) / 4;
+  const int4 vec4_i32 = asint(ub[scalar_offset_67 / 4]);
+  const uint scalar_offset_68 = (((800u * idx) + 144u)) / 4;
+  const uint4 vec4_u32 = ub[scalar_offset_68 / 4];
+  const uint scalar_offset_69 = (((800u * idx) + 160u)) / 4;
+  uint4 ubo_load_61 = ub[scalar_offset_69 / 4];
+  uint2 ubo_load_60 = ((scalar_offset_69 & 2) ? ubo_load_61.zw : ubo_load_61.xy);
+  vector<float16_t, 2> ubo_load_60_xz = vector<float16_t, 2>(f16tof32(ubo_load_60 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_60_yw = vector<float16_t, 2>(f16tof32(ubo_load_60 >> 16));
+  const vector<float16_t, 4> vec4_f16 = vector<float16_t, 4>(ubo_load_60_xz[0], ubo_load_60_yw[0], ubo_load_60_xz[1], ubo_load_60_yw[1]);
+  const float2x2 mat2x2_f32 = tint_symbol_18(ub, ((800u * idx) + 168u));
+  const float2x3 mat2x3_f32 = tint_symbol_19(ub, ((800u * idx) + 192u));
+  const float2x4 mat2x4_f32 = tint_symbol_20(ub, ((800u * idx) + 224u));
+  const float3x2 mat3x2_f32 = tint_symbol_21(ub, ((800u * idx) + 256u));
+  const float3x3 mat3x3_f32 = tint_symbol_22(ub, ((800u * idx) + 288u));
+  const float3x4 mat3x4_f32 = tint_symbol_23(ub, ((800u * idx) + 336u));
+  const float4x2 mat4x2_f32 = tint_symbol_24(ub, ((800u * idx) + 384u));
+  const float4x3 mat4x3_f32 = tint_symbol_25(ub, ((800u * idx) + 416u));
+  const float4x4 mat4x4_f32 = tint_symbol_26(ub, ((800u * idx) + 480u));
+  const matrix<float16_t, 2, 2> mat2x2_f16 = tint_symbol_27(ub, ((800u * idx) + 544u));
+  const matrix<float16_t, 2, 3> mat2x3_f16 = tint_symbol_28(ub, ((800u * idx) + 552u));
+  const matrix<float16_t, 2, 4> mat2x4_f16 = tint_symbol_29(ub, ((800u * idx) + 568u));
+  const matrix<float16_t, 3, 2> mat3x2_f16 = tint_symbol_30(ub, ((800u * idx) + 584u));
+  const matrix<float16_t, 3, 3> mat3x3_f16 = tint_symbol_31(ub, ((800u * idx) + 600u));
+  const matrix<float16_t, 3, 4> mat3x4_f16 = tint_symbol_32(ub, ((800u * idx) + 624u));
+  const matrix<float16_t, 4, 2> mat4x2_f16 = tint_symbol_33(ub, ((800u * idx) + 648u));
+  const matrix<float16_t, 4, 3> mat4x3_f16 = tint_symbol_34(ub, ((800u * idx) + 664u));
+  const matrix<float16_t, 4, 4> mat4x4_f16 = tint_symbol_35(ub, ((800u * idx) + 696u));
+  const float3 arr2_vec3_f32[2] = tint_symbol_36(ub, ((800u * idx) + 736u));
+  const matrix<float16_t, 4, 2> arr2_mat4x2_f16[2] = tint_symbol_37(ub, ((800u * idx) + 768u));
+}
+
+[numthreads(1, 1, 1)]
+void main(tint_symbol_1 tint_symbol) {
+  main_inner(tint_symbol.idx);
+  return;
+}
diff --git a/test/tint/buffer/uniform/dynamic_index/read_f16.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/dynamic_index/read_f16.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..623e140
--- /dev/null
+++ b/test/tint/buffer/uniform/dynamic_index/read_f16.wgsl.expected.fxc.hlsl
@@ -0,0 +1,325 @@
+SKIP: FAILED
+
+cbuffer cbuffer_ub : register(b0, space0) {
+  uint4 ub[400];
+};
+
+struct tint_symbol_1 {
+  uint idx : SV_GroupIndex;
+};
+
+float2x2 tint_symbol_18(uint4 buffer[400], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  return float2x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)));
+}
+
+float2x3 tint_symbol_19(uint4 buffer[400], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+float2x4 tint_symbol_20(uint4 buffer[400], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset_4 / 4]), asfloat(buffer[scalar_offset_5 / 4]));
+}
+
+float3x2 tint_symbol_21(uint4 buffer[400], uint offset) {
+  const uint scalar_offset_6 = ((offset + 0u)) / 4;
+  uint4 ubo_load_2 = buffer[scalar_offset_6 / 4];
+  const uint scalar_offset_7 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_7 / 4];
+  const uint scalar_offset_8 = ((offset + 16u)) / 4;
+  uint4 ubo_load_4 = buffer[scalar_offset_8 / 4];
+  return float3x2(asfloat(((scalar_offset_6 & 2) ? ubo_load_2.zw : ubo_load_2.xy)), asfloat(((scalar_offset_7 & 2) ? ubo_load_3.zw : ubo_load_3.xy)), asfloat(((scalar_offset_8 & 2) ? ubo_load_4.zw : ubo_load_4.xy)));
+}
+
+float3x3 tint_symbol_22(uint4 buffer[400], uint offset) {
+  const uint scalar_offset_9 = ((offset + 0u)) / 4;
+  const uint scalar_offset_10 = ((offset + 16u)) / 4;
+  const uint scalar_offset_11 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset_9 / 4].xyz), asfloat(buffer[scalar_offset_10 / 4].xyz), asfloat(buffer[scalar_offset_11 / 4].xyz));
+}
+
+float3x4 tint_symbol_23(uint4 buffer[400], uint offset) {
+  const uint scalar_offset_12 = ((offset + 0u)) / 4;
+  const uint scalar_offset_13 = ((offset + 16u)) / 4;
+  const uint scalar_offset_14 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset_12 / 4]), asfloat(buffer[scalar_offset_13 / 4]), asfloat(buffer[scalar_offset_14 / 4]));
+}
+
+float4x2 tint_symbol_24(uint4 buffer[400], uint offset) {
+  const uint scalar_offset_15 = ((offset + 0u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_15 / 4];
+  const uint scalar_offset_16 = ((offset + 8u)) / 4;
+  uint4 ubo_load_6 = buffer[scalar_offset_16 / 4];
+  const uint scalar_offset_17 = ((offset + 16u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_17 / 4];
+  const uint scalar_offset_18 = ((offset + 24u)) / 4;
+  uint4 ubo_load_8 = buffer[scalar_offset_18 / 4];
+  return float4x2(asfloat(((scalar_offset_15 & 2) ? ubo_load_5.zw : ubo_load_5.xy)), asfloat(((scalar_offset_16 & 2) ? ubo_load_6.zw : ubo_load_6.xy)), asfloat(((scalar_offset_17 & 2) ? ubo_load_7.zw : ubo_load_7.xy)), asfloat(((scalar_offset_18 & 2) ? ubo_load_8.zw : ubo_load_8.xy)));
+}
+
+float4x3 tint_symbol_25(uint4 buffer[400], uint offset) {
+  const uint scalar_offset_19 = ((offset + 0u)) / 4;
+  const uint scalar_offset_20 = ((offset + 16u)) / 4;
+  const uint scalar_offset_21 = ((offset + 32u)) / 4;
+  const uint scalar_offset_22 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset_19 / 4].xyz), asfloat(buffer[scalar_offset_20 / 4].xyz), asfloat(buffer[scalar_offset_21 / 4].xyz), asfloat(buffer[scalar_offset_22 / 4].xyz));
+}
+
+float4x4 tint_symbol_26(uint4 buffer[400], uint offset) {
+  const uint scalar_offset_23 = ((offset + 0u)) / 4;
+  const uint scalar_offset_24 = ((offset + 16u)) / 4;
+  const uint scalar_offset_25 = ((offset + 32u)) / 4;
+  const uint scalar_offset_26 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset_23 / 4]), asfloat(buffer[scalar_offset_24 / 4]), asfloat(buffer[scalar_offset_25 / 4]), asfloat(buffer[scalar_offset_26 / 4]));
+}
+
+matrix<float16_t, 2, 2> tint_symbol_27(uint4 buffer[400], uint offset) {
+  const uint scalar_offset_27 = ((offset + 0u)) / 4;
+  uint ubo_load_9 = buffer[scalar_offset_27 / 4][scalar_offset_27 % 4];
+  const uint scalar_offset_28 = ((offset + 4u)) / 4;
+  uint ubo_load_10 = buffer[scalar_offset_28 / 4][scalar_offset_28 % 4];
+  return matrix<float16_t, 2, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_9 & 0xFFFF)), float16_t(f16tof32(ubo_load_9 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_10 & 0xFFFF)), float16_t(f16tof32(ubo_load_10 >> 16))));
+}
+
+matrix<float16_t, 2, 3> tint_symbol_28(uint4 buffer[400], uint offset) {
+  const uint scalar_offset_29 = ((offset + 0u)) / 4;
+  uint4 ubo_load_12 = buffer[scalar_offset_29 / 4];
+  uint2 ubo_load_11 = ((scalar_offset_29 & 2) ? ubo_load_12.zw : ubo_load_12.xy);
+  vector<float16_t, 2> ubo_load_11_xz = vector<float16_t, 2>(f16tof32(ubo_load_11 & 0xFFFF));
+  float16_t ubo_load_11_y = f16tof32(ubo_load_11[0] >> 16);
+  const uint scalar_offset_30 = ((offset + 8u)) / 4;
+  uint4 ubo_load_14 = buffer[scalar_offset_30 / 4];
+  uint2 ubo_load_13 = ((scalar_offset_30 & 2) ? ubo_load_14.zw : ubo_load_14.xy);
+  vector<float16_t, 2> ubo_load_13_xz = vector<float16_t, 2>(f16tof32(ubo_load_13 & 0xFFFF));
+  float16_t ubo_load_13_y = f16tof32(ubo_load_13[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_11_xz[0], ubo_load_11_y, ubo_load_11_xz[1]), vector<float16_t, 3>(ubo_load_13_xz[0], ubo_load_13_y, ubo_load_13_xz[1]));
+}
+
+matrix<float16_t, 2, 4> tint_symbol_29(uint4 buffer[400], uint offset) {
+  const uint scalar_offset_31 = ((offset + 0u)) / 4;
+  uint4 ubo_load_16 = buffer[scalar_offset_31 / 4];
+  uint2 ubo_load_15 = ((scalar_offset_31 & 2) ? ubo_load_16.zw : ubo_load_16.xy);
+  vector<float16_t, 2> ubo_load_15_xz = vector<float16_t, 2>(f16tof32(ubo_load_15 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_15_yw = vector<float16_t, 2>(f16tof32(ubo_load_15 >> 16));
+  const uint scalar_offset_32 = ((offset + 8u)) / 4;
+  uint4 ubo_load_18 = buffer[scalar_offset_32 / 4];
+  uint2 ubo_load_17 = ((scalar_offset_32 & 2) ? ubo_load_18.zw : ubo_load_18.xy);
+  vector<float16_t, 2> ubo_load_17_xz = vector<float16_t, 2>(f16tof32(ubo_load_17 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_17_yw = vector<float16_t, 2>(f16tof32(ubo_load_17 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_15_xz[0], ubo_load_15_yw[0], ubo_load_15_xz[1], ubo_load_15_yw[1]), vector<float16_t, 4>(ubo_load_17_xz[0], ubo_load_17_yw[0], ubo_load_17_xz[1], ubo_load_17_yw[1]));
+}
+
+matrix<float16_t, 3, 2> tint_symbol_30(uint4 buffer[400], uint offset) {
+  const uint scalar_offset_33 = ((offset + 0u)) / 4;
+  uint ubo_load_19 = buffer[scalar_offset_33 / 4][scalar_offset_33 % 4];
+  const uint scalar_offset_34 = ((offset + 4u)) / 4;
+  uint ubo_load_20 = buffer[scalar_offset_34 / 4][scalar_offset_34 % 4];
+  const uint scalar_offset_35 = ((offset + 8u)) / 4;
+  uint ubo_load_21 = buffer[scalar_offset_35 / 4][scalar_offset_35 % 4];
+  return matrix<float16_t, 3, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_19 & 0xFFFF)), float16_t(f16tof32(ubo_load_19 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_20 & 0xFFFF)), float16_t(f16tof32(ubo_load_20 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_21 & 0xFFFF)), float16_t(f16tof32(ubo_load_21 >> 16))));
+}
+
+matrix<float16_t, 3, 3> tint_symbol_31(uint4 buffer[400], uint offset) {
+  const uint scalar_offset_36 = ((offset + 0u)) / 4;
+  uint4 ubo_load_23 = buffer[scalar_offset_36 / 4];
+  uint2 ubo_load_22 = ((scalar_offset_36 & 2) ? ubo_load_23.zw : ubo_load_23.xy);
+  vector<float16_t, 2> ubo_load_22_xz = vector<float16_t, 2>(f16tof32(ubo_load_22 & 0xFFFF));
+  float16_t ubo_load_22_y = f16tof32(ubo_load_22[0] >> 16);
+  const uint scalar_offset_37 = ((offset + 8u)) / 4;
+  uint4 ubo_load_25 = buffer[scalar_offset_37 / 4];
+  uint2 ubo_load_24 = ((scalar_offset_37 & 2) ? ubo_load_25.zw : ubo_load_25.xy);
+  vector<float16_t, 2> ubo_load_24_xz = vector<float16_t, 2>(f16tof32(ubo_load_24 & 0xFFFF));
+  float16_t ubo_load_24_y = f16tof32(ubo_load_24[0] >> 16);
+  const uint scalar_offset_38 = ((offset + 16u)) / 4;
+  uint4 ubo_load_27 = buffer[scalar_offset_38 / 4];
+  uint2 ubo_load_26 = ((scalar_offset_38 & 2) ? ubo_load_27.zw : ubo_load_27.xy);
+  vector<float16_t, 2> ubo_load_26_xz = vector<float16_t, 2>(f16tof32(ubo_load_26 & 0xFFFF));
+  float16_t ubo_load_26_y = f16tof32(ubo_load_26[0] >> 16);
+  return matrix<float16_t, 3, 3>(vector<float16_t, 3>(ubo_load_22_xz[0], ubo_load_22_y, ubo_load_22_xz[1]), vector<float16_t, 3>(ubo_load_24_xz[0], ubo_load_24_y, ubo_load_24_xz[1]), vector<float16_t, 3>(ubo_load_26_xz[0], ubo_load_26_y, ubo_load_26_xz[1]));
+}
+
+matrix<float16_t, 3, 4> tint_symbol_32(uint4 buffer[400], uint offset) {
+  const uint scalar_offset_39 = ((offset + 0u)) / 4;
+  uint4 ubo_load_29 = buffer[scalar_offset_39 / 4];
+  uint2 ubo_load_28 = ((scalar_offset_39 & 2) ? ubo_load_29.zw : ubo_load_29.xy);
+  vector<float16_t, 2> ubo_load_28_xz = vector<float16_t, 2>(f16tof32(ubo_load_28 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_28_yw = vector<float16_t, 2>(f16tof32(ubo_load_28 >> 16));
+  const uint scalar_offset_40 = ((offset + 8u)) / 4;
+  uint4 ubo_load_31 = buffer[scalar_offset_40 / 4];
+  uint2 ubo_load_30 = ((scalar_offset_40 & 2) ? ubo_load_31.zw : ubo_load_31.xy);
+  vector<float16_t, 2> ubo_load_30_xz = vector<float16_t, 2>(f16tof32(ubo_load_30 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_30_yw = vector<float16_t, 2>(f16tof32(ubo_load_30 >> 16));
+  const uint scalar_offset_41 = ((offset + 16u)) / 4;
+  uint4 ubo_load_33 = buffer[scalar_offset_41 / 4];
+  uint2 ubo_load_32 = ((scalar_offset_41 & 2) ? ubo_load_33.zw : ubo_load_33.xy);
+  vector<float16_t, 2> ubo_load_32_xz = vector<float16_t, 2>(f16tof32(ubo_load_32 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_32_yw = vector<float16_t, 2>(f16tof32(ubo_load_32 >> 16));
+  return matrix<float16_t, 3, 4>(vector<float16_t, 4>(ubo_load_28_xz[0], ubo_load_28_yw[0], ubo_load_28_xz[1], ubo_load_28_yw[1]), vector<float16_t, 4>(ubo_load_30_xz[0], ubo_load_30_yw[0], ubo_load_30_xz[1], ubo_load_30_yw[1]), vector<float16_t, 4>(ubo_load_32_xz[0], ubo_load_32_yw[0], ubo_load_32_xz[1], ubo_load_32_yw[1]));
+}
+
+matrix<float16_t, 4, 2> tint_symbol_33(uint4 buffer[400], uint offset) {
+  const uint scalar_offset_42 = ((offset + 0u)) / 4;
+  uint ubo_load_34 = buffer[scalar_offset_42 / 4][scalar_offset_42 % 4];
+  const uint scalar_offset_43 = ((offset + 4u)) / 4;
+  uint ubo_load_35 = buffer[scalar_offset_43 / 4][scalar_offset_43 % 4];
+  const uint scalar_offset_44 = ((offset + 8u)) / 4;
+  uint ubo_load_36 = buffer[scalar_offset_44 / 4][scalar_offset_44 % 4];
+  const uint scalar_offset_45 = ((offset + 12u)) / 4;
+  uint ubo_load_37 = buffer[scalar_offset_45 / 4][scalar_offset_45 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_34 & 0xFFFF)), float16_t(f16tof32(ubo_load_34 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_35 & 0xFFFF)), float16_t(f16tof32(ubo_load_35 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_36 & 0xFFFF)), float16_t(f16tof32(ubo_load_36 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_37 & 0xFFFF)), float16_t(f16tof32(ubo_load_37 >> 16))));
+}
+
+matrix<float16_t, 4, 3> tint_symbol_34(uint4 buffer[400], uint offset) {
+  const uint scalar_offset_46 = ((offset + 0u)) / 4;
+  uint4 ubo_load_39 = buffer[scalar_offset_46 / 4];
+  uint2 ubo_load_38 = ((scalar_offset_46 & 2) ? ubo_load_39.zw : ubo_load_39.xy);
+  vector<float16_t, 2> ubo_load_38_xz = vector<float16_t, 2>(f16tof32(ubo_load_38 & 0xFFFF));
+  float16_t ubo_load_38_y = f16tof32(ubo_load_38[0] >> 16);
+  const uint scalar_offset_47 = ((offset + 8u)) / 4;
+  uint4 ubo_load_41 = buffer[scalar_offset_47 / 4];
+  uint2 ubo_load_40 = ((scalar_offset_47 & 2) ? ubo_load_41.zw : ubo_load_41.xy);
+  vector<float16_t, 2> ubo_load_40_xz = vector<float16_t, 2>(f16tof32(ubo_load_40 & 0xFFFF));
+  float16_t ubo_load_40_y = f16tof32(ubo_load_40[0] >> 16);
+  const uint scalar_offset_48 = ((offset + 16u)) / 4;
+  uint4 ubo_load_43 = buffer[scalar_offset_48 / 4];
+  uint2 ubo_load_42 = ((scalar_offset_48 & 2) ? ubo_load_43.zw : ubo_load_43.xy);
+  vector<float16_t, 2> ubo_load_42_xz = vector<float16_t, 2>(f16tof32(ubo_load_42 & 0xFFFF));
+  float16_t ubo_load_42_y = f16tof32(ubo_load_42[0] >> 16);
+  const uint scalar_offset_49 = ((offset + 24u)) / 4;
+  uint4 ubo_load_45 = buffer[scalar_offset_49 / 4];
+  uint2 ubo_load_44 = ((scalar_offset_49 & 2) ? ubo_load_45.zw : ubo_load_45.xy);
+  vector<float16_t, 2> ubo_load_44_xz = vector<float16_t, 2>(f16tof32(ubo_load_44 & 0xFFFF));
+  float16_t ubo_load_44_y = f16tof32(ubo_load_44[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_38_xz[0], ubo_load_38_y, ubo_load_38_xz[1]), vector<float16_t, 3>(ubo_load_40_xz[0], ubo_load_40_y, ubo_load_40_xz[1]), vector<float16_t, 3>(ubo_load_42_xz[0], ubo_load_42_y, ubo_load_42_xz[1]), vector<float16_t, 3>(ubo_load_44_xz[0], ubo_load_44_y, ubo_load_44_xz[1]));
+}
+
+matrix<float16_t, 4, 4> tint_symbol_35(uint4 buffer[400], uint offset) {
+  const uint scalar_offset_50 = ((offset + 0u)) / 4;
+  uint4 ubo_load_47 = buffer[scalar_offset_50 / 4];
+  uint2 ubo_load_46 = ((scalar_offset_50 & 2) ? ubo_load_47.zw : ubo_load_47.xy);
+  vector<float16_t, 2> ubo_load_46_xz = vector<float16_t, 2>(f16tof32(ubo_load_46 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_46_yw = vector<float16_t, 2>(f16tof32(ubo_load_46 >> 16));
+  const uint scalar_offset_51 = ((offset + 8u)) / 4;
+  uint4 ubo_load_49 = buffer[scalar_offset_51 / 4];
+  uint2 ubo_load_48 = ((scalar_offset_51 & 2) ? ubo_load_49.zw : ubo_load_49.xy);
+  vector<float16_t, 2> ubo_load_48_xz = vector<float16_t, 2>(f16tof32(ubo_load_48 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_48_yw = vector<float16_t, 2>(f16tof32(ubo_load_48 >> 16));
+  const uint scalar_offset_52 = ((offset + 16u)) / 4;
+  uint4 ubo_load_51 = buffer[scalar_offset_52 / 4];
+  uint2 ubo_load_50 = ((scalar_offset_52 & 2) ? ubo_load_51.zw : ubo_load_51.xy);
+  vector<float16_t, 2> ubo_load_50_xz = vector<float16_t, 2>(f16tof32(ubo_load_50 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_50_yw = vector<float16_t, 2>(f16tof32(ubo_load_50 >> 16));
+  const uint scalar_offset_53 = ((offset + 24u)) / 4;
+  uint4 ubo_load_53 = buffer[scalar_offset_53 / 4];
+  uint2 ubo_load_52 = ((scalar_offset_53 & 2) ? ubo_load_53.zw : ubo_load_53.xy);
+  vector<float16_t, 2> ubo_load_52_xz = vector<float16_t, 2>(f16tof32(ubo_load_52 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_52_yw = vector<float16_t, 2>(f16tof32(ubo_load_52 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_46_xz[0], ubo_load_46_yw[0], ubo_load_46_xz[1], ubo_load_46_yw[1]), vector<float16_t, 4>(ubo_load_48_xz[0], ubo_load_48_yw[0], ubo_load_48_xz[1], ubo_load_48_yw[1]), vector<float16_t, 4>(ubo_load_50_xz[0], ubo_load_50_yw[0], ubo_load_50_xz[1], ubo_load_50_yw[1]), vector<float16_t, 4>(ubo_load_52_xz[0], ubo_load_52_yw[0], ubo_load_52_xz[1], ubo_load_52_yw[1]));
+}
+
+typedef float3 tint_symbol_36_ret[2];
+tint_symbol_36_ret tint_symbol_36(uint4 buffer[400], uint offset) {
+  float3 arr_1[2] = (float3[2])0;
+  {
+    for(uint i = 0u; (i < 2u); i = (i + 1u)) {
+      const uint scalar_offset_54 = ((offset + (i * 16u))) / 4;
+      arr_1[i] = asfloat(buffer[scalar_offset_54 / 4].xyz);
+    }
+  }
+  return arr_1;
+}
+
+typedef matrix<float16_t, 4, 2> tint_symbol_37_ret[2];
+tint_symbol_37_ret tint_symbol_37(uint4 buffer[400], uint offset) {
+  matrix<float16_t, 4, 2> arr_2[2] = (matrix<float16_t, 4, 2>[2])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
+      arr_2[i_1] = tint_symbol_33(buffer, (offset + (i_1 * 16u)));
+    }
+  }
+  return arr_2;
+}
+
+void main_inner(uint idx) {
+  const uint scalar_offset_55 = ((800u * idx)) / 4;
+  const float scalar_f32 = asfloat(ub[scalar_offset_55 / 4][scalar_offset_55 % 4]);
+  const uint scalar_offset_56 = (((800u * idx) + 4u)) / 4;
+  const int scalar_i32 = asint(ub[scalar_offset_56 / 4][scalar_offset_56 % 4]);
+  const uint scalar_offset_57 = (((800u * idx) + 8u)) / 4;
+  const uint scalar_u32 = ub[scalar_offset_57 / 4][scalar_offset_57 % 4];
+  const uint scalar_offset_bytes = (((800u * idx) + 12u));
+  const uint scalar_offset_index = scalar_offset_bytes / 4;
+  const float16_t scalar_f16 = float16_t(f16tof32(((ub[scalar_offset_index / 4][scalar_offset_index % 4] >> (scalar_offset_bytes % 4 == 0 ? 0 : 16)) & 0xFFFF)));
+  const uint scalar_offset_58 = (((800u * idx) + 16u)) / 4;
+  uint4 ubo_load_54 = ub[scalar_offset_58 / 4];
+  const float2 vec2_f32 = asfloat(((scalar_offset_58 & 2) ? ubo_load_54.zw : ubo_load_54.xy));
+  const uint scalar_offset_59 = (((800u * idx) + 24u)) / 4;
+  uint4 ubo_load_55 = ub[scalar_offset_59 / 4];
+  const int2 vec2_i32 = asint(((scalar_offset_59 & 2) ? ubo_load_55.zw : ubo_load_55.xy));
+  const uint scalar_offset_60 = (((800u * idx) + 32u)) / 4;
+  uint4 ubo_load_56 = ub[scalar_offset_60 / 4];
+  const uint2 vec2_u32 = ((scalar_offset_60 & 2) ? ubo_load_56.zw : ubo_load_56.xy);
+  const uint scalar_offset_61 = (((800u * idx) + 40u)) / 4;
+  uint ubo_load_57 = ub[scalar_offset_61 / 4][scalar_offset_61 % 4];
+  const vector<float16_t, 2> vec2_f16 = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_57 & 0xFFFF)), float16_t(f16tof32(ubo_load_57 >> 16)));
+  const uint scalar_offset_62 = (((800u * idx) + 48u)) / 4;
+  const float3 vec3_f32 = asfloat(ub[scalar_offset_62 / 4].xyz);
+  const uint scalar_offset_63 = (((800u * idx) + 64u)) / 4;
+  const int3 vec3_i32 = asint(ub[scalar_offset_63 / 4].xyz);
+  const uint scalar_offset_64 = (((800u * idx) + 80u)) / 4;
+  const uint3 vec3_u32 = ub[scalar_offset_64 / 4].xyz;
+  const uint scalar_offset_65 = (((800u * idx) + 96u)) / 4;
+  uint4 ubo_load_59 = ub[scalar_offset_65 / 4];
+  uint2 ubo_load_58 = ((scalar_offset_65 & 2) ? ubo_load_59.zw : ubo_load_59.xy);
+  vector<float16_t, 2> ubo_load_58_xz = vector<float16_t, 2>(f16tof32(ubo_load_58 & 0xFFFF));
+  float16_t ubo_load_58_y = f16tof32(ubo_load_58[0] >> 16);
+  const vector<float16_t, 3> vec3_f16 = vector<float16_t, 3>(ubo_load_58_xz[0], ubo_load_58_y, ubo_load_58_xz[1]);
+  const uint scalar_offset_66 = (((800u * idx) + 112u)) / 4;
+  const float4 vec4_f32 = asfloat(ub[scalar_offset_66 / 4]);
+  const uint scalar_offset_67 = (((800u * idx) + 128u)) / 4;
+  const int4 vec4_i32 = asint(ub[scalar_offset_67 / 4]);
+  const uint scalar_offset_68 = (((800u * idx) + 144u)) / 4;
+  const uint4 vec4_u32 = ub[scalar_offset_68 / 4];
+  const uint scalar_offset_69 = (((800u * idx) + 160u)) / 4;
+  uint4 ubo_load_61 = ub[scalar_offset_69 / 4];
+  uint2 ubo_load_60 = ((scalar_offset_69 & 2) ? ubo_load_61.zw : ubo_load_61.xy);
+  vector<float16_t, 2> ubo_load_60_xz = vector<float16_t, 2>(f16tof32(ubo_load_60 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_60_yw = vector<float16_t, 2>(f16tof32(ubo_load_60 >> 16));
+  const vector<float16_t, 4> vec4_f16 = vector<float16_t, 4>(ubo_load_60_xz[0], ubo_load_60_yw[0], ubo_load_60_xz[1], ubo_load_60_yw[1]);
+  const float2x2 mat2x2_f32 = tint_symbol_18(ub, ((800u * idx) + 168u));
+  const float2x3 mat2x3_f32 = tint_symbol_19(ub, ((800u * idx) + 192u));
+  const float2x4 mat2x4_f32 = tint_symbol_20(ub, ((800u * idx) + 224u));
+  const float3x2 mat3x2_f32 = tint_symbol_21(ub, ((800u * idx) + 256u));
+  const float3x3 mat3x3_f32 = tint_symbol_22(ub, ((800u * idx) + 288u));
+  const float3x4 mat3x4_f32 = tint_symbol_23(ub, ((800u * idx) + 336u));
+  const float4x2 mat4x2_f32 = tint_symbol_24(ub, ((800u * idx) + 384u));
+  const float4x3 mat4x3_f32 = tint_symbol_25(ub, ((800u * idx) + 416u));
+  const float4x4 mat4x4_f32 = tint_symbol_26(ub, ((800u * idx) + 480u));
+  const matrix<float16_t, 2, 2> mat2x2_f16 = tint_symbol_27(ub, ((800u * idx) + 544u));
+  const matrix<float16_t, 2, 3> mat2x3_f16 = tint_symbol_28(ub, ((800u * idx) + 552u));
+  const matrix<float16_t, 2, 4> mat2x4_f16 = tint_symbol_29(ub, ((800u * idx) + 568u));
+  const matrix<float16_t, 3, 2> mat3x2_f16 = tint_symbol_30(ub, ((800u * idx) + 584u));
+  const matrix<float16_t, 3, 3> mat3x3_f16 = tint_symbol_31(ub, ((800u * idx) + 600u));
+  const matrix<float16_t, 3, 4> mat3x4_f16 = tint_symbol_32(ub, ((800u * idx) + 624u));
+  const matrix<float16_t, 4, 2> mat4x2_f16 = tint_symbol_33(ub, ((800u * idx) + 648u));
+  const matrix<float16_t, 4, 3> mat4x3_f16 = tint_symbol_34(ub, ((800u * idx) + 664u));
+  const matrix<float16_t, 4, 4> mat4x4_f16 = tint_symbol_35(ub, ((800u * idx) + 696u));
+  const float3 arr2_vec3_f32[2] = tint_symbol_36(ub, ((800u * idx) + 736u));
+  const matrix<float16_t, 4, 2> arr2_mat4x2_f16[2] = tint_symbol_37(ub, ((800u * idx) + 768u));
+}
+
+[numthreads(1, 1, 1)]
+void main(tint_symbol_1 tint_symbol) {
+  main_inner(tint_symbol.idx);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x00000183446E4210(81,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/dynamic_index/read_f16.wgsl.expected.glsl b/test/tint/buffer/uniform/dynamic_index/read_f16.wgsl.expected.glsl
new file mode 100644
index 0000000..a03e972
--- /dev/null
+++ b/test/tint/buffer/uniform/dynamic_index/read_f16.wgsl.expected.glsl
@@ -0,0 +1,268 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct mat4x2_f16_4 {
+  f16vec2 col0;
+  f16vec2 col1;
+  f16vec2 col2;
+  f16vec2 col3;
+};
+
+struct Inner {
+  float scalar_f32;
+  int scalar_i32;
+  uint scalar_u32;
+  float16_t scalar_f16;
+  vec2 vec2_f32;
+  ivec2 vec2_i32;
+  uvec2 vec2_u32;
+  f16vec2 vec2_f16;
+  uint pad;
+  vec3 vec3_f32;
+  uint pad_1;
+  ivec3 vec3_i32;
+  uint pad_2;
+  uvec3 vec3_u32;
+  uint pad_3;
+  f16vec3 vec3_f16;
+  uint pad_4;
+  uint pad_5;
+  vec4 vec4_f32;
+  ivec4 vec4_i32;
+  uvec4 vec4_u32;
+  f16vec4 vec4_f16;
+  mat2 mat2x2_f32;
+  uint pad_6;
+  uint pad_7;
+  mat2x3 mat2x3_f32;
+  mat2x4 mat2x4_f32;
+  mat3x2 mat3x2_f32;
+  uint pad_8;
+  uint pad_9;
+  mat3 mat3x3_f32;
+  mat3x4 mat3x4_f32;
+  mat4x2 mat4x2_f32;
+  mat4x3 mat4x3_f32;
+  mat4 mat4x4_f32;
+  f16mat2 mat2x2_f16;
+  f16mat2x3 mat2x3_f16;
+  f16mat2x4 mat2x4_f16;
+  f16mat3x2 mat3x2_f16;
+  uint pad_10;
+  f16mat3 mat3x3_f16;
+  f16mat3x4 mat3x4_f16;
+  f16mat4x2 mat4x2_f16;
+  f16mat4x3 mat4x3_f16;
+  f16mat4 mat4x4_f16;
+  uint pad_11;
+  uint pad_12;
+  vec3 arr2_vec3_f32[2];
+  f16mat4x2 arr2_mat4x2_f16[2];
+};
+
+struct Inner_std140 {
+  float scalar_f32;
+  int scalar_i32;
+  uint scalar_u32;
+  float16_t scalar_f16;
+  vec2 vec2_f32;
+  ivec2 vec2_i32;
+  uvec2 vec2_u32;
+  f16vec2 vec2_f16;
+  uint pad;
+  vec3 vec3_f32;
+  uint pad_1;
+  ivec3 vec3_i32;
+  uint pad_2;
+  uvec3 vec3_u32;
+  uint pad_3;
+  f16vec3 vec3_f16;
+  uint pad_4;
+  uint pad_5;
+  vec4 vec4_f32;
+  ivec4 vec4_i32;
+  uvec4 vec4_u32;
+  f16vec4 vec4_f16;
+  vec2 mat2x2_f32_0;
+  vec2 mat2x2_f32_1;
+  uint pad_6;
+  uint pad_7;
+  mat2x3 mat2x3_f32;
+  mat2x4 mat2x4_f32;
+  vec2 mat3x2_f32_0;
+  vec2 mat3x2_f32_1;
+  vec2 mat3x2_f32_2;
+  uint pad_8;
+  uint pad_9;
+  mat3 mat3x3_f32;
+  mat3x4 mat3x4_f32;
+  vec2 mat4x2_f32_0;
+  vec2 mat4x2_f32_1;
+  vec2 mat4x2_f32_2;
+  vec2 mat4x2_f32_3;
+  mat4x3 mat4x3_f32;
+  mat4 mat4x4_f32;
+  f16vec2 mat2x2_f16_0;
+  f16vec2 mat2x2_f16_1;
+  f16vec3 mat2x3_f16_0;
+  f16vec3 mat2x3_f16_1;
+  f16vec4 mat2x4_f16_0;
+  f16vec4 mat2x4_f16_1;
+  f16vec2 mat3x2_f16_0;
+  f16vec2 mat3x2_f16_1;
+  f16vec2 mat3x2_f16_2;
+  uint pad_10;
+  f16vec3 mat3x3_f16_0;
+  f16vec3 mat3x3_f16_1;
+  f16vec3 mat3x3_f16_2;
+  f16vec4 mat3x4_f16_0;
+  f16vec4 mat3x4_f16_1;
+  f16vec4 mat3x4_f16_2;
+  f16vec2 mat4x2_f16_0;
+  f16vec2 mat4x2_f16_1;
+  f16vec2 mat4x2_f16_2;
+  f16vec2 mat4x2_f16_3;
+  f16vec3 mat4x3_f16_0;
+  f16vec3 mat4x3_f16_1;
+  f16vec3 mat4x3_f16_2;
+  f16vec3 mat4x3_f16_3;
+  f16vec4 mat4x4_f16_0;
+  f16vec4 mat4x4_f16_1;
+  f16vec4 mat4x4_f16_2;
+  f16vec4 mat4x4_f16_3;
+  uint pad_11;
+  uint pad_12;
+  vec3 arr2_vec3_f32[2];
+  mat4x2_f16_4 arr2_mat4x2_f16[2];
+};
+
+struct S {
+  Inner arr[8];
+};
+
+struct S_std140 {
+  Inner_std140 arr[8];
+};
+
+layout(binding = 0, std140) uniform ub_block_std140_ubo {
+  S_std140 inner;
+} ub;
+
+mat2 load_ub_inner_arr_p0_mat2x2_f32(uint p0) {
+  uint s_save = p0;
+  return mat2(ub.inner.arr[s_save].mat2x2_f32_0, ub.inner.arr[s_save].mat2x2_f32_1);
+}
+
+mat3x2 load_ub_inner_arr_p0_mat3x2_f32(uint p0) {
+  uint s_save_1 = p0;
+  return mat3x2(ub.inner.arr[s_save_1].mat3x2_f32_0, ub.inner.arr[s_save_1].mat3x2_f32_1, ub.inner.arr[s_save_1].mat3x2_f32_2);
+}
+
+mat4x2 load_ub_inner_arr_p0_mat4x2_f32(uint p0) {
+  uint s_save_2 = p0;
+  return mat4x2(ub.inner.arr[s_save_2].mat4x2_f32_0, ub.inner.arr[s_save_2].mat4x2_f32_1, ub.inner.arr[s_save_2].mat4x2_f32_2, ub.inner.arr[s_save_2].mat4x2_f32_3);
+}
+
+f16mat2 load_ub_inner_arr_p0_mat2x2_f16(uint p0) {
+  uint s_save_3 = p0;
+  return f16mat2(ub.inner.arr[s_save_3].mat2x2_f16_0, ub.inner.arr[s_save_3].mat2x2_f16_1);
+}
+
+f16mat2x3 load_ub_inner_arr_p0_mat2x3_f16(uint p0) {
+  uint s_save_4 = p0;
+  return f16mat2x3(ub.inner.arr[s_save_4].mat2x3_f16_0, ub.inner.arr[s_save_4].mat2x3_f16_1);
+}
+
+f16mat2x4 load_ub_inner_arr_p0_mat2x4_f16(uint p0) {
+  uint s_save_5 = p0;
+  return f16mat2x4(ub.inner.arr[s_save_5].mat2x4_f16_0, ub.inner.arr[s_save_5].mat2x4_f16_1);
+}
+
+f16mat3x2 load_ub_inner_arr_p0_mat3x2_f16(uint p0) {
+  uint s_save_6 = p0;
+  return f16mat3x2(ub.inner.arr[s_save_6].mat3x2_f16_0, ub.inner.arr[s_save_6].mat3x2_f16_1, ub.inner.arr[s_save_6].mat3x2_f16_2);
+}
+
+f16mat3 load_ub_inner_arr_p0_mat3x3_f16(uint p0) {
+  uint s_save_7 = p0;
+  return f16mat3(ub.inner.arr[s_save_7].mat3x3_f16_0, ub.inner.arr[s_save_7].mat3x3_f16_1, ub.inner.arr[s_save_7].mat3x3_f16_2);
+}
+
+f16mat3x4 load_ub_inner_arr_p0_mat3x4_f16(uint p0) {
+  uint s_save_8 = p0;
+  return f16mat3x4(ub.inner.arr[s_save_8].mat3x4_f16_0, ub.inner.arr[s_save_8].mat3x4_f16_1, ub.inner.arr[s_save_8].mat3x4_f16_2);
+}
+
+f16mat4x2 load_ub_inner_arr_p0_mat4x2_f16(uint p0) {
+  uint s_save_9 = p0;
+  return f16mat4x2(ub.inner.arr[s_save_9].mat4x2_f16_0, ub.inner.arr[s_save_9].mat4x2_f16_1, ub.inner.arr[s_save_9].mat4x2_f16_2, ub.inner.arr[s_save_9].mat4x2_f16_3);
+}
+
+f16mat4x3 load_ub_inner_arr_p0_mat4x3_f16(uint p0) {
+  uint s_save_10 = p0;
+  return f16mat4x3(ub.inner.arr[s_save_10].mat4x3_f16_0, ub.inner.arr[s_save_10].mat4x3_f16_1, ub.inner.arr[s_save_10].mat4x3_f16_2, ub.inner.arr[s_save_10].mat4x3_f16_3);
+}
+
+f16mat4 load_ub_inner_arr_p0_mat4x4_f16(uint p0) {
+  uint s_save_11 = p0;
+  return f16mat4(ub.inner.arr[s_save_11].mat4x4_f16_0, ub.inner.arr[s_save_11].mat4x4_f16_1, ub.inner.arr[s_save_11].mat4x4_f16_2, ub.inner.arr[s_save_11].mat4x4_f16_3);
+}
+
+f16mat4x2 conv_mat4x2_f16(mat4x2_f16_4 val) {
+  return f16mat4x2(val.col0, val.col1, val.col2, val.col3);
+}
+
+f16mat4x2[2] conv_arr2_mat4x2_f16(mat4x2_f16_4 val[2]) {
+  f16mat4x2 arr[2] = f16mat4x2[2](f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf));
+  {
+    for(uint i = 0u; (i < 2u); i = (i + 1u)) {
+      arr[i] = conv_mat4x2_f16(val[i]);
+    }
+  }
+  return arr;
+}
+
+void tint_symbol(uint idx) {
+  float scalar_f32 = ub.inner.arr[idx].scalar_f32;
+  int scalar_i32 = ub.inner.arr[idx].scalar_i32;
+  uint scalar_u32 = ub.inner.arr[idx].scalar_u32;
+  float16_t scalar_f16 = ub.inner.arr[idx].scalar_f16;
+  vec2 vec2_f32 = ub.inner.arr[idx].vec2_f32;
+  ivec2 vec2_i32 = ub.inner.arr[idx].vec2_i32;
+  uvec2 vec2_u32 = ub.inner.arr[idx].vec2_u32;
+  f16vec2 vec2_f16 = ub.inner.arr[idx].vec2_f16;
+  vec3 vec3_f32 = ub.inner.arr[idx].vec3_f32;
+  ivec3 vec3_i32 = ub.inner.arr[idx].vec3_i32;
+  uvec3 vec3_u32 = ub.inner.arr[idx].vec3_u32;
+  f16vec3 vec3_f16 = ub.inner.arr[idx].vec3_f16;
+  vec4 vec4_f32 = ub.inner.arr[idx].vec4_f32;
+  ivec4 vec4_i32 = ub.inner.arr[idx].vec4_i32;
+  uvec4 vec4_u32 = ub.inner.arr[idx].vec4_u32;
+  f16vec4 vec4_f16 = ub.inner.arr[idx].vec4_f16;
+  mat2 mat2x2_f32 = load_ub_inner_arr_p0_mat2x2_f32(uint(idx));
+  mat2x3 mat2x3_f32 = ub.inner.arr[idx].mat2x3_f32;
+  mat2x4 mat2x4_f32 = ub.inner.arr[idx].mat2x4_f32;
+  mat3x2 mat3x2_f32 = load_ub_inner_arr_p0_mat3x2_f32(uint(idx));
+  mat3 mat3x3_f32 = ub.inner.arr[idx].mat3x3_f32;
+  mat3x4 mat3x4_f32 = ub.inner.arr[idx].mat3x4_f32;
+  mat4x2 mat4x2_f32 = load_ub_inner_arr_p0_mat4x2_f32(uint(idx));
+  mat4x3 mat4x3_f32 = ub.inner.arr[idx].mat4x3_f32;
+  mat4 mat4x4_f32 = ub.inner.arr[idx].mat4x4_f32;
+  f16mat2 mat2x2_f16 = load_ub_inner_arr_p0_mat2x2_f16(uint(idx));
+  f16mat2x3 mat2x3_f16 = load_ub_inner_arr_p0_mat2x3_f16(uint(idx));
+  f16mat2x4 mat2x4_f16 = load_ub_inner_arr_p0_mat2x4_f16(uint(idx));
+  f16mat3x2 mat3x2_f16 = load_ub_inner_arr_p0_mat3x2_f16(uint(idx));
+  f16mat3 mat3x3_f16 = load_ub_inner_arr_p0_mat3x3_f16(uint(idx));
+  f16mat3x4 mat3x4_f16 = load_ub_inner_arr_p0_mat3x4_f16(uint(idx));
+  f16mat4x2 mat4x2_f16 = load_ub_inner_arr_p0_mat4x2_f16(uint(idx));
+  f16mat4x3 mat4x3_f16 = load_ub_inner_arr_p0_mat4x3_f16(uint(idx));
+  f16mat4 mat4x4_f16 = load_ub_inner_arr_p0_mat4x4_f16(uint(idx));
+  vec3 arr2_vec3_f32[2] = ub.inner.arr[idx].arr2_vec3_f32;
+  f16mat4x2 arr2_mat4x2_f16[2] = conv_arr2_mat4x2_f16(ub.inner.arr[idx].arr2_mat4x2_f16);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/dynamic_index/read_f16.wgsl.expected.msl b/test/tint/buffer/uniform/dynamic_index/read_f16.wgsl.expected.msl
new file mode 100644
index 0000000..f6b667e
--- /dev/null
+++ b/test/tint/buffer/uniform/dynamic_index/read_f16.wgsl.expected.msl
@@ -0,0 +1,113 @@
+#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 Inner {
+  /* 0x0000 */ float scalar_f32;
+  /* 0x0004 */ int scalar_i32;
+  /* 0x0008 */ uint scalar_u32;
+  /* 0x000c */ half scalar_f16;
+  /* 0x000e */ tint_array<int8_t, 2> tint_pad;
+  /* 0x0010 */ float2 vec2_f32;
+  /* 0x0018 */ int2 vec2_i32;
+  /* 0x0020 */ uint2 vec2_u32;
+  /* 0x0028 */ half2 vec2_f16;
+  /* 0x002c */ tint_array<int8_t, 4> tint_pad_1;
+  /* 0x0030 */ packed_float3 vec3_f32;
+  /* 0x003c */ tint_array<int8_t, 4> tint_pad_2;
+  /* 0x0040 */ packed_int3 vec3_i32;
+  /* 0x004c */ tint_array<int8_t, 4> tint_pad_3;
+  /* 0x0050 */ packed_uint3 vec3_u32;
+  /* 0x005c */ tint_array<int8_t, 4> tint_pad_4;
+  /* 0x0060 */ packed_half3 vec3_f16;
+  /* 0x0066 */ tint_array<int8_t, 10> tint_pad_5;
+  /* 0x0070 */ float4 vec4_f32;
+  /* 0x0080 */ int4 vec4_i32;
+  /* 0x0090 */ uint4 vec4_u32;
+  /* 0x00a0 */ half4 vec4_f16;
+  /* 0x00a8 */ float2x2 mat2x2_f32;
+  /* 0x00b8 */ tint_array<int8_t, 8> tint_pad_6;
+  /* 0x00c0 */ float2x3 mat2x3_f32;
+  /* 0x00e0 */ float2x4 mat2x4_f32;
+  /* 0x0100 */ float3x2 mat3x2_f32;
+  /* 0x0118 */ tint_array<int8_t, 8> tint_pad_7;
+  /* 0x0120 */ float3x3 mat3x3_f32;
+  /* 0x0150 */ float3x4 mat3x4_f32;
+  /* 0x0180 */ float4x2 mat4x2_f32;
+  /* 0x01a0 */ float4x3 mat4x3_f32;
+  /* 0x01e0 */ float4x4 mat4x4_f32;
+  /* 0x0220 */ half2x2 mat2x2_f16;
+  /* 0x0228 */ half2x3 mat2x3_f16;
+  /* 0x0238 */ half2x4 mat2x4_f16;
+  /* 0x0248 */ half3x2 mat3x2_f16;
+  /* 0x0254 */ tint_array<int8_t, 4> tint_pad_8;
+  /* 0x0258 */ half3x3 mat3x3_f16;
+  /* 0x0270 */ half3x4 mat3x4_f16;
+  /* 0x0288 */ half4x2 mat4x2_f16;
+  /* 0x0298 */ half4x3 mat4x3_f16;
+  /* 0x02b8 */ half4x4 mat4x4_f16;
+  /* 0x02d8 */ tint_array<int8_t, 8> tint_pad_9;
+  /* 0x02e0 */ tint_array<float3, 2> arr2_vec3_f32;
+  /* 0x0300 */ tint_array<half4x2, 2> arr2_mat4x2_f16;
+};
+
+struct S {
+  /* 0x0000 */ tint_array<Inner, 8> arr;
+};
+
+void tint_symbol_inner(uint idx, const constant S* const tint_symbol_1) {
+  float const scalar_f32 = (*(tint_symbol_1)).arr[idx].scalar_f32;
+  int const scalar_i32 = (*(tint_symbol_1)).arr[idx].scalar_i32;
+  uint const scalar_u32 = (*(tint_symbol_1)).arr[idx].scalar_u32;
+  half const scalar_f16 = (*(tint_symbol_1)).arr[idx].scalar_f16;
+  float2 const vec2_f32 = (*(tint_symbol_1)).arr[idx].vec2_f32;
+  int2 const vec2_i32 = (*(tint_symbol_1)).arr[idx].vec2_i32;
+  uint2 const vec2_u32 = (*(tint_symbol_1)).arr[idx].vec2_u32;
+  half2 const vec2_f16 = (*(tint_symbol_1)).arr[idx].vec2_f16;
+  float3 const vec3_f32 = float3((*(tint_symbol_1)).arr[idx].vec3_f32);
+  int3 const vec3_i32 = int3((*(tint_symbol_1)).arr[idx].vec3_i32);
+  uint3 const vec3_u32 = uint3((*(tint_symbol_1)).arr[idx].vec3_u32);
+  half3 const vec3_f16 = half3((*(tint_symbol_1)).arr[idx].vec3_f16);
+  float4 const vec4_f32 = (*(tint_symbol_1)).arr[idx].vec4_f32;
+  int4 const vec4_i32 = (*(tint_symbol_1)).arr[idx].vec4_i32;
+  uint4 const vec4_u32 = (*(tint_symbol_1)).arr[idx].vec4_u32;
+  half4 const vec4_f16 = (*(tint_symbol_1)).arr[idx].vec4_f16;
+  float2x2 const mat2x2_f32 = (*(tint_symbol_1)).arr[idx].mat2x2_f32;
+  float2x3 const mat2x3_f32 = (*(tint_symbol_1)).arr[idx].mat2x3_f32;
+  float2x4 const mat2x4_f32 = (*(tint_symbol_1)).arr[idx].mat2x4_f32;
+  float3x2 const mat3x2_f32 = (*(tint_symbol_1)).arr[idx].mat3x2_f32;
+  float3x3 const mat3x3_f32 = (*(tint_symbol_1)).arr[idx].mat3x3_f32;
+  float3x4 const mat3x4_f32 = (*(tint_symbol_1)).arr[idx].mat3x4_f32;
+  float4x2 const mat4x2_f32 = (*(tint_symbol_1)).arr[idx].mat4x2_f32;
+  float4x3 const mat4x3_f32 = (*(tint_symbol_1)).arr[idx].mat4x3_f32;
+  float4x4 const mat4x4_f32 = (*(tint_symbol_1)).arr[idx].mat4x4_f32;
+  half2x2 const mat2x2_f16 = (*(tint_symbol_1)).arr[idx].mat2x2_f16;
+  half2x3 const mat2x3_f16 = (*(tint_symbol_1)).arr[idx].mat2x3_f16;
+  half2x4 const mat2x4_f16 = (*(tint_symbol_1)).arr[idx].mat2x4_f16;
+  half3x2 const mat3x2_f16 = (*(tint_symbol_1)).arr[idx].mat3x2_f16;
+  half3x3 const mat3x3_f16 = (*(tint_symbol_1)).arr[idx].mat3x3_f16;
+  half3x4 const mat3x4_f16 = (*(tint_symbol_1)).arr[idx].mat3x4_f16;
+  half4x2 const mat4x2_f16 = (*(tint_symbol_1)).arr[idx].mat4x2_f16;
+  half4x3 const mat4x3_f16 = (*(tint_symbol_1)).arr[idx].mat4x3_f16;
+  half4x4 const mat4x4_f16 = (*(tint_symbol_1)).arr[idx].mat4x4_f16;
+  tint_array<float3, 2> const arr2_vec3_f32 = (*(tint_symbol_1)).arr[idx].arr2_vec3_f32;
+  tint_array<half4x2, 2> const arr2_mat4x2_f16 = (*(tint_symbol_1)).arr[idx].arr2_mat4x2_f16;
+}
+
+kernel void tint_symbol(const constant S* tint_symbol_2 [[buffer(0)]], uint idx [[thread_index_in_threadgroup]]) {
+  tint_symbol_inner(idx, tint_symbol_2);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/dynamic_index/read_f16.wgsl.expected.spvasm b/test/tint/buffer/uniform/dynamic_index/read_f16.wgsl.expected.spvasm
new file mode 100644
index 0000000..e504459
--- /dev/null
+++ b/test/tint/buffer/uniform/dynamic_index/read_f16.wgsl.expected.spvasm
@@ -0,0 +1,638 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 450
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main" %idx_1
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %idx_1 "idx_1"
+               OpName %ub_block_std140 "ub_block_std140"
+               OpMemberName %ub_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "arr"
+               OpName %Inner_std140 "Inner_std140"
+               OpMemberName %Inner_std140 0 "scalar_f32"
+               OpMemberName %Inner_std140 1 "scalar_i32"
+               OpMemberName %Inner_std140 2 "scalar_u32"
+               OpMemberName %Inner_std140 3 "scalar_f16"
+               OpMemberName %Inner_std140 4 "vec2_f32"
+               OpMemberName %Inner_std140 5 "vec2_i32"
+               OpMemberName %Inner_std140 6 "vec2_u32"
+               OpMemberName %Inner_std140 7 "vec2_f16"
+               OpMemberName %Inner_std140 8 "vec3_f32"
+               OpMemberName %Inner_std140 9 "vec3_i32"
+               OpMemberName %Inner_std140 10 "vec3_u32"
+               OpMemberName %Inner_std140 11 "vec3_f16"
+               OpMemberName %Inner_std140 12 "vec4_f32"
+               OpMemberName %Inner_std140 13 "vec4_i32"
+               OpMemberName %Inner_std140 14 "vec4_u32"
+               OpMemberName %Inner_std140 15 "vec4_f16"
+               OpMemberName %Inner_std140 16 "mat2x2_f32_0"
+               OpMemberName %Inner_std140 17 "mat2x2_f32_1"
+               OpMemberName %Inner_std140 18 "mat2x3_f32"
+               OpMemberName %Inner_std140 19 "mat2x4_f32"
+               OpMemberName %Inner_std140 20 "mat3x2_f32_0"
+               OpMemberName %Inner_std140 21 "mat3x2_f32_1"
+               OpMemberName %Inner_std140 22 "mat3x2_f32_2"
+               OpMemberName %Inner_std140 23 "mat3x3_f32"
+               OpMemberName %Inner_std140 24 "mat3x4_f32"
+               OpMemberName %Inner_std140 25 "mat4x2_f32_0"
+               OpMemberName %Inner_std140 26 "mat4x2_f32_1"
+               OpMemberName %Inner_std140 27 "mat4x2_f32_2"
+               OpMemberName %Inner_std140 28 "mat4x2_f32_3"
+               OpMemberName %Inner_std140 29 "mat4x3_f32"
+               OpMemberName %Inner_std140 30 "mat4x4_f32"
+               OpMemberName %Inner_std140 31 "mat2x2_f16_0"
+               OpMemberName %Inner_std140 32 "mat2x2_f16_1"
+               OpMemberName %Inner_std140 33 "mat2x3_f16_0"
+               OpMemberName %Inner_std140 34 "mat2x3_f16_1"
+               OpMemberName %Inner_std140 35 "mat2x4_f16_0"
+               OpMemberName %Inner_std140 36 "mat2x4_f16_1"
+               OpMemberName %Inner_std140 37 "mat3x2_f16_0"
+               OpMemberName %Inner_std140 38 "mat3x2_f16_1"
+               OpMemberName %Inner_std140 39 "mat3x2_f16_2"
+               OpMemberName %Inner_std140 40 "mat3x3_f16_0"
+               OpMemberName %Inner_std140 41 "mat3x3_f16_1"
+               OpMemberName %Inner_std140 42 "mat3x3_f16_2"
+               OpMemberName %Inner_std140 43 "mat3x4_f16_0"
+               OpMemberName %Inner_std140 44 "mat3x4_f16_1"
+               OpMemberName %Inner_std140 45 "mat3x4_f16_2"
+               OpMemberName %Inner_std140 46 "mat4x2_f16_0"
+               OpMemberName %Inner_std140 47 "mat4x2_f16_1"
+               OpMemberName %Inner_std140 48 "mat4x2_f16_2"
+               OpMemberName %Inner_std140 49 "mat4x2_f16_3"
+               OpMemberName %Inner_std140 50 "mat4x3_f16_0"
+               OpMemberName %Inner_std140 51 "mat4x3_f16_1"
+               OpMemberName %Inner_std140 52 "mat4x3_f16_2"
+               OpMemberName %Inner_std140 53 "mat4x3_f16_3"
+               OpMemberName %Inner_std140 54 "mat4x4_f16_0"
+               OpMemberName %Inner_std140 55 "mat4x4_f16_1"
+               OpMemberName %Inner_std140 56 "mat4x4_f16_2"
+               OpMemberName %Inner_std140 57 "mat4x4_f16_3"
+               OpMemberName %Inner_std140 58 "arr2_vec3_f32"
+               OpMemberName %Inner_std140 59 "arr2_mat4x2_f16"
+               OpName %mat4x2_f16_4 "mat4x2_f16_4"
+               OpMemberName %mat4x2_f16_4 0 "col0"
+               OpMemberName %mat4x2_f16_4 1 "col1"
+               OpMemberName %mat4x2_f16_4 2 "col2"
+               OpMemberName %mat4x2_f16_4 3 "col3"
+               OpName %ub "ub"
+               OpName %load_ub_inner_arr_p0_mat2x2_f32 "load_ub_inner_arr_p0_mat2x2_f32"
+               OpName %p0 "p0"
+               OpName %load_ub_inner_arr_p0_mat3x2_f32 "load_ub_inner_arr_p0_mat3x2_f32"
+               OpName %p0_0 "p0"
+               OpName %load_ub_inner_arr_p0_mat4x2_f32 "load_ub_inner_arr_p0_mat4x2_f32"
+               OpName %p0_1 "p0"
+               OpName %load_ub_inner_arr_p0_mat2x2_f16 "load_ub_inner_arr_p0_mat2x2_f16"
+               OpName %p0_2 "p0"
+               OpName %load_ub_inner_arr_p0_mat2x3_f16 "load_ub_inner_arr_p0_mat2x3_f16"
+               OpName %p0_3 "p0"
+               OpName %load_ub_inner_arr_p0_mat2x4_f16 "load_ub_inner_arr_p0_mat2x4_f16"
+               OpName %p0_4 "p0"
+               OpName %load_ub_inner_arr_p0_mat3x2_f16 "load_ub_inner_arr_p0_mat3x2_f16"
+               OpName %p0_5 "p0"
+               OpName %load_ub_inner_arr_p0_mat3x3_f16 "load_ub_inner_arr_p0_mat3x3_f16"
+               OpName %p0_6 "p0"
+               OpName %load_ub_inner_arr_p0_mat3x4_f16 "load_ub_inner_arr_p0_mat3x4_f16"
+               OpName %p0_7 "p0"
+               OpName %load_ub_inner_arr_p0_mat4x2_f16 "load_ub_inner_arr_p0_mat4x2_f16"
+               OpName %p0_8 "p0"
+               OpName %load_ub_inner_arr_p0_mat4x3_f16 "load_ub_inner_arr_p0_mat4x3_f16"
+               OpName %p0_9 "p0"
+               OpName %load_ub_inner_arr_p0_mat4x4_f16 "load_ub_inner_arr_p0_mat4x4_f16"
+               OpName %p0_10 "p0"
+               OpName %conv_mat4x2_f16 "conv_mat4x2_f16"
+               OpName %val "val"
+               OpName %conv_arr2_mat4x2_f16 "conv_arr2_mat4x2_f16"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %main_inner "main_inner"
+               OpName %idx "idx"
+               OpName %main "main"
+               OpDecorate %idx_1 BuiltIn LocalInvocationIndex
+               OpDecorate %ub_block_std140 Block
+               OpMemberDecorate %ub_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 1 Offset 4
+               OpMemberDecorate %Inner_std140 2 Offset 8
+               OpMemberDecorate %Inner_std140 3 Offset 12
+               OpMemberDecorate %Inner_std140 4 Offset 16
+               OpMemberDecorate %Inner_std140 5 Offset 24
+               OpMemberDecorate %Inner_std140 6 Offset 32
+               OpMemberDecorate %Inner_std140 7 Offset 40
+               OpMemberDecorate %Inner_std140 8 Offset 48
+               OpMemberDecorate %Inner_std140 9 Offset 64
+               OpMemberDecorate %Inner_std140 10 Offset 80
+               OpMemberDecorate %Inner_std140 11 Offset 96
+               OpMemberDecorate %Inner_std140 12 Offset 112
+               OpMemberDecorate %Inner_std140 13 Offset 128
+               OpMemberDecorate %Inner_std140 14 Offset 144
+               OpMemberDecorate %Inner_std140 15 Offset 160
+               OpMemberDecorate %Inner_std140 16 Offset 168
+               OpMemberDecorate %Inner_std140 17 Offset 176
+               OpMemberDecorate %Inner_std140 18 Offset 192
+               OpMemberDecorate %Inner_std140 18 ColMajor
+               OpMemberDecorate %Inner_std140 18 MatrixStride 16
+               OpMemberDecorate %Inner_std140 19 Offset 224
+               OpMemberDecorate %Inner_std140 19 ColMajor
+               OpMemberDecorate %Inner_std140 19 MatrixStride 16
+               OpMemberDecorate %Inner_std140 20 Offset 256
+               OpMemberDecorate %Inner_std140 21 Offset 264
+               OpMemberDecorate %Inner_std140 22 Offset 272
+               OpMemberDecorate %Inner_std140 23 Offset 288
+               OpMemberDecorate %Inner_std140 23 ColMajor
+               OpMemberDecorate %Inner_std140 23 MatrixStride 16
+               OpMemberDecorate %Inner_std140 24 Offset 336
+               OpMemberDecorate %Inner_std140 24 ColMajor
+               OpMemberDecorate %Inner_std140 24 MatrixStride 16
+               OpMemberDecorate %Inner_std140 25 Offset 384
+               OpMemberDecorate %Inner_std140 26 Offset 392
+               OpMemberDecorate %Inner_std140 27 Offset 400
+               OpMemberDecorate %Inner_std140 28 Offset 408
+               OpMemberDecorate %Inner_std140 29 Offset 416
+               OpMemberDecorate %Inner_std140 29 ColMajor
+               OpMemberDecorate %Inner_std140 29 MatrixStride 16
+               OpMemberDecorate %Inner_std140 30 Offset 480
+               OpMemberDecorate %Inner_std140 30 ColMajor
+               OpMemberDecorate %Inner_std140 30 MatrixStride 16
+               OpMemberDecorate %Inner_std140 31 Offset 544
+               OpMemberDecorate %Inner_std140 32 Offset 548
+               OpMemberDecorate %Inner_std140 33 Offset 552
+               OpMemberDecorate %Inner_std140 34 Offset 560
+               OpMemberDecorate %Inner_std140 35 Offset 568
+               OpMemberDecorate %Inner_std140 36 Offset 576
+               OpMemberDecorate %Inner_std140 37 Offset 584
+               OpMemberDecorate %Inner_std140 38 Offset 588
+               OpMemberDecorate %Inner_std140 39 Offset 592
+               OpMemberDecorate %Inner_std140 40 Offset 600
+               OpMemberDecorate %Inner_std140 41 Offset 608
+               OpMemberDecorate %Inner_std140 42 Offset 616
+               OpMemberDecorate %Inner_std140 43 Offset 624
+               OpMemberDecorate %Inner_std140 44 Offset 632
+               OpMemberDecorate %Inner_std140 45 Offset 640
+               OpMemberDecorate %Inner_std140 46 Offset 648
+               OpMemberDecorate %Inner_std140 47 Offset 652
+               OpMemberDecorate %Inner_std140 48 Offset 656
+               OpMemberDecorate %Inner_std140 49 Offset 660
+               OpMemberDecorate %Inner_std140 50 Offset 664
+               OpMemberDecorate %Inner_std140 51 Offset 672
+               OpMemberDecorate %Inner_std140 52 Offset 680
+               OpMemberDecorate %Inner_std140 53 Offset 688
+               OpMemberDecorate %Inner_std140 54 Offset 696
+               OpMemberDecorate %Inner_std140 55 Offset 704
+               OpMemberDecorate %Inner_std140 56 Offset 712
+               OpMemberDecorate %Inner_std140 57 Offset 720
+               OpMemberDecorate %Inner_std140 58 Offset 736
+               OpDecorate %_arr_v3float_uint_2 ArrayStride 16
+               OpMemberDecorate %Inner_std140 59 Offset 768
+               OpMemberDecorate %mat4x2_f16_4 0 Offset 0
+               OpMemberDecorate %mat4x2_f16_4 1 Offset 4
+               OpMemberDecorate %mat4x2_f16_4 2 Offset 8
+               OpMemberDecorate %mat4x2_f16_4 3 Offset 12
+               OpDecorate %_arr_mat4x2_f16_4_uint_2 ArrayStride 16
+               OpDecorate %_arr_Inner_std140_uint_8 ArrayStride 800
+               OpDecorate %ub NonWritable
+               OpDecorate %ub Binding 0
+               OpDecorate %ub DescriptorSet 0
+               OpDecorate %_arr_mat4v2half_uint_2 ArrayStride 16
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+      %idx_1 = OpVariable %_ptr_Input_uint Input
+      %float = OpTypeFloat 32
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+    %v2float = OpTypeVector %float 2
+      %v2int = OpTypeVector %int 2
+     %v2uint = OpTypeVector %uint 2
+     %v2half = OpTypeVector %half 2
+    %v3float = OpTypeVector %float 3
+      %v3int = OpTypeVector %int 3
+     %v3uint = OpTypeVector %uint 3
+     %v3half = OpTypeVector %half 3
+    %v4float = OpTypeVector %float 4
+      %v4int = OpTypeVector %int 4
+     %v4uint = OpTypeVector %uint 4
+     %v4half = OpTypeVector %half 4
+%mat2v3float = OpTypeMatrix %v3float 2
+%mat2v4float = OpTypeMatrix %v4float 2
+%mat3v3float = OpTypeMatrix %v3float 3
+%mat3v4float = OpTypeMatrix %v4float 3
+%mat4v3float = OpTypeMatrix %v3float 4
+%mat4v4float = OpTypeMatrix %v4float 4
+     %uint_2 = OpConstant %uint 2
+%_arr_v3float_uint_2 = OpTypeArray %v3float %uint_2
+%mat4x2_f16_4 = OpTypeStruct %v2half %v2half %v2half %v2half
+%_arr_mat4x2_f16_4_uint_2 = OpTypeArray %mat4x2_f16_4 %uint_2
+%Inner_std140 = OpTypeStruct %float %int %uint %half %v2float %v2int %v2uint %v2half %v3float %v3int %v3uint %v3half %v4float %v4int %v4uint %v4half %v2float %v2float %mat2v3float %mat2v4float %v2float %v2float %v2float %mat3v3float %mat3v4float %v2float %v2float %v2float %v2float %mat4v3float %mat4v4float %v2half %v2half %v3half %v3half %v4half %v4half %v2half %v2half %v2half %v3half %v3half %v3half %v4half %v4half %v4half %v2half %v2half %v2half %v2half %v3half %v3half %v3half %v3half %v4half %v4half %v4half %v4half %_arr_v3float_uint_2 %_arr_mat4x2_f16_4_uint_2
+     %uint_8 = OpConstant %uint 8
+%_arr_Inner_std140_uint_8 = OpTypeArray %Inner_std140 %uint_8
+   %S_std140 = OpTypeStruct %_arr_Inner_std140_uint_8
+%ub_block_std140 = OpTypeStruct %S_std140
+%_ptr_Uniform_ub_block_std140 = OpTypePointer Uniform %ub_block_std140
+         %ub = OpVariable %_ptr_Uniform_ub_block_std140 Uniform
+%mat2v2float = OpTypeMatrix %v2float 2
+         %36 = OpTypeFunction %mat2v2float %uint
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_Inner_std140 = OpTypePointer Uniform %Inner_std140
+    %uint_16 = OpConstant %uint 16
+%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
+    %uint_17 = OpConstant %uint 17
+%mat3v2float = OpTypeMatrix %v2float 3
+         %55 = OpTypeFunction %mat3v2float %uint
+    %uint_20 = OpConstant %uint 20
+    %uint_21 = OpConstant %uint 21
+    %uint_22 = OpConstant %uint 22
+%mat4v2float = OpTypeMatrix %v2float 4
+         %75 = OpTypeFunction %mat4v2float %uint
+    %uint_25 = OpConstant %uint 25
+    %uint_26 = OpConstant %uint 26
+    %uint_27 = OpConstant %uint 27
+    %uint_28 = OpConstant %uint 28
+ %mat2v2half = OpTypeMatrix %v2half 2
+         %99 = OpTypeFunction %mat2v2half %uint
+    %uint_31 = OpConstant %uint 31
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+    %uint_32 = OpConstant %uint 32
+ %mat2v3half = OpTypeMatrix %v3half 2
+        %116 = OpTypeFunction %mat2v3half %uint
+    %uint_33 = OpConstant %uint 33
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+    %uint_34 = OpConstant %uint 34
+ %mat2v4half = OpTypeMatrix %v4half 2
+        %133 = OpTypeFunction %mat2v4half %uint
+    %uint_35 = OpConstant %uint 35
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+    %uint_36 = OpConstant %uint 36
+ %mat3v2half = OpTypeMatrix %v2half 3
+        %150 = OpTypeFunction %mat3v2half %uint
+    %uint_37 = OpConstant %uint 37
+    %uint_38 = OpConstant %uint 38
+    %uint_39 = OpConstant %uint 39
+ %mat3v3half = OpTypeMatrix %v3half 3
+        %170 = OpTypeFunction %mat3v3half %uint
+    %uint_40 = OpConstant %uint 40
+    %uint_41 = OpConstant %uint 41
+    %uint_42 = OpConstant %uint 42
+ %mat3v4half = OpTypeMatrix %v4half 3
+        %190 = OpTypeFunction %mat3v4half %uint
+    %uint_43 = OpConstant %uint 43
+    %uint_44 = OpConstant %uint 44
+    %uint_45 = OpConstant %uint 45
+ %mat4v2half = OpTypeMatrix %v2half 4
+        %210 = OpTypeFunction %mat4v2half %uint
+    %uint_46 = OpConstant %uint 46
+    %uint_47 = OpConstant %uint 47
+    %uint_48 = OpConstant %uint 48
+    %uint_49 = OpConstant %uint 49
+ %mat4v3half = OpTypeMatrix %v3half 4
+        %234 = OpTypeFunction %mat4v3half %uint
+    %uint_50 = OpConstant %uint 50
+    %uint_51 = OpConstant %uint 51
+    %uint_52 = OpConstant %uint 52
+    %uint_53 = OpConstant %uint 53
+ %mat4v4half = OpTypeMatrix %v4half 4
+        %258 = OpTypeFunction %mat4v4half %uint
+    %uint_54 = OpConstant %uint 54
+    %uint_55 = OpConstant %uint 55
+    %uint_56 = OpConstant %uint 56
+    %uint_57 = OpConstant %uint 57
+        %282 = OpTypeFunction %mat4v2half %mat4x2_f16_4
+%_arr_mat4v2half_uint_2 = OpTypeArray %mat4v2half %uint_2
+        %291 = OpTypeFunction %_arr_mat4v2half_uint_2 %_arr_mat4x2_f16_4_uint_2
+%_ptr_Function__arr_mat4v2half_uint_2 = OpTypePointer Function %_arr_mat4v2half_uint_2
+        %298 = OpConstantNull %_arr_mat4v2half_uint_2
+%_ptr_Function_uint = OpTypePointer Function %uint
+        %301 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_mat4x2_f16_4_uint_2 = OpTypePointer Function %_arr_mat4x2_f16_4_uint_2
+        %314 = OpConstantNull %_arr_mat4x2_f16_4_uint_2
+%_ptr_Function_mat4v2half = OpTypePointer Function %mat4v2half
+%_ptr_Function_mat4x2_f16_4 = OpTypePointer Function %mat4x2_f16_4
+     %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+        %327 = OpTypeFunction %void %uint
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+%_ptr_Uniform_int = OpTypePointer Uniform %int
+%_ptr_Uniform_uint = OpTypePointer Uniform %uint
+     %uint_3 = OpConstant %uint 3
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+     %uint_4 = OpConstant %uint 4
+     %uint_5 = OpConstant %uint 5
+%_ptr_Uniform_v2int = OpTypePointer Uniform %v2int
+     %uint_6 = OpConstant %uint 6
+%_ptr_Uniform_v2uint = OpTypePointer Uniform %v2uint
+     %uint_7 = OpConstant %uint 7
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+     %uint_9 = OpConstant %uint 9
+%_ptr_Uniform_v3int = OpTypePointer Uniform %v3int
+    %uint_10 = OpConstant %uint 10
+%_ptr_Uniform_v3uint = OpTypePointer Uniform %v3uint
+    %uint_11 = OpConstant %uint 11
+    %uint_12 = OpConstant %uint 12
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+    %uint_13 = OpConstant %uint 13
+%_ptr_Uniform_v4int = OpTypePointer Uniform %v4int
+    %uint_14 = OpConstant %uint 14
+%_ptr_Uniform_v4uint = OpTypePointer Uniform %v4uint
+    %uint_15 = OpConstant %uint 15
+    %uint_18 = OpConstant %uint 18
+%_ptr_Uniform_mat2v3float = OpTypePointer Uniform %mat2v3float
+    %uint_19 = OpConstant %uint 19
+%_ptr_Uniform_mat2v4float = OpTypePointer Uniform %mat2v4float
+    %uint_23 = OpConstant %uint 23
+%_ptr_Uniform_mat3v3float = OpTypePointer Uniform %mat3v3float
+    %uint_24 = OpConstant %uint 24
+%_ptr_Uniform_mat3v4float = OpTypePointer Uniform %mat3v4float
+    %uint_29 = OpConstant %uint 29
+%_ptr_Uniform_mat4v3float = OpTypePointer Uniform %mat4v3float
+    %uint_30 = OpConstant %uint 30
+%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float
+    %uint_58 = OpConstant %uint 58
+%_ptr_Uniform__arr_v3float_uint_2 = OpTypePointer Uniform %_arr_v3float_uint_2
+    %uint_59 = OpConstant %uint 59
+%_ptr_Uniform__arr_mat4x2_f16_4_uint_2 = OpTypePointer Uniform %_arr_mat4x2_f16_4_uint_2
+        %445 = OpTypeFunction %void
+%load_ub_inner_arr_p0_mat2x2_f32 = OpFunction %mat2v2float None %36
+         %p0 = OpFunctionParameter %uint
+         %40 = OpLabel
+         %44 = OpAccessChain %_ptr_Uniform_Inner_std140 %ub %uint_0 %uint_0 %p0
+         %48 = OpAccessChain %_ptr_Uniform_v2float %44 %uint_16
+         %49 = OpLoad %v2float %48
+         %52 = OpAccessChain %_ptr_Uniform_v2float %44 %uint_17
+         %53 = OpLoad %v2float %52
+         %54 = OpCompositeConstruct %mat2v2float %49 %53
+               OpReturnValue %54
+               OpFunctionEnd
+%load_ub_inner_arr_p0_mat3x2_f32 = OpFunction %mat3v2float None %55
+       %p0_0 = OpFunctionParameter %uint
+         %59 = OpLabel
+         %61 = OpAccessChain %_ptr_Uniform_Inner_std140 %ub %uint_0 %uint_0 %p0_0
+         %64 = OpAccessChain %_ptr_Uniform_v2float %61 %uint_20
+         %65 = OpLoad %v2float %64
+         %68 = OpAccessChain %_ptr_Uniform_v2float %61 %uint_21
+         %69 = OpLoad %v2float %68
+         %72 = OpAccessChain %_ptr_Uniform_v2float %61 %uint_22
+         %73 = OpLoad %v2float %72
+         %74 = OpCompositeConstruct %mat3v2float %65 %69 %73
+               OpReturnValue %74
+               OpFunctionEnd
+%load_ub_inner_arr_p0_mat4x2_f32 = OpFunction %mat4v2float None %75
+       %p0_1 = OpFunctionParameter %uint
+         %79 = OpLabel
+         %81 = OpAccessChain %_ptr_Uniform_Inner_std140 %ub %uint_0 %uint_0 %p0_1
+         %84 = OpAccessChain %_ptr_Uniform_v2float %81 %uint_25
+         %85 = OpLoad %v2float %84
+         %88 = OpAccessChain %_ptr_Uniform_v2float %81 %uint_26
+         %89 = OpLoad %v2float %88
+         %92 = OpAccessChain %_ptr_Uniform_v2float %81 %uint_27
+         %93 = OpLoad %v2float %92
+         %96 = OpAccessChain %_ptr_Uniform_v2float %81 %uint_28
+         %97 = OpLoad %v2float %96
+         %98 = OpCompositeConstruct %mat4v2float %85 %89 %93 %97
+               OpReturnValue %98
+               OpFunctionEnd
+%load_ub_inner_arr_p0_mat2x2_f16 = OpFunction %mat2v2half None %99
+       %p0_2 = OpFunctionParameter %uint
+        %103 = OpLabel
+        %105 = OpAccessChain %_ptr_Uniform_Inner_std140 %ub %uint_0 %uint_0 %p0_2
+        %109 = OpAccessChain %_ptr_Uniform_v2half %105 %uint_31
+        %110 = OpLoad %v2half %109
+        %113 = OpAccessChain %_ptr_Uniform_v2half %105 %uint_32
+        %114 = OpLoad %v2half %113
+        %115 = OpCompositeConstruct %mat2v2half %110 %114
+               OpReturnValue %115
+               OpFunctionEnd
+%load_ub_inner_arr_p0_mat2x3_f16 = OpFunction %mat2v3half None %116
+       %p0_3 = OpFunctionParameter %uint
+        %120 = OpLabel
+        %122 = OpAccessChain %_ptr_Uniform_Inner_std140 %ub %uint_0 %uint_0 %p0_3
+        %126 = OpAccessChain %_ptr_Uniform_v3half %122 %uint_33
+        %127 = OpLoad %v3half %126
+        %130 = OpAccessChain %_ptr_Uniform_v3half %122 %uint_34
+        %131 = OpLoad %v3half %130
+        %132 = OpCompositeConstruct %mat2v3half %127 %131
+               OpReturnValue %132
+               OpFunctionEnd
+%load_ub_inner_arr_p0_mat2x4_f16 = OpFunction %mat2v4half None %133
+       %p0_4 = OpFunctionParameter %uint
+        %137 = OpLabel
+        %139 = OpAccessChain %_ptr_Uniform_Inner_std140 %ub %uint_0 %uint_0 %p0_4
+        %143 = OpAccessChain %_ptr_Uniform_v4half %139 %uint_35
+        %144 = OpLoad %v4half %143
+        %147 = OpAccessChain %_ptr_Uniform_v4half %139 %uint_36
+        %148 = OpLoad %v4half %147
+        %149 = OpCompositeConstruct %mat2v4half %144 %148
+               OpReturnValue %149
+               OpFunctionEnd
+%load_ub_inner_arr_p0_mat3x2_f16 = OpFunction %mat3v2half None %150
+       %p0_5 = OpFunctionParameter %uint
+        %154 = OpLabel
+        %156 = OpAccessChain %_ptr_Uniform_Inner_std140 %ub %uint_0 %uint_0 %p0_5
+        %159 = OpAccessChain %_ptr_Uniform_v2half %156 %uint_37
+        %160 = OpLoad %v2half %159
+        %163 = OpAccessChain %_ptr_Uniform_v2half %156 %uint_38
+        %164 = OpLoad %v2half %163
+        %167 = OpAccessChain %_ptr_Uniform_v2half %156 %uint_39
+        %168 = OpLoad %v2half %167
+        %169 = OpCompositeConstruct %mat3v2half %160 %164 %168
+               OpReturnValue %169
+               OpFunctionEnd
+%load_ub_inner_arr_p0_mat3x3_f16 = OpFunction %mat3v3half None %170
+       %p0_6 = OpFunctionParameter %uint
+        %174 = OpLabel
+        %176 = OpAccessChain %_ptr_Uniform_Inner_std140 %ub %uint_0 %uint_0 %p0_6
+        %179 = OpAccessChain %_ptr_Uniform_v3half %176 %uint_40
+        %180 = OpLoad %v3half %179
+        %183 = OpAccessChain %_ptr_Uniform_v3half %176 %uint_41
+        %184 = OpLoad %v3half %183
+        %187 = OpAccessChain %_ptr_Uniform_v3half %176 %uint_42
+        %188 = OpLoad %v3half %187
+        %189 = OpCompositeConstruct %mat3v3half %180 %184 %188
+               OpReturnValue %189
+               OpFunctionEnd
+%load_ub_inner_arr_p0_mat3x4_f16 = OpFunction %mat3v4half None %190
+       %p0_7 = OpFunctionParameter %uint
+        %194 = OpLabel
+        %196 = OpAccessChain %_ptr_Uniform_Inner_std140 %ub %uint_0 %uint_0 %p0_7
+        %199 = OpAccessChain %_ptr_Uniform_v4half %196 %uint_43
+        %200 = OpLoad %v4half %199
+        %203 = OpAccessChain %_ptr_Uniform_v4half %196 %uint_44
+        %204 = OpLoad %v4half %203
+        %207 = OpAccessChain %_ptr_Uniform_v4half %196 %uint_45
+        %208 = OpLoad %v4half %207
+        %209 = OpCompositeConstruct %mat3v4half %200 %204 %208
+               OpReturnValue %209
+               OpFunctionEnd
+%load_ub_inner_arr_p0_mat4x2_f16 = OpFunction %mat4v2half None %210
+       %p0_8 = OpFunctionParameter %uint
+        %214 = OpLabel
+        %216 = OpAccessChain %_ptr_Uniform_Inner_std140 %ub %uint_0 %uint_0 %p0_8
+        %219 = OpAccessChain %_ptr_Uniform_v2half %216 %uint_46
+        %220 = OpLoad %v2half %219
+        %223 = OpAccessChain %_ptr_Uniform_v2half %216 %uint_47
+        %224 = OpLoad %v2half %223
+        %227 = OpAccessChain %_ptr_Uniform_v2half %216 %uint_48
+        %228 = OpLoad %v2half %227
+        %231 = OpAccessChain %_ptr_Uniform_v2half %216 %uint_49
+        %232 = OpLoad %v2half %231
+        %233 = OpCompositeConstruct %mat4v2half %220 %224 %228 %232
+               OpReturnValue %233
+               OpFunctionEnd
+%load_ub_inner_arr_p0_mat4x3_f16 = OpFunction %mat4v3half None %234
+       %p0_9 = OpFunctionParameter %uint
+        %238 = OpLabel
+        %240 = OpAccessChain %_ptr_Uniform_Inner_std140 %ub %uint_0 %uint_0 %p0_9
+        %243 = OpAccessChain %_ptr_Uniform_v3half %240 %uint_50
+        %244 = OpLoad %v3half %243
+        %247 = OpAccessChain %_ptr_Uniform_v3half %240 %uint_51
+        %248 = OpLoad %v3half %247
+        %251 = OpAccessChain %_ptr_Uniform_v3half %240 %uint_52
+        %252 = OpLoad %v3half %251
+        %255 = OpAccessChain %_ptr_Uniform_v3half %240 %uint_53
+        %256 = OpLoad %v3half %255
+        %257 = OpCompositeConstruct %mat4v3half %244 %248 %252 %256
+               OpReturnValue %257
+               OpFunctionEnd
+%load_ub_inner_arr_p0_mat4x4_f16 = OpFunction %mat4v4half None %258
+      %p0_10 = OpFunctionParameter %uint
+        %262 = OpLabel
+        %264 = OpAccessChain %_ptr_Uniform_Inner_std140 %ub %uint_0 %uint_0 %p0_10
+        %267 = OpAccessChain %_ptr_Uniform_v4half %264 %uint_54
+        %268 = OpLoad %v4half %267
+        %271 = OpAccessChain %_ptr_Uniform_v4half %264 %uint_55
+        %272 = OpLoad %v4half %271
+        %275 = OpAccessChain %_ptr_Uniform_v4half %264 %uint_56
+        %276 = OpLoad %v4half %275
+        %279 = OpAccessChain %_ptr_Uniform_v4half %264 %uint_57
+        %280 = OpLoad %v4half %279
+        %281 = OpCompositeConstruct %mat4v4half %268 %272 %276 %280
+               OpReturnValue %281
+               OpFunctionEnd
+%conv_mat4x2_f16 = OpFunction %mat4v2half None %282
+        %val = OpFunctionParameter %mat4x2_f16_4
+        %285 = OpLabel
+        %286 = OpCompositeExtract %v2half %val 0
+        %287 = OpCompositeExtract %v2half %val 1
+        %288 = OpCompositeExtract %v2half %val 2
+        %289 = OpCompositeExtract %v2half %val 3
+        %290 = OpCompositeConstruct %mat4v2half %286 %287 %288 %289
+               OpReturnValue %290
+               OpFunctionEnd
+%conv_arr2_mat4x2_f16 = OpFunction %_arr_mat4v2half_uint_2 None %291
+      %val_0 = OpFunctionParameter %_arr_mat4x2_f16_4_uint_2
+        %295 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_mat4v2half_uint_2 Function %298
+          %i = OpVariable %_ptr_Function_uint Function %301
+%var_for_index = OpVariable %_ptr_Function__arr_mat4x2_f16_4_uint_2 Function %314
+               OpBranch %302
+        %302 = OpLabel
+               OpLoopMerge %303 %304 None
+               OpBranch %305
+        %305 = OpLabel
+        %307 = OpLoad %uint %i
+        %308 = OpULessThan %bool %307 %uint_2
+        %306 = OpLogicalNot %bool %308
+               OpSelectionMerge %310 None
+               OpBranchConditional %306 %311 %310
+        %311 = OpLabel
+               OpBranch %303
+        %310 = OpLabel
+               OpStore %var_for_index %val_0
+        %315 = OpLoad %uint %i
+        %317 = OpAccessChain %_ptr_Function_mat4v2half %arr %315
+        %319 = OpLoad %uint %i
+        %321 = OpAccessChain %_ptr_Function_mat4x2_f16_4 %var_for_index %319
+        %322 = OpLoad %mat4x2_f16_4 %321
+        %318 = OpFunctionCall %mat4v2half %conv_mat4x2_f16 %322
+               OpStore %317 %318
+               OpBranch %304
+        %304 = OpLabel
+        %323 = OpLoad %uint %i
+        %325 = OpIAdd %uint %323 %uint_1
+               OpStore %i %325
+               OpBranch %302
+        %303 = OpLabel
+        %326 = OpLoad %_arr_mat4v2half_uint_2 %arr
+               OpReturnValue %326
+               OpFunctionEnd
+ %main_inner = OpFunction %void None %327
+        %idx = OpFunctionParameter %uint
+        %331 = OpLabel
+        %333 = OpAccessChain %_ptr_Uniform_float %ub %uint_0 %uint_0 %idx %uint_0
+        %334 = OpLoad %float %333
+        %336 = OpAccessChain %_ptr_Uniform_int %ub %uint_0 %uint_0 %idx %uint_1
+        %337 = OpLoad %int %336
+        %339 = OpAccessChain %_ptr_Uniform_uint %ub %uint_0 %uint_0 %idx %uint_2
+        %340 = OpLoad %uint %339
+        %343 = OpAccessChain %_ptr_Uniform_half %ub %uint_0 %uint_0 %idx %uint_3
+        %344 = OpLoad %half %343
+        %346 = OpAccessChain %_ptr_Uniform_v2float %ub %uint_0 %uint_0 %idx %uint_4
+        %347 = OpLoad %v2float %346
+        %350 = OpAccessChain %_ptr_Uniform_v2int %ub %uint_0 %uint_0 %idx %uint_5
+        %351 = OpLoad %v2int %350
+        %354 = OpAccessChain %_ptr_Uniform_v2uint %ub %uint_0 %uint_0 %idx %uint_6
+        %355 = OpLoad %v2uint %354
+        %357 = OpAccessChain %_ptr_Uniform_v2half %ub %uint_0 %uint_0 %idx %uint_7
+        %358 = OpLoad %v2half %357
+        %360 = OpAccessChain %_ptr_Uniform_v3float %ub %uint_0 %uint_0 %idx %uint_8
+        %361 = OpLoad %v3float %360
+        %364 = OpAccessChain %_ptr_Uniform_v3int %ub %uint_0 %uint_0 %idx %uint_9
+        %365 = OpLoad %v3int %364
+        %368 = OpAccessChain %_ptr_Uniform_v3uint %ub %uint_0 %uint_0 %idx %uint_10
+        %369 = OpLoad %v3uint %368
+        %371 = OpAccessChain %_ptr_Uniform_v3half %ub %uint_0 %uint_0 %idx %uint_11
+        %372 = OpLoad %v3half %371
+        %375 = OpAccessChain %_ptr_Uniform_v4float %ub %uint_0 %uint_0 %idx %uint_12
+        %376 = OpLoad %v4float %375
+        %379 = OpAccessChain %_ptr_Uniform_v4int %ub %uint_0 %uint_0 %idx %uint_13
+        %380 = OpLoad %v4int %379
+        %383 = OpAccessChain %_ptr_Uniform_v4uint %ub %uint_0 %uint_0 %idx %uint_14
+        %384 = OpLoad %v4uint %383
+        %386 = OpAccessChain %_ptr_Uniform_v4half %ub %uint_0 %uint_0 %idx %uint_15
+        %387 = OpLoad %v4half %386
+        %388 = OpFunctionCall %mat2v2float %load_ub_inner_arr_p0_mat2x2_f32 %idx
+        %392 = OpAccessChain %_ptr_Uniform_mat2v3float %ub %uint_0 %uint_0 %idx %uint_18
+        %393 = OpLoad %mat2v3float %392
+        %396 = OpAccessChain %_ptr_Uniform_mat2v4float %ub %uint_0 %uint_0 %idx %uint_19
+        %397 = OpLoad %mat2v4float %396
+        %398 = OpFunctionCall %mat3v2float %load_ub_inner_arr_p0_mat3x2_f32 %idx
+        %402 = OpAccessChain %_ptr_Uniform_mat3v3float %ub %uint_0 %uint_0 %idx %uint_23
+        %403 = OpLoad %mat3v3float %402
+        %406 = OpAccessChain %_ptr_Uniform_mat3v4float %ub %uint_0 %uint_0 %idx %uint_24
+        %407 = OpLoad %mat3v4float %406
+        %408 = OpFunctionCall %mat4v2float %load_ub_inner_arr_p0_mat4x2_f32 %idx
+        %412 = OpAccessChain %_ptr_Uniform_mat4v3float %ub %uint_0 %uint_0 %idx %uint_29
+        %413 = OpLoad %mat4v3float %412
+        %416 = OpAccessChain %_ptr_Uniform_mat4v4float %ub %uint_0 %uint_0 %idx %uint_30
+        %417 = OpLoad %mat4v4float %416
+        %418 = OpFunctionCall %mat2v2half %load_ub_inner_arr_p0_mat2x2_f16 %idx
+        %420 = OpFunctionCall %mat2v3half %load_ub_inner_arr_p0_mat2x3_f16 %idx
+        %422 = OpFunctionCall %mat2v4half %load_ub_inner_arr_p0_mat2x4_f16 %idx
+        %424 = OpFunctionCall %mat3v2half %load_ub_inner_arr_p0_mat3x2_f16 %idx
+        %426 = OpFunctionCall %mat3v3half %load_ub_inner_arr_p0_mat3x3_f16 %idx
+        %428 = OpFunctionCall %mat3v4half %load_ub_inner_arr_p0_mat3x4_f16 %idx
+        %430 = OpFunctionCall %mat4v2half %load_ub_inner_arr_p0_mat4x2_f16 %idx
+        %432 = OpFunctionCall %mat4v3half %load_ub_inner_arr_p0_mat4x3_f16 %idx
+        %434 = OpFunctionCall %mat4v4half %load_ub_inner_arr_p0_mat4x4_f16 %idx
+        %438 = OpAccessChain %_ptr_Uniform__arr_v3float_uint_2 %ub %uint_0 %uint_0 %idx %uint_58
+        %439 = OpLoad %_arr_v3float_uint_2 %438
+        %443 = OpAccessChain %_ptr_Uniform__arr_mat4x2_f16_4_uint_2 %ub %uint_0 %uint_0 %idx %uint_59
+        %444 = OpLoad %_arr_mat4x2_f16_4_uint_2 %443
+        %440 = OpFunctionCall %_arr_mat4v2half_uint_2 %conv_arr2_mat4x2_f16 %444
+               OpReturn
+               OpFunctionEnd
+       %main = OpFunction %void None %445
+        %447 = OpLabel
+        %449 = OpLoad %uint %idx_1
+        %448 = OpFunctionCall %void %main_inner %449
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/dynamic_index/read_f16.wgsl.expected.wgsl b/test/tint/buffer/uniform/dynamic_index/read_f16.wgsl.expected.wgsl
new file mode 100644
index 0000000..3b14216
--- /dev/null
+++ b/test/tint/buffer/uniform/dynamic_index/read_f16.wgsl.expected.wgsl
@@ -0,0 +1,87 @@
+enable f16;
+
+struct Inner {
+  scalar_f32 : f32,
+  scalar_i32 : i32,
+  scalar_u32 : u32,
+  scalar_f16 : f16,
+  vec2_f32 : vec2<f32>,
+  vec2_i32 : vec2<i32>,
+  vec2_u32 : vec2<u32>,
+  vec2_f16 : vec2<f16>,
+  vec3_f32 : vec3<f32>,
+  vec3_i32 : vec3<i32>,
+  vec3_u32 : vec3<u32>,
+  vec3_f16 : vec3<f16>,
+  vec4_f32 : vec4<f32>,
+  vec4_i32 : vec4<i32>,
+  vec4_u32 : vec4<u32>,
+  vec4_f16 : vec4<f16>,
+  mat2x2_f32 : mat2x2<f32>,
+  mat2x3_f32 : mat2x3<f32>,
+  mat2x4_f32 : mat2x4<f32>,
+  mat3x2_f32 : mat3x2<f32>,
+  mat3x3_f32 : mat3x3<f32>,
+  mat3x4_f32 : mat3x4<f32>,
+  mat4x2_f32 : mat4x2<f32>,
+  mat4x3_f32 : mat4x3<f32>,
+  mat4x4_f32 : mat4x4<f32>,
+  mat2x2_f16 : mat2x2<f16>,
+  mat2x3_f16 : mat2x3<f16>,
+  mat2x4_f16 : mat2x4<f16>,
+  mat3x2_f16 : mat3x2<f16>,
+  mat3x3_f16 : mat3x3<f16>,
+  mat3x4_f16 : mat3x4<f16>,
+  mat4x2_f16 : mat4x2<f16>,
+  mat4x3_f16 : mat4x3<f16>,
+  mat4x4_f16 : mat4x4<f16>,
+  @align(16)
+  arr2_vec3_f32 : array<vec3<f32>, 2>,
+  arr2_mat4x2_f16 : array<mat4x2<f16>, 2>,
+}
+
+struct S {
+  arr : array<Inner, 8>,
+}
+
+@binding(0) @group(0) var<uniform> ub : S;
+
+@compute @workgroup_size(1)
+fn main(@builtin(local_invocation_index) idx : u32) {
+  let scalar_f32 : f32 = ub.arr[idx].scalar_f32;
+  let scalar_i32 : i32 = ub.arr[idx].scalar_i32;
+  let scalar_u32 : u32 = ub.arr[idx].scalar_u32;
+  let scalar_f16 : f16 = ub.arr[idx].scalar_f16;
+  let vec2_f32 : vec2<f32> = ub.arr[idx].vec2_f32;
+  let vec2_i32 : vec2<i32> = ub.arr[idx].vec2_i32;
+  let vec2_u32 : vec2<u32> = ub.arr[idx].vec2_u32;
+  let vec2_f16 : vec2<f16> = ub.arr[idx].vec2_f16;
+  let vec3_f32 : vec3<f32> = ub.arr[idx].vec3_f32;
+  let vec3_i32 : vec3<i32> = ub.arr[idx].vec3_i32;
+  let vec3_u32 : vec3<u32> = ub.arr[idx].vec3_u32;
+  let vec3_f16 : vec3<f16> = ub.arr[idx].vec3_f16;
+  let vec4_f32 : vec4<f32> = ub.arr[idx].vec4_f32;
+  let vec4_i32 : vec4<i32> = ub.arr[idx].vec4_i32;
+  let vec4_u32 : vec4<u32> = ub.arr[idx].vec4_u32;
+  let vec4_f16 : vec4<f16> = ub.arr[idx].vec4_f16;
+  let mat2x2_f32 : mat2x2<f32> = ub.arr[idx].mat2x2_f32;
+  let mat2x3_f32 : mat2x3<f32> = ub.arr[idx].mat2x3_f32;
+  let mat2x4_f32 : mat2x4<f32> = ub.arr[idx].mat2x4_f32;
+  let mat3x2_f32 : mat3x2<f32> = ub.arr[idx].mat3x2_f32;
+  let mat3x3_f32 : mat3x3<f32> = ub.arr[idx].mat3x3_f32;
+  let mat3x4_f32 : mat3x4<f32> = ub.arr[idx].mat3x4_f32;
+  let mat4x2_f32 : mat4x2<f32> = ub.arr[idx].mat4x2_f32;
+  let mat4x3_f32 : mat4x3<f32> = ub.arr[idx].mat4x3_f32;
+  let mat4x4_f32 : mat4x4<f32> = ub.arr[idx].mat4x4_f32;
+  let mat2x2_f16 : mat2x2<f16> = ub.arr[idx].mat2x2_f16;
+  let mat2x3_f16 : mat2x3<f16> = ub.arr[idx].mat2x3_f16;
+  let mat2x4_f16 : mat2x4<f16> = ub.arr[idx].mat2x4_f16;
+  let mat3x2_f16 : mat3x2<f16> = ub.arr[idx].mat3x2_f16;
+  let mat3x3_f16 : mat3x3<f16> = ub.arr[idx].mat3x3_f16;
+  let mat3x4_f16 : mat3x4<f16> = ub.arr[idx].mat3x4_f16;
+  let mat4x2_f16 : mat4x2<f16> = ub.arr[idx].mat4x2_f16;
+  let mat4x3_f16 : mat4x3<f16> = ub.arr[idx].mat4x3_f16;
+  let mat4x4_f16 : mat4x4<f16> = ub.arr[idx].mat4x4_f16;
+  let arr2_vec3_f32 : array<vec3<f32>, 2> = ub.arr[idx].arr2_vec3_f32;
+  let arr2_mat4x2_f16 : array<mat4x2<f16>, 2> = ub.arr[idx].arr2_mat4x2_f16;
+}
diff --git a/test/tint/buffer/uniform/static_index/read.wgsl b/test/tint/buffer/uniform/static_index/read.wgsl
index ed6e7dc..8d064d9 100644
--- a/test/tint/buffer/uniform/static_index/read.wgsl
+++ b/test/tint/buffer/uniform/static_index/read.wgsl
@@ -1,36 +1,62 @@
 struct Inner {
-    @size(16) x : i32,
+    scalar_i32 : i32,
+    @align(16) @size(16)
+    scalar_f32 : f32,
 };
 
 struct S {
-    a : vec3<i32>,
-    b : i32,
-    c : vec3<u32>,
-    d : u32,
-    e : vec3<f32>,
-    f : f32,
-    g : vec2<i32>,
-    h : vec2<i32>,
-    i : mat2x3<f32>,
-    j : mat3x2<f32>,
-    @align(16) k : Inner,
-    @align(16) l : array<Inner, 4>,
+    scalar_f32 : f32,
+    scalar_i32 : i32,
+    scalar_u32 : u32,
+    vec2_f32 : vec2<f32>,
+    vec2_i32 : vec2<i32>,
+    vec2_u32 : vec2<u32>,
+    vec3_f32 : vec3<f32>,
+    vec3_i32 : vec3<i32>,
+    vec3_u32 : vec3<u32>,
+    vec4_f32 : vec4<f32>,
+    vec4_i32 : vec4<i32>,
+    vec4_u32 : vec4<u32>,
+    mat2x2_f32 : mat2x2<f32>,
+    mat2x3_f32 : mat2x3<f32>,
+    mat2x4_f32 : mat2x4<f32>,
+    mat3x2_f32 : mat3x2<f32>,
+    mat3x3_f32 : mat3x3<f32>,
+    mat3x4_f32 : mat3x4<f32>,
+    mat4x2_f32 : mat4x2<f32>,
+    mat4x3_f32 : mat4x3<f32>,
+    mat4x4_f32 : mat4x4<f32>,
+    @align(16) arr2_vec3_f32 : array<vec3<f32>, 2>,
+    @align(16) struct_inner : Inner,
+    @align(16) array_struct_inner : array<Inner, 4>,
 };
 
-@binding(0) @group(0) var<uniform> s : S;
+@binding(0) @group(0) var<uniform> ub : S;
 
 @compute @workgroup_size(1)
 fn main() {
-    let a = s.a;
-    let b = s.b;
-    let c = s.c;
-    let d = s.d;
-    let e = s.e;
-    let f = s.f;
-    let g = s.g;
-    let h = s.h;
-    let i = s.i;
-    let j = s.j;
-    let k = s.k;
-    let l = s.l;
+    let scalar_f32 = ub.scalar_f32;
+    let scalar_i32 = ub.scalar_i32;
+    let scalar_u32 = ub.scalar_u32;
+    let vec2_f32 = ub.vec2_f32;
+    let vec2_i32 = ub.vec2_i32;
+    let vec2_u32 = ub.vec2_u32;
+    let vec3_f32 = ub.vec3_f32;
+    let vec3_i32 = ub.vec3_i32;
+    let vec3_u32 = ub.vec3_u32;
+    let vec4_f32 = ub.vec4_f32;
+    let vec4_i32 = ub.vec4_i32;
+    let vec4_u32 = ub.vec4_u32;
+    let mat2x2_f32 = ub.mat2x2_f32;
+    let mat2x3_f32 = ub.mat2x3_f32;
+    let mat2x4_f32 = ub.mat2x4_f32;
+    let mat3x2_f32 = ub.mat3x2_f32;
+    let mat3x3_f32 = ub.mat3x3_f32;
+    let mat3x4_f32 = ub.mat3x4_f32;
+    let mat4x2_f32 = ub.mat4x2_f32;
+    let mat4x3_f32 = ub.mat4x3_f32;
+    let mat4x4_f32 = ub.mat4x4_f32;
+    let arr2_vec3_f32 = ub.arr2_vec3_f32;
+    let struct_inner = ub.struct_inner;
+    let array_struct_inner = ub.array_struct_inner;
 }
diff --git a/test/tint/buffer/uniform/static_index/read.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/static_index/read.wgsl.expected.dxc.hlsl
index 8538133..7a69526 100644
--- a/test/tint/buffer/uniform/static_index/read.wgsl.expected.dxc.hlsl
+++ b/test/tint/buffer/uniform/static_index/read.wgsl.expected.dxc.hlsl
@@ -1,57 +1,139 @@
 struct Inner {
-  int x;
+  int scalar_i32;
+  float scalar_f32;
 };
 
-cbuffer cbuffer_s : register(b0, space0) {
-  uint4 s[13];
+cbuffer cbuffer_ub : register(b0, space0) {
+  uint4 ub[44];
 };
 
-float2x3 tint_symbol_7(uint4 buffer[13], uint offset) {
+float2x2 tint_symbol_12(uint4 buffer[44], uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
-  const uint scalar_offset_1 = ((offset + 16u)) / 4;
-  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  return float2x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)));
 }
 
-float3x2 tint_symbol_8(uint4 buffer[13], uint offset) {
+float2x3 tint_symbol_13(uint4 buffer[44], uint offset) {
   const uint scalar_offset_2 = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset_2 / 4];
-  const uint scalar_offset_3 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_3 / 4];
-  const uint scalar_offset_4 = ((offset + 16u)) / 4;
-  uint4 ubo_load_2 = buffer[scalar_offset_4 / 4];
-  return float3x2(asfloat(((scalar_offset_2 & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_3 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_4 & 2) ? ubo_load_2.zw : ubo_load_2.xy)));
+  const uint scalar_offset_3 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
 }
 
-Inner tint_symbol_10(uint4 buffer[13], uint offset) {
-  const uint scalar_offset_5 = ((offset + 0u)) / 4;
-  const Inner tint_symbol_12 = {asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
-  return tint_symbol_12;
+float2x4 tint_symbol_14(uint4 buffer[44], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset_4 / 4]), asfloat(buffer[scalar_offset_5 / 4]));
 }
 
-typedef Inner tint_symbol_11_ret[4];
-tint_symbol_11_ret tint_symbol_11(uint4 buffer[13], uint offset) {
-  Inner arr[4] = (Inner[4])0;
+float3x2 tint_symbol_15(uint4 buffer[44], uint offset) {
+  const uint scalar_offset_6 = ((offset + 0u)) / 4;
+  uint4 ubo_load_2 = buffer[scalar_offset_6 / 4];
+  const uint scalar_offset_7 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_7 / 4];
+  const uint scalar_offset_8 = ((offset + 16u)) / 4;
+  uint4 ubo_load_4 = buffer[scalar_offset_8 / 4];
+  return float3x2(asfloat(((scalar_offset_6 & 2) ? ubo_load_2.zw : ubo_load_2.xy)), asfloat(((scalar_offset_7 & 2) ? ubo_load_3.zw : ubo_load_3.xy)), asfloat(((scalar_offset_8 & 2) ? ubo_load_4.zw : ubo_load_4.xy)));
+}
+
+float3x3 tint_symbol_16(uint4 buffer[44], uint offset) {
+  const uint scalar_offset_9 = ((offset + 0u)) / 4;
+  const uint scalar_offset_10 = ((offset + 16u)) / 4;
+  const uint scalar_offset_11 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset_9 / 4].xyz), asfloat(buffer[scalar_offset_10 / 4].xyz), asfloat(buffer[scalar_offset_11 / 4].xyz));
+}
+
+float3x4 tint_symbol_17(uint4 buffer[44], uint offset) {
+  const uint scalar_offset_12 = ((offset + 0u)) / 4;
+  const uint scalar_offset_13 = ((offset + 16u)) / 4;
+  const uint scalar_offset_14 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset_12 / 4]), asfloat(buffer[scalar_offset_13 / 4]), asfloat(buffer[scalar_offset_14 / 4]));
+}
+
+float4x2 tint_symbol_18(uint4 buffer[44], uint offset) {
+  const uint scalar_offset_15 = ((offset + 0u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_15 / 4];
+  const uint scalar_offset_16 = ((offset + 8u)) / 4;
+  uint4 ubo_load_6 = buffer[scalar_offset_16 / 4];
+  const uint scalar_offset_17 = ((offset + 16u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_17 / 4];
+  const uint scalar_offset_18 = ((offset + 24u)) / 4;
+  uint4 ubo_load_8 = buffer[scalar_offset_18 / 4];
+  return float4x2(asfloat(((scalar_offset_15 & 2) ? ubo_load_5.zw : ubo_load_5.xy)), asfloat(((scalar_offset_16 & 2) ? ubo_load_6.zw : ubo_load_6.xy)), asfloat(((scalar_offset_17 & 2) ? ubo_load_7.zw : ubo_load_7.xy)), asfloat(((scalar_offset_18 & 2) ? ubo_load_8.zw : ubo_load_8.xy)));
+}
+
+float4x3 tint_symbol_19(uint4 buffer[44], uint offset) {
+  const uint scalar_offset_19 = ((offset + 0u)) / 4;
+  const uint scalar_offset_20 = ((offset + 16u)) / 4;
+  const uint scalar_offset_21 = ((offset + 32u)) / 4;
+  const uint scalar_offset_22 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset_19 / 4].xyz), asfloat(buffer[scalar_offset_20 / 4].xyz), asfloat(buffer[scalar_offset_21 / 4].xyz), asfloat(buffer[scalar_offset_22 / 4].xyz));
+}
+
+float4x4 tint_symbol_20(uint4 buffer[44], uint offset) {
+  const uint scalar_offset_23 = ((offset + 0u)) / 4;
+  const uint scalar_offset_24 = ((offset + 16u)) / 4;
+  const uint scalar_offset_25 = ((offset + 32u)) / 4;
+  const uint scalar_offset_26 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset_23 / 4]), asfloat(buffer[scalar_offset_24 / 4]), asfloat(buffer[scalar_offset_25 / 4]), asfloat(buffer[scalar_offset_26 / 4]));
+}
+
+typedef float3 tint_symbol_21_ret[2];
+tint_symbol_21_ret tint_symbol_21(uint4 buffer[44], uint offset) {
+  float3 arr[2] = (float3[2])0;
   {
-    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
-      arr[i_1] = tint_symbol_10(buffer, (offset + (i_1 * 16u)));
+    for(uint i = 0u; (i < 2u); i = (i + 1u)) {
+      const uint scalar_offset_27 = ((offset + (i * 16u))) / 4;
+      arr[i] = asfloat(buffer[scalar_offset_27 / 4].xyz);
     }
   }
   return arr;
 }
 
+Inner tint_symbol_22(uint4 buffer[44], uint offset) {
+  const uint scalar_offset_28 = ((offset + 0u)) / 4;
+  const uint scalar_offset_29 = ((offset + 16u)) / 4;
+  const Inner tint_symbol_24 = {asint(buffer[scalar_offset_28 / 4][scalar_offset_28 % 4]), asfloat(buffer[scalar_offset_29 / 4][scalar_offset_29 % 4])};
+  return tint_symbol_24;
+}
+
+typedef Inner tint_symbol_23_ret[4];
+tint_symbol_23_ret tint_symbol_23(uint4 buffer[44], uint offset) {
+  Inner arr_1[4] = (Inner[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr_1[i_1] = tint_symbol_22(buffer, (offset + (i_1 * 32u)));
+    }
+  }
+  return arr_1;
+}
+
 [numthreads(1, 1, 1)]
 void main() {
-  const int3 a = asint(s[0].xyz);
-  const int b = asint(s[0].w);
-  const uint3 c = s[1].xyz;
-  const uint d = s[1].w;
-  const float3 e = asfloat(s[2].xyz);
-  const float f = asfloat(s[2].w);
-  const int2 g = asint(s[3].xy);
-  const int2 h = asint(s[3].zw);
-  const float2x3 i = tint_symbol_7(s, 64u);
-  const float3x2 j = tint_symbol_8(s, 96u);
-  const Inner k = tint_symbol_10(s, 128u);
-  const Inner l[4] = tint_symbol_11(s, 144u);
+  const float scalar_f32 = asfloat(ub[0].x);
+  const int scalar_i32 = asint(ub[0].y);
+  const uint scalar_u32 = ub[0].z;
+  const float2 vec2_f32 = asfloat(ub[1].xy);
+  const int2 vec2_i32 = asint(ub[1].zw);
+  const uint2 vec2_u32 = ub[2].xy;
+  const float3 vec3_f32 = asfloat(ub[3].xyz);
+  const int3 vec3_i32 = asint(ub[4].xyz);
+  const uint3 vec3_u32 = ub[5].xyz;
+  const float4 vec4_f32 = asfloat(ub[6]);
+  const int4 vec4_i32 = asint(ub[7]);
+  const uint4 vec4_u32 = ub[8];
+  const float2x2 mat2x2_f32 = tint_symbol_12(ub, 144u);
+  const float2x3 mat2x3_f32 = tint_symbol_13(ub, 160u);
+  const float2x4 mat2x4_f32 = tint_symbol_14(ub, 192u);
+  const float3x2 mat3x2_f32 = tint_symbol_15(ub, 224u);
+  const float3x3 mat3x3_f32 = tint_symbol_16(ub, 256u);
+  const float3x4 mat3x4_f32 = tint_symbol_17(ub, 304u);
+  const float4x2 mat4x2_f32 = tint_symbol_18(ub, 352u);
+  const float4x3 mat4x3_f32 = tint_symbol_19(ub, 384u);
+  const float4x4 mat4x4_f32 = tint_symbol_20(ub, 448u);
+  const float3 arr2_vec3_f32[2] = tint_symbol_21(ub, 512u);
+  const Inner struct_inner = tint_symbol_22(ub, 544u);
+  const Inner array_struct_inner[4] = tint_symbol_23(ub, 576u);
   return;
 }
diff --git a/test/tint/buffer/uniform/static_index/read.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/static_index/read.wgsl.expected.fxc.hlsl
index 8538133..7a69526 100644
--- a/test/tint/buffer/uniform/static_index/read.wgsl.expected.fxc.hlsl
+++ b/test/tint/buffer/uniform/static_index/read.wgsl.expected.fxc.hlsl
@@ -1,57 +1,139 @@
 struct Inner {
-  int x;
+  int scalar_i32;
+  float scalar_f32;
 };
 
-cbuffer cbuffer_s : register(b0, space0) {
-  uint4 s[13];
+cbuffer cbuffer_ub : register(b0, space0) {
+  uint4 ub[44];
 };
 
-float2x3 tint_symbol_7(uint4 buffer[13], uint offset) {
+float2x2 tint_symbol_12(uint4 buffer[44], uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
-  const uint scalar_offset_1 = ((offset + 16u)) / 4;
-  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  return float2x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)));
 }
 
-float3x2 tint_symbol_8(uint4 buffer[13], uint offset) {
+float2x3 tint_symbol_13(uint4 buffer[44], uint offset) {
   const uint scalar_offset_2 = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset_2 / 4];
-  const uint scalar_offset_3 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_3 / 4];
-  const uint scalar_offset_4 = ((offset + 16u)) / 4;
-  uint4 ubo_load_2 = buffer[scalar_offset_4 / 4];
-  return float3x2(asfloat(((scalar_offset_2 & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_3 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_4 & 2) ? ubo_load_2.zw : ubo_load_2.xy)));
+  const uint scalar_offset_3 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
 }
 
-Inner tint_symbol_10(uint4 buffer[13], uint offset) {
-  const uint scalar_offset_5 = ((offset + 0u)) / 4;
-  const Inner tint_symbol_12 = {asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
-  return tint_symbol_12;
+float2x4 tint_symbol_14(uint4 buffer[44], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset_4 / 4]), asfloat(buffer[scalar_offset_5 / 4]));
 }
 
-typedef Inner tint_symbol_11_ret[4];
-tint_symbol_11_ret tint_symbol_11(uint4 buffer[13], uint offset) {
-  Inner arr[4] = (Inner[4])0;
+float3x2 tint_symbol_15(uint4 buffer[44], uint offset) {
+  const uint scalar_offset_6 = ((offset + 0u)) / 4;
+  uint4 ubo_load_2 = buffer[scalar_offset_6 / 4];
+  const uint scalar_offset_7 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_7 / 4];
+  const uint scalar_offset_8 = ((offset + 16u)) / 4;
+  uint4 ubo_load_4 = buffer[scalar_offset_8 / 4];
+  return float3x2(asfloat(((scalar_offset_6 & 2) ? ubo_load_2.zw : ubo_load_2.xy)), asfloat(((scalar_offset_7 & 2) ? ubo_load_3.zw : ubo_load_3.xy)), asfloat(((scalar_offset_8 & 2) ? ubo_load_4.zw : ubo_load_4.xy)));
+}
+
+float3x3 tint_symbol_16(uint4 buffer[44], uint offset) {
+  const uint scalar_offset_9 = ((offset + 0u)) / 4;
+  const uint scalar_offset_10 = ((offset + 16u)) / 4;
+  const uint scalar_offset_11 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset_9 / 4].xyz), asfloat(buffer[scalar_offset_10 / 4].xyz), asfloat(buffer[scalar_offset_11 / 4].xyz));
+}
+
+float3x4 tint_symbol_17(uint4 buffer[44], uint offset) {
+  const uint scalar_offset_12 = ((offset + 0u)) / 4;
+  const uint scalar_offset_13 = ((offset + 16u)) / 4;
+  const uint scalar_offset_14 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset_12 / 4]), asfloat(buffer[scalar_offset_13 / 4]), asfloat(buffer[scalar_offset_14 / 4]));
+}
+
+float4x2 tint_symbol_18(uint4 buffer[44], uint offset) {
+  const uint scalar_offset_15 = ((offset + 0u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_15 / 4];
+  const uint scalar_offset_16 = ((offset + 8u)) / 4;
+  uint4 ubo_load_6 = buffer[scalar_offset_16 / 4];
+  const uint scalar_offset_17 = ((offset + 16u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_17 / 4];
+  const uint scalar_offset_18 = ((offset + 24u)) / 4;
+  uint4 ubo_load_8 = buffer[scalar_offset_18 / 4];
+  return float4x2(asfloat(((scalar_offset_15 & 2) ? ubo_load_5.zw : ubo_load_5.xy)), asfloat(((scalar_offset_16 & 2) ? ubo_load_6.zw : ubo_load_6.xy)), asfloat(((scalar_offset_17 & 2) ? ubo_load_7.zw : ubo_load_7.xy)), asfloat(((scalar_offset_18 & 2) ? ubo_load_8.zw : ubo_load_8.xy)));
+}
+
+float4x3 tint_symbol_19(uint4 buffer[44], uint offset) {
+  const uint scalar_offset_19 = ((offset + 0u)) / 4;
+  const uint scalar_offset_20 = ((offset + 16u)) / 4;
+  const uint scalar_offset_21 = ((offset + 32u)) / 4;
+  const uint scalar_offset_22 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset_19 / 4].xyz), asfloat(buffer[scalar_offset_20 / 4].xyz), asfloat(buffer[scalar_offset_21 / 4].xyz), asfloat(buffer[scalar_offset_22 / 4].xyz));
+}
+
+float4x4 tint_symbol_20(uint4 buffer[44], uint offset) {
+  const uint scalar_offset_23 = ((offset + 0u)) / 4;
+  const uint scalar_offset_24 = ((offset + 16u)) / 4;
+  const uint scalar_offset_25 = ((offset + 32u)) / 4;
+  const uint scalar_offset_26 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset_23 / 4]), asfloat(buffer[scalar_offset_24 / 4]), asfloat(buffer[scalar_offset_25 / 4]), asfloat(buffer[scalar_offset_26 / 4]));
+}
+
+typedef float3 tint_symbol_21_ret[2];
+tint_symbol_21_ret tint_symbol_21(uint4 buffer[44], uint offset) {
+  float3 arr[2] = (float3[2])0;
   {
-    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
-      arr[i_1] = tint_symbol_10(buffer, (offset + (i_1 * 16u)));
+    for(uint i = 0u; (i < 2u); i = (i + 1u)) {
+      const uint scalar_offset_27 = ((offset + (i * 16u))) / 4;
+      arr[i] = asfloat(buffer[scalar_offset_27 / 4].xyz);
     }
   }
   return arr;
 }
 
+Inner tint_symbol_22(uint4 buffer[44], uint offset) {
+  const uint scalar_offset_28 = ((offset + 0u)) / 4;
+  const uint scalar_offset_29 = ((offset + 16u)) / 4;
+  const Inner tint_symbol_24 = {asint(buffer[scalar_offset_28 / 4][scalar_offset_28 % 4]), asfloat(buffer[scalar_offset_29 / 4][scalar_offset_29 % 4])};
+  return tint_symbol_24;
+}
+
+typedef Inner tint_symbol_23_ret[4];
+tint_symbol_23_ret tint_symbol_23(uint4 buffer[44], uint offset) {
+  Inner arr_1[4] = (Inner[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr_1[i_1] = tint_symbol_22(buffer, (offset + (i_1 * 32u)));
+    }
+  }
+  return arr_1;
+}
+
 [numthreads(1, 1, 1)]
 void main() {
-  const int3 a = asint(s[0].xyz);
-  const int b = asint(s[0].w);
-  const uint3 c = s[1].xyz;
-  const uint d = s[1].w;
-  const float3 e = asfloat(s[2].xyz);
-  const float f = asfloat(s[2].w);
-  const int2 g = asint(s[3].xy);
-  const int2 h = asint(s[3].zw);
-  const float2x3 i = tint_symbol_7(s, 64u);
-  const float3x2 j = tint_symbol_8(s, 96u);
-  const Inner k = tint_symbol_10(s, 128u);
-  const Inner l[4] = tint_symbol_11(s, 144u);
+  const float scalar_f32 = asfloat(ub[0].x);
+  const int scalar_i32 = asint(ub[0].y);
+  const uint scalar_u32 = ub[0].z;
+  const float2 vec2_f32 = asfloat(ub[1].xy);
+  const int2 vec2_i32 = asint(ub[1].zw);
+  const uint2 vec2_u32 = ub[2].xy;
+  const float3 vec3_f32 = asfloat(ub[3].xyz);
+  const int3 vec3_i32 = asint(ub[4].xyz);
+  const uint3 vec3_u32 = ub[5].xyz;
+  const float4 vec4_f32 = asfloat(ub[6]);
+  const int4 vec4_i32 = asint(ub[7]);
+  const uint4 vec4_u32 = ub[8];
+  const float2x2 mat2x2_f32 = tint_symbol_12(ub, 144u);
+  const float2x3 mat2x3_f32 = tint_symbol_13(ub, 160u);
+  const float2x4 mat2x4_f32 = tint_symbol_14(ub, 192u);
+  const float3x2 mat3x2_f32 = tint_symbol_15(ub, 224u);
+  const float3x3 mat3x3_f32 = tint_symbol_16(ub, 256u);
+  const float3x4 mat3x4_f32 = tint_symbol_17(ub, 304u);
+  const float4x2 mat4x2_f32 = tint_symbol_18(ub, 352u);
+  const float4x3 mat4x3_f32 = tint_symbol_19(ub, 384u);
+  const float4x4 mat4x4_f32 = tint_symbol_20(ub, 448u);
+  const float3 arr2_vec3_f32[2] = tint_symbol_21(ub, 512u);
+  const Inner struct_inner = tint_symbol_22(ub, 544u);
+  const Inner array_struct_inner[4] = tint_symbol_23(ub, 576u);
   return;
 }
diff --git a/test/tint/buffer/uniform/static_index/read.wgsl.expected.glsl b/test/tint/buffer/uniform/static_index/read.wgsl.expected.glsl
index 3315e42..89ce45b 100644
--- a/test/tint/buffer/uniform/static_index/read.wgsl.expected.glsl
+++ b/test/tint/buffer/uniform/static_index/read.wgsl.expected.glsl
@@ -1,69 +1,133 @@
 #version 310 es
 
 struct Inner {
-  int x;
+  int scalar_i32;
   uint pad;
   uint pad_1;
   uint pad_2;
+  float scalar_f32;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
 };
 
 struct S {
-  ivec3 a;
-  int b;
-  uvec3 c;
-  uint d;
-  vec3 e;
-  float f;
-  ivec2 g;
-  ivec2 h;
-  mat2x3 i;
-  mat3x2 j;
-  uint pad_3;
-  uint pad_4;
-  Inner k;
-  Inner l[4];
+  float scalar_f32;
+  int scalar_i32;
+  uint scalar_u32;
+  uint pad_6;
+  vec2 vec2_f32;
+  ivec2 vec2_i32;
+  uvec2 vec2_u32;
+  uint pad_7;
+  uint pad_8;
+  vec3 vec3_f32;
+  uint pad_9;
+  ivec3 vec3_i32;
+  uint pad_10;
+  uvec3 vec3_u32;
+  uint pad_11;
+  vec4 vec4_f32;
+  ivec4 vec4_i32;
+  uvec4 vec4_u32;
+  mat2 mat2x2_f32;
+  mat2x3 mat2x3_f32;
+  mat2x4 mat2x4_f32;
+  mat3x2 mat3x2_f32;
+  uint pad_12;
+  uint pad_13;
+  mat3 mat3x3_f32;
+  mat3x4 mat3x4_f32;
+  mat4x2 mat4x2_f32;
+  mat4x3 mat4x3_f32;
+  mat4 mat4x4_f32;
+  vec3 arr2_vec3_f32[2];
+  Inner struct_inner;
+  Inner array_struct_inner[4];
 };
 
 struct S_std140 {
-  ivec3 a;
-  int b;
-  uvec3 c;
-  uint d;
-  vec3 e;
-  float f;
-  ivec2 g;
-  ivec2 h;
-  mat2x3 i;
-  vec2 j_0;
-  vec2 j_1;
-  vec2 j_2;
-  uint pad_3;
-  uint pad_4;
-  Inner k;
-  Inner l[4];
+  float scalar_f32;
+  int scalar_i32;
+  uint scalar_u32;
+  uint pad_6;
+  vec2 vec2_f32;
+  ivec2 vec2_i32;
+  uvec2 vec2_u32;
+  uint pad_7;
+  uint pad_8;
+  vec3 vec3_f32;
+  uint pad_9;
+  ivec3 vec3_i32;
+  uint pad_10;
+  uvec3 vec3_u32;
+  uint pad_11;
+  vec4 vec4_f32;
+  ivec4 vec4_i32;
+  uvec4 vec4_u32;
+  vec2 mat2x2_f32_0;
+  vec2 mat2x2_f32_1;
+  mat2x3 mat2x3_f32;
+  mat2x4 mat2x4_f32;
+  vec2 mat3x2_f32_0;
+  vec2 mat3x2_f32_1;
+  vec2 mat3x2_f32_2;
+  uint pad_12;
+  uint pad_13;
+  mat3 mat3x3_f32;
+  mat3x4 mat3x4_f32;
+  vec2 mat4x2_f32_0;
+  vec2 mat4x2_f32_1;
+  vec2 mat4x2_f32_2;
+  vec2 mat4x2_f32_3;
+  mat4x3 mat4x3_f32;
+  mat4 mat4x4_f32;
+  vec3 arr2_vec3_f32[2];
+  Inner struct_inner;
+  Inner array_struct_inner[4];
 };
 
-layout(binding = 0, std140) uniform s_block_std140_ubo {
+layout(binding = 0, std140) uniform ub_block_std140_ubo {
   S_std140 inner;
-} s;
+} ub;
 
-mat3x2 load_s_inner_j() {
-  return mat3x2(s.inner.j_0, s.inner.j_1, s.inner.j_2);
+mat2 load_ub_inner_mat2x2_f32() {
+  return mat2(ub.inner.mat2x2_f32_0, ub.inner.mat2x2_f32_1);
+}
+
+mat3x2 load_ub_inner_mat3x2_f32() {
+  return mat3x2(ub.inner.mat3x2_f32_0, ub.inner.mat3x2_f32_1, ub.inner.mat3x2_f32_2);
+}
+
+mat4x2 load_ub_inner_mat4x2_f32() {
+  return mat4x2(ub.inner.mat4x2_f32_0, ub.inner.mat4x2_f32_1, ub.inner.mat4x2_f32_2, ub.inner.mat4x2_f32_3);
 }
 
 void tint_symbol() {
-  ivec3 a = s.inner.a;
-  int b = s.inner.b;
-  uvec3 c = s.inner.c;
-  uint d = s.inner.d;
-  vec3 e = s.inner.e;
-  float f = s.inner.f;
-  ivec2 g = s.inner.g;
-  ivec2 h = s.inner.h;
-  mat2x3 i = s.inner.i;
-  mat3x2 j = load_s_inner_j();
-  Inner k = s.inner.k;
-  Inner l[4] = s.inner.l;
+  float scalar_f32 = ub.inner.scalar_f32;
+  int scalar_i32 = ub.inner.scalar_i32;
+  uint scalar_u32 = ub.inner.scalar_u32;
+  vec2 vec2_f32 = ub.inner.vec2_f32;
+  ivec2 vec2_i32 = ub.inner.vec2_i32;
+  uvec2 vec2_u32 = ub.inner.vec2_u32;
+  vec3 vec3_f32 = ub.inner.vec3_f32;
+  ivec3 vec3_i32 = ub.inner.vec3_i32;
+  uvec3 vec3_u32 = ub.inner.vec3_u32;
+  vec4 vec4_f32 = ub.inner.vec4_f32;
+  ivec4 vec4_i32 = ub.inner.vec4_i32;
+  uvec4 vec4_u32 = ub.inner.vec4_u32;
+  mat2 mat2x2_f32 = load_ub_inner_mat2x2_f32();
+  mat2x3 mat2x3_f32 = ub.inner.mat2x3_f32;
+  mat2x4 mat2x4_f32 = ub.inner.mat2x4_f32;
+  mat3x2 mat3x2_f32 = load_ub_inner_mat3x2_f32();
+  mat3 mat3x3_f32 = ub.inner.mat3x3_f32;
+  mat3x4 mat3x4_f32 = ub.inner.mat3x4_f32;
+  mat4x2 mat4x2_f32 = load_ub_inner_mat4x2_f32();
+  mat4x3 mat4x3_f32 = ub.inner.mat4x3_f32;
+  mat4 mat4x4_f32 = ub.inner.mat4x4_f32;
+  vec3 arr2_vec3_f32[2] = ub.inner.arr2_vec3_f32;
+  Inner struct_inner = ub.inner.struct_inner;
+  Inner array_struct_inner[4] = ub.inner.array_struct_inner;
 }
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
diff --git a/test/tint/buffer/uniform/static_index/read.wgsl.expected.msl b/test/tint/buffer/uniform/static_index/read.wgsl.expected.msl
index 02d091d..93dc443 100644
--- a/test/tint/buffer/uniform/static_index/read.wgsl.expected.msl
+++ b/test/tint/buffer/uniform/static_index/read.wgsl.expected.msl
@@ -15,39 +15,70 @@
 };
 
 struct Inner {
-  /* 0x0000 */ int x;
+  /* 0x0000 */ int scalar_i32;
   /* 0x0004 */ tint_array<int8_t, 12> tint_pad;
+  /* 0x0010 */ float scalar_f32;
+  /* 0x0014 */ tint_array<int8_t, 12> tint_pad_1;
 };
 
 struct S {
-  /* 0x0000 */ packed_int3 a;
-  /* 0x000c */ int b;
-  /* 0x0010 */ packed_uint3 c;
-  /* 0x001c */ uint d;
-  /* 0x0020 */ packed_float3 e;
-  /* 0x002c */ float f;
-  /* 0x0030 */ int2 g;
-  /* 0x0038 */ int2 h;
-  /* 0x0040 */ float2x3 i;
-  /* 0x0060 */ float3x2 j;
-  /* 0x0078 */ tint_array<int8_t, 8> tint_pad_1;
-  /* 0x0080 */ Inner k;
-  /* 0x0090 */ tint_array<Inner, 4> l;
+  /* 0x0000 */ float scalar_f32;
+  /* 0x0004 */ int scalar_i32;
+  /* 0x0008 */ uint scalar_u32;
+  /* 0x000c */ tint_array<int8_t, 4> tint_pad_2;
+  /* 0x0010 */ float2 vec2_f32;
+  /* 0x0018 */ int2 vec2_i32;
+  /* 0x0020 */ uint2 vec2_u32;
+  /* 0x0028 */ tint_array<int8_t, 8> tint_pad_3;
+  /* 0x0030 */ packed_float3 vec3_f32;
+  /* 0x003c */ tint_array<int8_t, 4> tint_pad_4;
+  /* 0x0040 */ packed_int3 vec3_i32;
+  /* 0x004c */ tint_array<int8_t, 4> tint_pad_5;
+  /* 0x0050 */ packed_uint3 vec3_u32;
+  /* 0x005c */ tint_array<int8_t, 4> tint_pad_6;
+  /* 0x0060 */ float4 vec4_f32;
+  /* 0x0070 */ int4 vec4_i32;
+  /* 0x0080 */ uint4 vec4_u32;
+  /* 0x0090 */ float2x2 mat2x2_f32;
+  /* 0x00a0 */ float2x3 mat2x3_f32;
+  /* 0x00c0 */ float2x4 mat2x4_f32;
+  /* 0x00e0 */ float3x2 mat3x2_f32;
+  /* 0x00f8 */ tint_array<int8_t, 8> tint_pad_7;
+  /* 0x0100 */ float3x3 mat3x3_f32;
+  /* 0x0130 */ float3x4 mat3x4_f32;
+  /* 0x0160 */ float4x2 mat4x2_f32;
+  /* 0x0180 */ float4x3 mat4x3_f32;
+  /* 0x01c0 */ float4x4 mat4x4_f32;
+  /* 0x0200 */ tint_array<float3, 2> arr2_vec3_f32;
+  /* 0x0220 */ Inner struct_inner;
+  /* 0x0240 */ tint_array<Inner, 4> array_struct_inner;
 };
 
 kernel void tint_symbol(const constant S* tint_symbol_1 [[buffer(0)]]) {
-  int3 const a = int3((*(tint_symbol_1)).a);
-  int const b = (*(tint_symbol_1)).b;
-  uint3 const c = uint3((*(tint_symbol_1)).c);
-  uint const d = (*(tint_symbol_1)).d;
-  float3 const e = float3((*(tint_symbol_1)).e);
-  float const f = (*(tint_symbol_1)).f;
-  int2 const g = (*(tint_symbol_1)).g;
-  int2 const h = (*(tint_symbol_1)).h;
-  float2x3 const i = (*(tint_symbol_1)).i;
-  float3x2 const j = (*(tint_symbol_1)).j;
-  Inner const k = (*(tint_symbol_1)).k;
-  tint_array<Inner, 4> const l = (*(tint_symbol_1)).l;
+  float const scalar_f32 = (*(tint_symbol_1)).scalar_f32;
+  int const scalar_i32 = (*(tint_symbol_1)).scalar_i32;
+  uint const scalar_u32 = (*(tint_symbol_1)).scalar_u32;
+  float2 const vec2_f32 = (*(tint_symbol_1)).vec2_f32;
+  int2 const vec2_i32 = (*(tint_symbol_1)).vec2_i32;
+  uint2 const vec2_u32 = (*(tint_symbol_1)).vec2_u32;
+  float3 const vec3_f32 = float3((*(tint_symbol_1)).vec3_f32);
+  int3 const vec3_i32 = int3((*(tint_symbol_1)).vec3_i32);
+  uint3 const vec3_u32 = uint3((*(tint_symbol_1)).vec3_u32);
+  float4 const vec4_f32 = (*(tint_symbol_1)).vec4_f32;
+  int4 const vec4_i32 = (*(tint_symbol_1)).vec4_i32;
+  uint4 const vec4_u32 = (*(tint_symbol_1)).vec4_u32;
+  float2x2 const mat2x2_f32 = (*(tint_symbol_1)).mat2x2_f32;
+  float2x3 const mat2x3_f32 = (*(tint_symbol_1)).mat2x3_f32;
+  float2x4 const mat2x4_f32 = (*(tint_symbol_1)).mat2x4_f32;
+  float3x2 const mat3x2_f32 = (*(tint_symbol_1)).mat3x2_f32;
+  float3x3 const mat3x3_f32 = (*(tint_symbol_1)).mat3x3_f32;
+  float3x4 const mat3x4_f32 = (*(tint_symbol_1)).mat3x4_f32;
+  float4x2 const mat4x2_f32 = (*(tint_symbol_1)).mat4x2_f32;
+  float4x3 const mat4x3_f32 = (*(tint_symbol_1)).mat4x3_f32;
+  float4x4 const mat4x4_f32 = (*(tint_symbol_1)).mat4x4_f32;
+  tint_array<float3, 2> const arr2_vec3_f32 = (*(tint_symbol_1)).arr2_vec3_f32;
+  Inner const struct_inner = (*(tint_symbol_1)).struct_inner;
+  tint_array<Inner, 4> const array_struct_inner = (*(tint_symbol_1)).array_struct_inner;
   return;
 }
 
diff --git a/test/tint/buffer/uniform/static_index/read.wgsl.expected.spvasm b/test/tint/buffer/uniform/static_index/read.wgsl.expected.spvasm
index 11b5abb..95b5802 100644
--- a/test/tint/buffer/uniform/static_index/read.wgsl.expected.spvasm
+++ b/test/tint/buffer/uniform/static_index/read.wgsl.expected.spvasm
@@ -1,138 +1,271 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 85
+; Bound: 175
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
                OpEntryPoint GLCompute %main "main"
                OpExecutionMode %main LocalSize 1 1 1
-               OpName %s_block_std140 "s_block_std140"
-               OpMemberName %s_block_std140 0 "inner"
+               OpName %ub_block_std140 "ub_block_std140"
+               OpMemberName %ub_block_std140 0 "inner"
                OpName %S_std140 "S_std140"
-               OpMemberName %S_std140 0 "a"
-               OpMemberName %S_std140 1 "b"
-               OpMemberName %S_std140 2 "c"
-               OpMemberName %S_std140 3 "d"
-               OpMemberName %S_std140 4 "e"
-               OpMemberName %S_std140 5 "f"
-               OpMemberName %S_std140 6 "g"
-               OpMemberName %S_std140 7 "h"
-               OpMemberName %S_std140 8 "i"
-               OpMemberName %S_std140 9 "j_0"
-               OpMemberName %S_std140 10 "j_1"
-               OpMemberName %S_std140 11 "j_2"
-               OpMemberName %S_std140 12 "k"
+               OpMemberName %S_std140 0 "scalar_f32"
+               OpMemberName %S_std140 1 "scalar_i32"
+               OpMemberName %S_std140 2 "scalar_u32"
+               OpMemberName %S_std140 3 "vec2_f32"
+               OpMemberName %S_std140 4 "vec2_i32"
+               OpMemberName %S_std140 5 "vec2_u32"
+               OpMemberName %S_std140 6 "vec3_f32"
+               OpMemberName %S_std140 7 "vec3_i32"
+               OpMemberName %S_std140 8 "vec3_u32"
+               OpMemberName %S_std140 9 "vec4_f32"
+               OpMemberName %S_std140 10 "vec4_i32"
+               OpMemberName %S_std140 11 "vec4_u32"
+               OpMemberName %S_std140 12 "mat2x2_f32_0"
+               OpMemberName %S_std140 13 "mat2x2_f32_1"
+               OpMemberName %S_std140 14 "mat2x3_f32"
+               OpMemberName %S_std140 15 "mat2x4_f32"
+               OpMemberName %S_std140 16 "mat3x2_f32_0"
+               OpMemberName %S_std140 17 "mat3x2_f32_1"
+               OpMemberName %S_std140 18 "mat3x2_f32_2"
+               OpMemberName %S_std140 19 "mat3x3_f32"
+               OpMemberName %S_std140 20 "mat3x4_f32"
+               OpMemberName %S_std140 21 "mat4x2_f32_0"
+               OpMemberName %S_std140 22 "mat4x2_f32_1"
+               OpMemberName %S_std140 23 "mat4x2_f32_2"
+               OpMemberName %S_std140 24 "mat4x2_f32_3"
+               OpMemberName %S_std140 25 "mat4x3_f32"
+               OpMemberName %S_std140 26 "mat4x4_f32"
+               OpMemberName %S_std140 27 "arr2_vec3_f32"
+               OpMemberName %S_std140 28 "struct_inner"
                OpName %Inner "Inner"
-               OpMemberName %Inner 0 "x"
-               OpMemberName %S_std140 13 "l"
-               OpName %s "s"
-               OpName %load_s_inner_j "load_s_inner_j"
+               OpMemberName %Inner 0 "scalar_i32"
+               OpMemberName %Inner 1 "scalar_f32"
+               OpMemberName %S_std140 29 "array_struct_inner"
+               OpName %ub "ub"
+               OpName %load_ub_inner_mat2x2_f32 "load_ub_inner_mat2x2_f32"
+               OpName %load_ub_inner_mat3x2_f32 "load_ub_inner_mat3x2_f32"
+               OpName %load_ub_inner_mat4x2_f32 "load_ub_inner_mat4x2_f32"
                OpName %main "main"
-               OpDecorate %s_block_std140 Block
-               OpMemberDecorate %s_block_std140 0 Offset 0
+               OpDecorate %ub_block_std140 Block
+               OpMemberDecorate %ub_block_std140 0 Offset 0
                OpMemberDecorate %S_std140 0 Offset 0
-               OpMemberDecorate %S_std140 1 Offset 12
-               OpMemberDecorate %S_std140 2 Offset 16
-               OpMemberDecorate %S_std140 3 Offset 28
-               OpMemberDecorate %S_std140 4 Offset 32
-               OpMemberDecorate %S_std140 5 Offset 44
+               OpMemberDecorate %S_std140 1 Offset 4
+               OpMemberDecorate %S_std140 2 Offset 8
+               OpMemberDecorate %S_std140 3 Offset 16
+               OpMemberDecorate %S_std140 4 Offset 24
+               OpMemberDecorate %S_std140 5 Offset 32
                OpMemberDecorate %S_std140 6 Offset 48
-               OpMemberDecorate %S_std140 7 Offset 56
-               OpMemberDecorate %S_std140 8 Offset 64
-               OpMemberDecorate %S_std140 8 ColMajor
-               OpMemberDecorate %S_std140 8 MatrixStride 16
+               OpMemberDecorate %S_std140 7 Offset 64
+               OpMemberDecorate %S_std140 8 Offset 80
                OpMemberDecorate %S_std140 9 Offset 96
-               OpMemberDecorate %S_std140 10 Offset 104
-               OpMemberDecorate %S_std140 11 Offset 112
-               OpMemberDecorate %S_std140 12 Offset 128
+               OpMemberDecorate %S_std140 10 Offset 112
+               OpMemberDecorate %S_std140 11 Offset 128
+               OpMemberDecorate %S_std140 12 Offset 144
+               OpMemberDecorate %S_std140 13 Offset 152
+               OpMemberDecorate %S_std140 14 Offset 160
+               OpMemberDecorate %S_std140 14 ColMajor
+               OpMemberDecorate %S_std140 14 MatrixStride 16
+               OpMemberDecorate %S_std140 15 Offset 192
+               OpMemberDecorate %S_std140 15 ColMajor
+               OpMemberDecorate %S_std140 15 MatrixStride 16
+               OpMemberDecorate %S_std140 16 Offset 224
+               OpMemberDecorate %S_std140 17 Offset 232
+               OpMemberDecorate %S_std140 18 Offset 240
+               OpMemberDecorate %S_std140 19 Offset 256
+               OpMemberDecorate %S_std140 19 ColMajor
+               OpMemberDecorate %S_std140 19 MatrixStride 16
+               OpMemberDecorate %S_std140 20 Offset 304
+               OpMemberDecorate %S_std140 20 ColMajor
+               OpMemberDecorate %S_std140 20 MatrixStride 16
+               OpMemberDecorate %S_std140 21 Offset 352
+               OpMemberDecorate %S_std140 22 Offset 360
+               OpMemberDecorate %S_std140 23 Offset 368
+               OpMemberDecorate %S_std140 24 Offset 376
+               OpMemberDecorate %S_std140 25 Offset 384
+               OpMemberDecorate %S_std140 25 ColMajor
+               OpMemberDecorate %S_std140 25 MatrixStride 16
+               OpMemberDecorate %S_std140 26 Offset 448
+               OpMemberDecorate %S_std140 26 ColMajor
+               OpMemberDecorate %S_std140 26 MatrixStride 16
+               OpMemberDecorate %S_std140 27 Offset 512
+               OpDecorate %_arr_v3float_uint_2 ArrayStride 16
+               OpMemberDecorate %S_std140 28 Offset 544
                OpMemberDecorate %Inner 0 Offset 0
-               OpMemberDecorate %S_std140 13 Offset 144
-               OpDecorate %_arr_Inner_uint_4 ArrayStride 16
-               OpDecorate %s NonWritable
-               OpDecorate %s Binding 0
-               OpDecorate %s DescriptorSet 0
-        %int = OpTypeInt 32 1
-      %v3int = OpTypeVector %int 3
-       %uint = OpTypeInt 32 0
-     %v3uint = OpTypeVector %uint 3
+               OpMemberDecorate %Inner 1 Offset 16
+               OpMemberDecorate %S_std140 29 Offset 576
+               OpDecorate %_arr_Inner_uint_4 ArrayStride 32
+               OpDecorate %ub NonWritable
+               OpDecorate %ub Binding 0
+               OpDecorate %ub DescriptorSet 0
       %float = OpTypeFloat 32
-    %v3float = OpTypeVector %float 3
-      %v2int = OpTypeVector %int 2
-%mat2v3float = OpTypeMatrix %v3float 2
+        %int = OpTypeInt 32 1
+       %uint = OpTypeInt 32 0
     %v2float = OpTypeVector %float 2
-      %Inner = OpTypeStruct %int
+      %v2int = OpTypeVector %int 2
+     %v2uint = OpTypeVector %uint 2
+    %v3float = OpTypeVector %float 3
+      %v3int = OpTypeVector %int 3
+     %v3uint = OpTypeVector %uint 3
+    %v4float = OpTypeVector %float 4
+      %v4int = OpTypeVector %int 4
+     %v4uint = OpTypeVector %uint 4
+%mat2v3float = OpTypeMatrix %v3float 2
+%mat2v4float = OpTypeMatrix %v4float 2
+%mat3v3float = OpTypeMatrix %v3float 3
+%mat3v4float = OpTypeMatrix %v4float 3
+%mat4v3float = OpTypeMatrix %v3float 4
+%mat4v4float = OpTypeMatrix %v4float 4
+     %uint_2 = OpConstant %uint 2
+%_arr_v3float_uint_2 = OpTypeArray %v3float %uint_2
+      %Inner = OpTypeStruct %int %float
      %uint_4 = OpConstant %uint 4
 %_arr_Inner_uint_4 = OpTypeArray %Inner %uint_4
-   %S_std140 = OpTypeStruct %v3int %int %v3uint %uint %v3float %float %v2int %v2int %mat2v3float %v2float %v2float %v2float %Inner %_arr_Inner_uint_4
-%s_block_std140 = OpTypeStruct %S_std140
-%_ptr_Uniform_s_block_std140 = OpTypePointer Uniform %s_block_std140
-          %s = OpVariable %_ptr_Uniform_s_block_std140 Uniform
-%mat3v2float = OpTypeMatrix %v2float 3
-         %17 = OpTypeFunction %mat3v2float
+   %S_std140 = OpTypeStruct %float %int %uint %v2float %v2int %v2uint %v3float %v3int %v3uint %v4float %v4int %v4uint %v2float %v2float %mat2v3float %mat2v4float %v2float %v2float %v2float %mat3v3float %mat3v4float %v2float %v2float %v2float %v2float %mat4v3float %mat4v4float %_arr_v3float_uint_2 %Inner %_arr_Inner_uint_4
+%ub_block_std140 = OpTypeStruct %S_std140
+%_ptr_Uniform_ub_block_std140 = OpTypePointer Uniform %ub_block_std140
+         %ub = OpVariable %_ptr_Uniform_ub_block_std140 Uniform
+%mat2v2float = OpTypeMatrix %v2float 2
+         %28 = OpTypeFunction %mat2v2float
      %uint_0 = OpConstant %uint 0
 %_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
-     %uint_9 = OpConstant %uint 9
+    %uint_12 = OpConstant %uint 12
 %_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
-    %uint_10 = OpConstant %uint 10
-    %uint_11 = OpConstant %uint 11
+    %uint_13 = OpConstant %uint 13
+%mat3v2float = OpTypeMatrix %v2float 3
+         %46 = OpTypeFunction %mat3v2float
+    %uint_16 = OpConstant %uint 16
+    %uint_17 = OpConstant %uint 17
+    %uint_18 = OpConstant %uint 18
+%mat4v2float = OpTypeMatrix %v2float 4
+         %65 = OpTypeFunction %mat4v2float
+    %uint_21 = OpConstant %uint 21
+    %uint_22 = OpConstant %uint 22
+    %uint_23 = OpConstant %uint 23
+    %uint_24 = OpConstant %uint 24
        %void = OpTypeVoid
-         %39 = OpTypeFunction %void
-%_ptr_Uniform_v3int = OpTypePointer Uniform %v3int
+         %88 = OpTypeFunction %void
+%_ptr_Uniform_float = OpTypePointer Uniform %float
      %uint_1 = OpConstant %uint 1
 %_ptr_Uniform_int = OpTypePointer Uniform %int
-     %uint_2 = OpConstant %uint 2
-%_ptr_Uniform_v3uint = OpTypePointer Uniform %v3uint
-     %uint_3 = OpConstant %uint 3
 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
-%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
-     %uint_5 = OpConstant %uint 5
-%_ptr_Uniform_float = OpTypePointer Uniform %float
-     %uint_6 = OpConstant %uint 6
+     %uint_3 = OpConstant %uint 3
 %_ptr_Uniform_v2int = OpTypePointer Uniform %v2int
+     %uint_5 = OpConstant %uint 5
+%_ptr_Uniform_v2uint = OpTypePointer Uniform %v2uint
+     %uint_6 = OpConstant %uint 6
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
      %uint_7 = OpConstant %uint 7
+%_ptr_Uniform_v3int = OpTypePointer Uniform %v3int
      %uint_8 = OpConstant %uint 8
+%_ptr_Uniform_v3uint = OpTypePointer Uniform %v3uint
+     %uint_9 = OpConstant %uint 9
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+    %uint_10 = OpConstant %uint 10
+%_ptr_Uniform_v4int = OpTypePointer Uniform %v4int
+    %uint_11 = OpConstant %uint 11
+%_ptr_Uniform_v4uint = OpTypePointer Uniform %v4uint
+    %uint_14 = OpConstant %uint 14
 %_ptr_Uniform_mat2v3float = OpTypePointer Uniform %mat2v3float
-    %uint_12 = OpConstant %uint 12
+    %uint_15 = OpConstant %uint 15
+%_ptr_Uniform_mat2v4float = OpTypePointer Uniform %mat2v4float
+    %uint_19 = OpConstant %uint 19
+%_ptr_Uniform_mat3v3float = OpTypePointer Uniform %mat3v3float
+    %uint_20 = OpConstant %uint 20
+%_ptr_Uniform_mat3v4float = OpTypePointer Uniform %mat3v4float
+    %uint_25 = OpConstant %uint 25
+%_ptr_Uniform_mat4v3float = OpTypePointer Uniform %mat4v3float
+    %uint_26 = OpConstant %uint 26
+%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float
+    %uint_27 = OpConstant %uint 27
+%_ptr_Uniform__arr_v3float_uint_2 = OpTypePointer Uniform %_arr_v3float_uint_2
+    %uint_28 = OpConstant %uint 28
 %_ptr_Uniform_Inner = OpTypePointer Uniform %Inner
-    %uint_13 = OpConstant %uint 13
+    %uint_29 = OpConstant %uint 29
 %_ptr_Uniform__arr_Inner_uint_4 = OpTypePointer Uniform %_arr_Inner_uint_4
-%load_s_inner_j = OpFunction %mat3v2float None %17
-         %20 = OpLabel
-         %24 = OpAccessChain %_ptr_Uniform_S_std140 %s %uint_0
-         %28 = OpAccessChain %_ptr_Uniform_v2float %24 %uint_9
-         %29 = OpLoad %v2float %28
-         %32 = OpAccessChain %_ptr_Uniform_v2float %24 %uint_10
-         %33 = OpLoad %v2float %32
-         %36 = OpAccessChain %_ptr_Uniform_v2float %24 %uint_11
-         %37 = OpLoad %v2float %36
-         %38 = OpCompositeConstruct %mat3v2float %29 %33 %37
-               OpReturnValue %38
+%load_ub_inner_mat2x2_f32 = OpFunction %mat2v2float None %28
+         %31 = OpLabel
+         %35 = OpAccessChain %_ptr_Uniform_S_std140 %ub %uint_0
+         %39 = OpAccessChain %_ptr_Uniform_v2float %35 %uint_12
+         %40 = OpLoad %v2float %39
+         %43 = OpAccessChain %_ptr_Uniform_v2float %35 %uint_13
+         %44 = OpLoad %v2float %43
+         %45 = OpCompositeConstruct %mat2v2float %40 %44
+               OpReturnValue %45
                OpFunctionEnd
-       %main = OpFunction %void None %39
-         %42 = OpLabel
-         %44 = OpAccessChain %_ptr_Uniform_v3int %s %uint_0 %uint_0
-         %45 = OpLoad %v3int %44
-         %48 = OpAccessChain %_ptr_Uniform_int %s %uint_0 %uint_1
-         %49 = OpLoad %int %48
-         %52 = OpAccessChain %_ptr_Uniform_v3uint %s %uint_0 %uint_2
-         %53 = OpLoad %v3uint %52
-         %56 = OpAccessChain %_ptr_Uniform_uint %s %uint_0 %uint_3
-         %57 = OpLoad %uint %56
-         %59 = OpAccessChain %_ptr_Uniform_v3float %s %uint_0 %uint_4
-         %60 = OpLoad %v3float %59
-         %63 = OpAccessChain %_ptr_Uniform_float %s %uint_0 %uint_5
-         %64 = OpLoad %float %63
-         %67 = OpAccessChain %_ptr_Uniform_v2int %s %uint_0 %uint_6
-         %68 = OpLoad %v2int %67
-         %70 = OpAccessChain %_ptr_Uniform_v2int %s %uint_0 %uint_7
-         %71 = OpLoad %v2int %70
-         %74 = OpAccessChain %_ptr_Uniform_mat2v3float %s %uint_0 %uint_8
-         %75 = OpLoad %mat2v3float %74
-         %76 = OpFunctionCall %mat3v2float %load_s_inner_j
-         %79 = OpAccessChain %_ptr_Uniform_Inner %s %uint_0 %uint_12
-         %80 = OpLoad %Inner %79
-         %83 = OpAccessChain %_ptr_Uniform__arr_Inner_uint_4 %s %uint_0 %uint_13
-         %84 = OpLoad %_arr_Inner_uint_4 %83
+%load_ub_inner_mat3x2_f32 = OpFunction %mat3v2float None %46
+         %49 = OpLabel
+         %51 = OpAccessChain %_ptr_Uniform_S_std140 %ub %uint_0
+         %54 = OpAccessChain %_ptr_Uniform_v2float %51 %uint_16
+         %55 = OpLoad %v2float %54
+         %58 = OpAccessChain %_ptr_Uniform_v2float %51 %uint_17
+         %59 = OpLoad %v2float %58
+         %62 = OpAccessChain %_ptr_Uniform_v2float %51 %uint_18
+         %63 = OpLoad %v2float %62
+         %64 = OpCompositeConstruct %mat3v2float %55 %59 %63
+               OpReturnValue %64
+               OpFunctionEnd
+%load_ub_inner_mat4x2_f32 = OpFunction %mat4v2float None %65
+         %68 = OpLabel
+         %70 = OpAccessChain %_ptr_Uniform_S_std140 %ub %uint_0
+         %73 = OpAccessChain %_ptr_Uniform_v2float %70 %uint_21
+         %74 = OpLoad %v2float %73
+         %77 = OpAccessChain %_ptr_Uniform_v2float %70 %uint_22
+         %78 = OpLoad %v2float %77
+         %81 = OpAccessChain %_ptr_Uniform_v2float %70 %uint_23
+         %82 = OpLoad %v2float %81
+         %85 = OpAccessChain %_ptr_Uniform_v2float %70 %uint_24
+         %86 = OpLoad %v2float %85
+         %87 = OpCompositeConstruct %mat4v2float %74 %78 %82 %86
+               OpReturnValue %87
+               OpFunctionEnd
+       %main = OpFunction %void None %88
+         %91 = OpLabel
+         %93 = OpAccessChain %_ptr_Uniform_float %ub %uint_0 %uint_0
+         %94 = OpLoad %float %93
+         %97 = OpAccessChain %_ptr_Uniform_int %ub %uint_0 %uint_1
+         %98 = OpLoad %int %97
+        %100 = OpAccessChain %_ptr_Uniform_uint %ub %uint_0 %uint_2
+        %101 = OpLoad %uint %100
+        %103 = OpAccessChain %_ptr_Uniform_v2float %ub %uint_0 %uint_3
+        %104 = OpLoad %v2float %103
+        %106 = OpAccessChain %_ptr_Uniform_v2int %ub %uint_0 %uint_4
+        %107 = OpLoad %v2int %106
+        %110 = OpAccessChain %_ptr_Uniform_v2uint %ub %uint_0 %uint_5
+        %111 = OpLoad %v2uint %110
+        %114 = OpAccessChain %_ptr_Uniform_v3float %ub %uint_0 %uint_6
+        %115 = OpLoad %v3float %114
+        %118 = OpAccessChain %_ptr_Uniform_v3int %ub %uint_0 %uint_7
+        %119 = OpLoad %v3int %118
+        %122 = OpAccessChain %_ptr_Uniform_v3uint %ub %uint_0 %uint_8
+        %123 = OpLoad %v3uint %122
+        %126 = OpAccessChain %_ptr_Uniform_v4float %ub %uint_0 %uint_9
+        %127 = OpLoad %v4float %126
+        %130 = OpAccessChain %_ptr_Uniform_v4int %ub %uint_0 %uint_10
+        %131 = OpLoad %v4int %130
+        %134 = OpAccessChain %_ptr_Uniform_v4uint %ub %uint_0 %uint_11
+        %135 = OpLoad %v4uint %134
+        %136 = OpFunctionCall %mat2v2float %load_ub_inner_mat2x2_f32
+        %139 = OpAccessChain %_ptr_Uniform_mat2v3float %ub %uint_0 %uint_14
+        %140 = OpLoad %mat2v3float %139
+        %143 = OpAccessChain %_ptr_Uniform_mat2v4float %ub %uint_0 %uint_15
+        %144 = OpLoad %mat2v4float %143
+        %145 = OpFunctionCall %mat3v2float %load_ub_inner_mat3x2_f32
+        %148 = OpAccessChain %_ptr_Uniform_mat3v3float %ub %uint_0 %uint_19
+        %149 = OpLoad %mat3v3float %148
+        %152 = OpAccessChain %_ptr_Uniform_mat3v4float %ub %uint_0 %uint_20
+        %153 = OpLoad %mat3v4float %152
+        %154 = OpFunctionCall %mat4v2float %load_ub_inner_mat4x2_f32
+        %157 = OpAccessChain %_ptr_Uniform_mat4v3float %ub %uint_0 %uint_25
+        %158 = OpLoad %mat4v3float %157
+        %161 = OpAccessChain %_ptr_Uniform_mat4v4float %ub %uint_0 %uint_26
+        %162 = OpLoad %mat4v4float %161
+        %165 = OpAccessChain %_ptr_Uniform__arr_v3float_uint_2 %ub %uint_0 %uint_27
+        %166 = OpLoad %_arr_v3float_uint_2 %165
+        %169 = OpAccessChain %_ptr_Uniform_Inner %ub %uint_0 %uint_28
+        %170 = OpLoad %Inner %169
+        %173 = OpAccessChain %_ptr_Uniform__arr_Inner_uint_4 %ub %uint_0 %uint_29
+        %174 = OpLoad %_arr_Inner_uint_4 %173
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/buffer/uniform/static_index/read.wgsl.expected.wgsl b/test/tint/buffer/uniform/static_index/read.wgsl.expected.wgsl
index 3c5c891..46b7e07 100644
--- a/test/tint/buffer/uniform/static_index/read.wgsl.expected.wgsl
+++ b/test/tint/buffer/uniform/static_index/read.wgsl.expected.wgsl
@@ -1,39 +1,65 @@
 struct Inner {
-  @size(16)
-  x : i32,
+  scalar_i32 : i32,
+  @align(16) @size(16)
+  scalar_f32 : f32,
 }
 
 struct S {
-  a : vec3<i32>,
-  b : i32,
-  c : vec3<u32>,
-  d : u32,
-  e : vec3<f32>,
-  f : f32,
-  g : vec2<i32>,
-  h : vec2<i32>,
-  i : mat2x3<f32>,
-  j : mat3x2<f32>,
+  scalar_f32 : f32,
+  scalar_i32 : i32,
+  scalar_u32 : u32,
+  vec2_f32 : vec2<f32>,
+  vec2_i32 : vec2<i32>,
+  vec2_u32 : vec2<u32>,
+  vec3_f32 : vec3<f32>,
+  vec3_i32 : vec3<i32>,
+  vec3_u32 : vec3<u32>,
+  vec4_f32 : vec4<f32>,
+  vec4_i32 : vec4<i32>,
+  vec4_u32 : vec4<u32>,
+  mat2x2_f32 : mat2x2<f32>,
+  mat2x3_f32 : mat2x3<f32>,
+  mat2x4_f32 : mat2x4<f32>,
+  mat3x2_f32 : mat3x2<f32>,
+  mat3x3_f32 : mat3x3<f32>,
+  mat3x4_f32 : mat3x4<f32>,
+  mat4x2_f32 : mat4x2<f32>,
+  mat4x3_f32 : mat4x3<f32>,
+  mat4x4_f32 : mat4x4<f32>,
   @align(16)
-  k : Inner,
+  arr2_vec3_f32 : array<vec3<f32>, 2>,
   @align(16)
-  l : array<Inner, 4>,
+  struct_inner : Inner,
+  @align(16)
+  array_struct_inner : array<Inner, 4>,
 }
 
-@binding(0) @group(0) var<uniform> s : S;
+@binding(0) @group(0) var<uniform> ub : S;
 
 @compute @workgroup_size(1)
 fn main() {
-  let a = s.a;
-  let b = s.b;
-  let c = s.c;
-  let d = s.d;
-  let e = s.e;
-  let f = s.f;
-  let g = s.g;
-  let h = s.h;
-  let i = s.i;
-  let j = s.j;
-  let k = s.k;
-  let l = s.l;
+  let scalar_f32 = ub.scalar_f32;
+  let scalar_i32 = ub.scalar_i32;
+  let scalar_u32 = ub.scalar_u32;
+  let vec2_f32 = ub.vec2_f32;
+  let vec2_i32 = ub.vec2_i32;
+  let vec2_u32 = ub.vec2_u32;
+  let vec3_f32 = ub.vec3_f32;
+  let vec3_i32 = ub.vec3_i32;
+  let vec3_u32 = ub.vec3_u32;
+  let vec4_f32 = ub.vec4_f32;
+  let vec4_i32 = ub.vec4_i32;
+  let vec4_u32 = ub.vec4_u32;
+  let mat2x2_f32 = ub.mat2x2_f32;
+  let mat2x3_f32 = ub.mat2x3_f32;
+  let mat2x4_f32 = ub.mat2x4_f32;
+  let mat3x2_f32 = ub.mat3x2_f32;
+  let mat3x3_f32 = ub.mat3x3_f32;
+  let mat3x4_f32 = ub.mat3x4_f32;
+  let mat4x2_f32 = ub.mat4x2_f32;
+  let mat4x3_f32 = ub.mat4x3_f32;
+  let mat4x4_f32 = ub.mat4x4_f32;
+  let arr2_vec3_f32 = ub.arr2_vec3_f32;
+  let struct_inner = ub.struct_inner;
+  let array_struct_inner = ub.array_struct_inner;
 }
diff --git a/test/tint/buffer/uniform/static_index/read_f16.wgsl b/test/tint/buffer/uniform/static_index/read_f16.wgsl
new file mode 100644
index 0000000..2343a12
--- /dev/null
+++ b/test/tint/buffer/uniform/static_index/read_f16.wgsl
@@ -0,0 +1,92 @@
+enable f16;
+
+struct Inner {
+    scalar_i32 : i32,
+    scalar_f32 : f32,
+    @size(8) scalar_f16 : f16,
+};
+
+struct S {
+    scalar_f32 : f32,
+    scalar_i32 : i32,
+    scalar_u32 : u32,
+    scalar_f16 : f16,
+    vec2_f32 : vec2<f32>,
+    vec2_i32 : vec2<i32>,
+    vec2_u32 : vec2<u32>,
+    vec2_f16 : vec2<f16>,
+    vec3_f32 : vec3<f32>,
+    vec3_i32 : vec3<i32>,
+    vec3_u32 : vec3<u32>,
+    vec3_f16 : vec3<f16>,
+    vec4_f32 : vec4<f32>,
+    vec4_i32 : vec4<i32>,
+    vec4_u32 : vec4<u32>,
+    vec4_f16 : vec4<f16>,
+    mat2x2_f32 : mat2x2<f32>,
+    mat2x3_f32 : mat2x3<f32>,
+    mat2x4_f32 : mat2x4<f32>,
+    mat3x2_f32 : mat3x2<f32>,
+    mat3x3_f32 : mat3x3<f32>,
+    mat3x4_f32 : mat3x4<f32>,
+    mat4x2_f32 : mat4x2<f32>,
+    mat4x3_f32 : mat4x3<f32>,
+    mat4x4_f32 : mat4x4<f32>,
+    mat2x2_f16 : mat2x2<f16>,
+    mat2x3_f16 : mat2x3<f16>,
+    mat2x4_f16 : mat2x4<f16>,
+    mat3x2_f16 : mat3x2<f16>,
+    mat3x3_f16 : mat3x3<f16>,
+    mat3x4_f16 : mat3x4<f16>,
+    mat4x2_f16 : mat4x2<f16>,
+    mat4x3_f16 : mat4x3<f16>,
+    mat4x4_f16 : mat4x4<f16>,
+    @align(16) arr2_vec3_f32 : array<vec3<f32>, 2>,
+    arr2_mat4x2_f16 : array<mat4x2<f16>, 2>,
+    @align(16) struct_inner : Inner,
+    @align(16) array_struct_inner : array<Inner, 4>,
+};
+
+@binding(0) @group(0) var<uniform> ub : S;
+
+@compute @workgroup_size(1)
+fn main() {
+    let scalar_f32 = ub.scalar_f32;
+    let scalar_i32 = ub.scalar_i32;
+    let scalar_u32 = ub.scalar_u32;
+    let scalar_f16 = ub.scalar_f16;
+    let vec2_f32 = ub.vec2_f32;
+    let vec2_i32 = ub.vec2_i32;
+    let vec2_u32 = ub.vec2_u32;
+    let vec2_f16 = ub.vec2_f16;
+    let vec3_f32 = ub.vec3_f32;
+    let vec3_i32 = ub.vec3_i32;
+    let vec3_u32 = ub.vec3_u32;
+    let vec3_f16 = ub.vec3_f16;
+    let vec4_f32 = ub.vec4_f32;
+    let vec4_i32 = ub.vec4_i32;
+    let vec4_u32 = ub.vec4_u32;
+    let vec4_f16 = ub.vec4_f16;
+    let mat2x2_f32 = ub.mat2x2_f32;
+    let mat2x3_f32 = ub.mat2x3_f32;
+    let mat2x4_f32 = ub.mat2x4_f32;
+    let mat3x2_f32 = ub.mat3x2_f32;
+    let mat3x3_f32 = ub.mat3x3_f32;
+    let mat3x4_f32 = ub.mat3x4_f32;
+    let mat4x2_f32 = ub.mat4x2_f32;
+    let mat4x3_f32 = ub.mat4x3_f32;
+    let mat4x4_f32 = ub.mat4x4_f32;
+    let mat2x2_f16 = ub.mat2x2_f16;
+    let mat2x3_f16 = ub.mat2x3_f16;
+    let mat2x4_f16 = ub.mat2x4_f16;
+    let mat3x2_f16 = ub.mat3x2_f16;
+    let mat3x3_f16 = ub.mat3x3_f16;
+    let mat3x4_f16 = ub.mat3x4_f16;
+    let mat4x2_f16 = ub.mat4x2_f16;
+    let mat4x3_f16 = ub.mat4x3_f16;
+    let mat4x4_f16 = ub.mat4x4_f16;
+    let arr2_vec3_f32 = ub.arr2_vec3_f32;
+    let arr2_mat4x2_f16 = ub.arr2_mat4x2_f16;
+    let struct_inner = ub.struct_inner;
+    let array_struct_inner = ub.array_struct_inner;
+}
diff --git a/test/tint/buffer/uniform/static_index/read_f16.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/static_index/read_f16.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..d0e6ba8
--- /dev/null
+++ b/test/tint/buffer/uniform/static_index/read_f16.wgsl.expected.dxc.hlsl
@@ -0,0 +1,318 @@
+struct Inner {
+  int scalar_i32;
+  float scalar_f32;
+  float16_t scalar_f16;
+};
+
+cbuffer cbuffer_ub : register(b0, space0) {
+  uint4 ub[55];
+};
+
+float2x2 tint_symbol_16(uint4 buffer[55], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  return float2x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)));
+}
+
+float2x3 tint_symbol_17(uint4 buffer[55], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+float2x4 tint_symbol_18(uint4 buffer[55], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset_4 / 4]), asfloat(buffer[scalar_offset_5 / 4]));
+}
+
+float3x2 tint_symbol_19(uint4 buffer[55], uint offset) {
+  const uint scalar_offset_6 = ((offset + 0u)) / 4;
+  uint4 ubo_load_2 = buffer[scalar_offset_6 / 4];
+  const uint scalar_offset_7 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_7 / 4];
+  const uint scalar_offset_8 = ((offset + 16u)) / 4;
+  uint4 ubo_load_4 = buffer[scalar_offset_8 / 4];
+  return float3x2(asfloat(((scalar_offset_6 & 2) ? ubo_load_2.zw : ubo_load_2.xy)), asfloat(((scalar_offset_7 & 2) ? ubo_load_3.zw : ubo_load_3.xy)), asfloat(((scalar_offset_8 & 2) ? ubo_load_4.zw : ubo_load_4.xy)));
+}
+
+float3x3 tint_symbol_20(uint4 buffer[55], uint offset) {
+  const uint scalar_offset_9 = ((offset + 0u)) / 4;
+  const uint scalar_offset_10 = ((offset + 16u)) / 4;
+  const uint scalar_offset_11 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset_9 / 4].xyz), asfloat(buffer[scalar_offset_10 / 4].xyz), asfloat(buffer[scalar_offset_11 / 4].xyz));
+}
+
+float3x4 tint_symbol_21(uint4 buffer[55], uint offset) {
+  const uint scalar_offset_12 = ((offset + 0u)) / 4;
+  const uint scalar_offset_13 = ((offset + 16u)) / 4;
+  const uint scalar_offset_14 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset_12 / 4]), asfloat(buffer[scalar_offset_13 / 4]), asfloat(buffer[scalar_offset_14 / 4]));
+}
+
+float4x2 tint_symbol_22(uint4 buffer[55], uint offset) {
+  const uint scalar_offset_15 = ((offset + 0u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_15 / 4];
+  const uint scalar_offset_16 = ((offset + 8u)) / 4;
+  uint4 ubo_load_6 = buffer[scalar_offset_16 / 4];
+  const uint scalar_offset_17 = ((offset + 16u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_17 / 4];
+  const uint scalar_offset_18 = ((offset + 24u)) / 4;
+  uint4 ubo_load_8 = buffer[scalar_offset_18 / 4];
+  return float4x2(asfloat(((scalar_offset_15 & 2) ? ubo_load_5.zw : ubo_load_5.xy)), asfloat(((scalar_offset_16 & 2) ? ubo_load_6.zw : ubo_load_6.xy)), asfloat(((scalar_offset_17 & 2) ? ubo_load_7.zw : ubo_load_7.xy)), asfloat(((scalar_offset_18 & 2) ? ubo_load_8.zw : ubo_load_8.xy)));
+}
+
+float4x3 tint_symbol_23(uint4 buffer[55], uint offset) {
+  const uint scalar_offset_19 = ((offset + 0u)) / 4;
+  const uint scalar_offset_20 = ((offset + 16u)) / 4;
+  const uint scalar_offset_21 = ((offset + 32u)) / 4;
+  const uint scalar_offset_22 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset_19 / 4].xyz), asfloat(buffer[scalar_offset_20 / 4].xyz), asfloat(buffer[scalar_offset_21 / 4].xyz), asfloat(buffer[scalar_offset_22 / 4].xyz));
+}
+
+float4x4 tint_symbol_24(uint4 buffer[55], uint offset) {
+  const uint scalar_offset_23 = ((offset + 0u)) / 4;
+  const uint scalar_offset_24 = ((offset + 16u)) / 4;
+  const uint scalar_offset_25 = ((offset + 32u)) / 4;
+  const uint scalar_offset_26 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset_23 / 4]), asfloat(buffer[scalar_offset_24 / 4]), asfloat(buffer[scalar_offset_25 / 4]), asfloat(buffer[scalar_offset_26 / 4]));
+}
+
+matrix<float16_t, 2, 2> tint_symbol_25(uint4 buffer[55], uint offset) {
+  const uint scalar_offset_27 = ((offset + 0u)) / 4;
+  uint ubo_load_9 = buffer[scalar_offset_27 / 4][scalar_offset_27 % 4];
+  const uint scalar_offset_28 = ((offset + 4u)) / 4;
+  uint ubo_load_10 = buffer[scalar_offset_28 / 4][scalar_offset_28 % 4];
+  return matrix<float16_t, 2, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_9 & 0xFFFF)), float16_t(f16tof32(ubo_load_9 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_10 & 0xFFFF)), float16_t(f16tof32(ubo_load_10 >> 16))));
+}
+
+matrix<float16_t, 2, 3> tint_symbol_26(uint4 buffer[55], uint offset) {
+  const uint scalar_offset_29 = ((offset + 0u)) / 4;
+  uint4 ubo_load_12 = buffer[scalar_offset_29 / 4];
+  uint2 ubo_load_11 = ((scalar_offset_29 & 2) ? ubo_load_12.zw : ubo_load_12.xy);
+  vector<float16_t, 2> ubo_load_11_xz = vector<float16_t, 2>(f16tof32(ubo_load_11 & 0xFFFF));
+  float16_t ubo_load_11_y = f16tof32(ubo_load_11[0] >> 16);
+  const uint scalar_offset_30 = ((offset + 8u)) / 4;
+  uint4 ubo_load_14 = buffer[scalar_offset_30 / 4];
+  uint2 ubo_load_13 = ((scalar_offset_30 & 2) ? ubo_load_14.zw : ubo_load_14.xy);
+  vector<float16_t, 2> ubo_load_13_xz = vector<float16_t, 2>(f16tof32(ubo_load_13 & 0xFFFF));
+  float16_t ubo_load_13_y = f16tof32(ubo_load_13[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_11_xz[0], ubo_load_11_y, ubo_load_11_xz[1]), vector<float16_t, 3>(ubo_load_13_xz[0], ubo_load_13_y, ubo_load_13_xz[1]));
+}
+
+matrix<float16_t, 2, 4> tint_symbol_27(uint4 buffer[55], uint offset) {
+  const uint scalar_offset_31 = ((offset + 0u)) / 4;
+  uint4 ubo_load_16 = buffer[scalar_offset_31 / 4];
+  uint2 ubo_load_15 = ((scalar_offset_31 & 2) ? ubo_load_16.zw : ubo_load_16.xy);
+  vector<float16_t, 2> ubo_load_15_xz = vector<float16_t, 2>(f16tof32(ubo_load_15 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_15_yw = vector<float16_t, 2>(f16tof32(ubo_load_15 >> 16));
+  const uint scalar_offset_32 = ((offset + 8u)) / 4;
+  uint4 ubo_load_18 = buffer[scalar_offset_32 / 4];
+  uint2 ubo_load_17 = ((scalar_offset_32 & 2) ? ubo_load_18.zw : ubo_load_18.xy);
+  vector<float16_t, 2> ubo_load_17_xz = vector<float16_t, 2>(f16tof32(ubo_load_17 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_17_yw = vector<float16_t, 2>(f16tof32(ubo_load_17 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_15_xz[0], ubo_load_15_yw[0], ubo_load_15_xz[1], ubo_load_15_yw[1]), vector<float16_t, 4>(ubo_load_17_xz[0], ubo_load_17_yw[0], ubo_load_17_xz[1], ubo_load_17_yw[1]));
+}
+
+matrix<float16_t, 3, 2> tint_symbol_28(uint4 buffer[55], uint offset) {
+  const uint scalar_offset_33 = ((offset + 0u)) / 4;
+  uint ubo_load_19 = buffer[scalar_offset_33 / 4][scalar_offset_33 % 4];
+  const uint scalar_offset_34 = ((offset + 4u)) / 4;
+  uint ubo_load_20 = buffer[scalar_offset_34 / 4][scalar_offset_34 % 4];
+  const uint scalar_offset_35 = ((offset + 8u)) / 4;
+  uint ubo_load_21 = buffer[scalar_offset_35 / 4][scalar_offset_35 % 4];
+  return matrix<float16_t, 3, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_19 & 0xFFFF)), float16_t(f16tof32(ubo_load_19 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_20 & 0xFFFF)), float16_t(f16tof32(ubo_load_20 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_21 & 0xFFFF)), float16_t(f16tof32(ubo_load_21 >> 16))));
+}
+
+matrix<float16_t, 3, 3> tint_symbol_29(uint4 buffer[55], uint offset) {
+  const uint scalar_offset_36 = ((offset + 0u)) / 4;
+  uint4 ubo_load_23 = buffer[scalar_offset_36 / 4];
+  uint2 ubo_load_22 = ((scalar_offset_36 & 2) ? ubo_load_23.zw : ubo_load_23.xy);
+  vector<float16_t, 2> ubo_load_22_xz = vector<float16_t, 2>(f16tof32(ubo_load_22 & 0xFFFF));
+  float16_t ubo_load_22_y = f16tof32(ubo_load_22[0] >> 16);
+  const uint scalar_offset_37 = ((offset + 8u)) / 4;
+  uint4 ubo_load_25 = buffer[scalar_offset_37 / 4];
+  uint2 ubo_load_24 = ((scalar_offset_37 & 2) ? ubo_load_25.zw : ubo_load_25.xy);
+  vector<float16_t, 2> ubo_load_24_xz = vector<float16_t, 2>(f16tof32(ubo_load_24 & 0xFFFF));
+  float16_t ubo_load_24_y = f16tof32(ubo_load_24[0] >> 16);
+  const uint scalar_offset_38 = ((offset + 16u)) / 4;
+  uint4 ubo_load_27 = buffer[scalar_offset_38 / 4];
+  uint2 ubo_load_26 = ((scalar_offset_38 & 2) ? ubo_load_27.zw : ubo_load_27.xy);
+  vector<float16_t, 2> ubo_load_26_xz = vector<float16_t, 2>(f16tof32(ubo_load_26 & 0xFFFF));
+  float16_t ubo_load_26_y = f16tof32(ubo_load_26[0] >> 16);
+  return matrix<float16_t, 3, 3>(vector<float16_t, 3>(ubo_load_22_xz[0], ubo_load_22_y, ubo_load_22_xz[1]), vector<float16_t, 3>(ubo_load_24_xz[0], ubo_load_24_y, ubo_load_24_xz[1]), vector<float16_t, 3>(ubo_load_26_xz[0], ubo_load_26_y, ubo_load_26_xz[1]));
+}
+
+matrix<float16_t, 3, 4> tint_symbol_30(uint4 buffer[55], uint offset) {
+  const uint scalar_offset_39 = ((offset + 0u)) / 4;
+  uint4 ubo_load_29 = buffer[scalar_offset_39 / 4];
+  uint2 ubo_load_28 = ((scalar_offset_39 & 2) ? ubo_load_29.zw : ubo_load_29.xy);
+  vector<float16_t, 2> ubo_load_28_xz = vector<float16_t, 2>(f16tof32(ubo_load_28 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_28_yw = vector<float16_t, 2>(f16tof32(ubo_load_28 >> 16));
+  const uint scalar_offset_40 = ((offset + 8u)) / 4;
+  uint4 ubo_load_31 = buffer[scalar_offset_40 / 4];
+  uint2 ubo_load_30 = ((scalar_offset_40 & 2) ? ubo_load_31.zw : ubo_load_31.xy);
+  vector<float16_t, 2> ubo_load_30_xz = vector<float16_t, 2>(f16tof32(ubo_load_30 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_30_yw = vector<float16_t, 2>(f16tof32(ubo_load_30 >> 16));
+  const uint scalar_offset_41 = ((offset + 16u)) / 4;
+  uint4 ubo_load_33 = buffer[scalar_offset_41 / 4];
+  uint2 ubo_load_32 = ((scalar_offset_41 & 2) ? ubo_load_33.zw : ubo_load_33.xy);
+  vector<float16_t, 2> ubo_load_32_xz = vector<float16_t, 2>(f16tof32(ubo_load_32 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_32_yw = vector<float16_t, 2>(f16tof32(ubo_load_32 >> 16));
+  return matrix<float16_t, 3, 4>(vector<float16_t, 4>(ubo_load_28_xz[0], ubo_load_28_yw[0], ubo_load_28_xz[1], ubo_load_28_yw[1]), vector<float16_t, 4>(ubo_load_30_xz[0], ubo_load_30_yw[0], ubo_load_30_xz[1], ubo_load_30_yw[1]), vector<float16_t, 4>(ubo_load_32_xz[0], ubo_load_32_yw[0], ubo_load_32_xz[1], ubo_load_32_yw[1]));
+}
+
+matrix<float16_t, 4, 2> tint_symbol_31(uint4 buffer[55], uint offset) {
+  const uint scalar_offset_42 = ((offset + 0u)) / 4;
+  uint ubo_load_34 = buffer[scalar_offset_42 / 4][scalar_offset_42 % 4];
+  const uint scalar_offset_43 = ((offset + 4u)) / 4;
+  uint ubo_load_35 = buffer[scalar_offset_43 / 4][scalar_offset_43 % 4];
+  const uint scalar_offset_44 = ((offset + 8u)) / 4;
+  uint ubo_load_36 = buffer[scalar_offset_44 / 4][scalar_offset_44 % 4];
+  const uint scalar_offset_45 = ((offset + 12u)) / 4;
+  uint ubo_load_37 = buffer[scalar_offset_45 / 4][scalar_offset_45 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_34 & 0xFFFF)), float16_t(f16tof32(ubo_load_34 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_35 & 0xFFFF)), float16_t(f16tof32(ubo_load_35 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_36 & 0xFFFF)), float16_t(f16tof32(ubo_load_36 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_37 & 0xFFFF)), float16_t(f16tof32(ubo_load_37 >> 16))));
+}
+
+matrix<float16_t, 4, 3> tint_symbol_32(uint4 buffer[55], uint offset) {
+  const uint scalar_offset_46 = ((offset + 0u)) / 4;
+  uint4 ubo_load_39 = buffer[scalar_offset_46 / 4];
+  uint2 ubo_load_38 = ((scalar_offset_46 & 2) ? ubo_load_39.zw : ubo_load_39.xy);
+  vector<float16_t, 2> ubo_load_38_xz = vector<float16_t, 2>(f16tof32(ubo_load_38 & 0xFFFF));
+  float16_t ubo_load_38_y = f16tof32(ubo_load_38[0] >> 16);
+  const uint scalar_offset_47 = ((offset + 8u)) / 4;
+  uint4 ubo_load_41 = buffer[scalar_offset_47 / 4];
+  uint2 ubo_load_40 = ((scalar_offset_47 & 2) ? ubo_load_41.zw : ubo_load_41.xy);
+  vector<float16_t, 2> ubo_load_40_xz = vector<float16_t, 2>(f16tof32(ubo_load_40 & 0xFFFF));
+  float16_t ubo_load_40_y = f16tof32(ubo_load_40[0] >> 16);
+  const uint scalar_offset_48 = ((offset + 16u)) / 4;
+  uint4 ubo_load_43 = buffer[scalar_offset_48 / 4];
+  uint2 ubo_load_42 = ((scalar_offset_48 & 2) ? ubo_load_43.zw : ubo_load_43.xy);
+  vector<float16_t, 2> ubo_load_42_xz = vector<float16_t, 2>(f16tof32(ubo_load_42 & 0xFFFF));
+  float16_t ubo_load_42_y = f16tof32(ubo_load_42[0] >> 16);
+  const uint scalar_offset_49 = ((offset + 24u)) / 4;
+  uint4 ubo_load_45 = buffer[scalar_offset_49 / 4];
+  uint2 ubo_load_44 = ((scalar_offset_49 & 2) ? ubo_load_45.zw : ubo_load_45.xy);
+  vector<float16_t, 2> ubo_load_44_xz = vector<float16_t, 2>(f16tof32(ubo_load_44 & 0xFFFF));
+  float16_t ubo_load_44_y = f16tof32(ubo_load_44[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_38_xz[0], ubo_load_38_y, ubo_load_38_xz[1]), vector<float16_t, 3>(ubo_load_40_xz[0], ubo_load_40_y, ubo_load_40_xz[1]), vector<float16_t, 3>(ubo_load_42_xz[0], ubo_load_42_y, ubo_load_42_xz[1]), vector<float16_t, 3>(ubo_load_44_xz[0], ubo_load_44_y, ubo_load_44_xz[1]));
+}
+
+matrix<float16_t, 4, 4> tint_symbol_33(uint4 buffer[55], uint offset) {
+  const uint scalar_offset_50 = ((offset + 0u)) / 4;
+  uint4 ubo_load_47 = buffer[scalar_offset_50 / 4];
+  uint2 ubo_load_46 = ((scalar_offset_50 & 2) ? ubo_load_47.zw : ubo_load_47.xy);
+  vector<float16_t, 2> ubo_load_46_xz = vector<float16_t, 2>(f16tof32(ubo_load_46 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_46_yw = vector<float16_t, 2>(f16tof32(ubo_load_46 >> 16));
+  const uint scalar_offset_51 = ((offset + 8u)) / 4;
+  uint4 ubo_load_49 = buffer[scalar_offset_51 / 4];
+  uint2 ubo_load_48 = ((scalar_offset_51 & 2) ? ubo_load_49.zw : ubo_load_49.xy);
+  vector<float16_t, 2> ubo_load_48_xz = vector<float16_t, 2>(f16tof32(ubo_load_48 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_48_yw = vector<float16_t, 2>(f16tof32(ubo_load_48 >> 16));
+  const uint scalar_offset_52 = ((offset + 16u)) / 4;
+  uint4 ubo_load_51 = buffer[scalar_offset_52 / 4];
+  uint2 ubo_load_50 = ((scalar_offset_52 & 2) ? ubo_load_51.zw : ubo_load_51.xy);
+  vector<float16_t, 2> ubo_load_50_xz = vector<float16_t, 2>(f16tof32(ubo_load_50 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_50_yw = vector<float16_t, 2>(f16tof32(ubo_load_50 >> 16));
+  const uint scalar_offset_53 = ((offset + 24u)) / 4;
+  uint4 ubo_load_53 = buffer[scalar_offset_53 / 4];
+  uint2 ubo_load_52 = ((scalar_offset_53 & 2) ? ubo_load_53.zw : ubo_load_53.xy);
+  vector<float16_t, 2> ubo_load_52_xz = vector<float16_t, 2>(f16tof32(ubo_load_52 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_52_yw = vector<float16_t, 2>(f16tof32(ubo_load_52 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_46_xz[0], ubo_load_46_yw[0], ubo_load_46_xz[1], ubo_load_46_yw[1]), vector<float16_t, 4>(ubo_load_48_xz[0], ubo_load_48_yw[0], ubo_load_48_xz[1], ubo_load_48_yw[1]), vector<float16_t, 4>(ubo_load_50_xz[0], ubo_load_50_yw[0], ubo_load_50_xz[1], ubo_load_50_yw[1]), vector<float16_t, 4>(ubo_load_52_xz[0], ubo_load_52_yw[0], ubo_load_52_xz[1], ubo_load_52_yw[1]));
+}
+
+typedef float3 tint_symbol_34_ret[2];
+tint_symbol_34_ret tint_symbol_34(uint4 buffer[55], uint offset) {
+  float3 arr[2] = (float3[2])0;
+  {
+    for(uint i = 0u; (i < 2u); i = (i + 1u)) {
+      const uint scalar_offset_54 = ((offset + (i * 16u))) / 4;
+      arr[i] = asfloat(buffer[scalar_offset_54 / 4].xyz);
+    }
+  }
+  return arr;
+}
+
+typedef matrix<float16_t, 4, 2> tint_symbol_35_ret[2];
+tint_symbol_35_ret tint_symbol_35(uint4 buffer[55], uint offset) {
+  matrix<float16_t, 4, 2> arr_1[2] = (matrix<float16_t, 4, 2>[2])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
+      arr_1[i_1] = tint_symbol_31(buffer, (offset + (i_1 * 16u)));
+    }
+  }
+  return arr_1;
+}
+
+Inner tint_symbol_36(uint4 buffer[55], uint offset) {
+  const uint scalar_offset_55 = ((offset + 0u)) / 4;
+  const uint scalar_offset_56 = ((offset + 4u)) / 4;
+  const uint scalar_offset_bytes = ((offset + 8u));
+  const uint scalar_offset_index = scalar_offset_bytes / 4;
+  const Inner tint_symbol_38 = {asint(buffer[scalar_offset_55 / 4][scalar_offset_55 % 4]), asfloat(buffer[scalar_offset_56 / 4][scalar_offset_56 % 4]), float16_t(f16tof32(((buffer[scalar_offset_index / 4][scalar_offset_index % 4] >> (scalar_offset_bytes % 4 == 0 ? 0 : 16)) & 0xFFFF)))};
+  return tint_symbol_38;
+}
+
+typedef Inner tint_symbol_37_ret[4];
+tint_symbol_37_ret tint_symbol_37(uint4 buffer[55], uint offset) {
+  Inner arr_2[4] = (Inner[4])0;
+  {
+    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
+      arr_2[i_2] = tint_symbol_36(buffer, (offset + (i_2 * 16u)));
+    }
+  }
+  return arr_2;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  const float scalar_f32 = asfloat(ub[0].x);
+  const int scalar_i32 = asint(ub[0].y);
+  const uint scalar_u32 = ub[0].z;
+  const float16_t scalar_f16 = float16_t(f16tof32(((ub[0].w) & 0xFFFF)));
+  const float2 vec2_f32 = asfloat(ub[1].xy);
+  const int2 vec2_i32 = asint(ub[1].zw);
+  const uint2 vec2_u32 = ub[2].xy;
+  uint ubo_load_54 = ub[2].z;
+  const vector<float16_t, 2> vec2_f16 = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_54 & 0xFFFF)), float16_t(f16tof32(ubo_load_54 >> 16)));
+  const float3 vec3_f32 = asfloat(ub[3].xyz);
+  const int3 vec3_i32 = asint(ub[4].xyz);
+  const uint3 vec3_u32 = ub[5].xyz;
+  uint2 ubo_load_55 = ub[6].xy;
+  vector<float16_t, 2> ubo_load_55_xz = vector<float16_t, 2>(f16tof32(ubo_load_55 & 0xFFFF));
+  float16_t ubo_load_55_y = f16tof32(ubo_load_55[0] >> 16);
+  const vector<float16_t, 3> vec3_f16 = vector<float16_t, 3>(ubo_load_55_xz[0], ubo_load_55_y, ubo_load_55_xz[1]);
+  const float4 vec4_f32 = asfloat(ub[7]);
+  const int4 vec4_i32 = asint(ub[8]);
+  const uint4 vec4_u32 = ub[9];
+  uint2 ubo_load_56 = ub[10].xy;
+  vector<float16_t, 2> ubo_load_56_xz = vector<float16_t, 2>(f16tof32(ubo_load_56 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_56_yw = vector<float16_t, 2>(f16tof32(ubo_load_56 >> 16));
+  const vector<float16_t, 4> vec4_f16 = vector<float16_t, 4>(ubo_load_56_xz[0], ubo_load_56_yw[0], ubo_load_56_xz[1], ubo_load_56_yw[1]);
+  const float2x2 mat2x2_f32 = tint_symbol_16(ub, 168u);
+  const float2x3 mat2x3_f32 = tint_symbol_17(ub, 192u);
+  const float2x4 mat2x4_f32 = tint_symbol_18(ub, 224u);
+  const float3x2 mat3x2_f32 = tint_symbol_19(ub, 256u);
+  const float3x3 mat3x3_f32 = tint_symbol_20(ub, 288u);
+  const float3x4 mat3x4_f32 = tint_symbol_21(ub, 336u);
+  const float4x2 mat4x2_f32 = tint_symbol_22(ub, 384u);
+  const float4x3 mat4x3_f32 = tint_symbol_23(ub, 416u);
+  const float4x4 mat4x4_f32 = tint_symbol_24(ub, 480u);
+  const matrix<float16_t, 2, 2> mat2x2_f16 = tint_symbol_25(ub, 544u);
+  const matrix<float16_t, 2, 3> mat2x3_f16 = tint_symbol_26(ub, 552u);
+  const matrix<float16_t, 2, 4> mat2x4_f16 = tint_symbol_27(ub, 568u);
+  const matrix<float16_t, 3, 2> mat3x2_f16 = tint_symbol_28(ub, 584u);
+  const matrix<float16_t, 3, 3> mat3x3_f16 = tint_symbol_29(ub, 600u);
+  const matrix<float16_t, 3, 4> mat3x4_f16 = tint_symbol_30(ub, 624u);
+  const matrix<float16_t, 4, 2> mat4x2_f16 = tint_symbol_31(ub, 648u);
+  const matrix<float16_t, 4, 3> mat4x3_f16 = tint_symbol_32(ub, 664u);
+  const matrix<float16_t, 4, 4> mat4x4_f16 = tint_symbol_33(ub, 696u);
+  const float3 arr2_vec3_f32[2] = tint_symbol_34(ub, 736u);
+  const matrix<float16_t, 4, 2> arr2_mat4x2_f16[2] = tint_symbol_35(ub, 768u);
+  const Inner struct_inner = tint_symbol_36(ub, 800u);
+  const Inner array_struct_inner[4] = tint_symbol_37(ub, 816u);
+  return;
+}
diff --git a/test/tint/buffer/uniform/static_index/read_f16.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/static_index/read_f16.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..1ee7543
--- /dev/null
+++ b/test/tint/buffer/uniform/static_index/read_f16.wgsl.expected.fxc.hlsl
@@ -0,0 +1,323 @@
+SKIP: FAILED
+
+struct Inner {
+  int scalar_i32;
+  float scalar_f32;
+  float16_t scalar_f16;
+};
+
+cbuffer cbuffer_ub : register(b0, space0) {
+  uint4 ub[55];
+};
+
+float2x2 tint_symbol_16(uint4 buffer[55], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  return float2x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)));
+}
+
+float2x3 tint_symbol_17(uint4 buffer[55], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+float2x4 tint_symbol_18(uint4 buffer[55], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset_4 / 4]), asfloat(buffer[scalar_offset_5 / 4]));
+}
+
+float3x2 tint_symbol_19(uint4 buffer[55], uint offset) {
+  const uint scalar_offset_6 = ((offset + 0u)) / 4;
+  uint4 ubo_load_2 = buffer[scalar_offset_6 / 4];
+  const uint scalar_offset_7 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_7 / 4];
+  const uint scalar_offset_8 = ((offset + 16u)) / 4;
+  uint4 ubo_load_4 = buffer[scalar_offset_8 / 4];
+  return float3x2(asfloat(((scalar_offset_6 & 2) ? ubo_load_2.zw : ubo_load_2.xy)), asfloat(((scalar_offset_7 & 2) ? ubo_load_3.zw : ubo_load_3.xy)), asfloat(((scalar_offset_8 & 2) ? ubo_load_4.zw : ubo_load_4.xy)));
+}
+
+float3x3 tint_symbol_20(uint4 buffer[55], uint offset) {
+  const uint scalar_offset_9 = ((offset + 0u)) / 4;
+  const uint scalar_offset_10 = ((offset + 16u)) / 4;
+  const uint scalar_offset_11 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset_9 / 4].xyz), asfloat(buffer[scalar_offset_10 / 4].xyz), asfloat(buffer[scalar_offset_11 / 4].xyz));
+}
+
+float3x4 tint_symbol_21(uint4 buffer[55], uint offset) {
+  const uint scalar_offset_12 = ((offset + 0u)) / 4;
+  const uint scalar_offset_13 = ((offset + 16u)) / 4;
+  const uint scalar_offset_14 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset_12 / 4]), asfloat(buffer[scalar_offset_13 / 4]), asfloat(buffer[scalar_offset_14 / 4]));
+}
+
+float4x2 tint_symbol_22(uint4 buffer[55], uint offset) {
+  const uint scalar_offset_15 = ((offset + 0u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_15 / 4];
+  const uint scalar_offset_16 = ((offset + 8u)) / 4;
+  uint4 ubo_load_6 = buffer[scalar_offset_16 / 4];
+  const uint scalar_offset_17 = ((offset + 16u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_17 / 4];
+  const uint scalar_offset_18 = ((offset + 24u)) / 4;
+  uint4 ubo_load_8 = buffer[scalar_offset_18 / 4];
+  return float4x2(asfloat(((scalar_offset_15 & 2) ? ubo_load_5.zw : ubo_load_5.xy)), asfloat(((scalar_offset_16 & 2) ? ubo_load_6.zw : ubo_load_6.xy)), asfloat(((scalar_offset_17 & 2) ? ubo_load_7.zw : ubo_load_7.xy)), asfloat(((scalar_offset_18 & 2) ? ubo_load_8.zw : ubo_load_8.xy)));
+}
+
+float4x3 tint_symbol_23(uint4 buffer[55], uint offset) {
+  const uint scalar_offset_19 = ((offset + 0u)) / 4;
+  const uint scalar_offset_20 = ((offset + 16u)) / 4;
+  const uint scalar_offset_21 = ((offset + 32u)) / 4;
+  const uint scalar_offset_22 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset_19 / 4].xyz), asfloat(buffer[scalar_offset_20 / 4].xyz), asfloat(buffer[scalar_offset_21 / 4].xyz), asfloat(buffer[scalar_offset_22 / 4].xyz));
+}
+
+float4x4 tint_symbol_24(uint4 buffer[55], uint offset) {
+  const uint scalar_offset_23 = ((offset + 0u)) / 4;
+  const uint scalar_offset_24 = ((offset + 16u)) / 4;
+  const uint scalar_offset_25 = ((offset + 32u)) / 4;
+  const uint scalar_offset_26 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset_23 / 4]), asfloat(buffer[scalar_offset_24 / 4]), asfloat(buffer[scalar_offset_25 / 4]), asfloat(buffer[scalar_offset_26 / 4]));
+}
+
+matrix<float16_t, 2, 2> tint_symbol_25(uint4 buffer[55], uint offset) {
+  const uint scalar_offset_27 = ((offset + 0u)) / 4;
+  uint ubo_load_9 = buffer[scalar_offset_27 / 4][scalar_offset_27 % 4];
+  const uint scalar_offset_28 = ((offset + 4u)) / 4;
+  uint ubo_load_10 = buffer[scalar_offset_28 / 4][scalar_offset_28 % 4];
+  return matrix<float16_t, 2, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_9 & 0xFFFF)), float16_t(f16tof32(ubo_load_9 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_10 & 0xFFFF)), float16_t(f16tof32(ubo_load_10 >> 16))));
+}
+
+matrix<float16_t, 2, 3> tint_symbol_26(uint4 buffer[55], uint offset) {
+  const uint scalar_offset_29 = ((offset + 0u)) / 4;
+  uint4 ubo_load_12 = buffer[scalar_offset_29 / 4];
+  uint2 ubo_load_11 = ((scalar_offset_29 & 2) ? ubo_load_12.zw : ubo_load_12.xy);
+  vector<float16_t, 2> ubo_load_11_xz = vector<float16_t, 2>(f16tof32(ubo_load_11 & 0xFFFF));
+  float16_t ubo_load_11_y = f16tof32(ubo_load_11[0] >> 16);
+  const uint scalar_offset_30 = ((offset + 8u)) / 4;
+  uint4 ubo_load_14 = buffer[scalar_offset_30 / 4];
+  uint2 ubo_load_13 = ((scalar_offset_30 & 2) ? ubo_load_14.zw : ubo_load_14.xy);
+  vector<float16_t, 2> ubo_load_13_xz = vector<float16_t, 2>(f16tof32(ubo_load_13 & 0xFFFF));
+  float16_t ubo_load_13_y = f16tof32(ubo_load_13[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_11_xz[0], ubo_load_11_y, ubo_load_11_xz[1]), vector<float16_t, 3>(ubo_load_13_xz[0], ubo_load_13_y, ubo_load_13_xz[1]));
+}
+
+matrix<float16_t, 2, 4> tint_symbol_27(uint4 buffer[55], uint offset) {
+  const uint scalar_offset_31 = ((offset + 0u)) / 4;
+  uint4 ubo_load_16 = buffer[scalar_offset_31 / 4];
+  uint2 ubo_load_15 = ((scalar_offset_31 & 2) ? ubo_load_16.zw : ubo_load_16.xy);
+  vector<float16_t, 2> ubo_load_15_xz = vector<float16_t, 2>(f16tof32(ubo_load_15 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_15_yw = vector<float16_t, 2>(f16tof32(ubo_load_15 >> 16));
+  const uint scalar_offset_32 = ((offset + 8u)) / 4;
+  uint4 ubo_load_18 = buffer[scalar_offset_32 / 4];
+  uint2 ubo_load_17 = ((scalar_offset_32 & 2) ? ubo_load_18.zw : ubo_load_18.xy);
+  vector<float16_t, 2> ubo_load_17_xz = vector<float16_t, 2>(f16tof32(ubo_load_17 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_17_yw = vector<float16_t, 2>(f16tof32(ubo_load_17 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_15_xz[0], ubo_load_15_yw[0], ubo_load_15_xz[1], ubo_load_15_yw[1]), vector<float16_t, 4>(ubo_load_17_xz[0], ubo_load_17_yw[0], ubo_load_17_xz[1], ubo_load_17_yw[1]));
+}
+
+matrix<float16_t, 3, 2> tint_symbol_28(uint4 buffer[55], uint offset) {
+  const uint scalar_offset_33 = ((offset + 0u)) / 4;
+  uint ubo_load_19 = buffer[scalar_offset_33 / 4][scalar_offset_33 % 4];
+  const uint scalar_offset_34 = ((offset + 4u)) / 4;
+  uint ubo_load_20 = buffer[scalar_offset_34 / 4][scalar_offset_34 % 4];
+  const uint scalar_offset_35 = ((offset + 8u)) / 4;
+  uint ubo_load_21 = buffer[scalar_offset_35 / 4][scalar_offset_35 % 4];
+  return matrix<float16_t, 3, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_19 & 0xFFFF)), float16_t(f16tof32(ubo_load_19 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_20 & 0xFFFF)), float16_t(f16tof32(ubo_load_20 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_21 & 0xFFFF)), float16_t(f16tof32(ubo_load_21 >> 16))));
+}
+
+matrix<float16_t, 3, 3> tint_symbol_29(uint4 buffer[55], uint offset) {
+  const uint scalar_offset_36 = ((offset + 0u)) / 4;
+  uint4 ubo_load_23 = buffer[scalar_offset_36 / 4];
+  uint2 ubo_load_22 = ((scalar_offset_36 & 2) ? ubo_load_23.zw : ubo_load_23.xy);
+  vector<float16_t, 2> ubo_load_22_xz = vector<float16_t, 2>(f16tof32(ubo_load_22 & 0xFFFF));
+  float16_t ubo_load_22_y = f16tof32(ubo_load_22[0] >> 16);
+  const uint scalar_offset_37 = ((offset + 8u)) / 4;
+  uint4 ubo_load_25 = buffer[scalar_offset_37 / 4];
+  uint2 ubo_load_24 = ((scalar_offset_37 & 2) ? ubo_load_25.zw : ubo_load_25.xy);
+  vector<float16_t, 2> ubo_load_24_xz = vector<float16_t, 2>(f16tof32(ubo_load_24 & 0xFFFF));
+  float16_t ubo_load_24_y = f16tof32(ubo_load_24[0] >> 16);
+  const uint scalar_offset_38 = ((offset + 16u)) / 4;
+  uint4 ubo_load_27 = buffer[scalar_offset_38 / 4];
+  uint2 ubo_load_26 = ((scalar_offset_38 & 2) ? ubo_load_27.zw : ubo_load_27.xy);
+  vector<float16_t, 2> ubo_load_26_xz = vector<float16_t, 2>(f16tof32(ubo_load_26 & 0xFFFF));
+  float16_t ubo_load_26_y = f16tof32(ubo_load_26[0] >> 16);
+  return matrix<float16_t, 3, 3>(vector<float16_t, 3>(ubo_load_22_xz[0], ubo_load_22_y, ubo_load_22_xz[1]), vector<float16_t, 3>(ubo_load_24_xz[0], ubo_load_24_y, ubo_load_24_xz[1]), vector<float16_t, 3>(ubo_load_26_xz[0], ubo_load_26_y, ubo_load_26_xz[1]));
+}
+
+matrix<float16_t, 3, 4> tint_symbol_30(uint4 buffer[55], uint offset) {
+  const uint scalar_offset_39 = ((offset + 0u)) / 4;
+  uint4 ubo_load_29 = buffer[scalar_offset_39 / 4];
+  uint2 ubo_load_28 = ((scalar_offset_39 & 2) ? ubo_load_29.zw : ubo_load_29.xy);
+  vector<float16_t, 2> ubo_load_28_xz = vector<float16_t, 2>(f16tof32(ubo_load_28 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_28_yw = vector<float16_t, 2>(f16tof32(ubo_load_28 >> 16));
+  const uint scalar_offset_40 = ((offset + 8u)) / 4;
+  uint4 ubo_load_31 = buffer[scalar_offset_40 / 4];
+  uint2 ubo_load_30 = ((scalar_offset_40 & 2) ? ubo_load_31.zw : ubo_load_31.xy);
+  vector<float16_t, 2> ubo_load_30_xz = vector<float16_t, 2>(f16tof32(ubo_load_30 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_30_yw = vector<float16_t, 2>(f16tof32(ubo_load_30 >> 16));
+  const uint scalar_offset_41 = ((offset + 16u)) / 4;
+  uint4 ubo_load_33 = buffer[scalar_offset_41 / 4];
+  uint2 ubo_load_32 = ((scalar_offset_41 & 2) ? ubo_load_33.zw : ubo_load_33.xy);
+  vector<float16_t, 2> ubo_load_32_xz = vector<float16_t, 2>(f16tof32(ubo_load_32 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_32_yw = vector<float16_t, 2>(f16tof32(ubo_load_32 >> 16));
+  return matrix<float16_t, 3, 4>(vector<float16_t, 4>(ubo_load_28_xz[0], ubo_load_28_yw[0], ubo_load_28_xz[1], ubo_load_28_yw[1]), vector<float16_t, 4>(ubo_load_30_xz[0], ubo_load_30_yw[0], ubo_load_30_xz[1], ubo_load_30_yw[1]), vector<float16_t, 4>(ubo_load_32_xz[0], ubo_load_32_yw[0], ubo_load_32_xz[1], ubo_load_32_yw[1]));
+}
+
+matrix<float16_t, 4, 2> tint_symbol_31(uint4 buffer[55], uint offset) {
+  const uint scalar_offset_42 = ((offset + 0u)) / 4;
+  uint ubo_load_34 = buffer[scalar_offset_42 / 4][scalar_offset_42 % 4];
+  const uint scalar_offset_43 = ((offset + 4u)) / 4;
+  uint ubo_load_35 = buffer[scalar_offset_43 / 4][scalar_offset_43 % 4];
+  const uint scalar_offset_44 = ((offset + 8u)) / 4;
+  uint ubo_load_36 = buffer[scalar_offset_44 / 4][scalar_offset_44 % 4];
+  const uint scalar_offset_45 = ((offset + 12u)) / 4;
+  uint ubo_load_37 = buffer[scalar_offset_45 / 4][scalar_offset_45 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_34 & 0xFFFF)), float16_t(f16tof32(ubo_load_34 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_35 & 0xFFFF)), float16_t(f16tof32(ubo_load_35 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_36 & 0xFFFF)), float16_t(f16tof32(ubo_load_36 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_37 & 0xFFFF)), float16_t(f16tof32(ubo_load_37 >> 16))));
+}
+
+matrix<float16_t, 4, 3> tint_symbol_32(uint4 buffer[55], uint offset) {
+  const uint scalar_offset_46 = ((offset + 0u)) / 4;
+  uint4 ubo_load_39 = buffer[scalar_offset_46 / 4];
+  uint2 ubo_load_38 = ((scalar_offset_46 & 2) ? ubo_load_39.zw : ubo_load_39.xy);
+  vector<float16_t, 2> ubo_load_38_xz = vector<float16_t, 2>(f16tof32(ubo_load_38 & 0xFFFF));
+  float16_t ubo_load_38_y = f16tof32(ubo_load_38[0] >> 16);
+  const uint scalar_offset_47 = ((offset + 8u)) / 4;
+  uint4 ubo_load_41 = buffer[scalar_offset_47 / 4];
+  uint2 ubo_load_40 = ((scalar_offset_47 & 2) ? ubo_load_41.zw : ubo_load_41.xy);
+  vector<float16_t, 2> ubo_load_40_xz = vector<float16_t, 2>(f16tof32(ubo_load_40 & 0xFFFF));
+  float16_t ubo_load_40_y = f16tof32(ubo_load_40[0] >> 16);
+  const uint scalar_offset_48 = ((offset + 16u)) / 4;
+  uint4 ubo_load_43 = buffer[scalar_offset_48 / 4];
+  uint2 ubo_load_42 = ((scalar_offset_48 & 2) ? ubo_load_43.zw : ubo_load_43.xy);
+  vector<float16_t, 2> ubo_load_42_xz = vector<float16_t, 2>(f16tof32(ubo_load_42 & 0xFFFF));
+  float16_t ubo_load_42_y = f16tof32(ubo_load_42[0] >> 16);
+  const uint scalar_offset_49 = ((offset + 24u)) / 4;
+  uint4 ubo_load_45 = buffer[scalar_offset_49 / 4];
+  uint2 ubo_load_44 = ((scalar_offset_49 & 2) ? ubo_load_45.zw : ubo_load_45.xy);
+  vector<float16_t, 2> ubo_load_44_xz = vector<float16_t, 2>(f16tof32(ubo_load_44 & 0xFFFF));
+  float16_t ubo_load_44_y = f16tof32(ubo_load_44[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_38_xz[0], ubo_load_38_y, ubo_load_38_xz[1]), vector<float16_t, 3>(ubo_load_40_xz[0], ubo_load_40_y, ubo_load_40_xz[1]), vector<float16_t, 3>(ubo_load_42_xz[0], ubo_load_42_y, ubo_load_42_xz[1]), vector<float16_t, 3>(ubo_load_44_xz[0], ubo_load_44_y, ubo_load_44_xz[1]));
+}
+
+matrix<float16_t, 4, 4> tint_symbol_33(uint4 buffer[55], uint offset) {
+  const uint scalar_offset_50 = ((offset + 0u)) / 4;
+  uint4 ubo_load_47 = buffer[scalar_offset_50 / 4];
+  uint2 ubo_load_46 = ((scalar_offset_50 & 2) ? ubo_load_47.zw : ubo_load_47.xy);
+  vector<float16_t, 2> ubo_load_46_xz = vector<float16_t, 2>(f16tof32(ubo_load_46 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_46_yw = vector<float16_t, 2>(f16tof32(ubo_load_46 >> 16));
+  const uint scalar_offset_51 = ((offset + 8u)) / 4;
+  uint4 ubo_load_49 = buffer[scalar_offset_51 / 4];
+  uint2 ubo_load_48 = ((scalar_offset_51 & 2) ? ubo_load_49.zw : ubo_load_49.xy);
+  vector<float16_t, 2> ubo_load_48_xz = vector<float16_t, 2>(f16tof32(ubo_load_48 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_48_yw = vector<float16_t, 2>(f16tof32(ubo_load_48 >> 16));
+  const uint scalar_offset_52 = ((offset + 16u)) / 4;
+  uint4 ubo_load_51 = buffer[scalar_offset_52 / 4];
+  uint2 ubo_load_50 = ((scalar_offset_52 & 2) ? ubo_load_51.zw : ubo_load_51.xy);
+  vector<float16_t, 2> ubo_load_50_xz = vector<float16_t, 2>(f16tof32(ubo_load_50 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_50_yw = vector<float16_t, 2>(f16tof32(ubo_load_50 >> 16));
+  const uint scalar_offset_53 = ((offset + 24u)) / 4;
+  uint4 ubo_load_53 = buffer[scalar_offset_53 / 4];
+  uint2 ubo_load_52 = ((scalar_offset_53 & 2) ? ubo_load_53.zw : ubo_load_53.xy);
+  vector<float16_t, 2> ubo_load_52_xz = vector<float16_t, 2>(f16tof32(ubo_load_52 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_52_yw = vector<float16_t, 2>(f16tof32(ubo_load_52 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_46_xz[0], ubo_load_46_yw[0], ubo_load_46_xz[1], ubo_load_46_yw[1]), vector<float16_t, 4>(ubo_load_48_xz[0], ubo_load_48_yw[0], ubo_load_48_xz[1], ubo_load_48_yw[1]), vector<float16_t, 4>(ubo_load_50_xz[0], ubo_load_50_yw[0], ubo_load_50_xz[1], ubo_load_50_yw[1]), vector<float16_t, 4>(ubo_load_52_xz[0], ubo_load_52_yw[0], ubo_load_52_xz[1], ubo_load_52_yw[1]));
+}
+
+typedef float3 tint_symbol_34_ret[2];
+tint_symbol_34_ret tint_symbol_34(uint4 buffer[55], uint offset) {
+  float3 arr[2] = (float3[2])0;
+  {
+    for(uint i = 0u; (i < 2u); i = (i + 1u)) {
+      const uint scalar_offset_54 = ((offset + (i * 16u))) / 4;
+      arr[i] = asfloat(buffer[scalar_offset_54 / 4].xyz);
+    }
+  }
+  return arr;
+}
+
+typedef matrix<float16_t, 4, 2> tint_symbol_35_ret[2];
+tint_symbol_35_ret tint_symbol_35(uint4 buffer[55], uint offset) {
+  matrix<float16_t, 4, 2> arr_1[2] = (matrix<float16_t, 4, 2>[2])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 2u); i_1 = (i_1 + 1u)) {
+      arr_1[i_1] = tint_symbol_31(buffer, (offset + (i_1 * 16u)));
+    }
+  }
+  return arr_1;
+}
+
+Inner tint_symbol_36(uint4 buffer[55], uint offset) {
+  const uint scalar_offset_55 = ((offset + 0u)) / 4;
+  const uint scalar_offset_56 = ((offset + 4u)) / 4;
+  const uint scalar_offset_bytes = ((offset + 8u));
+  const uint scalar_offset_index = scalar_offset_bytes / 4;
+  const Inner tint_symbol_38 = {asint(buffer[scalar_offset_55 / 4][scalar_offset_55 % 4]), asfloat(buffer[scalar_offset_56 / 4][scalar_offset_56 % 4]), float16_t(f16tof32(((buffer[scalar_offset_index / 4][scalar_offset_index % 4] >> (scalar_offset_bytes % 4 == 0 ? 0 : 16)) & 0xFFFF)))};
+  return tint_symbol_38;
+}
+
+typedef Inner tint_symbol_37_ret[4];
+tint_symbol_37_ret tint_symbol_37(uint4 buffer[55], uint offset) {
+  Inner arr_2[4] = (Inner[4])0;
+  {
+    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
+      arr_2[i_2] = tint_symbol_36(buffer, (offset + (i_2 * 16u)));
+    }
+  }
+  return arr_2;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  const float scalar_f32 = asfloat(ub[0].x);
+  const int scalar_i32 = asint(ub[0].y);
+  const uint scalar_u32 = ub[0].z;
+  const float16_t scalar_f16 = float16_t(f16tof32(((ub[0].w) & 0xFFFF)));
+  const float2 vec2_f32 = asfloat(ub[1].xy);
+  const int2 vec2_i32 = asint(ub[1].zw);
+  const uint2 vec2_u32 = ub[2].xy;
+  uint ubo_load_54 = ub[2].z;
+  const vector<float16_t, 2> vec2_f16 = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_54 & 0xFFFF)), float16_t(f16tof32(ubo_load_54 >> 16)));
+  const float3 vec3_f32 = asfloat(ub[3].xyz);
+  const int3 vec3_i32 = asint(ub[4].xyz);
+  const uint3 vec3_u32 = ub[5].xyz;
+  uint2 ubo_load_55 = ub[6].xy;
+  vector<float16_t, 2> ubo_load_55_xz = vector<float16_t, 2>(f16tof32(ubo_load_55 & 0xFFFF));
+  float16_t ubo_load_55_y = f16tof32(ubo_load_55[0] >> 16);
+  const vector<float16_t, 3> vec3_f16 = vector<float16_t, 3>(ubo_load_55_xz[0], ubo_load_55_y, ubo_load_55_xz[1]);
+  const float4 vec4_f32 = asfloat(ub[7]);
+  const int4 vec4_i32 = asint(ub[8]);
+  const uint4 vec4_u32 = ub[9];
+  uint2 ubo_load_56 = ub[10].xy;
+  vector<float16_t, 2> ubo_load_56_xz = vector<float16_t, 2>(f16tof32(ubo_load_56 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_56_yw = vector<float16_t, 2>(f16tof32(ubo_load_56 >> 16));
+  const vector<float16_t, 4> vec4_f16 = vector<float16_t, 4>(ubo_load_56_xz[0], ubo_load_56_yw[0], ubo_load_56_xz[1], ubo_load_56_yw[1]);
+  const float2x2 mat2x2_f32 = tint_symbol_16(ub, 168u);
+  const float2x3 mat2x3_f32 = tint_symbol_17(ub, 192u);
+  const float2x4 mat2x4_f32 = tint_symbol_18(ub, 224u);
+  const float3x2 mat3x2_f32 = tint_symbol_19(ub, 256u);
+  const float3x3 mat3x3_f32 = tint_symbol_20(ub, 288u);
+  const float3x4 mat3x4_f32 = tint_symbol_21(ub, 336u);
+  const float4x2 mat4x2_f32 = tint_symbol_22(ub, 384u);
+  const float4x3 mat4x3_f32 = tint_symbol_23(ub, 416u);
+  const float4x4 mat4x4_f32 = tint_symbol_24(ub, 480u);
+  const matrix<float16_t, 2, 2> mat2x2_f16 = tint_symbol_25(ub, 544u);
+  const matrix<float16_t, 2, 3> mat2x3_f16 = tint_symbol_26(ub, 552u);
+  const matrix<float16_t, 2, 4> mat2x4_f16 = tint_symbol_27(ub, 568u);
+  const matrix<float16_t, 3, 2> mat3x2_f16 = tint_symbol_28(ub, 584u);
+  const matrix<float16_t, 3, 3> mat3x3_f16 = tint_symbol_29(ub, 600u);
+  const matrix<float16_t, 3, 4> mat3x4_f16 = tint_symbol_30(ub, 624u);
+  const matrix<float16_t, 4, 2> mat4x2_f16 = tint_symbol_31(ub, 648u);
+  const matrix<float16_t, 4, 3> mat4x3_f16 = tint_symbol_32(ub, 664u);
+  const matrix<float16_t, 4, 4> mat4x4_f16 = tint_symbol_33(ub, 696u);
+  const float3 arr2_vec3_f32[2] = tint_symbol_34(ub, 736u);
+  const matrix<float16_t, 4, 2> arr2_mat4x2_f16[2] = tint_symbol_35(ub, 768u);
+  const Inner struct_inner = tint_symbol_36(ub, 800u);
+  const Inner array_struct_inner[4] = tint_symbol_37(ub, 816u);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001A0147F5100(4,3-11): error X3000: unrecognized identifier 'float16_t'
+
diff --git a/test/tint/buffer/uniform/static_index/read_f16.wgsl.expected.glsl b/test/tint/buffer/uniform/static_index/read_f16.wgsl.expected.glsl
new file mode 100644
index 0000000..bf9f260
--- /dev/null
+++ b/test/tint/buffer/uniform/static_index/read_f16.wgsl.expected.glsl
@@ -0,0 +1,261 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct mat4x2_f16_4 {
+  f16vec2 col0;
+  f16vec2 col1;
+  f16vec2 col2;
+  f16vec2 col3;
+};
+
+struct Inner {
+  int scalar_i32;
+  float scalar_f32;
+  float16_t scalar_f16;
+  uint pad;
+};
+
+struct S {
+  float scalar_f32;
+  int scalar_i32;
+  uint scalar_u32;
+  float16_t scalar_f16;
+  vec2 vec2_f32;
+  ivec2 vec2_i32;
+  uvec2 vec2_u32;
+  f16vec2 vec2_f16;
+  uint pad_1;
+  vec3 vec3_f32;
+  uint pad_2;
+  ivec3 vec3_i32;
+  uint pad_3;
+  uvec3 vec3_u32;
+  uint pad_4;
+  f16vec3 vec3_f16;
+  uint pad_5;
+  uint pad_6;
+  vec4 vec4_f32;
+  ivec4 vec4_i32;
+  uvec4 vec4_u32;
+  f16vec4 vec4_f16;
+  mat2 mat2x2_f32;
+  uint pad_7;
+  uint pad_8;
+  mat2x3 mat2x3_f32;
+  mat2x4 mat2x4_f32;
+  mat3x2 mat3x2_f32;
+  uint pad_9;
+  uint pad_10;
+  mat3 mat3x3_f32;
+  mat3x4 mat3x4_f32;
+  mat4x2 mat4x2_f32;
+  mat4x3 mat4x3_f32;
+  mat4 mat4x4_f32;
+  f16mat2 mat2x2_f16;
+  f16mat2x3 mat2x3_f16;
+  f16mat2x4 mat2x4_f16;
+  f16mat3x2 mat3x2_f16;
+  uint pad_11;
+  f16mat3 mat3x3_f16;
+  f16mat3x4 mat3x4_f16;
+  f16mat4x2 mat4x2_f16;
+  f16mat4x3 mat4x3_f16;
+  f16mat4 mat4x4_f16;
+  uint pad_12;
+  uint pad_13;
+  vec3 arr2_vec3_f32[2];
+  f16mat4x2 arr2_mat4x2_f16[2];
+  Inner struct_inner;
+  Inner array_struct_inner[4];
+};
+
+struct S_std140 {
+  float scalar_f32;
+  int scalar_i32;
+  uint scalar_u32;
+  float16_t scalar_f16;
+  vec2 vec2_f32;
+  ivec2 vec2_i32;
+  uvec2 vec2_u32;
+  f16vec2 vec2_f16;
+  uint pad_1;
+  vec3 vec3_f32;
+  uint pad_2;
+  ivec3 vec3_i32;
+  uint pad_3;
+  uvec3 vec3_u32;
+  uint pad_4;
+  f16vec3 vec3_f16;
+  uint pad_5;
+  uint pad_6;
+  vec4 vec4_f32;
+  ivec4 vec4_i32;
+  uvec4 vec4_u32;
+  f16vec4 vec4_f16;
+  vec2 mat2x2_f32_0;
+  vec2 mat2x2_f32_1;
+  uint pad_7;
+  uint pad_8;
+  mat2x3 mat2x3_f32;
+  mat2x4 mat2x4_f32;
+  vec2 mat3x2_f32_0;
+  vec2 mat3x2_f32_1;
+  vec2 mat3x2_f32_2;
+  uint pad_9;
+  uint pad_10;
+  mat3 mat3x3_f32;
+  mat3x4 mat3x4_f32;
+  vec2 mat4x2_f32_0;
+  vec2 mat4x2_f32_1;
+  vec2 mat4x2_f32_2;
+  vec2 mat4x2_f32_3;
+  mat4x3 mat4x3_f32;
+  mat4 mat4x4_f32;
+  f16vec2 mat2x2_f16_0;
+  f16vec2 mat2x2_f16_1;
+  f16vec3 mat2x3_f16_0;
+  f16vec3 mat2x3_f16_1;
+  f16vec4 mat2x4_f16_0;
+  f16vec4 mat2x4_f16_1;
+  f16vec2 mat3x2_f16_0;
+  f16vec2 mat3x2_f16_1;
+  f16vec2 mat3x2_f16_2;
+  uint pad_11;
+  f16vec3 mat3x3_f16_0;
+  f16vec3 mat3x3_f16_1;
+  f16vec3 mat3x3_f16_2;
+  f16vec4 mat3x4_f16_0;
+  f16vec4 mat3x4_f16_1;
+  f16vec4 mat3x4_f16_2;
+  f16vec2 mat4x2_f16_0;
+  f16vec2 mat4x2_f16_1;
+  f16vec2 mat4x2_f16_2;
+  f16vec2 mat4x2_f16_3;
+  f16vec3 mat4x3_f16_0;
+  f16vec3 mat4x3_f16_1;
+  f16vec3 mat4x3_f16_2;
+  f16vec3 mat4x3_f16_3;
+  f16vec4 mat4x4_f16_0;
+  f16vec4 mat4x4_f16_1;
+  f16vec4 mat4x4_f16_2;
+  f16vec4 mat4x4_f16_3;
+  uint pad_12;
+  uint pad_13;
+  vec3 arr2_vec3_f32[2];
+  mat4x2_f16_4 arr2_mat4x2_f16[2];
+  Inner struct_inner;
+  Inner array_struct_inner[4];
+};
+
+layout(binding = 0, std140) uniform ub_block_std140_ubo {
+  S_std140 inner;
+} ub;
+
+mat2 load_ub_inner_mat2x2_f32() {
+  return mat2(ub.inner.mat2x2_f32_0, ub.inner.mat2x2_f32_1);
+}
+
+mat3x2 load_ub_inner_mat3x2_f32() {
+  return mat3x2(ub.inner.mat3x2_f32_0, ub.inner.mat3x2_f32_1, ub.inner.mat3x2_f32_2);
+}
+
+mat4x2 load_ub_inner_mat4x2_f32() {
+  return mat4x2(ub.inner.mat4x2_f32_0, ub.inner.mat4x2_f32_1, ub.inner.mat4x2_f32_2, ub.inner.mat4x2_f32_3);
+}
+
+f16mat2 load_ub_inner_mat2x2_f16() {
+  return f16mat2(ub.inner.mat2x2_f16_0, ub.inner.mat2x2_f16_1);
+}
+
+f16mat2x3 load_ub_inner_mat2x3_f16() {
+  return f16mat2x3(ub.inner.mat2x3_f16_0, ub.inner.mat2x3_f16_1);
+}
+
+f16mat2x4 load_ub_inner_mat2x4_f16() {
+  return f16mat2x4(ub.inner.mat2x4_f16_0, ub.inner.mat2x4_f16_1);
+}
+
+f16mat3x2 load_ub_inner_mat3x2_f16() {
+  return f16mat3x2(ub.inner.mat3x2_f16_0, ub.inner.mat3x2_f16_1, ub.inner.mat3x2_f16_2);
+}
+
+f16mat3 load_ub_inner_mat3x3_f16() {
+  return f16mat3(ub.inner.mat3x3_f16_0, ub.inner.mat3x3_f16_1, ub.inner.mat3x3_f16_2);
+}
+
+f16mat3x4 load_ub_inner_mat3x4_f16() {
+  return f16mat3x4(ub.inner.mat3x4_f16_0, ub.inner.mat3x4_f16_1, ub.inner.mat3x4_f16_2);
+}
+
+f16mat4x2 load_ub_inner_mat4x2_f16() {
+  return f16mat4x2(ub.inner.mat4x2_f16_0, ub.inner.mat4x2_f16_1, ub.inner.mat4x2_f16_2, ub.inner.mat4x2_f16_3);
+}
+
+f16mat4x3 load_ub_inner_mat4x3_f16() {
+  return f16mat4x3(ub.inner.mat4x3_f16_0, ub.inner.mat4x3_f16_1, ub.inner.mat4x3_f16_2, ub.inner.mat4x3_f16_3);
+}
+
+f16mat4 load_ub_inner_mat4x4_f16() {
+  return f16mat4(ub.inner.mat4x4_f16_0, ub.inner.mat4x4_f16_1, ub.inner.mat4x4_f16_2, ub.inner.mat4x4_f16_3);
+}
+
+f16mat4x2 conv_mat4x2_f16(mat4x2_f16_4 val) {
+  return f16mat4x2(val.col0, val.col1, val.col2, val.col3);
+}
+
+f16mat4x2[2] conv_arr2_mat4x2_f16(mat4x2_f16_4 val[2]) {
+  f16mat4x2 arr[2] = f16mat4x2[2](f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf));
+  {
+    for(uint i = 0u; (i < 2u); i = (i + 1u)) {
+      arr[i] = conv_mat4x2_f16(val[i]);
+    }
+  }
+  return arr;
+}
+
+void tint_symbol() {
+  float scalar_f32 = ub.inner.scalar_f32;
+  int scalar_i32 = ub.inner.scalar_i32;
+  uint scalar_u32 = ub.inner.scalar_u32;
+  float16_t scalar_f16 = ub.inner.scalar_f16;
+  vec2 vec2_f32 = ub.inner.vec2_f32;
+  ivec2 vec2_i32 = ub.inner.vec2_i32;
+  uvec2 vec2_u32 = ub.inner.vec2_u32;
+  f16vec2 vec2_f16 = ub.inner.vec2_f16;
+  vec3 vec3_f32 = ub.inner.vec3_f32;
+  ivec3 vec3_i32 = ub.inner.vec3_i32;
+  uvec3 vec3_u32 = ub.inner.vec3_u32;
+  f16vec3 vec3_f16 = ub.inner.vec3_f16;
+  vec4 vec4_f32 = ub.inner.vec4_f32;
+  ivec4 vec4_i32 = ub.inner.vec4_i32;
+  uvec4 vec4_u32 = ub.inner.vec4_u32;
+  f16vec4 vec4_f16 = ub.inner.vec4_f16;
+  mat2 mat2x2_f32 = load_ub_inner_mat2x2_f32();
+  mat2x3 mat2x3_f32 = ub.inner.mat2x3_f32;
+  mat2x4 mat2x4_f32 = ub.inner.mat2x4_f32;
+  mat3x2 mat3x2_f32 = load_ub_inner_mat3x2_f32();
+  mat3 mat3x3_f32 = ub.inner.mat3x3_f32;
+  mat3x4 mat3x4_f32 = ub.inner.mat3x4_f32;
+  mat4x2 mat4x2_f32 = load_ub_inner_mat4x2_f32();
+  mat4x3 mat4x3_f32 = ub.inner.mat4x3_f32;
+  mat4 mat4x4_f32 = ub.inner.mat4x4_f32;
+  f16mat2 mat2x2_f16 = load_ub_inner_mat2x2_f16();
+  f16mat2x3 mat2x3_f16 = load_ub_inner_mat2x3_f16();
+  f16mat2x4 mat2x4_f16 = load_ub_inner_mat2x4_f16();
+  f16mat3x2 mat3x2_f16 = load_ub_inner_mat3x2_f16();
+  f16mat3 mat3x3_f16 = load_ub_inner_mat3x3_f16();
+  f16mat3x4 mat3x4_f16 = load_ub_inner_mat3x4_f16();
+  f16mat4x2 mat4x2_f16 = load_ub_inner_mat4x2_f16();
+  f16mat4x3 mat4x3_f16 = load_ub_inner_mat4x3_f16();
+  f16mat4 mat4x4_f16 = load_ub_inner_mat4x4_f16();
+  vec3 arr2_vec3_f32[2] = ub.inner.arr2_vec3_f32;
+  f16mat4x2 arr2_mat4x2_f16[2] = conv_arr2_mat4x2_f16(ub.inner.arr2_mat4x2_f16);
+  Inner struct_inner = ub.inner.struct_inner;
+  Inner array_struct_inner[4] = ub.inner.array_struct_inner;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol();
+  return;
+}
diff --git a/test/tint/buffer/uniform/static_index/read_f16.wgsl.expected.msl b/test/tint/buffer/uniform/static_index/read_f16.wgsl.expected.msl
new file mode 100644
index 0000000..99638ed
--- /dev/null
+++ b/test/tint/buffer/uniform/static_index/read_f16.wgsl.expected.msl
@@ -0,0 +1,116 @@
+#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 Inner {
+  /* 0x0000 */ int scalar_i32;
+  /* 0x0004 */ float scalar_f32;
+  /* 0x0008 */ half scalar_f16;
+  /* 0x000a */ tint_array<int8_t, 6> tint_pad;
+};
+
+struct S {
+  /* 0x0000 */ float scalar_f32;
+  /* 0x0004 */ int scalar_i32;
+  /* 0x0008 */ uint scalar_u32;
+  /* 0x000c */ half scalar_f16;
+  /* 0x000e */ tint_array<int8_t, 2> tint_pad_1;
+  /* 0x0010 */ float2 vec2_f32;
+  /* 0x0018 */ int2 vec2_i32;
+  /* 0x0020 */ uint2 vec2_u32;
+  /* 0x0028 */ half2 vec2_f16;
+  /* 0x002c */ tint_array<int8_t, 4> tint_pad_2;
+  /* 0x0030 */ packed_float3 vec3_f32;
+  /* 0x003c */ tint_array<int8_t, 4> tint_pad_3;
+  /* 0x0040 */ packed_int3 vec3_i32;
+  /* 0x004c */ tint_array<int8_t, 4> tint_pad_4;
+  /* 0x0050 */ packed_uint3 vec3_u32;
+  /* 0x005c */ tint_array<int8_t, 4> tint_pad_5;
+  /* 0x0060 */ packed_half3 vec3_f16;
+  /* 0x0066 */ tint_array<int8_t, 10> tint_pad_6;
+  /* 0x0070 */ float4 vec4_f32;
+  /* 0x0080 */ int4 vec4_i32;
+  /* 0x0090 */ uint4 vec4_u32;
+  /* 0x00a0 */ half4 vec4_f16;
+  /* 0x00a8 */ float2x2 mat2x2_f32;
+  /* 0x00b8 */ tint_array<int8_t, 8> tint_pad_7;
+  /* 0x00c0 */ float2x3 mat2x3_f32;
+  /* 0x00e0 */ float2x4 mat2x4_f32;
+  /* 0x0100 */ float3x2 mat3x2_f32;
+  /* 0x0118 */ tint_array<int8_t, 8> tint_pad_8;
+  /* 0x0120 */ float3x3 mat3x3_f32;
+  /* 0x0150 */ float3x4 mat3x4_f32;
+  /* 0x0180 */ float4x2 mat4x2_f32;
+  /* 0x01a0 */ float4x3 mat4x3_f32;
+  /* 0x01e0 */ float4x4 mat4x4_f32;
+  /* 0x0220 */ half2x2 mat2x2_f16;
+  /* 0x0228 */ half2x3 mat2x3_f16;
+  /* 0x0238 */ half2x4 mat2x4_f16;
+  /* 0x0248 */ half3x2 mat3x2_f16;
+  /* 0x0254 */ tint_array<int8_t, 4> tint_pad_9;
+  /* 0x0258 */ half3x3 mat3x3_f16;
+  /* 0x0270 */ half3x4 mat3x4_f16;
+  /* 0x0288 */ half4x2 mat4x2_f16;
+  /* 0x0298 */ half4x3 mat4x3_f16;
+  /* 0x02b8 */ half4x4 mat4x4_f16;
+  /* 0x02d8 */ tint_array<int8_t, 8> tint_pad_10;
+  /* 0x02e0 */ tint_array<float3, 2> arr2_vec3_f32;
+  /* 0x0300 */ tint_array<half4x2, 2> arr2_mat4x2_f16;
+  /* 0x0320 */ Inner struct_inner;
+  /* 0x0330 */ tint_array<Inner, 4> array_struct_inner;
+};
+
+kernel void tint_symbol(const constant S* tint_symbol_1 [[buffer(0)]]) {
+  float const scalar_f32 = (*(tint_symbol_1)).scalar_f32;
+  int const scalar_i32 = (*(tint_symbol_1)).scalar_i32;
+  uint const scalar_u32 = (*(tint_symbol_1)).scalar_u32;
+  half const scalar_f16 = (*(tint_symbol_1)).scalar_f16;
+  float2 const vec2_f32 = (*(tint_symbol_1)).vec2_f32;
+  int2 const vec2_i32 = (*(tint_symbol_1)).vec2_i32;
+  uint2 const vec2_u32 = (*(tint_symbol_1)).vec2_u32;
+  half2 const vec2_f16 = (*(tint_symbol_1)).vec2_f16;
+  float3 const vec3_f32 = float3((*(tint_symbol_1)).vec3_f32);
+  int3 const vec3_i32 = int3((*(tint_symbol_1)).vec3_i32);
+  uint3 const vec3_u32 = uint3((*(tint_symbol_1)).vec3_u32);
+  half3 const vec3_f16 = half3((*(tint_symbol_1)).vec3_f16);
+  float4 const vec4_f32 = (*(tint_symbol_1)).vec4_f32;
+  int4 const vec4_i32 = (*(tint_symbol_1)).vec4_i32;
+  uint4 const vec4_u32 = (*(tint_symbol_1)).vec4_u32;
+  half4 const vec4_f16 = (*(tint_symbol_1)).vec4_f16;
+  float2x2 const mat2x2_f32 = (*(tint_symbol_1)).mat2x2_f32;
+  float2x3 const mat2x3_f32 = (*(tint_symbol_1)).mat2x3_f32;
+  float2x4 const mat2x4_f32 = (*(tint_symbol_1)).mat2x4_f32;
+  float3x2 const mat3x2_f32 = (*(tint_symbol_1)).mat3x2_f32;
+  float3x3 const mat3x3_f32 = (*(tint_symbol_1)).mat3x3_f32;
+  float3x4 const mat3x4_f32 = (*(tint_symbol_1)).mat3x4_f32;
+  float4x2 const mat4x2_f32 = (*(tint_symbol_1)).mat4x2_f32;
+  float4x3 const mat4x3_f32 = (*(tint_symbol_1)).mat4x3_f32;
+  float4x4 const mat4x4_f32 = (*(tint_symbol_1)).mat4x4_f32;
+  half2x2 const mat2x2_f16 = (*(tint_symbol_1)).mat2x2_f16;
+  half2x3 const mat2x3_f16 = (*(tint_symbol_1)).mat2x3_f16;
+  half2x4 const mat2x4_f16 = (*(tint_symbol_1)).mat2x4_f16;
+  half3x2 const mat3x2_f16 = (*(tint_symbol_1)).mat3x2_f16;
+  half3x3 const mat3x3_f16 = (*(tint_symbol_1)).mat3x3_f16;
+  half3x4 const mat3x4_f16 = (*(tint_symbol_1)).mat3x4_f16;
+  half4x2 const mat4x2_f16 = (*(tint_symbol_1)).mat4x2_f16;
+  half4x3 const mat4x3_f16 = (*(tint_symbol_1)).mat4x3_f16;
+  half4x4 const mat4x4_f16 = (*(tint_symbol_1)).mat4x4_f16;
+  tint_array<float3, 2> const arr2_vec3_f32 = (*(tint_symbol_1)).arr2_vec3_f32;
+  tint_array<half4x2, 2> const arr2_mat4x2_f16 = (*(tint_symbol_1)).arr2_mat4x2_f16;
+  Inner const struct_inner = (*(tint_symbol_1)).struct_inner;
+  tint_array<Inner, 4> const array_struct_inner = (*(tint_symbol_1)).array_struct_inner;
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/static_index/read_f16.wgsl.expected.spvasm b/test/tint/buffer/uniform/static_index/read_f16.wgsl.expected.spvasm
new file mode 100644
index 0000000..16735d1
--- /dev/null
+++ b/test/tint/buffer/uniform/static_index/read_f16.wgsl.expected.spvasm
@@ -0,0 +1,616 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 426
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %ub_block_std140 "ub_block_std140"
+               OpMemberName %ub_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "scalar_f32"
+               OpMemberName %S_std140 1 "scalar_i32"
+               OpMemberName %S_std140 2 "scalar_u32"
+               OpMemberName %S_std140 3 "scalar_f16"
+               OpMemberName %S_std140 4 "vec2_f32"
+               OpMemberName %S_std140 5 "vec2_i32"
+               OpMemberName %S_std140 6 "vec2_u32"
+               OpMemberName %S_std140 7 "vec2_f16"
+               OpMemberName %S_std140 8 "vec3_f32"
+               OpMemberName %S_std140 9 "vec3_i32"
+               OpMemberName %S_std140 10 "vec3_u32"
+               OpMemberName %S_std140 11 "vec3_f16"
+               OpMemberName %S_std140 12 "vec4_f32"
+               OpMemberName %S_std140 13 "vec4_i32"
+               OpMemberName %S_std140 14 "vec4_u32"
+               OpMemberName %S_std140 15 "vec4_f16"
+               OpMemberName %S_std140 16 "mat2x2_f32_0"
+               OpMemberName %S_std140 17 "mat2x2_f32_1"
+               OpMemberName %S_std140 18 "mat2x3_f32"
+               OpMemberName %S_std140 19 "mat2x4_f32"
+               OpMemberName %S_std140 20 "mat3x2_f32_0"
+               OpMemberName %S_std140 21 "mat3x2_f32_1"
+               OpMemberName %S_std140 22 "mat3x2_f32_2"
+               OpMemberName %S_std140 23 "mat3x3_f32"
+               OpMemberName %S_std140 24 "mat3x4_f32"
+               OpMemberName %S_std140 25 "mat4x2_f32_0"
+               OpMemberName %S_std140 26 "mat4x2_f32_1"
+               OpMemberName %S_std140 27 "mat4x2_f32_2"
+               OpMemberName %S_std140 28 "mat4x2_f32_3"
+               OpMemberName %S_std140 29 "mat4x3_f32"
+               OpMemberName %S_std140 30 "mat4x4_f32"
+               OpMemberName %S_std140 31 "mat2x2_f16_0"
+               OpMemberName %S_std140 32 "mat2x2_f16_1"
+               OpMemberName %S_std140 33 "mat2x3_f16_0"
+               OpMemberName %S_std140 34 "mat2x3_f16_1"
+               OpMemberName %S_std140 35 "mat2x4_f16_0"
+               OpMemberName %S_std140 36 "mat2x4_f16_1"
+               OpMemberName %S_std140 37 "mat3x2_f16_0"
+               OpMemberName %S_std140 38 "mat3x2_f16_1"
+               OpMemberName %S_std140 39 "mat3x2_f16_2"
+               OpMemberName %S_std140 40 "mat3x3_f16_0"
+               OpMemberName %S_std140 41 "mat3x3_f16_1"
+               OpMemberName %S_std140 42 "mat3x3_f16_2"
+               OpMemberName %S_std140 43 "mat3x4_f16_0"
+               OpMemberName %S_std140 44 "mat3x4_f16_1"
+               OpMemberName %S_std140 45 "mat3x4_f16_2"
+               OpMemberName %S_std140 46 "mat4x2_f16_0"
+               OpMemberName %S_std140 47 "mat4x2_f16_1"
+               OpMemberName %S_std140 48 "mat4x2_f16_2"
+               OpMemberName %S_std140 49 "mat4x2_f16_3"
+               OpMemberName %S_std140 50 "mat4x3_f16_0"
+               OpMemberName %S_std140 51 "mat4x3_f16_1"
+               OpMemberName %S_std140 52 "mat4x3_f16_2"
+               OpMemberName %S_std140 53 "mat4x3_f16_3"
+               OpMemberName %S_std140 54 "mat4x4_f16_0"
+               OpMemberName %S_std140 55 "mat4x4_f16_1"
+               OpMemberName %S_std140 56 "mat4x4_f16_2"
+               OpMemberName %S_std140 57 "mat4x4_f16_3"
+               OpMemberName %S_std140 58 "arr2_vec3_f32"
+               OpMemberName %S_std140 59 "arr2_mat4x2_f16"
+               OpName %mat4x2_f16_4 "mat4x2_f16_4"
+               OpMemberName %mat4x2_f16_4 0 "col0"
+               OpMemberName %mat4x2_f16_4 1 "col1"
+               OpMemberName %mat4x2_f16_4 2 "col2"
+               OpMemberName %mat4x2_f16_4 3 "col3"
+               OpMemberName %S_std140 60 "struct_inner"
+               OpName %Inner "Inner"
+               OpMemberName %Inner 0 "scalar_i32"
+               OpMemberName %Inner 1 "scalar_f32"
+               OpMemberName %Inner 2 "scalar_f16"
+               OpMemberName %S_std140 61 "array_struct_inner"
+               OpName %ub "ub"
+               OpName %load_ub_inner_mat2x2_f32 "load_ub_inner_mat2x2_f32"
+               OpName %load_ub_inner_mat3x2_f32 "load_ub_inner_mat3x2_f32"
+               OpName %load_ub_inner_mat4x2_f32 "load_ub_inner_mat4x2_f32"
+               OpName %load_ub_inner_mat2x2_f16 "load_ub_inner_mat2x2_f16"
+               OpName %load_ub_inner_mat2x3_f16 "load_ub_inner_mat2x3_f16"
+               OpName %load_ub_inner_mat2x4_f16 "load_ub_inner_mat2x4_f16"
+               OpName %load_ub_inner_mat3x2_f16 "load_ub_inner_mat3x2_f16"
+               OpName %load_ub_inner_mat3x3_f16 "load_ub_inner_mat3x3_f16"
+               OpName %load_ub_inner_mat3x4_f16 "load_ub_inner_mat3x4_f16"
+               OpName %load_ub_inner_mat4x2_f16 "load_ub_inner_mat4x2_f16"
+               OpName %load_ub_inner_mat4x3_f16 "load_ub_inner_mat4x3_f16"
+               OpName %load_ub_inner_mat4x4_f16 "load_ub_inner_mat4x4_f16"
+               OpName %conv_mat4x2_f16 "conv_mat4x2_f16"
+               OpName %val "val"
+               OpName %conv_arr2_mat4x2_f16 "conv_arr2_mat4x2_f16"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %main "main"
+               OpDecorate %ub_block_std140 Block
+               OpMemberDecorate %ub_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 4
+               OpMemberDecorate %S_std140 2 Offset 8
+               OpMemberDecorate %S_std140 3 Offset 12
+               OpMemberDecorate %S_std140 4 Offset 16
+               OpMemberDecorate %S_std140 5 Offset 24
+               OpMemberDecorate %S_std140 6 Offset 32
+               OpMemberDecorate %S_std140 7 Offset 40
+               OpMemberDecorate %S_std140 8 Offset 48
+               OpMemberDecorate %S_std140 9 Offset 64
+               OpMemberDecorate %S_std140 10 Offset 80
+               OpMemberDecorate %S_std140 11 Offset 96
+               OpMemberDecorate %S_std140 12 Offset 112
+               OpMemberDecorate %S_std140 13 Offset 128
+               OpMemberDecorate %S_std140 14 Offset 144
+               OpMemberDecorate %S_std140 15 Offset 160
+               OpMemberDecorate %S_std140 16 Offset 168
+               OpMemberDecorate %S_std140 17 Offset 176
+               OpMemberDecorate %S_std140 18 Offset 192
+               OpMemberDecorate %S_std140 18 ColMajor
+               OpMemberDecorate %S_std140 18 MatrixStride 16
+               OpMemberDecorate %S_std140 19 Offset 224
+               OpMemberDecorate %S_std140 19 ColMajor
+               OpMemberDecorate %S_std140 19 MatrixStride 16
+               OpMemberDecorate %S_std140 20 Offset 256
+               OpMemberDecorate %S_std140 21 Offset 264
+               OpMemberDecorate %S_std140 22 Offset 272
+               OpMemberDecorate %S_std140 23 Offset 288
+               OpMemberDecorate %S_std140 23 ColMajor
+               OpMemberDecorate %S_std140 23 MatrixStride 16
+               OpMemberDecorate %S_std140 24 Offset 336
+               OpMemberDecorate %S_std140 24 ColMajor
+               OpMemberDecorate %S_std140 24 MatrixStride 16
+               OpMemberDecorate %S_std140 25 Offset 384
+               OpMemberDecorate %S_std140 26 Offset 392
+               OpMemberDecorate %S_std140 27 Offset 400
+               OpMemberDecorate %S_std140 28 Offset 408
+               OpMemberDecorate %S_std140 29 Offset 416
+               OpMemberDecorate %S_std140 29 ColMajor
+               OpMemberDecorate %S_std140 29 MatrixStride 16
+               OpMemberDecorate %S_std140 30 Offset 480
+               OpMemberDecorate %S_std140 30 ColMajor
+               OpMemberDecorate %S_std140 30 MatrixStride 16
+               OpMemberDecorate %S_std140 31 Offset 544
+               OpMemberDecorate %S_std140 32 Offset 548
+               OpMemberDecorate %S_std140 33 Offset 552
+               OpMemberDecorate %S_std140 34 Offset 560
+               OpMemberDecorate %S_std140 35 Offset 568
+               OpMemberDecorate %S_std140 36 Offset 576
+               OpMemberDecorate %S_std140 37 Offset 584
+               OpMemberDecorate %S_std140 38 Offset 588
+               OpMemberDecorate %S_std140 39 Offset 592
+               OpMemberDecorate %S_std140 40 Offset 600
+               OpMemberDecorate %S_std140 41 Offset 608
+               OpMemberDecorate %S_std140 42 Offset 616
+               OpMemberDecorate %S_std140 43 Offset 624
+               OpMemberDecorate %S_std140 44 Offset 632
+               OpMemberDecorate %S_std140 45 Offset 640
+               OpMemberDecorate %S_std140 46 Offset 648
+               OpMemberDecorate %S_std140 47 Offset 652
+               OpMemberDecorate %S_std140 48 Offset 656
+               OpMemberDecorate %S_std140 49 Offset 660
+               OpMemberDecorate %S_std140 50 Offset 664
+               OpMemberDecorate %S_std140 51 Offset 672
+               OpMemberDecorate %S_std140 52 Offset 680
+               OpMemberDecorate %S_std140 53 Offset 688
+               OpMemberDecorate %S_std140 54 Offset 696
+               OpMemberDecorate %S_std140 55 Offset 704
+               OpMemberDecorate %S_std140 56 Offset 712
+               OpMemberDecorate %S_std140 57 Offset 720
+               OpMemberDecorate %S_std140 58 Offset 736
+               OpDecorate %_arr_v3float_uint_2 ArrayStride 16
+               OpMemberDecorate %S_std140 59 Offset 768
+               OpMemberDecorate %mat4x2_f16_4 0 Offset 0
+               OpMemberDecorate %mat4x2_f16_4 1 Offset 4
+               OpMemberDecorate %mat4x2_f16_4 2 Offset 8
+               OpMemberDecorate %mat4x2_f16_4 3 Offset 12
+               OpDecorate %_arr_mat4x2_f16_4_uint_2 ArrayStride 16
+               OpMemberDecorate %S_std140 60 Offset 800
+               OpMemberDecorate %Inner 0 Offset 0
+               OpMemberDecorate %Inner 1 Offset 4
+               OpMemberDecorate %Inner 2 Offset 8
+               OpMemberDecorate %S_std140 61 Offset 816
+               OpDecorate %_arr_Inner_uint_4 ArrayStride 16
+               OpDecorate %ub NonWritable
+               OpDecorate %ub Binding 0
+               OpDecorate %ub DescriptorSet 0
+               OpDecorate %_arr_mat4v2half_uint_2 ArrayStride 16
+      %float = OpTypeFloat 32
+        %int = OpTypeInt 32 1
+       %uint = OpTypeInt 32 0
+       %half = OpTypeFloat 16
+    %v2float = OpTypeVector %float 2
+      %v2int = OpTypeVector %int 2
+     %v2uint = OpTypeVector %uint 2
+     %v2half = OpTypeVector %half 2
+    %v3float = OpTypeVector %float 3
+      %v3int = OpTypeVector %int 3
+     %v3uint = OpTypeVector %uint 3
+     %v3half = OpTypeVector %half 3
+    %v4float = OpTypeVector %float 4
+      %v4int = OpTypeVector %int 4
+     %v4uint = OpTypeVector %uint 4
+     %v4half = OpTypeVector %half 4
+%mat2v3float = OpTypeMatrix %v3float 2
+%mat2v4float = OpTypeMatrix %v4float 2
+%mat3v3float = OpTypeMatrix %v3float 3
+%mat3v4float = OpTypeMatrix %v4float 3
+%mat4v3float = OpTypeMatrix %v3float 4
+%mat4v4float = OpTypeMatrix %v4float 4
+     %uint_2 = OpConstant %uint 2
+%_arr_v3float_uint_2 = OpTypeArray %v3float %uint_2
+%mat4x2_f16_4 = OpTypeStruct %v2half %v2half %v2half %v2half
+%_arr_mat4x2_f16_4_uint_2 = OpTypeArray %mat4x2_f16_4 %uint_2
+      %Inner = OpTypeStruct %int %float %half
+     %uint_4 = OpConstant %uint 4
+%_arr_Inner_uint_4 = OpTypeArray %Inner %uint_4
+   %S_std140 = OpTypeStruct %float %int %uint %half %v2float %v2int %v2uint %v2half %v3float %v3int %v3uint %v3half %v4float %v4int %v4uint %v4half %v2float %v2float %mat2v3float %mat2v4float %v2float %v2float %v2float %mat3v3float %mat3v4float %v2float %v2float %v2float %v2float %mat4v3float %mat4v4float %v2half %v2half %v3half %v3half %v4half %v4half %v2half %v2half %v2half %v3half %v3half %v3half %v4half %v4half %v4half %v2half %v2half %v2half %v2half %v3half %v3half %v3half %v3half %v4half %v4half %v4half %v4half %_arr_v3float_uint_2 %_arr_mat4x2_f16_4_uint_2 %Inner %_arr_Inner_uint_4
+%ub_block_std140 = OpTypeStruct %S_std140
+%_ptr_Uniform_ub_block_std140 = OpTypePointer Uniform %ub_block_std140
+         %ub = OpVariable %_ptr_Uniform_ub_block_std140 Uniform
+%mat2v2float = OpTypeMatrix %v2float 2
+         %34 = OpTypeFunction %mat2v2float
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+    %uint_16 = OpConstant %uint 16
+%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
+    %uint_17 = OpConstant %uint 17
+%mat3v2float = OpTypeMatrix %v2float 3
+         %52 = OpTypeFunction %mat3v2float
+    %uint_20 = OpConstant %uint 20
+    %uint_21 = OpConstant %uint 21
+    %uint_22 = OpConstant %uint 22
+%mat4v2float = OpTypeMatrix %v2float 4
+         %71 = OpTypeFunction %mat4v2float
+    %uint_25 = OpConstant %uint 25
+    %uint_26 = OpConstant %uint 26
+    %uint_27 = OpConstant %uint 27
+    %uint_28 = OpConstant %uint 28
+ %mat2v2half = OpTypeMatrix %v2half 2
+         %94 = OpTypeFunction %mat2v2half
+    %uint_31 = OpConstant %uint 31
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+    %uint_32 = OpConstant %uint 32
+ %mat2v3half = OpTypeMatrix %v3half 2
+        %110 = OpTypeFunction %mat2v3half
+    %uint_33 = OpConstant %uint 33
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+    %uint_34 = OpConstant %uint 34
+ %mat2v4half = OpTypeMatrix %v4half 2
+        %126 = OpTypeFunction %mat2v4half
+    %uint_35 = OpConstant %uint 35
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+    %uint_36 = OpConstant %uint 36
+ %mat3v2half = OpTypeMatrix %v2half 3
+        %142 = OpTypeFunction %mat3v2half
+    %uint_37 = OpConstant %uint 37
+    %uint_38 = OpConstant %uint 38
+    %uint_39 = OpConstant %uint 39
+ %mat3v3half = OpTypeMatrix %v3half 3
+        %161 = OpTypeFunction %mat3v3half
+    %uint_40 = OpConstant %uint 40
+    %uint_41 = OpConstant %uint 41
+    %uint_42 = OpConstant %uint 42
+ %mat3v4half = OpTypeMatrix %v4half 3
+        %180 = OpTypeFunction %mat3v4half
+    %uint_43 = OpConstant %uint 43
+    %uint_44 = OpConstant %uint 44
+    %uint_45 = OpConstant %uint 45
+ %mat4v2half = OpTypeMatrix %v2half 4
+        %199 = OpTypeFunction %mat4v2half
+    %uint_46 = OpConstant %uint 46
+    %uint_47 = OpConstant %uint 47
+    %uint_48 = OpConstant %uint 48
+    %uint_49 = OpConstant %uint 49
+ %mat4v3half = OpTypeMatrix %v3half 4
+        %222 = OpTypeFunction %mat4v3half
+    %uint_50 = OpConstant %uint 50
+    %uint_51 = OpConstant %uint 51
+    %uint_52 = OpConstant %uint 52
+    %uint_53 = OpConstant %uint 53
+ %mat4v4half = OpTypeMatrix %v4half 4
+        %245 = OpTypeFunction %mat4v4half
+    %uint_54 = OpConstant %uint 54
+    %uint_55 = OpConstant %uint 55
+    %uint_56 = OpConstant %uint 56
+    %uint_57 = OpConstant %uint 57
+        %268 = OpTypeFunction %mat4v2half %mat4x2_f16_4
+%_arr_mat4v2half_uint_2 = OpTypeArray %mat4v2half %uint_2
+        %277 = OpTypeFunction %_arr_mat4v2half_uint_2 %_arr_mat4x2_f16_4_uint_2
+%_ptr_Function__arr_mat4v2half_uint_2 = OpTypePointer Function %_arr_mat4v2half_uint_2
+        %284 = OpConstantNull %_arr_mat4v2half_uint_2
+%_ptr_Function_uint = OpTypePointer Function %uint
+        %287 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_mat4x2_f16_4_uint_2 = OpTypePointer Function %_arr_mat4x2_f16_4_uint_2
+        %300 = OpConstantNull %_arr_mat4x2_f16_4_uint_2
+%_ptr_Function_mat4v2half = OpTypePointer Function %mat4v2half
+%_ptr_Function_mat4x2_f16_4 = OpTypePointer Function %mat4x2_f16_4
+     %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+        %313 = OpTypeFunction %void
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+%_ptr_Uniform_int = OpTypePointer Uniform %int
+%_ptr_Uniform_uint = OpTypePointer Uniform %uint
+     %uint_3 = OpConstant %uint 3
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+     %uint_5 = OpConstant %uint 5
+%_ptr_Uniform_v2int = OpTypePointer Uniform %v2int
+     %uint_6 = OpConstant %uint 6
+%_ptr_Uniform_v2uint = OpTypePointer Uniform %v2uint
+     %uint_7 = OpConstant %uint 7
+     %uint_8 = OpConstant %uint 8
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+     %uint_9 = OpConstant %uint 9
+%_ptr_Uniform_v3int = OpTypePointer Uniform %v3int
+    %uint_10 = OpConstant %uint 10
+%_ptr_Uniform_v3uint = OpTypePointer Uniform %v3uint
+    %uint_11 = OpConstant %uint 11
+    %uint_12 = OpConstant %uint 12
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+    %uint_13 = OpConstant %uint 13
+%_ptr_Uniform_v4int = OpTypePointer Uniform %v4int
+    %uint_14 = OpConstant %uint 14
+%_ptr_Uniform_v4uint = OpTypePointer Uniform %v4uint
+    %uint_15 = OpConstant %uint 15
+    %uint_18 = OpConstant %uint 18
+%_ptr_Uniform_mat2v3float = OpTypePointer Uniform %mat2v3float
+    %uint_19 = OpConstant %uint 19
+%_ptr_Uniform_mat2v4float = OpTypePointer Uniform %mat2v4float
+    %uint_23 = OpConstant %uint 23
+%_ptr_Uniform_mat3v3float = OpTypePointer Uniform %mat3v3float
+    %uint_24 = OpConstant %uint 24
+%_ptr_Uniform_mat3v4float = OpTypePointer Uniform %mat3v4float
+    %uint_29 = OpConstant %uint 29
+%_ptr_Uniform_mat4v3float = OpTypePointer Uniform %mat4v3float
+    %uint_30 = OpConstant %uint 30
+%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float
+    %uint_58 = OpConstant %uint 58
+%_ptr_Uniform__arr_v3float_uint_2 = OpTypePointer Uniform %_arr_v3float_uint_2
+    %uint_59 = OpConstant %uint 59
+%_ptr_Uniform__arr_mat4x2_f16_4_uint_2 = OpTypePointer Uniform %_arr_mat4x2_f16_4_uint_2
+    %uint_60 = OpConstant %uint 60
+%_ptr_Uniform_Inner = OpTypePointer Uniform %Inner
+    %uint_61 = OpConstant %uint 61
+%_ptr_Uniform__arr_Inner_uint_4 = OpTypePointer Uniform %_arr_Inner_uint_4
+%load_ub_inner_mat2x2_f32 = OpFunction %mat2v2float None %34
+         %37 = OpLabel
+         %41 = OpAccessChain %_ptr_Uniform_S_std140 %ub %uint_0
+         %45 = OpAccessChain %_ptr_Uniform_v2float %41 %uint_16
+         %46 = OpLoad %v2float %45
+         %49 = OpAccessChain %_ptr_Uniform_v2float %41 %uint_17
+         %50 = OpLoad %v2float %49
+         %51 = OpCompositeConstruct %mat2v2float %46 %50
+               OpReturnValue %51
+               OpFunctionEnd
+%load_ub_inner_mat3x2_f32 = OpFunction %mat3v2float None %52
+         %55 = OpLabel
+         %57 = OpAccessChain %_ptr_Uniform_S_std140 %ub %uint_0
+         %60 = OpAccessChain %_ptr_Uniform_v2float %57 %uint_20
+         %61 = OpLoad %v2float %60
+         %64 = OpAccessChain %_ptr_Uniform_v2float %57 %uint_21
+         %65 = OpLoad %v2float %64
+         %68 = OpAccessChain %_ptr_Uniform_v2float %57 %uint_22
+         %69 = OpLoad %v2float %68
+         %70 = OpCompositeConstruct %mat3v2float %61 %65 %69
+               OpReturnValue %70
+               OpFunctionEnd
+%load_ub_inner_mat4x2_f32 = OpFunction %mat4v2float None %71
+         %74 = OpLabel
+         %76 = OpAccessChain %_ptr_Uniform_S_std140 %ub %uint_0
+         %79 = OpAccessChain %_ptr_Uniform_v2float %76 %uint_25
+         %80 = OpLoad %v2float %79
+         %83 = OpAccessChain %_ptr_Uniform_v2float %76 %uint_26
+         %84 = OpLoad %v2float %83
+         %87 = OpAccessChain %_ptr_Uniform_v2float %76 %uint_27
+         %88 = OpLoad %v2float %87
+         %91 = OpAccessChain %_ptr_Uniform_v2float %76 %uint_28
+         %92 = OpLoad %v2float %91
+         %93 = OpCompositeConstruct %mat4v2float %80 %84 %88 %92
+               OpReturnValue %93
+               OpFunctionEnd
+%load_ub_inner_mat2x2_f16 = OpFunction %mat2v2half None %94
+         %97 = OpLabel
+         %99 = OpAccessChain %_ptr_Uniform_S_std140 %ub %uint_0
+        %103 = OpAccessChain %_ptr_Uniform_v2half %99 %uint_31
+        %104 = OpLoad %v2half %103
+        %107 = OpAccessChain %_ptr_Uniform_v2half %99 %uint_32
+        %108 = OpLoad %v2half %107
+        %109 = OpCompositeConstruct %mat2v2half %104 %108
+               OpReturnValue %109
+               OpFunctionEnd
+%load_ub_inner_mat2x3_f16 = OpFunction %mat2v3half None %110
+        %113 = OpLabel
+        %115 = OpAccessChain %_ptr_Uniform_S_std140 %ub %uint_0
+        %119 = OpAccessChain %_ptr_Uniform_v3half %115 %uint_33
+        %120 = OpLoad %v3half %119
+        %123 = OpAccessChain %_ptr_Uniform_v3half %115 %uint_34
+        %124 = OpLoad %v3half %123
+        %125 = OpCompositeConstruct %mat2v3half %120 %124
+               OpReturnValue %125
+               OpFunctionEnd
+%load_ub_inner_mat2x4_f16 = OpFunction %mat2v4half None %126
+        %129 = OpLabel
+        %131 = OpAccessChain %_ptr_Uniform_S_std140 %ub %uint_0
+        %135 = OpAccessChain %_ptr_Uniform_v4half %131 %uint_35
+        %136 = OpLoad %v4half %135
+        %139 = OpAccessChain %_ptr_Uniform_v4half %131 %uint_36
+        %140 = OpLoad %v4half %139
+        %141 = OpCompositeConstruct %mat2v4half %136 %140
+               OpReturnValue %141
+               OpFunctionEnd
+%load_ub_inner_mat3x2_f16 = OpFunction %mat3v2half None %142
+        %145 = OpLabel
+        %147 = OpAccessChain %_ptr_Uniform_S_std140 %ub %uint_0
+        %150 = OpAccessChain %_ptr_Uniform_v2half %147 %uint_37
+        %151 = OpLoad %v2half %150
+        %154 = OpAccessChain %_ptr_Uniform_v2half %147 %uint_38
+        %155 = OpLoad %v2half %154
+        %158 = OpAccessChain %_ptr_Uniform_v2half %147 %uint_39
+        %159 = OpLoad %v2half %158
+        %160 = OpCompositeConstruct %mat3v2half %151 %155 %159
+               OpReturnValue %160
+               OpFunctionEnd
+%load_ub_inner_mat3x3_f16 = OpFunction %mat3v3half None %161
+        %164 = OpLabel
+        %166 = OpAccessChain %_ptr_Uniform_S_std140 %ub %uint_0
+        %169 = OpAccessChain %_ptr_Uniform_v3half %166 %uint_40
+        %170 = OpLoad %v3half %169
+        %173 = OpAccessChain %_ptr_Uniform_v3half %166 %uint_41
+        %174 = OpLoad %v3half %173
+        %177 = OpAccessChain %_ptr_Uniform_v3half %166 %uint_42
+        %178 = OpLoad %v3half %177
+        %179 = OpCompositeConstruct %mat3v3half %170 %174 %178
+               OpReturnValue %179
+               OpFunctionEnd
+%load_ub_inner_mat3x4_f16 = OpFunction %mat3v4half None %180
+        %183 = OpLabel
+        %185 = OpAccessChain %_ptr_Uniform_S_std140 %ub %uint_0
+        %188 = OpAccessChain %_ptr_Uniform_v4half %185 %uint_43
+        %189 = OpLoad %v4half %188
+        %192 = OpAccessChain %_ptr_Uniform_v4half %185 %uint_44
+        %193 = OpLoad %v4half %192
+        %196 = OpAccessChain %_ptr_Uniform_v4half %185 %uint_45
+        %197 = OpLoad %v4half %196
+        %198 = OpCompositeConstruct %mat3v4half %189 %193 %197
+               OpReturnValue %198
+               OpFunctionEnd
+%load_ub_inner_mat4x2_f16 = OpFunction %mat4v2half None %199
+        %202 = OpLabel
+        %204 = OpAccessChain %_ptr_Uniform_S_std140 %ub %uint_0
+        %207 = OpAccessChain %_ptr_Uniform_v2half %204 %uint_46
+        %208 = OpLoad %v2half %207
+        %211 = OpAccessChain %_ptr_Uniform_v2half %204 %uint_47
+        %212 = OpLoad %v2half %211
+        %215 = OpAccessChain %_ptr_Uniform_v2half %204 %uint_48
+        %216 = OpLoad %v2half %215
+        %219 = OpAccessChain %_ptr_Uniform_v2half %204 %uint_49
+        %220 = OpLoad %v2half %219
+        %221 = OpCompositeConstruct %mat4v2half %208 %212 %216 %220
+               OpReturnValue %221
+               OpFunctionEnd
+%load_ub_inner_mat4x3_f16 = OpFunction %mat4v3half None %222
+        %225 = OpLabel
+        %227 = OpAccessChain %_ptr_Uniform_S_std140 %ub %uint_0
+        %230 = OpAccessChain %_ptr_Uniform_v3half %227 %uint_50
+        %231 = OpLoad %v3half %230
+        %234 = OpAccessChain %_ptr_Uniform_v3half %227 %uint_51
+        %235 = OpLoad %v3half %234
+        %238 = OpAccessChain %_ptr_Uniform_v3half %227 %uint_52
+        %239 = OpLoad %v3half %238
+        %242 = OpAccessChain %_ptr_Uniform_v3half %227 %uint_53
+        %243 = OpLoad %v3half %242
+        %244 = OpCompositeConstruct %mat4v3half %231 %235 %239 %243
+               OpReturnValue %244
+               OpFunctionEnd
+%load_ub_inner_mat4x4_f16 = OpFunction %mat4v4half None %245
+        %248 = OpLabel
+        %250 = OpAccessChain %_ptr_Uniform_S_std140 %ub %uint_0
+        %253 = OpAccessChain %_ptr_Uniform_v4half %250 %uint_54
+        %254 = OpLoad %v4half %253
+        %257 = OpAccessChain %_ptr_Uniform_v4half %250 %uint_55
+        %258 = OpLoad %v4half %257
+        %261 = OpAccessChain %_ptr_Uniform_v4half %250 %uint_56
+        %262 = OpLoad %v4half %261
+        %265 = OpAccessChain %_ptr_Uniform_v4half %250 %uint_57
+        %266 = OpLoad %v4half %265
+        %267 = OpCompositeConstruct %mat4v4half %254 %258 %262 %266
+               OpReturnValue %267
+               OpFunctionEnd
+%conv_mat4x2_f16 = OpFunction %mat4v2half None %268
+        %val = OpFunctionParameter %mat4x2_f16_4
+        %271 = OpLabel
+        %272 = OpCompositeExtract %v2half %val 0
+        %273 = OpCompositeExtract %v2half %val 1
+        %274 = OpCompositeExtract %v2half %val 2
+        %275 = OpCompositeExtract %v2half %val 3
+        %276 = OpCompositeConstruct %mat4v2half %272 %273 %274 %275
+               OpReturnValue %276
+               OpFunctionEnd
+%conv_arr2_mat4x2_f16 = OpFunction %_arr_mat4v2half_uint_2 None %277
+      %val_0 = OpFunctionParameter %_arr_mat4x2_f16_4_uint_2
+        %281 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_mat4v2half_uint_2 Function %284
+          %i = OpVariable %_ptr_Function_uint Function %287
+%var_for_index = OpVariable %_ptr_Function__arr_mat4x2_f16_4_uint_2 Function %300
+               OpBranch %288
+        %288 = OpLabel
+               OpLoopMerge %289 %290 None
+               OpBranch %291
+        %291 = OpLabel
+        %293 = OpLoad %uint %i
+        %294 = OpULessThan %bool %293 %uint_2
+        %292 = OpLogicalNot %bool %294
+               OpSelectionMerge %296 None
+               OpBranchConditional %292 %297 %296
+        %297 = OpLabel
+               OpBranch %289
+        %296 = OpLabel
+               OpStore %var_for_index %val_0
+        %301 = OpLoad %uint %i
+        %303 = OpAccessChain %_ptr_Function_mat4v2half %arr %301
+        %305 = OpLoad %uint %i
+        %307 = OpAccessChain %_ptr_Function_mat4x2_f16_4 %var_for_index %305
+        %308 = OpLoad %mat4x2_f16_4 %307
+        %304 = OpFunctionCall %mat4v2half %conv_mat4x2_f16 %308
+               OpStore %303 %304
+               OpBranch %290
+        %290 = OpLabel
+        %309 = OpLoad %uint %i
+        %311 = OpIAdd %uint %309 %uint_1
+               OpStore %i %311
+               OpBranch %288
+        %289 = OpLabel
+        %312 = OpLoad %_arr_mat4v2half_uint_2 %arr
+               OpReturnValue %312
+               OpFunctionEnd
+       %main = OpFunction %void None %313
+        %316 = OpLabel
+        %318 = OpAccessChain %_ptr_Uniform_float %ub %uint_0 %uint_0
+        %319 = OpLoad %float %318
+        %321 = OpAccessChain %_ptr_Uniform_int %ub %uint_0 %uint_1
+        %322 = OpLoad %int %321
+        %324 = OpAccessChain %_ptr_Uniform_uint %ub %uint_0 %uint_2
+        %325 = OpLoad %uint %324
+        %328 = OpAccessChain %_ptr_Uniform_half %ub %uint_0 %uint_3
+        %329 = OpLoad %half %328
+        %330 = OpAccessChain %_ptr_Uniform_v2float %ub %uint_0 %uint_4
+        %331 = OpLoad %v2float %330
+        %334 = OpAccessChain %_ptr_Uniform_v2int %ub %uint_0 %uint_5
+        %335 = OpLoad %v2int %334
+        %338 = OpAccessChain %_ptr_Uniform_v2uint %ub %uint_0 %uint_6
+        %339 = OpLoad %v2uint %338
+        %341 = OpAccessChain %_ptr_Uniform_v2half %ub %uint_0 %uint_7
+        %342 = OpLoad %v2half %341
+        %345 = OpAccessChain %_ptr_Uniform_v3float %ub %uint_0 %uint_8
+        %346 = OpLoad %v3float %345
+        %349 = OpAccessChain %_ptr_Uniform_v3int %ub %uint_0 %uint_9
+        %350 = OpLoad %v3int %349
+        %353 = OpAccessChain %_ptr_Uniform_v3uint %ub %uint_0 %uint_10
+        %354 = OpLoad %v3uint %353
+        %356 = OpAccessChain %_ptr_Uniform_v3half %ub %uint_0 %uint_11
+        %357 = OpLoad %v3half %356
+        %360 = OpAccessChain %_ptr_Uniform_v4float %ub %uint_0 %uint_12
+        %361 = OpLoad %v4float %360
+        %364 = OpAccessChain %_ptr_Uniform_v4int %ub %uint_0 %uint_13
+        %365 = OpLoad %v4int %364
+        %368 = OpAccessChain %_ptr_Uniform_v4uint %ub %uint_0 %uint_14
+        %369 = OpLoad %v4uint %368
+        %371 = OpAccessChain %_ptr_Uniform_v4half %ub %uint_0 %uint_15
+        %372 = OpLoad %v4half %371
+        %373 = OpFunctionCall %mat2v2float %load_ub_inner_mat2x2_f32
+        %376 = OpAccessChain %_ptr_Uniform_mat2v3float %ub %uint_0 %uint_18
+        %377 = OpLoad %mat2v3float %376
+        %380 = OpAccessChain %_ptr_Uniform_mat2v4float %ub %uint_0 %uint_19
+        %381 = OpLoad %mat2v4float %380
+        %382 = OpFunctionCall %mat3v2float %load_ub_inner_mat3x2_f32
+        %385 = OpAccessChain %_ptr_Uniform_mat3v3float %ub %uint_0 %uint_23
+        %386 = OpLoad %mat3v3float %385
+        %389 = OpAccessChain %_ptr_Uniform_mat3v4float %ub %uint_0 %uint_24
+        %390 = OpLoad %mat3v4float %389
+        %391 = OpFunctionCall %mat4v2float %load_ub_inner_mat4x2_f32
+        %394 = OpAccessChain %_ptr_Uniform_mat4v3float %ub %uint_0 %uint_29
+        %395 = OpLoad %mat4v3float %394
+        %398 = OpAccessChain %_ptr_Uniform_mat4v4float %ub %uint_0 %uint_30
+        %399 = OpLoad %mat4v4float %398
+        %400 = OpFunctionCall %mat2v2half %load_ub_inner_mat2x2_f16
+        %401 = OpFunctionCall %mat2v3half %load_ub_inner_mat2x3_f16
+        %402 = OpFunctionCall %mat2v4half %load_ub_inner_mat2x4_f16
+        %403 = OpFunctionCall %mat3v2half %load_ub_inner_mat3x2_f16
+        %404 = OpFunctionCall %mat3v3half %load_ub_inner_mat3x3_f16
+        %405 = OpFunctionCall %mat3v4half %load_ub_inner_mat3x4_f16
+        %406 = OpFunctionCall %mat4v2half %load_ub_inner_mat4x2_f16
+        %407 = OpFunctionCall %mat4v3half %load_ub_inner_mat4x3_f16
+        %408 = OpFunctionCall %mat4v4half %load_ub_inner_mat4x4_f16
+        %411 = OpAccessChain %_ptr_Uniform__arr_v3float_uint_2 %ub %uint_0 %uint_58
+        %412 = OpLoad %_arr_v3float_uint_2 %411
+        %416 = OpAccessChain %_ptr_Uniform__arr_mat4x2_f16_4_uint_2 %ub %uint_0 %uint_59
+        %417 = OpLoad %_arr_mat4x2_f16_4_uint_2 %416
+        %413 = OpFunctionCall %_arr_mat4v2half_uint_2 %conv_arr2_mat4x2_f16 %417
+        %420 = OpAccessChain %_ptr_Uniform_Inner %ub %uint_0 %uint_60
+        %421 = OpLoad %Inner %420
+        %424 = OpAccessChain %_ptr_Uniform__arr_Inner_uint_4 %ub %uint_0 %uint_61
+        %425 = OpLoad %_arr_Inner_uint_4 %424
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/static_index/read_f16.wgsl.expected.wgsl b/test/tint/buffer/uniform/static_index/read_f16.wgsl.expected.wgsl
new file mode 100644
index 0000000..808033c
--- /dev/null
+++ b/test/tint/buffer/uniform/static_index/read_f16.wgsl.expected.wgsl
@@ -0,0 +1,96 @@
+enable f16;
+
+struct Inner {
+  scalar_i32 : i32,
+  scalar_f32 : f32,
+  @size(8)
+  scalar_f16 : f16,
+}
+
+struct S {
+  scalar_f32 : f32,
+  scalar_i32 : i32,
+  scalar_u32 : u32,
+  scalar_f16 : f16,
+  vec2_f32 : vec2<f32>,
+  vec2_i32 : vec2<i32>,
+  vec2_u32 : vec2<u32>,
+  vec2_f16 : vec2<f16>,
+  vec3_f32 : vec3<f32>,
+  vec3_i32 : vec3<i32>,
+  vec3_u32 : vec3<u32>,
+  vec3_f16 : vec3<f16>,
+  vec4_f32 : vec4<f32>,
+  vec4_i32 : vec4<i32>,
+  vec4_u32 : vec4<u32>,
+  vec4_f16 : vec4<f16>,
+  mat2x2_f32 : mat2x2<f32>,
+  mat2x3_f32 : mat2x3<f32>,
+  mat2x4_f32 : mat2x4<f32>,
+  mat3x2_f32 : mat3x2<f32>,
+  mat3x3_f32 : mat3x3<f32>,
+  mat3x4_f32 : mat3x4<f32>,
+  mat4x2_f32 : mat4x2<f32>,
+  mat4x3_f32 : mat4x3<f32>,
+  mat4x4_f32 : mat4x4<f32>,
+  mat2x2_f16 : mat2x2<f16>,
+  mat2x3_f16 : mat2x3<f16>,
+  mat2x4_f16 : mat2x4<f16>,
+  mat3x2_f16 : mat3x2<f16>,
+  mat3x3_f16 : mat3x3<f16>,
+  mat3x4_f16 : mat3x4<f16>,
+  mat4x2_f16 : mat4x2<f16>,
+  mat4x3_f16 : mat4x3<f16>,
+  mat4x4_f16 : mat4x4<f16>,
+  @align(16)
+  arr2_vec3_f32 : array<vec3<f32>, 2>,
+  arr2_mat4x2_f16 : array<mat4x2<f16>, 2>,
+  @align(16)
+  struct_inner : Inner,
+  @align(16)
+  array_struct_inner : array<Inner, 4>,
+}
+
+@binding(0) @group(0) var<uniform> ub : S;
+
+@compute @workgroup_size(1)
+fn main() {
+  let scalar_f32 = ub.scalar_f32;
+  let scalar_i32 = ub.scalar_i32;
+  let scalar_u32 = ub.scalar_u32;
+  let scalar_f16 = ub.scalar_f16;
+  let vec2_f32 = ub.vec2_f32;
+  let vec2_i32 = ub.vec2_i32;
+  let vec2_u32 = ub.vec2_u32;
+  let vec2_f16 = ub.vec2_f16;
+  let vec3_f32 = ub.vec3_f32;
+  let vec3_i32 = ub.vec3_i32;
+  let vec3_u32 = ub.vec3_u32;
+  let vec3_f16 = ub.vec3_f16;
+  let vec4_f32 = ub.vec4_f32;
+  let vec4_i32 = ub.vec4_i32;
+  let vec4_u32 = ub.vec4_u32;
+  let vec4_f16 = ub.vec4_f16;
+  let mat2x2_f32 = ub.mat2x2_f32;
+  let mat2x3_f32 = ub.mat2x3_f32;
+  let mat2x4_f32 = ub.mat2x4_f32;
+  let mat3x2_f32 = ub.mat3x2_f32;
+  let mat3x3_f32 = ub.mat3x3_f32;
+  let mat3x4_f32 = ub.mat3x4_f32;
+  let mat4x2_f32 = ub.mat4x2_f32;
+  let mat4x3_f32 = ub.mat4x3_f32;
+  let mat4x4_f32 = ub.mat4x4_f32;
+  let mat2x2_f16 = ub.mat2x2_f16;
+  let mat2x3_f16 = ub.mat2x3_f16;
+  let mat2x4_f16 = ub.mat2x4_f16;
+  let mat3x2_f16 = ub.mat3x2_f16;
+  let mat3x3_f16 = ub.mat3x3_f16;
+  let mat3x4_f16 = ub.mat3x4_f16;
+  let mat4x2_f16 = ub.mat4x2_f16;
+  let mat4x3_f16 = ub.mat4x3_f16;
+  let mat4x4_f16 = ub.mat4x4_f16;
+  let arr2_vec3_f32 = ub.arr2_vec3_f32;
+  let arr2_mat4x2_f16 = ub.arr2_mat4x2_f16;
+  let struct_inner = ub.struct_inner;
+  let array_struct_inner = ub.array_struct_inner;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/to_private.wgsl b/test/tint/buffer/uniform/std140/array/mat2x2/to_private.wgsl
deleted file mode 100644
index 8a421d8..0000000
--- a/test/tint/buffer/uniform/std140/array/mat2x2/to_private.wgsl
+++ /dev/null
@@ -1,16 +0,0 @@
-struct S {
-  before : i32,
-  m : mat2x2<f32>,
-  after : i32,
-}
-
-@group(0) @binding(0) var<uniform> u : array<mat2x2<f32>, 4>;
-var<private> p : array<mat2x2<f32>, 4>;
-
-@compute @workgroup_size(1)
-fn f() {
-    p = u;
-    p[1] = u[2];
-    p[1][0] = u[0][1].yx;
-    p[1][0].x = u[0][1].x;
-}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat2x2/to_private.wgsl.expected.glsl
deleted file mode 100644
index 2118347..0000000
--- a/test/tint/buffer/uniform/std140/array/mat2x2/to_private.wgsl.expected.glsl
+++ /dev/null
@@ -1,44 +0,0 @@
-#version 310 es
-
-struct mat2x2_f32 {
-  vec2 col0;
-  vec2 col1;
-};
-
-struct S {
-  int before;
-  mat2 m;
-  int after;
-};
-
-layout(binding = 0, std140) uniform u_block_std140_ubo {
-  mat2x2_f32 inner[4];
-} u;
-
-mat2 p[4] = mat2[4](mat2(0.0f, 0.0f, 0.0f, 0.0f), mat2(0.0f, 0.0f, 0.0f, 0.0f), mat2(0.0f, 0.0f, 0.0f, 0.0f), mat2(0.0f, 0.0f, 0.0f, 0.0f));
-mat2 conv_mat2x2_f32(mat2x2_f32 val) {
-  return mat2(val.col0, val.col1);
-}
-
-mat2[4] conv_arr4_mat2x2_f32(mat2x2_f32 val[4]) {
-  mat2 arr[4] = mat2[4](mat2(0.0f, 0.0f, 0.0f, 0.0f), mat2(0.0f, 0.0f, 0.0f, 0.0f), mat2(0.0f, 0.0f, 0.0f, 0.0f), mat2(0.0f, 0.0f, 0.0f, 0.0f));
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      arr[i] = conv_mat2x2_f32(val[i]);
-    }
-  }
-  return arr;
-}
-
-void f() {
-  p = conv_arr4_mat2x2_f32(u.inner);
-  p[1] = conv_mat2x2_f32(u.inner[2u]);
-  p[1][0] = u.inner[0u].col1.yx;
-  p[1][0].x = u.inner[0u].col1[0u];
-}
-
-layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
-void main() {
-  f();
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat2x2/to_private.wgsl.expected.msl
deleted file mode 100644
index ec3ed6d..0000000
--- a/test/tint/buffer/uniform/std140/array/mat2x2/to_private.wgsl.expected.msl
+++ /dev/null
@@ -1,31 +0,0 @@
-#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 S {
-  int before;
-  float2x2 m;
-  int after;
-};
-
-kernel void f(const constant tint_array<float2x2, 4>* tint_symbol_1 [[buffer(0)]]) {
-  thread tint_array<float2x2, 4> tint_symbol = {};
-  tint_symbol = *(tint_symbol_1);
-  tint_symbol[1] = (*(tint_symbol_1))[2];
-  tint_symbol[1][0] = float2((*(tint_symbol_1))[0][1]).yx;
-  tint_symbol[1][0][0] = (*(tint_symbol_1))[0][1][0];
-  return;
-}
-
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat2x2/to_private.wgsl.expected.wgsl
deleted file mode 100644
index 732f5d6..0000000
--- a/test/tint/buffer/uniform/std140/array/mat2x2/to_private.wgsl.expected.wgsl
+++ /dev/null
@@ -1,17 +0,0 @@
-struct S {
-  before : i32,
-  m : mat2x2<f32>,
-  after : i32,
-}
-
-@group(0) @binding(0) var<uniform> u : array<mat2x2<f32>, 4>;
-
-var<private> p : array<mat2x2<f32>, 4>;
-
-@compute @workgroup_size(1)
-fn f() {
-  p = u;
-  p[1] = u[2];
-  p[1][0] = u[0][1].yx;
-  p[1][0].x = u[0][1].x;
-}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/to_storage.wgsl b/test/tint/buffer/uniform/std140/array/mat2x2/to_storage.wgsl
deleted file mode 100644
index 3a40144..0000000
--- a/test/tint/buffer/uniform/std140/array/mat2x2/to_storage.wgsl
+++ /dev/null
@@ -1,16 +0,0 @@
-struct S {
-  before : i32,
-  m : mat2x2<f32>,
-  after : i32,
-}
-
-@group(0) @binding(0) var<uniform> u : array<mat2x2<f32>, 4>;
-@group(0) @binding(1) var<storage, read_write> s : array<mat2x2<f32>, 4>;
-
-@compute @workgroup_size(1)
-fn f() {
-    s = u;
-    s[1] = u[2];
-    s[1][0] = u[0][1].yx;
-    s[1][0].x = u[0][1].x;
-}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat2x2/to_storage.wgsl.expected.glsl
deleted file mode 100644
index c6be613..0000000
--- a/test/tint/buffer/uniform/std140/array/mat2x2/to_storage.wgsl.expected.glsl
+++ /dev/null
@@ -1,47 +0,0 @@
-#version 310 es
-
-struct mat2x2_f32 {
-  vec2 col0;
-  vec2 col1;
-};
-
-struct S {
-  int before;
-  mat2 m;
-  int after;
-};
-
-layout(binding = 0, std140) uniform u_block_std140_ubo {
-  mat2x2_f32 inner[4];
-} u;
-
-layout(binding = 1, std430) buffer u_block_ssbo {
-  mat2 inner[4];
-} s;
-
-mat2 conv_mat2x2_f32(mat2x2_f32 val) {
-  return mat2(val.col0, val.col1);
-}
-
-mat2[4] conv_arr4_mat2x2_f32(mat2x2_f32 val[4]) {
-  mat2 arr[4] = mat2[4](mat2(0.0f, 0.0f, 0.0f, 0.0f), mat2(0.0f, 0.0f, 0.0f, 0.0f), mat2(0.0f, 0.0f, 0.0f, 0.0f), mat2(0.0f, 0.0f, 0.0f, 0.0f));
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      arr[i] = conv_mat2x2_f32(val[i]);
-    }
-  }
-  return arr;
-}
-
-void f() {
-  s.inner = conv_arr4_mat2x2_f32(u.inner);
-  s.inner[1] = conv_mat2x2_f32(u.inner[2u]);
-  s.inner[1][0] = u.inner[0u].col1.yx;
-  s.inner[1][0].x = u.inner[0u].col1[0u];
-}
-
-layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
-void main() {
-  f();
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat2x2/to_storage.wgsl.expected.msl
deleted file mode 100644
index 892ef66..0000000
--- a/test/tint/buffer/uniform/std140/array/mat2x2/to_storage.wgsl.expected.msl
+++ /dev/null
@@ -1,30 +0,0 @@
-#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 S {
-  int before;
-  float2x2 m;
-  int after;
-};
-
-kernel void f(device tint_array<float2x2, 4>* tint_symbol [[buffer(1)]], const constant tint_array<float2x2, 4>* tint_symbol_1 [[buffer(0)]]) {
-  *(tint_symbol) = *(tint_symbol_1);
-  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
-  (*(tint_symbol))[1][0] = float2((*(tint_symbol_1))[0][1]).yx;
-  (*(tint_symbol))[1][0][0] = (*(tint_symbol_1))[0][1][0];
-  return;
-}
-
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat2x2/to_storage.wgsl.expected.wgsl
deleted file mode 100644
index 1173503..0000000
--- a/test/tint/buffer/uniform/std140/array/mat2x2/to_storage.wgsl.expected.wgsl
+++ /dev/null
@@ -1,17 +0,0 @@
-struct S {
-  before : i32,
-  m : mat2x2<f32>,
-  after : i32,
-}
-
-@group(0) @binding(0) var<uniform> u : array<mat2x2<f32>, 4>;
-
-@group(0) @binding(1) var<storage, read_write> s : array<mat2x2<f32>, 4>;
-
-@compute @workgroup_size(1)
-fn f() {
-  s = u;
-  s[1] = u[2];
-  s[1][0] = u[0][1].yx;
-  s[1][0].x = u[0][1].x;
-}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/array/mat2x2/to_workgroup.wgsl
deleted file mode 100644
index 08ce8f6..0000000
--- a/test/tint/buffer/uniform/std140/array/mat2x2/to_workgroup.wgsl
+++ /dev/null
@@ -1,16 +0,0 @@
-struct S {
-  before : i32,
-  m : mat2x2<f32>,
-  after : i32,
-}
-
-@group(0) @binding(0) var<uniform> u : array<mat2x2<f32>, 4>;
-var<workgroup> w : array<mat2x2<f32>, 4>;
-
-@compute @workgroup_size(1)
-fn f() {
-    w = u;
-    w[1] = u[2];
-    w[1][0] = u[0][1].yx;
-    w[1][0].x = u[0][1].x;
-}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat2x2/to_workgroup.wgsl.expected.glsl
deleted file mode 100644
index e459ce3..0000000
--- a/test/tint/buffer/uniform/std140/array/mat2x2/to_workgroup.wgsl.expected.glsl
+++ /dev/null
@@ -1,51 +0,0 @@
-#version 310 es
-
-struct mat2x2_f32 {
-  vec2 col0;
-  vec2 col1;
-};
-
-struct S {
-  int before;
-  mat2 m;
-  int after;
-};
-
-layout(binding = 0, std140) uniform u_block_std140_ubo {
-  mat2x2_f32 inner[4];
-} u;
-
-shared mat2 w[4];
-mat2 conv_mat2x2_f32(mat2x2_f32 val) {
-  return mat2(val.col0, val.col1);
-}
-
-mat2[4] conv_arr4_mat2x2_f32(mat2x2_f32 val[4]) {
-  mat2 arr[4] = mat2[4](mat2(0.0f, 0.0f, 0.0f, 0.0f), mat2(0.0f, 0.0f, 0.0f, 0.0f), mat2(0.0f, 0.0f, 0.0f, 0.0f), mat2(0.0f, 0.0f, 0.0f, 0.0f));
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      arr[i] = conv_mat2x2_f32(val[i]);
-    }
-  }
-  return arr;
-}
-
-void f(uint local_invocation_index) {
-  {
-    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
-      uint i = idx;
-      w[i] = mat2(vec2(0.0f), vec2(0.0f));
-    }
-  }
-  barrier();
-  w = conv_arr4_mat2x2_f32(u.inner);
-  w[1] = conv_mat2x2_f32(u.inner[2u]);
-  w[1][0] = u.inner[0u].col1.yx;
-  w[1][0].x = u.inner[0u].col1[0u];
-}
-
-layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
-void main() {
-  f(gl_LocalInvocationIndex);
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat2x2/to_workgroup.wgsl.expected.msl
deleted file mode 100644
index 4f8574d..0000000
--- a/test/tint/buffer/uniform/std140/array/mat2x2/to_workgroup.wgsl.expected.msl
+++ /dev/null
@@ -1,44 +0,0 @@
-#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_symbol_5 {
-  tint_array<float2x2, 4> w;
-};
-
-struct S {
-  int before;
-  float2x2 m;
-  int after;
-};
-
-void f_inner(uint local_invocation_index, threadgroup tint_array<float2x2, 4>* const tint_symbol, const constant tint_array<float2x2, 4>* const tint_symbol_1) {
-  for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
-    uint const i = idx;
-    (*(tint_symbol))[i] = float2x2(float2(0.0f), float2(0.0f));
-  }
-  threadgroup_barrier(mem_flags::mem_threadgroup);
-  *(tint_symbol) = *(tint_symbol_1);
-  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
-  (*(tint_symbol))[1][0] = float2((*(tint_symbol_1))[0][1]).yx;
-  (*(tint_symbol))[1][0][0] = (*(tint_symbol_1))[0][1][0];
-}
-
-kernel void f(const constant tint_array<float2x2, 4>* tint_symbol_4 [[buffer(0)]], threadgroup tint_symbol_5* tint_symbol_3 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
-  threadgroup tint_array<float2x2, 4>* const tint_symbol_2 = &((*(tint_symbol_3)).w);
-  f_inner(local_invocation_index, tint_symbol_2, tint_symbol_4);
-  return;
-}
-
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat2x2/to_workgroup.wgsl.expected.wgsl
deleted file mode 100644
index fdb82d0..0000000
--- a/test/tint/buffer/uniform/std140/array/mat2x2/to_workgroup.wgsl.expected.wgsl
+++ /dev/null
@@ -1,17 +0,0 @@
-struct S {
-  before : i32,
-  m : mat2x2<f32>,
-  after : i32,
-}
-
-@group(0) @binding(0) var<uniform> u : array<mat2x2<f32>, 4>;
-
-var<workgroup> w : array<mat2x2<f32>, 4>;
-
-@compute @workgroup_size(1)
-fn f() {
-  w = u;
-  w[1] = u[2];
-  w[1][0] = u[0][1].yx;
-  w[1][0].x = u[0][1].x;
-}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/array/mat2x2_f32/dynamic_index_via_ptr.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat2x2/dynamic_index_via_ptr.wgsl
rename to test/tint/buffer/uniform/std140/array/mat2x2_f32/dynamic_index_via_ptr.wgsl
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x2_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat2x2/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/uniform/std140/array/mat2x2_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x2_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat2x2/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/uniform/std140/array/mat2x2_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat2x2_f32/dynamic_index_via_ptr.wgsl.expected.glsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat2x2/dynamic_index_via_ptr.wgsl.expected.glsl
rename to test/tint/buffer/uniform/std140/array/mat2x2_f32/dynamic_index_via_ptr.wgsl.expected.glsl
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat2x2_f32/dynamic_index_via_ptr.wgsl.expected.msl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat2x2/dynamic_index_via_ptr.wgsl.expected.msl
rename to test/tint/buffer/uniform/std140/array/mat2x2_f32/dynamic_index_via_ptr.wgsl.expected.msl
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat2x2_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat2x2/dynamic_index_via_ptr.wgsl.expected.spvasm
rename to test/tint/buffer/uniform/std140/array/mat2x2_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat2x2_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat2x2/dynamic_index_via_ptr.wgsl.expected.wgsl
rename to test/tint/buffer/uniform/std140/array/mat2x2_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/array/mat2x2_f32/static_index_via_ptr.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat2x2/static_index_via_ptr.wgsl
rename to test/tint/buffer/uniform/std140/array/mat2x2_f32/static_index_via_ptr.wgsl
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x2_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat2x2/static_index_via_ptr.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/uniform/std140/array/mat2x2_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x2_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat2x2/static_index_via_ptr.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/uniform/std140/array/mat2x2_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat2x2_f32/static_index_via_ptr.wgsl.expected.glsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat2x2/static_index_via_ptr.wgsl.expected.glsl
rename to test/tint/buffer/uniform/std140/array/mat2x2_f32/static_index_via_ptr.wgsl.expected.glsl
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat2x2_f32/static_index_via_ptr.wgsl.expected.msl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat2x2/static_index_via_ptr.wgsl.expected.msl
rename to test/tint/buffer/uniform/std140/array/mat2x2_f32/static_index_via_ptr.wgsl.expected.msl
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat2x2_f32/static_index_via_ptr.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat2x2/static_index_via_ptr.wgsl.expected.spvasm
rename to test/tint/buffer/uniform/std140/array/mat2x2_f32/static_index_via_ptr.wgsl.expected.spvasm
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat2x2_f32/static_index_via_ptr.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat2x2/static_index_via_ptr.wgsl.expected.wgsl
rename to test/tint/buffer/uniform/std140/array/mat2x2_f32/static_index_via_ptr.wgsl.expected.wgsl
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/to_builtin.wgsl b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_builtin.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat2x2/to_builtin.wgsl
rename to test/tint/buffer/uniform/std140/array/mat2x2_f32/to_builtin.wgsl
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_builtin.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat2x2/to_builtin.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/uniform/std140/array/mat2x2_f32/to_builtin.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_builtin.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat2x2/to_builtin.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/uniform/std140/array/mat2x2_f32/to_builtin.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_builtin.wgsl.expected.glsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat2x2/to_builtin.wgsl.expected.glsl
rename to test/tint/buffer/uniform/std140/array/mat2x2_f32/to_builtin.wgsl.expected.glsl
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_builtin.wgsl.expected.msl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat2x2/to_builtin.wgsl.expected.msl
rename to test/tint/buffer/uniform/std140/array/mat2x2_f32/to_builtin.wgsl.expected.msl
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_builtin.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat2x2/to_builtin.wgsl.expected.spvasm
rename to test/tint/buffer/uniform/std140/array/mat2x2_f32/to_builtin.wgsl.expected.spvasm
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_builtin.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat2x2/to_builtin.wgsl.expected.wgsl
rename to test/tint/buffer/uniform/std140/array/mat2x2_f32/to_builtin.wgsl.expected.wgsl
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/to_fn.wgsl b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_fn.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat2x2/to_fn.wgsl
rename to test/tint/buffer/uniform/std140/array/mat2x2_f32/to_fn.wgsl
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_fn.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat2x2/to_fn.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/uniform/std140/array/mat2x2_f32/to_fn.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_fn.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat2x2/to_fn.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/uniform/std140/array/mat2x2_f32/to_fn.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_fn.wgsl.expected.glsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat2x2/to_fn.wgsl.expected.glsl
rename to test/tint/buffer/uniform/std140/array/mat2x2_f32/to_fn.wgsl.expected.glsl
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_fn.wgsl.expected.msl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat2x2/to_fn.wgsl.expected.msl
rename to test/tint/buffer/uniform/std140/array/mat2x2_f32/to_fn.wgsl.expected.msl
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_fn.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat2x2/to_fn.wgsl.expected.spvasm
rename to test/tint/buffer/uniform/std140/array/mat2x2_f32/to_fn.wgsl.expected.spvasm
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_fn.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat2x2/to_fn.wgsl.expected.wgsl
rename to test/tint/buffer/uniform/std140/array/mat2x2_f32/to_fn.wgsl.expected.wgsl
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_private.wgsl b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_private.wgsl
new file mode 100644
index 0000000..29bc615
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_private.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0) var<uniform> u : array<mat2x2<f32>, 4>;
+var<private> p : array<mat2x2<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[2];
+    p[1][0] = u[0][1].yx;
+    p[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_private.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat2x2/to_private.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/uniform/std140/array/mat2x2_f32/to_private.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_private.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat2x2/to_private.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/uniform/std140/array/mat2x2_f32/to_private.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..15386d0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_private.wgsl.expected.glsl
@@ -0,0 +1,38 @@
+#version 310 es
+
+struct mat2x2_f32 {
+  vec2 col0;
+  vec2 col1;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  mat2x2_f32 inner[4];
+} u;
+
+mat2 p[4] = mat2[4](mat2(0.0f, 0.0f, 0.0f, 0.0f), mat2(0.0f, 0.0f, 0.0f, 0.0f), mat2(0.0f, 0.0f, 0.0f, 0.0f), mat2(0.0f, 0.0f, 0.0f, 0.0f));
+mat2 conv_mat2x2_f32(mat2x2_f32 val) {
+  return mat2(val.col0, val.col1);
+}
+
+mat2[4] conv_arr4_mat2x2_f32(mat2x2_f32 val[4]) {
+  mat2 arr[4] = mat2[4](mat2(0.0f, 0.0f, 0.0f, 0.0f), mat2(0.0f, 0.0f, 0.0f, 0.0f), mat2(0.0f, 0.0f, 0.0f, 0.0f), mat2(0.0f, 0.0f, 0.0f, 0.0f));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat2x2_f32(val[i]);
+    }
+  }
+  return arr;
+}
+
+void f() {
+  p = conv_arr4_mat2x2_f32(u.inner);
+  p[1] = conv_mat2x2_f32(u.inner[2u]);
+  p[1][0] = u.inner[0u].col1.yx;
+  p[1][0].x = u.inner[0u].col1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..c9084b3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_private.wgsl.expected.msl
@@ -0,0 +1,25 @@
+#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];
+};
+
+kernel void f(const constant tint_array<float2x2, 4>* tint_symbol_1 [[buffer(0)]]) {
+  thread tint_array<float2x2, 4> tint_symbol = {};
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[2];
+  tint_symbol[1][0] = float2((*(tint_symbol_1))[0][1]).yx;
+  tint_symbol[1][0][0] = (*(tint_symbol_1))[0][1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_private.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat2x2/to_private.wgsl.expected.spvasm
rename to test/tint/buffer/uniform/std140/array/mat2x2_f32/to_private.wgsl.expected.spvasm
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..9636d9a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_private.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> u : array<mat2x2<f32>, 4>;
+
+var<private> p : array<mat2x2<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[2];
+  p[1][0] = u[0][1].yx;
+  p[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_storage.wgsl b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_storage.wgsl
new file mode 100644
index 0000000..3243429
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_storage.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0) var<uniform> u : array<mat2x2<f32>, 4>;
+@group(0) @binding(1) var<storage, read_write> s : array<mat2x2<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[2];
+    s[1][0] = u[0][1].yx;
+    s[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_storage.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat2x2/to_storage.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/uniform/std140/array/mat2x2_f32/to_storage.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_storage.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat2x2/to_storage.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/uniform/std140/array/mat2x2_f32/to_storage.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..059d58a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_storage.wgsl.expected.glsl
@@ -0,0 +1,41 @@
+#version 310 es
+
+struct mat2x2_f32 {
+  vec2 col0;
+  vec2 col1;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  mat2x2_f32 inner[4];
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  mat2 inner[4];
+} s;
+
+mat2 conv_mat2x2_f32(mat2x2_f32 val) {
+  return mat2(val.col0, val.col1);
+}
+
+mat2[4] conv_arr4_mat2x2_f32(mat2x2_f32 val[4]) {
+  mat2 arr[4] = mat2[4](mat2(0.0f, 0.0f, 0.0f, 0.0f), mat2(0.0f, 0.0f, 0.0f, 0.0f), mat2(0.0f, 0.0f, 0.0f, 0.0f), mat2(0.0f, 0.0f, 0.0f, 0.0f));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat2x2_f32(val[i]);
+    }
+  }
+  return arr;
+}
+
+void f() {
+  s.inner = conv_arr4_mat2x2_f32(u.inner);
+  s.inner[1] = conv_mat2x2_f32(u.inner[2u]);
+  s.inner[1][0] = u.inner[0u].col1.yx;
+  s.inner[1][0].x = u.inner[0u].col1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..2a08172
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_storage.wgsl.expected.msl
@@ -0,0 +1,24 @@
+#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];
+};
+
+kernel void f(device tint_array<float2x2, 4>* tint_symbol [[buffer(1)]], const constant tint_array<float2x2, 4>* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
+  (*(tint_symbol))[1][0] = float2((*(tint_symbol_1))[0][1]).yx;
+  (*(tint_symbol))[1][0][0] = (*(tint_symbol_1))[0][1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_storage.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat2x2/to_storage.wgsl.expected.spvasm
rename to test/tint/buffer/uniform/std140/array/mat2x2_f32/to_storage.wgsl.expected.spvasm
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..b19ff20
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> u : array<mat2x2<f32>, 4>;
+
+@group(0) @binding(1) var<storage, read_write> s : array<mat2x2<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[2];
+  s[1][0] = u[0][1].yx;
+  s[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_workgroup.wgsl
new file mode 100644
index 0000000..02839e7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_workgroup.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0) var<uniform> u : array<mat2x2<f32>, 4>;
+var<workgroup> w : array<mat2x2<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[2];
+    w[1][0] = u[0][1].yx;
+    w[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_workgroup.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat2x2/to_workgroup.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/uniform/std140/array/mat2x2_f32/to_workgroup.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_workgroup.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat2x2/to_workgroup.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/uniform/std140/array/mat2x2_f32/to_workgroup.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..9108de5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,45 @@
+#version 310 es
+
+struct mat2x2_f32 {
+  vec2 col0;
+  vec2 col1;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  mat2x2_f32 inner[4];
+} u;
+
+shared mat2 w[4];
+mat2 conv_mat2x2_f32(mat2x2_f32 val) {
+  return mat2(val.col0, val.col1);
+}
+
+mat2[4] conv_arr4_mat2x2_f32(mat2x2_f32 val[4]) {
+  mat2 arr[4] = mat2[4](mat2(0.0f, 0.0f, 0.0f, 0.0f), mat2(0.0f, 0.0f, 0.0f, 0.0f), mat2(0.0f, 0.0f, 0.0f, 0.0f), mat2(0.0f, 0.0f, 0.0f, 0.0f));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat2x2_f32(val[i]);
+    }
+  }
+  return arr;
+}
+
+void f(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      uint i = idx;
+      w[i] = mat2(vec2(0.0f), vec2(0.0f));
+    }
+  }
+  barrier();
+  w = conv_arr4_mat2x2_f32(u.inner);
+  w[1] = conv_mat2x2_f32(u.inner[2u]);
+  w[1][0] = u.inner[0u].col1.yx;
+  w[1][0].x = u.inner[0u].col1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..355d60e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,38 @@
+#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_symbol_5 {
+  tint_array<float2x2, 4> w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup tint_array<float2x2, 4>* const tint_symbol, const constant tint_array<float2x2, 4>* const tint_symbol_1) {
+  for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+    uint const i = idx;
+    (*(tint_symbol))[i] = float2x2(float2(0.0f), float2(0.0f));
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
+  (*(tint_symbol))[1][0] = float2((*(tint_symbol_1))[0][1]).yx;
+  (*(tint_symbol))[1][0][0] = (*(tint_symbol_1))[0][1][0];
+}
+
+kernel void f(const constant tint_array<float2x2, 4>* tint_symbol_4 [[buffer(0)]], threadgroup tint_symbol_5* tint_symbol_3 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup tint_array<float2x2, 4>* const tint_symbol_2 = &((*(tint_symbol_3)).w);
+  f_inner(local_invocation_index, tint_symbol_2, tint_symbol_4);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_workgroup.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat2x2/to_workgroup.wgsl.expected.spvasm
rename to test/tint/buffer/uniform/std140/array/mat2x2_f32/to_workgroup.wgsl.expected.spvasm
diff --git a/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..2aaff97
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x2_f32/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> u : array<mat2x2<f32>, 4>;
+
+var<workgroup> w : array<mat2x2<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[2];
+  w[1][0] = u[0][1].yx;
+  w[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/array/mat2x3_f16/dynamic_index_via_ptr.wgsl
new file mode 100644
index 0000000..d113381
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/dynamic_index_via_ptr.wgsl
@@ -0,0 +1,17 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> a : array<mat2x3<f16>, 4>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a       = &a;
+  let p_a_i     = &((*p_a)[i()]);
+  let p_a_i_i   = &((*p_a_i)[i()]);
+
+  let l_a       : array<mat2x3<f16>, 4> = *p_a;
+  let l_a_i     : mat2x3<f16>           = *p_a_i;
+  let l_a_i_i   : vec3<f16>             = *p_a_i_i;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..43a8682
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,49 @@
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[4];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 2, 3> tint_symbol_1(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
+}
+
+typedef matrix<float16_t, 2, 3> tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[4], uint offset) {
+  matrix<float16_t, 2, 3> arr[4] = (matrix<float16_t, 2, 3>[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 16u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_i_save = i();
+  const matrix<float16_t, 2, 3> l_a[4] = tint_symbol(a, 0u);
+  const matrix<float16_t, 2, 3> l_a_i = tint_symbol_1(a, (16u * uint(p_a_i_save)));
+  const uint scalar_offset_2 = (((16u * uint(p_a_i_save)) + (8u * uint(p_a_i_i_save)))) / 4;
+  uint4 ubo_load_5 = a[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const vector<float16_t, 3> l_a_i_i = vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..245be9a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,54 @@
+SKIP: FAILED
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[4];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 2, 3> tint_symbol_1(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
+}
+
+typedef matrix<float16_t, 2, 3> tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[4], uint offset) {
+  matrix<float16_t, 2, 3> arr[4] = (matrix<float16_t, 2, 3>[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 16u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_i_save = i();
+  const matrix<float16_t, 2, 3> l_a[4] = tint_symbol(a, 0u);
+  const matrix<float16_t, 2, 3> l_a_i = tint_symbol_1(a, (16u * uint(p_a_i_save)));
+  const uint scalar_offset_2 = (((16u * uint(p_a_i_save)) + (8u * uint(p_a_i_i_save)))) / 4;
+  uint4 ubo_load_5 = a[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const vector<float16_t, 3> l_a_i_i = vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001F4D5AC4540(11,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..75fe088
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,65 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct mat2x3_f16 {
+  f16vec3 col0;
+  f16vec3 col1;
+};
+
+layout(binding = 0, std140) uniform a_block_std140_ubo {
+  mat2x3_f16 inner[4];
+} a;
+
+int counter = 0;
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+f16mat2x3 conv_mat2x3_f16(mat2x3_f16 val) {
+  return f16mat2x3(val.col0, val.col1);
+}
+
+f16mat2x3[4] conv_arr4_mat2x3_f16(mat2x3_f16 val[4]) {
+  f16mat2x3 arr[4] = f16mat2x3[4](f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat2x3_f16(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16vec3 load_a_inner_p0_p1(uint p0, uint p1) {
+  switch(p1) {
+    case 0u: {
+      return a.inner[p0].col0;
+      break;
+    }
+    case 1u: {
+      return a.inner[p0].col1;
+      break;
+    }
+    default: {
+      return f16vec3(0.0hf);
+      break;
+    }
+  }
+}
+
+void f() {
+  f16mat2x3 p_a[4] = conv_arr4_mat2x3_f16(a.inner);
+  int tint_symbol = i();
+  f16mat2x3 p_a_i = conv_mat2x3_f16(a.inner[tint_symbol]);
+  int tint_symbol_1 = i();
+  f16vec3 p_a_i_i = load_a_inner_p0_p1(uint(tint_symbol), uint(tint_symbol_1));
+  f16mat2x3 l_a[4] = conv_arr4_mat2x3_f16(a.inner);
+  f16mat2x3 l_a_i = conv_mat2x3_f16(a.inner[tint_symbol]);
+  f16vec3 l_a_i_i = load_a_inner_p0_p1(uint(tint_symbol), uint(tint_symbol_1));
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..51600fc
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,33 @@
+#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];
+};
+
+int i() {
+  thread int tint_symbol_2 = 0;
+  tint_symbol_2 = as_type<int>((as_type<uint>(tint_symbol_2) + as_type<uint>(1)));
+  return tint_symbol_2;
+}
+
+kernel void f(const constant tint_array<half2x3, 4>* tint_symbol_3 [[buffer(0)]]) {
+  int const tint_symbol = i();
+  int const p_a_i_save = tint_symbol;
+  int const tint_symbol_1 = i();
+  int const p_a_i_i_save = tint_symbol_1;
+  tint_array<half2x3, 4> const l_a = *(tint_symbol_3);
+  half2x3 const l_a_i = (*(tint_symbol_3))[p_a_i_save];
+  half3 const l_a_i_i = (*(tint_symbol_3))[p_a_i_save][p_a_i_i_save];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..1834758
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,165 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 98
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block_std140 "a_block_std140"
+               OpMemberName %a_block_std140 0 "inner"
+               OpName %mat2x3_f16 "mat2x3_f16"
+               OpMemberName %mat2x3_f16 0 "col0"
+               OpMemberName %mat2x3_f16 1 "col1"
+               OpName %a "a"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %conv_mat2x3_f16 "conv_mat2x3_f16"
+               OpName %val "val"
+               OpName %conv_arr4_mat2x3_f16 "conv_arr4_mat2x3_f16"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i_0 "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_a_inner_p0_p1 "load_a_inner_p0_p1"
+               OpName %p0 "p0"
+               OpName %p1 "p1"
+               OpName %f "f"
+               OpDecorate %a_block_std140 Block
+               OpMemberDecorate %a_block_std140 0 Offset 0
+               OpMemberDecorate %mat2x3_f16 0 Offset 0
+               OpMemberDecorate %mat2x3_f16 1 Offset 8
+               OpDecorate %_arr_mat2x3_f16_uint_4 ArrayStride 16
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+               OpDecorate %_arr_mat2v3half_uint_4 ArrayStride 16
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+ %mat2x3_f16 = OpTypeStruct %v3half %v3half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat2x3_f16_uint_4 = OpTypeArray %mat2x3_f16 %uint_4
+%a_block_std140 = OpTypeStruct %_arr_mat2x3_f16_uint_4
+%_ptr_Uniform_a_block_std140 = OpTypePointer Uniform %a_block_std140
+          %a = OpVariable %_ptr_Uniform_a_block_std140 Uniform
+        %int = OpTypeInt 32 1
+         %11 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %11
+         %14 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+ %mat2v3half = OpTypeMatrix %v3half 2
+         %21 = OpTypeFunction %mat2v3half %mat2x3_f16
+%_arr_mat2v3half_uint_4 = OpTypeArray %mat2v3half %uint_4
+         %29 = OpTypeFunction %_arr_mat2v3half_uint_4 %_arr_mat2x3_f16_uint_4
+%_ptr_Function__arr_mat2v3half_uint_4 = OpTypePointer Function %_arr_mat2v3half_uint_4
+         %36 = OpConstantNull %_arr_mat2v3half_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %39 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_mat2x3_f16_uint_4 = OpTypePointer Function %_arr_mat2x3_f16_uint_4
+         %52 = OpConstantNull %_arr_mat2x3_f16_uint_4
+%_ptr_Function_mat2v3half = OpTypePointer Function %mat2v3half
+%_ptr_Function_mat2x3_f16 = OpTypePointer Function %mat2x3_f16
+     %uint_1 = OpConstant %uint 1
+         %65 = OpTypeFunction %v3half %uint %uint
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+         %80 = OpConstantNull %v3half
+       %void = OpTypeVoid
+         %81 = OpTypeFunction %void
+%_ptr_Uniform__arr_mat2x3_f16_uint_4 = OpTypePointer Uniform %_arr_mat2x3_f16_uint_4
+%_ptr_Uniform_mat2x3_f16 = OpTypePointer Uniform %mat2x3_f16
+          %i = OpFunction %int None %14
+         %16 = OpLabel
+         %17 = OpLoad %int %counter
+         %19 = OpIAdd %int %17 %int_1
+               OpStore %counter %19
+         %20 = OpLoad %int %counter
+               OpReturnValue %20
+               OpFunctionEnd
+%conv_mat2x3_f16 = OpFunction %mat2v3half None %21
+        %val = OpFunctionParameter %mat2x3_f16
+         %25 = OpLabel
+         %26 = OpCompositeExtract %v3half %val 0
+         %27 = OpCompositeExtract %v3half %val 1
+         %28 = OpCompositeConstruct %mat2v3half %26 %27
+               OpReturnValue %28
+               OpFunctionEnd
+%conv_arr4_mat2x3_f16 = OpFunction %_arr_mat2v3half_uint_4 None %29
+      %val_0 = OpFunctionParameter %_arr_mat2x3_f16_uint_4
+         %33 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_mat2v3half_uint_4 Function %36
+        %i_0 = OpVariable %_ptr_Function_uint Function %39
+%var_for_index = OpVariable %_ptr_Function__arr_mat2x3_f16_uint_4 Function %52
+               OpBranch %40
+         %40 = OpLabel
+               OpLoopMerge %41 %42 None
+               OpBranch %43
+         %43 = OpLabel
+         %45 = OpLoad %uint %i_0
+         %46 = OpULessThan %bool %45 %uint_4
+         %44 = OpLogicalNot %bool %46
+               OpSelectionMerge %48 None
+               OpBranchConditional %44 %49 %48
+         %49 = OpLabel
+               OpBranch %41
+         %48 = OpLabel
+               OpStore %var_for_index %val_0
+         %53 = OpLoad %uint %i_0
+         %55 = OpAccessChain %_ptr_Function_mat2v3half %arr %53
+         %57 = OpLoad %uint %i_0
+         %59 = OpAccessChain %_ptr_Function_mat2x3_f16 %var_for_index %57
+         %60 = OpLoad %mat2x3_f16 %59
+         %56 = OpFunctionCall %mat2v3half %conv_mat2x3_f16 %60
+               OpStore %55 %56
+               OpBranch %42
+         %42 = OpLabel
+         %61 = OpLoad %uint %i_0
+         %63 = OpIAdd %uint %61 %uint_1
+               OpStore %i_0 %63
+               OpBranch %40
+         %41 = OpLabel
+         %64 = OpLoad %_arr_mat2v3half_uint_4 %arr
+               OpReturnValue %64
+               OpFunctionEnd
+%load_a_inner_p0_p1 = OpFunction %v3half None %65
+         %p0 = OpFunctionParameter %uint
+         %p1 = OpFunctionParameter %uint
+         %69 = OpLabel
+               OpSelectionMerge %70 None
+               OpSwitch %p1 %71 0 %72 1 %73
+         %72 = OpLabel
+         %76 = OpAccessChain %_ptr_Uniform_v3half %a %uint_0 %p0 %uint_0
+         %77 = OpLoad %v3half %76
+               OpReturnValue %77
+         %73 = OpLabel
+         %78 = OpAccessChain %_ptr_Uniform_v3half %a %uint_0 %p0 %uint_1
+         %79 = OpLoad %v3half %78
+               OpReturnValue %79
+         %71 = OpLabel
+               OpReturnValue %80
+         %70 = OpLabel
+               OpReturnValue %80
+               OpFunctionEnd
+          %f = OpFunction %void None %81
+         %84 = OpLabel
+         %85 = OpFunctionCall %int %i
+         %86 = OpFunctionCall %int %i
+         %89 = OpAccessChain %_ptr_Uniform__arr_mat2x3_f16_uint_4 %a %uint_0
+         %90 = OpLoad %_arr_mat2x3_f16_uint_4 %89
+         %87 = OpFunctionCall %_arr_mat2v3half_uint_4 %conv_arr4_mat2x3_f16 %90
+         %93 = OpAccessChain %_ptr_Uniform_mat2x3_f16 %a %uint_0 %85
+         %94 = OpLoad %mat2x3_f16 %93
+         %91 = OpFunctionCall %mat2v3half %conv_mat2x3_f16 %94
+         %96 = OpBitcast %uint %85
+         %97 = OpBitcast %uint %86
+         %95 = OpFunctionCall %v3half %load_a_inner_p0_p1 %96 %97
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..ce82043
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,20 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> a : array<mat2x3<f16>, 4>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_i = &((*(p_a))[i()]);
+  let p_a_i_i = &((*(p_a_i))[i()]);
+  let l_a : array<mat2x3<f16>, 4> = *(p_a);
+  let l_a_i : mat2x3<f16> = *(p_a_i);
+  let l_a_i_i : vec3<f16> = *(p_a_i_i);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/array/mat2x3_f16/static_index_via_ptr.wgsl
new file mode 100644
index 0000000..2cd3d2e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/static_index_via_ptr.wgsl
@@ -0,0 +1,14 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> a : array<mat2x3<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a       = &a;
+  let p_a_2     = &((*p_a)[2]);
+  let p_a_2_1   = &((*p_a_2)[1]);
+
+  let l_a       : array<mat2x3<f16>, 4> = *p_a;
+  let l_a_i     : mat2x3<f16>           = *p_a_2;
+  let l_a_i_i   : vec3<f16>             = *p_a_2_1;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x3_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..6a66652
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,39 @@
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[4];
+};
+
+matrix<float16_t, 2, 3> tint_symbol_1(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
+}
+
+typedef matrix<float16_t, 2, 3> tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[4], uint offset) {
+  matrix<float16_t, 2, 3> arr[4] = (matrix<float16_t, 2, 3>[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 16u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 2, 3> l_a[4] = tint_symbol(a, 0u);
+  const matrix<float16_t, 2, 3> l_a_i = tint_symbol_1(a, 32u);
+  uint2 ubo_load_4 = a[2].zw;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const vector<float16_t, 3> l_a_i_i = vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x3_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..a57e6de
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,44 @@
+SKIP: FAILED
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[4];
+};
+
+matrix<float16_t, 2, 3> tint_symbol_1(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
+}
+
+typedef matrix<float16_t, 2, 3> tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[4], uint offset) {
+  matrix<float16_t, 2, 3> arr[4] = (matrix<float16_t, 2, 3>[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 16u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 2, 3> l_a[4] = tint_symbol(a, 0u);
+  const matrix<float16_t, 2, 3> l_a_i = tint_symbol_1(a, 32u);
+  uint2 ubo_load_4 = a[2].zw;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const vector<float16_t, 3> l_a_i_i = vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000016DBC7DD4E0(5,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat2x3_f16/static_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..4d2072d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/static_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,40 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct mat2x3_f16 {
+  f16vec3 col0;
+  f16vec3 col1;
+};
+
+layout(binding = 0, std140) uniform a_block_std140_ubo {
+  mat2x3_f16 inner[4];
+} a;
+
+f16mat2x3 conv_mat2x3_f16(mat2x3_f16 val) {
+  return f16mat2x3(val.col0, val.col1);
+}
+
+f16mat2x3[4] conv_arr4_mat2x3_f16(mat2x3_f16 val[4]) {
+  f16mat2x3 arr[4] = f16mat2x3[4](f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat2x3_f16(val[i]);
+    }
+  }
+  return arr;
+}
+
+void f() {
+  f16mat2x3 p_a[4] = conv_arr4_mat2x3_f16(a.inner);
+  f16mat2x3 p_a_2 = conv_mat2x3_f16(a.inner[2u]);
+  f16vec3 p_a_2_1 = a.inner[2u].col1;
+  f16mat2x3 l_a[4] = conv_arr4_mat2x3_f16(a.inner);
+  f16mat2x3 l_a_i = conv_mat2x3_f16(a.inner[2u]);
+  f16vec3 l_a_i_i = a.inner[2u].col1;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat2x3_f16/static_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..c864412
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/static_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,23 @@
+#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];
+};
+
+kernel void f(const constant tint_array<half2x3, 4>* tint_symbol [[buffer(0)]]) {
+  tint_array<half2x3, 4> const l_a = *(tint_symbol);
+  half2x3 const l_a_i = (*(tint_symbol))[2];
+  half3 const l_a_i_i = (*(tint_symbol))[2][1];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat2x3_f16/static_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..dbc9807
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/static_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,123 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 71
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block_std140 "a_block_std140"
+               OpMemberName %a_block_std140 0 "inner"
+               OpName %mat2x3_f16 "mat2x3_f16"
+               OpMemberName %mat2x3_f16 0 "col0"
+               OpMemberName %mat2x3_f16 1 "col1"
+               OpName %a "a"
+               OpName %conv_mat2x3_f16 "conv_mat2x3_f16"
+               OpName %val "val"
+               OpName %conv_arr4_mat2x3_f16 "conv_arr4_mat2x3_f16"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %f "f"
+               OpDecorate %a_block_std140 Block
+               OpMemberDecorate %a_block_std140 0 Offset 0
+               OpMemberDecorate %mat2x3_f16 0 Offset 0
+               OpMemberDecorate %mat2x3_f16 1 Offset 8
+               OpDecorate %_arr_mat2x3_f16_uint_4 ArrayStride 16
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+               OpDecorate %_arr_mat2v3half_uint_4 ArrayStride 16
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+ %mat2x3_f16 = OpTypeStruct %v3half %v3half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat2x3_f16_uint_4 = OpTypeArray %mat2x3_f16 %uint_4
+%a_block_std140 = OpTypeStruct %_arr_mat2x3_f16_uint_4
+%_ptr_Uniform_a_block_std140 = OpTypePointer Uniform %a_block_std140
+          %a = OpVariable %_ptr_Uniform_a_block_std140 Uniform
+ %mat2v3half = OpTypeMatrix %v3half 2
+         %10 = OpTypeFunction %mat2v3half %mat2x3_f16
+%_arr_mat2v3half_uint_4 = OpTypeArray %mat2v3half %uint_4
+         %18 = OpTypeFunction %_arr_mat2v3half_uint_4 %_arr_mat2x3_f16_uint_4
+%_ptr_Function__arr_mat2v3half_uint_4 = OpTypePointer Function %_arr_mat2v3half_uint_4
+         %25 = OpConstantNull %_arr_mat2v3half_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %28 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_mat2x3_f16_uint_4 = OpTypePointer Function %_arr_mat2x3_f16_uint_4
+         %41 = OpConstantNull %_arr_mat2x3_f16_uint_4
+%_ptr_Function_mat2v3half = OpTypePointer Function %mat2v3half
+%_ptr_Function_mat2x3_f16 = OpTypePointer Function %mat2x3_f16
+     %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %54 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat2x3_f16_uint_4 = OpTypePointer Uniform %_arr_mat2x3_f16_uint_4
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_mat2x3_f16 = OpTypePointer Uniform %mat2x3_f16
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+%conv_mat2x3_f16 = OpFunction %mat2v3half None %10
+        %val = OpFunctionParameter %mat2x3_f16
+         %14 = OpLabel
+         %15 = OpCompositeExtract %v3half %val 0
+         %16 = OpCompositeExtract %v3half %val 1
+         %17 = OpCompositeConstruct %mat2v3half %15 %16
+               OpReturnValue %17
+               OpFunctionEnd
+%conv_arr4_mat2x3_f16 = OpFunction %_arr_mat2v3half_uint_4 None %18
+      %val_0 = OpFunctionParameter %_arr_mat2x3_f16_uint_4
+         %22 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_mat2v3half_uint_4 Function %25
+          %i = OpVariable %_ptr_Function_uint Function %28
+%var_for_index = OpVariable %_ptr_Function__arr_mat2x3_f16_uint_4 Function %41
+               OpBranch %29
+         %29 = OpLabel
+               OpLoopMerge %30 %31 None
+               OpBranch %32
+         %32 = OpLabel
+         %34 = OpLoad %uint %i
+         %35 = OpULessThan %bool %34 %uint_4
+         %33 = OpLogicalNot %bool %35
+               OpSelectionMerge %37 None
+               OpBranchConditional %33 %38 %37
+         %38 = OpLabel
+               OpBranch %30
+         %37 = OpLabel
+               OpStore %var_for_index %val_0
+         %42 = OpLoad %uint %i
+         %44 = OpAccessChain %_ptr_Function_mat2v3half %arr %42
+         %46 = OpLoad %uint %i
+         %48 = OpAccessChain %_ptr_Function_mat2x3_f16 %var_for_index %46
+         %49 = OpLoad %mat2x3_f16 %48
+         %45 = OpFunctionCall %mat2v3half %conv_mat2x3_f16 %49
+               OpStore %44 %45
+               OpBranch %31
+         %31 = OpLabel
+         %50 = OpLoad %uint %i
+         %52 = OpIAdd %uint %50 %uint_1
+               OpStore %i %52
+               OpBranch %29
+         %30 = OpLabel
+         %53 = OpLoad %_arr_mat2v3half_uint_4 %arr
+               OpReturnValue %53
+               OpFunctionEnd
+          %f = OpFunction %void None %54
+         %57 = OpLabel
+         %61 = OpAccessChain %_ptr_Uniform__arr_mat2x3_f16_uint_4 %a %uint_0
+         %62 = OpLoad %_arr_mat2x3_f16_uint_4 %61
+         %58 = OpFunctionCall %_arr_mat2v3half_uint_4 %conv_arr4_mat2x3_f16 %62
+         %66 = OpAccessChain %_ptr_Uniform_mat2x3_f16 %a %uint_0 %uint_2
+         %67 = OpLoad %mat2x3_f16 %66
+         %63 = OpFunctionCall %mat2v3half %conv_mat2x3_f16 %67
+         %69 = OpAccessChain %_ptr_Uniform_v3half %a %uint_0 %uint_2 %uint_1
+         %70 = OpLoad %v3half %69
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat2x3_f16/static_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..89154db
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/static_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> a : array<mat2x3<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_2 = &((*(p_a))[2]);
+  let p_a_2_1 = &((*(p_a_2))[1]);
+  let l_a : array<mat2x3<f16>, 4> = *(p_a);
+  let l_a_i : mat2x3<f16> = *(p_a_2);
+  let l_a_i_i : vec3<f16> = *(p_a_2_1);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_builtin.wgsl b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_builtin.wgsl
new file mode 100644
index 0000000..b40fdcf
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_builtin.wgsl
@@ -0,0 +1,10 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat2x3<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    let t = transpose(u[2]);
+    let l = length(u[0][1].zxy);
+    let a = abs(u[0][1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_builtin.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..277e378
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_builtin.wgsl.expected.dxc.hlsl
@@ -0,0 +1,31 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+
+matrix<float16_t, 2, 3> tint_symbol(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 3, 2> t = transpose(tint_symbol(u, 32u));
+  uint2 ubo_load_4 = u[0].zw;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const float16_t l = length(vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]).zxy);
+  uint2 ubo_load_5 = u[0].zw;
+  vector<float16_t, 2> ubo_load_5_xz = vector<float16_t, 2>(f16tof32(ubo_load_5 & 0xFFFF));
+  float16_t ubo_load_5_y = f16tof32(ubo_load_5[0] >> 16);
+  const float16_t a = abs(vector<float16_t, 3>(ubo_load_5_xz[0], ubo_load_5_y, ubo_load_5_xz[1]).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_builtin.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..d47ca3e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_builtin.wgsl.expected.fxc.hlsl
@@ -0,0 +1,36 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+
+matrix<float16_t, 2, 3> tint_symbol(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 3, 2> t = transpose(tint_symbol(u, 32u));
+  uint2 ubo_load_4 = u[0].zw;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const float16_t l = length(vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]).zxy);
+  uint2 ubo_load_5 = u[0].zw;
+  vector<float16_t, 2> ubo_load_5_xz = vector<float16_t, 2>(f16tof32(ubo_load_5 & 0xFFFF));
+  float16_t ubo_load_5_y = f16tof32(ubo_load_5[0] >> 16);
+  const float16_t a = abs(vector<float16_t, 3>(ubo_load_5_xz[0], ubo_load_5_y, ubo_load_5_xz[1]).zxy.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001B4475A47D0(5,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_builtin.wgsl.expected.glsl
new file mode 100644
index 0000000..f13e21d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_builtin.wgsl.expected.glsl
@@ -0,0 +1,27 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct mat2x3_f16 {
+  f16vec3 col0;
+  f16vec3 col1;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  mat2x3_f16 inner[4];
+} u;
+
+f16mat2x3 conv_mat2x3_f16(mat2x3_f16 val) {
+  return f16mat2x3(val.col0, val.col1);
+}
+
+void f() {
+  f16mat3x2 t = transpose(conv_mat2x3_f16(u.inner[2u]));
+  float16_t l = length(u.inner[0u].col1.zxy);
+  float16_t a = abs(u.inner[0u].col1.zxy[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_builtin.wgsl.expected.msl
new file mode 100644
index 0000000..205944f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_builtin.wgsl.expected.msl
@@ -0,0 +1,23 @@
+#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];
+};
+
+kernel void f(const constant tint_array<half2x3, 4>* tint_symbol [[buffer(0)]]) {
+  half3x2 const t = transpose((*(tint_symbol))[2]);
+  half const l = length(half3((*(tint_symbol))[0][1]).zxy);
+  half const a = fabs(half3((*(tint_symbol))[0][1]).zxy[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_builtin.wgsl.expected.spvasm
new file mode 100644
index 0000000..ec52e3a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_builtin.wgsl.expected.spvasm
@@ -0,0 +1,77 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 44
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+         %32 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %mat2x3_f16 "mat2x3_f16"
+               OpMemberName %mat2x3_f16 0 "col0"
+               OpMemberName %mat2x3_f16 1 "col1"
+               OpName %u "u"
+               OpName %conv_mat2x3_f16 "conv_mat2x3_f16"
+               OpName %val "val"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %mat2x3_f16 0 Offset 0
+               OpMemberDecorate %mat2x3_f16 1 Offset 8
+               OpDecorate %_arr_mat2x3_f16_uint_4 ArrayStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+ %mat2x3_f16 = OpTypeStruct %v3half %v3half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat2x3_f16_uint_4 = OpTypeArray %mat2x3_f16 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_mat2x3_f16_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat2v3half = OpTypeMatrix %v3half 2
+         %10 = OpTypeFunction %mat2v3half %mat2x3_f16
+       %void = OpTypeVoid
+         %18 = OpTypeFunction %void
+     %v2half = OpTypeVector %half 2
+ %mat3v2half = OpTypeMatrix %v2half 3
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_mat2x3_f16 = OpTypePointer Uniform %mat2x3_f16
+         %33 = OpConstantNull %uint
+     %uint_1 = OpConstant %uint 1
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+%conv_mat2x3_f16 = OpFunction %mat2v3half None %10
+        %val = OpFunctionParameter %mat2x3_f16
+         %14 = OpLabel
+         %15 = OpCompositeExtract %v3half %val 0
+         %16 = OpCompositeExtract %v3half %val 1
+         %17 = OpCompositeConstruct %mat2v3half %15 %16
+               OpReturnValue %17
+               OpFunctionEnd
+          %f = OpFunction %void None %18
+         %21 = OpLabel
+         %29 = OpAccessChain %_ptr_Uniform_mat2x3_f16 %u %uint_0 %uint_2
+         %30 = OpLoad %mat2x3_f16 %29
+         %25 = OpFunctionCall %mat2v3half %conv_mat2x3_f16 %30
+         %22 = OpTranspose %mat3v2half %25
+         %36 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0 %33 %uint_1
+         %37 = OpLoad %v3half %36
+         %38 = OpVectorShuffle %v3half %37 %37 2 0 1
+         %31 = OpExtInst %half %32 Length %38
+         %40 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0 %33 %uint_1
+         %41 = OpLoad %v3half %40
+         %42 = OpVectorShuffle %v3half %41 %41 2 0 1
+         %43 = OpCompositeExtract %half %42 0
+         %39 = OpExtInst %half %32 FAbs %43
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_builtin.wgsl.expected.wgsl
new file mode 100644
index 0000000..8b29ec4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_builtin.wgsl.expected.wgsl
@@ -0,0 +1,10 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat2x3<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let t = transpose(u[2]);
+  let l = length(u[0][1].zxy);
+  let a = abs(u[0][1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_fn.wgsl b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_fn.wgsl
new file mode 100644
index 0000000..a2106b1
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_fn.wgsl
@@ -0,0 +1,16 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat2x3<f16>, 4>;
+
+fn a(a : array<mat2x3<f16>, 4>) {}
+fn b(m : mat2x3<f16>) {}
+fn c(v : vec3<f16>) {}
+fn d(f : f16) {}
+
+@compute @workgroup_size(1)
+fn f() {
+    a(u);
+    b(u[1]);
+    c(u[1][0].zxy);
+    d(u[1][0].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_fn.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..19bfcc6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_fn.wgsl.expected.dxc.hlsl
@@ -0,0 +1,55 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+
+void a(matrix<float16_t, 2, 3> a_1[4]) {
+}
+
+void b(matrix<float16_t, 2, 3> m) {
+}
+
+void c(vector<float16_t, 3> v) {
+}
+
+void d(float16_t f_1) {
+}
+
+matrix<float16_t, 2, 3> tint_symbol_1(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
+}
+
+typedef matrix<float16_t, 2, 3> tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[4], uint offset) {
+  matrix<float16_t, 2, 3> arr[4] = (matrix<float16_t, 2, 3>[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 16u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 16u));
+  uint2 ubo_load_4 = u[1].xy;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  c(vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]).zxy);
+  uint2 ubo_load_5 = u[1].xy;
+  vector<float16_t, 2> ubo_load_5_xz = vector<float16_t, 2>(f16tof32(ubo_load_5 & 0xFFFF));
+  float16_t ubo_load_5_y = f16tof32(ubo_load_5[0] >> 16);
+  d(vector<float16_t, 3>(ubo_load_5_xz[0], ubo_load_5_y, ubo_load_5_xz[1]).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_fn.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..c1210ac
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_fn.wgsl.expected.fxc.hlsl
@@ -0,0 +1,63 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+
+void a(matrix<float16_t, 2, 3> a_1[4]) {
+}
+
+void b(matrix<float16_t, 2, 3> m) {
+}
+
+void c(vector<float16_t, 3> v) {
+}
+
+void d(float16_t f_1) {
+}
+
+matrix<float16_t, 2, 3> tint_symbol_1(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
+}
+
+typedef matrix<float16_t, 2, 3> tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[4], uint offset) {
+  matrix<float16_t, 2, 3> arr[4] = (matrix<float16_t, 2, 3>[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 16u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 16u));
+  uint2 ubo_load_4 = u[1].xy;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  c(vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]).zxy);
+  uint2 ubo_load_5 = u[1].xy;
+  vector<float16_t, 2> ubo_load_5_xz = vector<float16_t, 2>(f16tof32(ubo_load_5 & 0xFFFF));
+  float16_t ubo_load_5_y = f16tof32(ubo_load_5[0] >> 16);
+  d(vector<float16_t, 3>(ubo_load_5_xz[0], ubo_load_5_y, ubo_load_5_xz[1]).zxy.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000002290980B6C0(5,15-23): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000002290980B6C0(8,15-23): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000002290980B6C0(11,15-23): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000002290980B6C0(14,8-16): error X3000: unrecognized identifier 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_fn.wgsl.expected.glsl
new file mode 100644
index 0000000..e385c2b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_fn.wgsl.expected.glsl
@@ -0,0 +1,50 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct mat2x3_f16 {
+  f16vec3 col0;
+  f16vec3 col1;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  mat2x3_f16 inner[4];
+} u;
+
+void a(f16mat2x3 a_1[4]) {
+}
+
+void b(f16mat2x3 m) {
+}
+
+void c(f16vec3 v) {
+}
+
+void d(float16_t f_1) {
+}
+
+f16mat2x3 conv_mat2x3_f16(mat2x3_f16 val) {
+  return f16mat2x3(val.col0, val.col1);
+}
+
+f16mat2x3[4] conv_arr4_mat2x3_f16(mat2x3_f16 val[4]) {
+  f16mat2x3 arr[4] = f16mat2x3[4](f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat2x3_f16(val[i]);
+    }
+  }
+  return arr;
+}
+
+void f() {
+  a(conv_arr4_mat2x3_f16(u.inner));
+  b(conv_mat2x3_f16(u.inner[1u]));
+  c(u.inner[1u].col0.zxy);
+  d(u.inner[1u].col0.zxy[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_fn.wgsl.expected.msl
new file mode 100644
index 0000000..a1cefb5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_fn.wgsl.expected.msl
@@ -0,0 +1,36 @@
+#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];
+};
+
+void a(tint_array<half2x3, 4> a_1) {
+}
+
+void b(half2x3 m) {
+}
+
+void c(half3 v) {
+}
+
+void d(half f_1) {
+}
+
+kernel void f(const constant tint_array<half2x3, 4>* tint_symbol [[buffer(0)]]) {
+  a(*(tint_symbol));
+  b((*(tint_symbol))[1]);
+  c(half3((*(tint_symbol))[1][0]).zxy);
+  d(half3((*(tint_symbol))[1][0]).zxy[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_fn.wgsl.expected.spvasm
new file mode 100644
index 0000000..bbd5798
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_fn.wgsl.expected.spvasm
@@ -0,0 +1,163 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 95
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %mat2x3_f16 "mat2x3_f16"
+               OpMemberName %mat2x3_f16 0 "col0"
+               OpMemberName %mat2x3_f16 1 "col1"
+               OpName %u "u"
+               OpName %a "a"
+               OpName %a_1 "a_1"
+               OpName %b "b"
+               OpName %m "m"
+               OpName %c "c"
+               OpName %v "v"
+               OpName %d "d"
+               OpName %f_1 "f_1"
+               OpName %conv_mat2x3_f16 "conv_mat2x3_f16"
+               OpName %val "val"
+               OpName %conv_arr4_mat2x3_f16 "conv_arr4_mat2x3_f16"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %mat2x3_f16 0 Offset 0
+               OpMemberDecorate %mat2x3_f16 1 Offset 8
+               OpDecorate %_arr_mat2x3_f16_uint_4 ArrayStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %_arr_mat2v3half_uint_4 ArrayStride 16
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+ %mat2x3_f16 = OpTypeStruct %v3half %v3half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat2x3_f16_uint_4 = OpTypeArray %mat2x3_f16 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_mat2x3_f16_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+       %void = OpTypeVoid
+ %mat2v3half = OpTypeMatrix %v3half 2
+%_arr_mat2v3half_uint_4 = OpTypeArray %mat2v3half %uint_4
+         %10 = OpTypeFunction %void %_arr_mat2v3half_uint_4
+         %17 = OpTypeFunction %void %mat2v3half
+         %21 = OpTypeFunction %void %v3half
+         %25 = OpTypeFunction %void %half
+         %29 = OpTypeFunction %mat2v3half %mat2x3_f16
+         %36 = OpTypeFunction %_arr_mat2v3half_uint_4 %_arr_mat2x3_f16_uint_4
+%_ptr_Function__arr_mat2v3half_uint_4 = OpTypePointer Function %_arr_mat2v3half_uint_4
+         %42 = OpConstantNull %_arr_mat2v3half_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %45 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_mat2x3_f16_uint_4 = OpTypePointer Function %_arr_mat2x3_f16_uint_4
+         %58 = OpConstantNull %_arr_mat2x3_f16_uint_4
+%_ptr_Function_mat2v3half = OpTypePointer Function %mat2v3half
+%_ptr_Function_mat2x3_f16 = OpTypePointer Function %mat2x3_f16
+     %uint_1 = OpConstant %uint 1
+         %71 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat2x3_f16_uint_4 = OpTypePointer Uniform %_arr_mat2x3_f16_uint_4
+%_ptr_Uniform_mat2x3_f16 = OpTypePointer Uniform %mat2x3_f16
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+          %a = OpFunction %void None %10
+        %a_1 = OpFunctionParameter %_arr_mat2v3half_uint_4
+         %16 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %b = OpFunction %void None %17
+          %m = OpFunctionParameter %mat2v3half
+         %20 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %c = OpFunction %void None %21
+          %v = OpFunctionParameter %v3half
+         %24 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %d = OpFunction %void None %25
+        %f_1 = OpFunctionParameter %half
+         %28 = OpLabel
+               OpReturn
+               OpFunctionEnd
+%conv_mat2x3_f16 = OpFunction %mat2v3half None %29
+        %val = OpFunctionParameter %mat2x3_f16
+         %32 = OpLabel
+         %33 = OpCompositeExtract %v3half %val 0
+         %34 = OpCompositeExtract %v3half %val 1
+         %35 = OpCompositeConstruct %mat2v3half %33 %34
+               OpReturnValue %35
+               OpFunctionEnd
+%conv_arr4_mat2x3_f16 = OpFunction %_arr_mat2v3half_uint_4 None %36
+      %val_0 = OpFunctionParameter %_arr_mat2x3_f16_uint_4
+         %39 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_mat2v3half_uint_4 Function %42
+          %i = OpVariable %_ptr_Function_uint Function %45
+%var_for_index = OpVariable %_ptr_Function__arr_mat2x3_f16_uint_4 Function %58
+               OpBranch %46
+         %46 = OpLabel
+               OpLoopMerge %47 %48 None
+               OpBranch %49
+         %49 = OpLabel
+         %51 = OpLoad %uint %i
+         %52 = OpULessThan %bool %51 %uint_4
+         %50 = OpLogicalNot %bool %52
+               OpSelectionMerge %54 None
+               OpBranchConditional %50 %55 %54
+         %55 = OpLabel
+               OpBranch %47
+         %54 = OpLabel
+               OpStore %var_for_index %val_0
+         %59 = OpLoad %uint %i
+         %61 = OpAccessChain %_ptr_Function_mat2v3half %arr %59
+         %63 = OpLoad %uint %i
+         %65 = OpAccessChain %_ptr_Function_mat2x3_f16 %var_for_index %63
+         %66 = OpLoad %mat2x3_f16 %65
+         %62 = OpFunctionCall %mat2v3half %conv_mat2x3_f16 %66
+               OpStore %61 %62
+               OpBranch %48
+         %48 = OpLabel
+         %67 = OpLoad %uint %i
+         %69 = OpIAdd %uint %67 %uint_1
+               OpStore %i %69
+               OpBranch %46
+         %47 = OpLabel
+         %70 = OpLoad %_arr_mat2v3half_uint_4 %arr
+               OpReturnValue %70
+               OpFunctionEnd
+          %f = OpFunction %void None %71
+         %73 = OpLabel
+         %78 = OpAccessChain %_ptr_Uniform__arr_mat2x3_f16_uint_4 %u %uint_0
+         %79 = OpLoad %_arr_mat2x3_f16_uint_4 %78
+         %75 = OpFunctionCall %_arr_mat2v3half_uint_4 %conv_arr4_mat2x3_f16 %79
+         %74 = OpFunctionCall %void %a %75
+         %83 = OpAccessChain %_ptr_Uniform_mat2x3_f16 %u %uint_0 %uint_1
+         %84 = OpLoad %mat2x3_f16 %83
+         %81 = OpFunctionCall %mat2v3half %conv_mat2x3_f16 %84
+         %80 = OpFunctionCall %void %b %81
+         %87 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0 %uint_1 %uint_0
+         %88 = OpLoad %v3half %87
+         %89 = OpVectorShuffle %v3half %88 %88 2 0 1
+         %85 = OpFunctionCall %void %c %89
+         %91 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0 %uint_1 %uint_0
+         %92 = OpLoad %v3half %91
+         %93 = OpVectorShuffle %v3half %92 %92 2 0 1
+         %94 = OpCompositeExtract %half %93 0
+         %90 = OpFunctionCall %void %d %94
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_fn.wgsl.expected.wgsl
new file mode 100644
index 0000000..d0132c8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_fn.wgsl.expected.wgsl
@@ -0,0 +1,23 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat2x3<f16>, 4>;
+
+fn a(a : array<mat2x3<f16>, 4>) {
+}
+
+fn b(m : mat2x3<f16>) {
+}
+
+fn c(v : vec3<f16>) {
+}
+
+fn d(f : f16) {
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  a(u);
+  b(u[1]);
+  c(u[1][0].zxy);
+  d(u[1][0].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_private.wgsl b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_private.wgsl
new file mode 100644
index 0000000..ce113f8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_private.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat2x3<f16>, 4>;
+var<private> p : array<mat2x3<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[2];
+    p[1][0] = u[0][1].zxy;
+    p[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_private.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..9fbd299
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_private.wgsl.expected.dxc.hlsl
@@ -0,0 +1,41 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+static matrix<float16_t, 2, 3> p[4] = (matrix<float16_t, 2, 3>[4])0;
+
+matrix<float16_t, 2, 3> tint_symbol_1(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
+}
+
+typedef matrix<float16_t, 2, 3> tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[4], uint offset) {
+  matrix<float16_t, 2, 3> arr[4] = (matrix<float16_t, 2, 3>[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 16u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 32u);
+  uint2 ubo_load_4 = u[0].zw;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  p[1][0] = vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]).zxy;
+  p[1][0].x = float16_t(f16tof32(((u[0].z) & 0xFFFF)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_private.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..a5d49fe
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_private.wgsl.expected.fxc.hlsl
@@ -0,0 +1,46 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+static matrix<float16_t, 2, 3> p[4] = (matrix<float16_t, 2, 3>[4])0;
+
+matrix<float16_t, 2, 3> tint_symbol_1(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
+}
+
+typedef matrix<float16_t, 2, 3> tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[4], uint offset) {
+  matrix<float16_t, 2, 3> arr[4] = (matrix<float16_t, 2, 3>[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 16u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 32u);
+  uint2 ubo_load_4 = u[0].zw;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  p[1][0] = vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]).zxy;
+  p[1][0].x = float16_t(f16tof32(((u[0].z) & 0xFFFF)));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001C62197B570(4,15-23): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..dde921b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_private.wgsl.expected.glsl
@@ -0,0 +1,39 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct mat2x3_f16 {
+  f16vec3 col0;
+  f16vec3 col1;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  mat2x3_f16 inner[4];
+} u;
+
+f16mat2x3 p[4] = f16mat2x3[4](f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf));
+f16mat2x3 conv_mat2x3_f16(mat2x3_f16 val) {
+  return f16mat2x3(val.col0, val.col1);
+}
+
+f16mat2x3[4] conv_arr4_mat2x3_f16(mat2x3_f16 val[4]) {
+  f16mat2x3 arr[4] = f16mat2x3[4](f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat2x3_f16(val[i]);
+    }
+  }
+  return arr;
+}
+
+void f() {
+  p = conv_arr4_mat2x3_f16(u.inner);
+  p[1] = conv_mat2x3_f16(u.inner[2u]);
+  p[1][0] = u.inner[0u].col1.zxy;
+  p[1][0].x = u.inner[0u].col1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..f406191
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_private.wgsl.expected.msl
@@ -0,0 +1,25 @@
+#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];
+};
+
+kernel void f(const constant tint_array<half2x3, 4>* tint_symbol_1 [[buffer(0)]]) {
+  thread tint_array<half2x3, 4> tint_symbol = {};
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[2];
+  tint_symbol[1][0] = half3((*(tint_symbol_1))[0][1]).zxy;
+  tint_symbol[1][0][0] = (*(tint_symbol_1))[0][1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_private.wgsl.expected.spvasm
new file mode 100644
index 0000000..eab324b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_private.wgsl.expected.spvasm
@@ -0,0 +1,143 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 86
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %mat2x3_f16 "mat2x3_f16"
+               OpMemberName %mat2x3_f16 0 "col0"
+               OpMemberName %mat2x3_f16 1 "col1"
+               OpName %u "u"
+               OpName %p "p"
+               OpName %conv_mat2x3_f16 "conv_mat2x3_f16"
+               OpName %val "val"
+               OpName %conv_arr4_mat2x3_f16 "conv_arr4_mat2x3_f16"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %mat2x3_f16 0 Offset 0
+               OpMemberDecorate %mat2x3_f16 1 Offset 8
+               OpDecorate %_arr_mat2x3_f16_uint_4 ArrayStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %_arr_mat2v3half_uint_4 ArrayStride 16
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+ %mat2x3_f16 = OpTypeStruct %v3half %v3half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat2x3_f16_uint_4 = OpTypeArray %mat2x3_f16 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_mat2x3_f16_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat2v3half = OpTypeMatrix %v3half 2
+%_arr_mat2v3half_uint_4 = OpTypeArray %mat2v3half %uint_4
+%_ptr_Private__arr_mat2v3half_uint_4 = OpTypePointer Private %_arr_mat2v3half_uint_4
+         %14 = OpConstantNull %_arr_mat2v3half_uint_4
+          %p = OpVariable %_ptr_Private__arr_mat2v3half_uint_4 Private %14
+         %15 = OpTypeFunction %mat2v3half %mat2x3_f16
+         %22 = OpTypeFunction %_arr_mat2v3half_uint_4 %_arr_mat2x3_f16_uint_4
+%_ptr_Function__arr_mat2v3half_uint_4 = OpTypePointer Function %_arr_mat2v3half_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %30 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_mat2x3_f16_uint_4 = OpTypePointer Function %_arr_mat2x3_f16_uint_4
+         %43 = OpConstantNull %_arr_mat2x3_f16_uint_4
+%_ptr_Function_mat2v3half = OpTypePointer Function %mat2v3half
+%_ptr_Function_mat2x3_f16 = OpTypePointer Function %mat2x3_f16
+     %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %56 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat2x3_f16_uint_4 = OpTypePointer Uniform %_arr_mat2x3_f16_uint_4
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Private_mat2v3half = OpTypePointer Private %mat2v3half
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_mat2x3_f16 = OpTypePointer Uniform %mat2x3_f16
+         %74 = OpConstantNull %int
+%_ptr_Private_v3half = OpTypePointer Private %v3half
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+%_ptr_Private_half = OpTypePointer Private %half
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+%conv_mat2x3_f16 = OpFunction %mat2v3half None %15
+        %val = OpFunctionParameter %mat2x3_f16
+         %18 = OpLabel
+         %19 = OpCompositeExtract %v3half %val 0
+         %20 = OpCompositeExtract %v3half %val 1
+         %21 = OpCompositeConstruct %mat2v3half %19 %20
+               OpReturnValue %21
+               OpFunctionEnd
+%conv_arr4_mat2x3_f16 = OpFunction %_arr_mat2v3half_uint_4 None %22
+      %val_0 = OpFunctionParameter %_arr_mat2x3_f16_uint_4
+         %25 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_mat2v3half_uint_4 Function %14
+          %i = OpVariable %_ptr_Function_uint Function %30
+%var_for_index = OpVariable %_ptr_Function__arr_mat2x3_f16_uint_4 Function %43
+               OpBranch %31
+         %31 = OpLabel
+               OpLoopMerge %32 %33 None
+               OpBranch %34
+         %34 = OpLabel
+         %36 = OpLoad %uint %i
+         %37 = OpULessThan %bool %36 %uint_4
+         %35 = OpLogicalNot %bool %37
+               OpSelectionMerge %39 None
+               OpBranchConditional %35 %40 %39
+         %40 = OpLabel
+               OpBranch %32
+         %39 = OpLabel
+               OpStore %var_for_index %val_0
+         %44 = OpLoad %uint %i
+         %46 = OpAccessChain %_ptr_Function_mat2v3half %arr %44
+         %48 = OpLoad %uint %i
+         %50 = OpAccessChain %_ptr_Function_mat2x3_f16 %var_for_index %48
+         %51 = OpLoad %mat2x3_f16 %50
+         %47 = OpFunctionCall %mat2v3half %conv_mat2x3_f16 %51
+               OpStore %46 %47
+               OpBranch %33
+         %33 = OpLabel
+         %52 = OpLoad %uint %i
+         %54 = OpIAdd %uint %52 %uint_1
+               OpStore %i %54
+               OpBranch %31
+         %32 = OpLabel
+         %55 = OpLoad %_arr_mat2v3half_uint_4 %arr
+               OpReturnValue %55
+               OpFunctionEnd
+          %f = OpFunction %void None %56
+         %59 = OpLabel
+         %63 = OpAccessChain %_ptr_Uniform__arr_mat2x3_f16_uint_4 %u %uint_0
+         %64 = OpLoad %_arr_mat2x3_f16_uint_4 %63
+         %60 = OpFunctionCall %_arr_mat2v3half_uint_4 %conv_arr4_mat2x3_f16 %64
+               OpStore %p %60
+         %68 = OpAccessChain %_ptr_Private_mat2v3half %p %int_1
+         %72 = OpAccessChain %_ptr_Uniform_mat2x3_f16 %u %uint_0 %uint_2
+         %73 = OpLoad %mat2x3_f16 %72
+         %69 = OpFunctionCall %mat2v3half %conv_mat2x3_f16 %73
+               OpStore %68 %69
+         %76 = OpAccessChain %_ptr_Private_v3half %p %int_1 %74
+         %78 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0 %30 %uint_1
+         %79 = OpLoad %v3half %78
+         %80 = OpVectorShuffle %v3half %79 %79 2 0 1
+               OpStore %76 %80
+         %82 = OpAccessChain %_ptr_Private_half %p %int_1 %74 %uint_0
+         %84 = OpAccessChain %_ptr_Uniform_half %u %uint_0 %30 %uint_1 %30
+         %85 = OpLoad %half %84
+               OpStore %82 %85
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..33edad7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_private.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat2x3<f16>, 4>;
+
+var<private> p : array<mat2x3<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[2];
+  p[1][0] = u[0][1].zxy;
+  p[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_storage.wgsl b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_storage.wgsl
new file mode 100644
index 0000000..adc8b56
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_storage.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat2x3<f16>, 4>;
+@group(0) @binding(1) var<storage, read_write> s : array<mat2x3<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[2];
+    s[1][0] = u[0][1].zxy;
+    s[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_storage.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..26f9723
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_storage.wgsl.expected.dxc.hlsl
@@ -0,0 +1,55 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 2, 3> value) {
+  buffer.Store<vector<float16_t, 3> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 8u), value[1u]);
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 2, 3> value[4]) {
+  matrix<float16_t, 2, 3> array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 16u)), array[i]);
+    }
+  }
+}
+
+matrix<float16_t, 2, 3> tint_symbol_4(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
+}
+
+typedef matrix<float16_t, 2, 3> tint_symbol_3_ret[4];
+tint_symbol_3_ret tint_symbol_3(uint4 buffer[4], uint offset) {
+  matrix<float16_t, 2, 3> arr[4] = (matrix<float16_t, 2, 3>[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_4(buffer, (offset + (i_1 * 16u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_3(u, 0u));
+  tint_symbol_1(s, 16u, tint_symbol_4(u, 32u));
+  uint2 ubo_load_4 = u[0].zw;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  s.Store<vector<float16_t, 3> >(16u, vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]).zxy);
+  s.Store<float16_t>(16u, float16_t(f16tof32(((u[0].z) & 0xFFFF))));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_storage.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..da9a817
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_storage.wgsl.expected.fxc.hlsl
@@ -0,0 +1,61 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 2, 3> value) {
+  buffer.Store<vector<float16_t, 3> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 8u), value[1u]);
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 2, 3> value[4]) {
+  matrix<float16_t, 2, 3> array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 16u)), array[i]);
+    }
+  }
+}
+
+matrix<float16_t, 2, 3> tint_symbol_4(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
+}
+
+typedef matrix<float16_t, 2, 3> tint_symbol_3_ret[4];
+tint_symbol_3_ret tint_symbol_3(uint4 buffer[4], uint offset) {
+  matrix<float16_t, 2, 3> arr[4] = (matrix<float16_t, 2, 3>[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_4(buffer, (offset + (i_1 * 16u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_3(u, 0u));
+  tint_symbol_1(s, 16u, tint_symbol_4(u, 32u));
+  uint2 ubo_load_4 = u[0].zw;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  s.Store<vector<float16_t, 3> >(16u, vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]).zxy);
+  s.Store<float16_t>(16u, float16_t(f16tof32(((u[0].z) & 0xFFFF))));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001AB590A03F0(6,68-76): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001AB590A03F0(7,3-14): error X3018: invalid subscript 'Store'
+
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..48da1c9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_storage.wgsl.expected.glsl
@@ -0,0 +1,42 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct mat2x3_f16 {
+  f16vec3 col0;
+  f16vec3 col1;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  mat2x3_f16 inner[4];
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  f16mat2x3 inner[4];
+} s;
+
+f16mat2x3 conv_mat2x3_f16(mat2x3_f16 val) {
+  return f16mat2x3(val.col0, val.col1);
+}
+
+f16mat2x3[4] conv_arr4_mat2x3_f16(mat2x3_f16 val[4]) {
+  f16mat2x3 arr[4] = f16mat2x3[4](f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat2x3_f16(val[i]);
+    }
+  }
+  return arr;
+}
+
+void f() {
+  s.inner = conv_arr4_mat2x3_f16(u.inner);
+  s.inner[1] = conv_mat2x3_f16(u.inner[2u]);
+  s.inner[1][0] = u.inner[0u].col1.zxy;
+  s.inner[1][0].x = u.inner[0u].col1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..edcc1d9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_storage.wgsl.expected.msl
@@ -0,0 +1,24 @@
+#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];
+};
+
+kernel void f(device tint_array<half2x3, 4>* tint_symbol [[buffer(1)]], const constant tint_array<half2x3, 4>* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
+  (*(tint_symbol))[1][0] = half3((*(tint_symbol_1))[0][1]).zxy;
+  (*(tint_symbol))[1][0][0] = (*(tint_symbol_1))[0][1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_storage.wgsl.expected.spvasm
new file mode 100644
index 0000000..8d6eba2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_storage.wgsl.expected.spvasm
@@ -0,0 +1,154 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 89
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %mat2x3_f16 "mat2x3_f16"
+               OpMemberName %mat2x3_f16 0 "col0"
+               OpMemberName %mat2x3_f16 1 "col1"
+               OpName %u "u"
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %s "s"
+               OpName %conv_mat2x3_f16 "conv_mat2x3_f16"
+               OpName %val "val"
+               OpName %conv_arr4_mat2x3_f16 "conv_arr4_mat2x3_f16"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %mat2x3_f16 0 Offset 0
+               OpMemberDecorate %mat2x3_f16 1 Offset 8
+               OpDecorate %_arr_mat2x3_f16_uint_4 ArrayStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 8
+               OpDecorate %_arr_mat2v3half_uint_4 ArrayStride 16
+               OpDecorate %s DescriptorSet 0
+               OpDecorate %s Binding 1
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+ %mat2x3_f16 = OpTypeStruct %v3half %v3half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat2x3_f16_uint_4 = OpTypeArray %mat2x3_f16 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_mat2x3_f16_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat2v3half = OpTypeMatrix %v3half 2
+%_arr_mat2v3half_uint_4 = OpTypeArray %mat2v3half %uint_4
+    %u_block = OpTypeStruct %_arr_mat2v3half_uint_4
+%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
+          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+         %15 = OpTypeFunction %mat2v3half %mat2x3_f16
+         %22 = OpTypeFunction %_arr_mat2v3half_uint_4 %_arr_mat2x3_f16_uint_4
+%_ptr_Function__arr_mat2v3half_uint_4 = OpTypePointer Function %_arr_mat2v3half_uint_4
+         %28 = OpConstantNull %_arr_mat2v3half_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %31 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_mat2x3_f16_uint_4 = OpTypePointer Function %_arr_mat2x3_f16_uint_4
+         %44 = OpConstantNull %_arr_mat2x3_f16_uint_4
+%_ptr_Function_mat2v3half = OpTypePointer Function %mat2v3half
+%_ptr_Function_mat2x3_f16 = OpTypePointer Function %mat2x3_f16
+     %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %57 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer__arr_mat2v3half_uint_4 = OpTypePointer StorageBuffer %_arr_mat2v3half_uint_4
+%_ptr_Uniform__arr_mat2x3_f16_uint_4 = OpTypePointer Uniform %_arr_mat2x3_f16_uint_4
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_mat2v3half = OpTypePointer StorageBuffer %mat2v3half
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_mat2x3_f16 = OpTypePointer Uniform %mat2x3_f16
+         %77 = OpConstantNull %int
+%_ptr_StorageBuffer_v3half = OpTypePointer StorageBuffer %v3half
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+%_ptr_StorageBuffer_half = OpTypePointer StorageBuffer %half
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+%conv_mat2x3_f16 = OpFunction %mat2v3half None %15
+        %val = OpFunctionParameter %mat2x3_f16
+         %18 = OpLabel
+         %19 = OpCompositeExtract %v3half %val 0
+         %20 = OpCompositeExtract %v3half %val 1
+         %21 = OpCompositeConstruct %mat2v3half %19 %20
+               OpReturnValue %21
+               OpFunctionEnd
+%conv_arr4_mat2x3_f16 = OpFunction %_arr_mat2v3half_uint_4 None %22
+      %val_0 = OpFunctionParameter %_arr_mat2x3_f16_uint_4
+         %25 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_mat2v3half_uint_4 Function %28
+          %i = OpVariable %_ptr_Function_uint Function %31
+%var_for_index = OpVariable %_ptr_Function__arr_mat2x3_f16_uint_4 Function %44
+               OpBranch %32
+         %32 = OpLabel
+               OpLoopMerge %33 %34 None
+               OpBranch %35
+         %35 = OpLabel
+         %37 = OpLoad %uint %i
+         %38 = OpULessThan %bool %37 %uint_4
+         %36 = OpLogicalNot %bool %38
+               OpSelectionMerge %40 None
+               OpBranchConditional %36 %41 %40
+         %41 = OpLabel
+               OpBranch %33
+         %40 = OpLabel
+               OpStore %var_for_index %val_0
+         %45 = OpLoad %uint %i
+         %47 = OpAccessChain %_ptr_Function_mat2v3half %arr %45
+         %49 = OpLoad %uint %i
+         %51 = OpAccessChain %_ptr_Function_mat2x3_f16 %var_for_index %49
+         %52 = OpLoad %mat2x3_f16 %51
+         %48 = OpFunctionCall %mat2v3half %conv_mat2x3_f16 %52
+               OpStore %47 %48
+               OpBranch %34
+         %34 = OpLabel
+         %53 = OpLoad %uint %i
+         %55 = OpIAdd %uint %53 %uint_1
+               OpStore %i %55
+               OpBranch %32
+         %33 = OpLabel
+         %56 = OpLoad %_arr_mat2v3half_uint_4 %arr
+               OpReturnValue %56
+               OpFunctionEnd
+          %f = OpFunction %void None %57
+         %60 = OpLabel
+         %63 = OpAccessChain %_ptr_StorageBuffer__arr_mat2v3half_uint_4 %s %uint_0
+         %66 = OpAccessChain %_ptr_Uniform__arr_mat2x3_f16_uint_4 %u %uint_0
+         %67 = OpLoad %_arr_mat2x3_f16_uint_4 %66
+         %64 = OpFunctionCall %_arr_mat2v3half_uint_4 %conv_arr4_mat2x3_f16 %67
+               OpStore %63 %64
+         %71 = OpAccessChain %_ptr_StorageBuffer_mat2v3half %s %uint_0 %int_1
+         %75 = OpAccessChain %_ptr_Uniform_mat2x3_f16 %u %uint_0 %uint_2
+         %76 = OpLoad %mat2x3_f16 %75
+         %72 = OpFunctionCall %mat2v3half %conv_mat2x3_f16 %76
+               OpStore %71 %72
+         %79 = OpAccessChain %_ptr_StorageBuffer_v3half %s %uint_0 %int_1 %77
+         %81 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0 %31 %uint_1
+         %82 = OpLoad %v3half %81
+         %83 = OpVectorShuffle %v3half %82 %82 2 0 1
+               OpStore %79 %83
+         %85 = OpAccessChain %_ptr_StorageBuffer_half %s %uint_0 %int_1 %77 %uint_0
+         %87 = OpAccessChain %_ptr_Uniform_half %u %uint_0 %31 %uint_1 %31
+         %88 = OpLoad %half %87
+               OpStore %85 %88
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..a29c5d3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat2x3<f16>, 4>;
+
+@group(0) @binding(1) var<storage, read_write> s : array<mat2x3<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[2];
+  s[1][0] = u[0][1].zxy;
+  s[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_workgroup.wgsl
new file mode 100644
index 0000000..dc18eed
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_workgroup.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat2x3<f16>, 4>;
+var<workgroup> w : array<mat2x3<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[2];
+    w[1][0] = u[0][1].zxy;
+    w[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_workgroup.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..4f956e9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_workgroup.wgsl.expected.dxc.hlsl
@@ -0,0 +1,56 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+groupshared matrix<float16_t, 2, 3> w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 2, 3> tint_symbol_3(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
+}
+
+typedef matrix<float16_t, 2, 3> tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[4], uint offset) {
+  matrix<float16_t, 2, 3> arr[4] = (matrix<float16_t, 2, 3>[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 16u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      w[i] = matrix<float16_t, 2, 3>((float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx);
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 32u);
+  uint2 ubo_load_4 = u[0].zw;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  w[1][0] = vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]).zxy;
+  w[1][0].x = float16_t(f16tof32(((u[0].z) & 0xFFFF)));
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_workgroup.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..b3d2fa5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_workgroup.wgsl.expected.fxc.hlsl
@@ -0,0 +1,61 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+groupshared matrix<float16_t, 2, 3> w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 2, 3> tint_symbol_3(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
+}
+
+typedef matrix<float16_t, 2, 3> tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[4], uint offset) {
+  matrix<float16_t, 2, 3> arr[4] = (matrix<float16_t, 2, 3>[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 16u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      w[i] = matrix<float16_t, 2, 3>((float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx);
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 32u);
+  uint2 ubo_load_4 = u[0].zw;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  w[1][0] = vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]).zxy;
+  w[1][0].x = float16_t(f16tof32(((u[0].z) & 0xFFFF)));
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000019397EFCDD0(4,20-28): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..36138b0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,46 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct mat2x3_f16 {
+  f16vec3 col0;
+  f16vec3 col1;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  mat2x3_f16 inner[4];
+} u;
+
+shared f16mat2x3 w[4];
+f16mat2x3 conv_mat2x3_f16(mat2x3_f16 val) {
+  return f16mat2x3(val.col0, val.col1);
+}
+
+f16mat2x3[4] conv_arr4_mat2x3_f16(mat2x3_f16 val[4]) {
+  f16mat2x3 arr[4] = f16mat2x3[4](f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat2x3_f16(val[i]);
+    }
+  }
+  return arr;
+}
+
+void f(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      uint i = idx;
+      w[i] = f16mat2x3(f16vec3(0.0hf), f16vec3(0.0hf));
+    }
+  }
+  barrier();
+  w = conv_arr4_mat2x3_f16(u.inner);
+  w[1] = conv_mat2x3_f16(u.inner[2u]);
+  w[1][0] = u.inner[0u].col1.zxy;
+  w[1][0].x = u.inner[0u].col1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..ac44a93
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,38 @@
+#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_symbol_5 {
+  tint_array<half2x3, 4> w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup tint_array<half2x3, 4>* const tint_symbol, const constant tint_array<half2x3, 4>* const tint_symbol_1) {
+  for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+    uint const i = idx;
+    (*(tint_symbol))[i] = half2x3(half3(0.0h), half3(0.0h));
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
+  (*(tint_symbol))[1][0] = half3((*(tint_symbol_1))[0][1]).zxy;
+  (*(tint_symbol))[1][0][0] = (*(tint_symbol_1))[0][1][0];
+}
+
+kernel void f(const constant tint_array<half2x3, 4>* tint_symbol_4 [[buffer(0)]], threadgroup tint_symbol_5* tint_symbol_3 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup tint_array<half2x3, 4>* const tint_symbol_2 = &((*(tint_symbol_3)).w);
+  f_inner(local_invocation_index, tint_symbol_2, tint_symbol_4);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_workgroup.wgsl.expected.spvasm
new file mode 100644
index 0000000..3cdc7db
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_workgroup.wgsl.expected.spvasm
@@ -0,0 +1,186 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 111
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %local_invocation_index_1 "local_invocation_index_1"
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %mat2x3_f16 "mat2x3_f16"
+               OpMemberName %mat2x3_f16 0 "col0"
+               OpMemberName %mat2x3_f16 1 "col1"
+               OpName %u "u"
+               OpName %w "w"
+               OpName %conv_mat2x3_f16 "conv_mat2x3_f16"
+               OpName %val "val"
+               OpName %conv_arr4_mat2x3_f16 "conv_arr4_mat2x3_f16"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %f_inner "f_inner"
+               OpName %local_invocation_index "local_invocation_index"
+               OpName %idx "idx"
+               OpName %f "f"
+               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %mat2x3_f16 0 Offset 0
+               OpMemberDecorate %mat2x3_f16 1 Offset 8
+               OpDecorate %_arr_mat2x3_f16_uint_4 ArrayStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %_arr_mat2v3half_uint_4 ArrayStride 16
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+ %mat2x3_f16 = OpTypeStruct %v3half %v3half
+     %uint_4 = OpConstant %uint 4
+%_arr_mat2x3_f16_uint_4 = OpTypeArray %mat2x3_f16 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_mat2x3_f16_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat2v3half = OpTypeMatrix %v3half 2
+%_arr_mat2v3half_uint_4 = OpTypeArray %mat2v3half %uint_4
+%_ptr_Workgroup__arr_mat2v3half_uint_4 = OpTypePointer Workgroup %_arr_mat2v3half_uint_4
+          %w = OpVariable %_ptr_Workgroup__arr_mat2v3half_uint_4 Workgroup
+         %16 = OpTypeFunction %mat2v3half %mat2x3_f16
+         %23 = OpTypeFunction %_arr_mat2v3half_uint_4 %_arr_mat2x3_f16_uint_4
+%_ptr_Function__arr_mat2v3half_uint_4 = OpTypePointer Function %_arr_mat2v3half_uint_4
+         %29 = OpConstantNull %_arr_mat2v3half_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %32 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_mat2x3_f16_uint_4 = OpTypePointer Function %_arr_mat2x3_f16_uint_4
+         %45 = OpConstantNull %_arr_mat2x3_f16_uint_4
+%_ptr_Function_mat2v3half = OpTypePointer Function %mat2v3half
+%_ptr_Function_mat2x3_f16 = OpTypePointer Function %mat2x3_f16
+     %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %58 = OpTypeFunction %void %uint
+%_ptr_Workgroup_mat2v3half = OpTypePointer Workgroup %mat2v3half
+         %76 = OpConstantNull %mat2v3half
+     %uint_2 = OpConstant %uint 2
+   %uint_264 = OpConstant %uint 264
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat2x3_f16_uint_4 = OpTypePointer Uniform %_arr_mat2x3_f16_uint_4
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_mat2x3_f16 = OpTypePointer Uniform %mat2x3_f16
+         %94 = OpConstantNull %int
+%_ptr_Workgroup_v3half = OpTypePointer Workgroup %v3half
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+%_ptr_Workgroup_half = OpTypePointer Workgroup %half
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+        %106 = OpTypeFunction %void
+%conv_mat2x3_f16 = OpFunction %mat2v3half None %16
+        %val = OpFunctionParameter %mat2x3_f16
+         %19 = OpLabel
+         %20 = OpCompositeExtract %v3half %val 0
+         %21 = OpCompositeExtract %v3half %val 1
+         %22 = OpCompositeConstruct %mat2v3half %20 %21
+               OpReturnValue %22
+               OpFunctionEnd
+%conv_arr4_mat2x3_f16 = OpFunction %_arr_mat2v3half_uint_4 None %23
+      %val_0 = OpFunctionParameter %_arr_mat2x3_f16_uint_4
+         %26 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_mat2v3half_uint_4 Function %29
+          %i = OpVariable %_ptr_Function_uint Function %32
+%var_for_index = OpVariable %_ptr_Function__arr_mat2x3_f16_uint_4 Function %45
+               OpBranch %33
+         %33 = OpLabel
+               OpLoopMerge %34 %35 None
+               OpBranch %36
+         %36 = OpLabel
+         %38 = OpLoad %uint %i
+         %39 = OpULessThan %bool %38 %uint_4
+         %37 = OpLogicalNot %bool %39
+               OpSelectionMerge %41 None
+               OpBranchConditional %37 %42 %41
+         %42 = OpLabel
+               OpBranch %34
+         %41 = OpLabel
+               OpStore %var_for_index %val_0
+         %46 = OpLoad %uint %i
+         %48 = OpAccessChain %_ptr_Function_mat2v3half %arr %46
+         %50 = OpLoad %uint %i
+         %52 = OpAccessChain %_ptr_Function_mat2x3_f16 %var_for_index %50
+         %53 = OpLoad %mat2x3_f16 %52
+         %49 = OpFunctionCall %mat2v3half %conv_mat2x3_f16 %53
+               OpStore %48 %49
+               OpBranch %35
+         %35 = OpLabel
+         %54 = OpLoad %uint %i
+         %56 = OpIAdd %uint %54 %uint_1
+               OpStore %i %56
+               OpBranch %33
+         %34 = OpLabel
+         %57 = OpLoad %_arr_mat2v3half_uint_4 %arr
+               OpReturnValue %57
+               OpFunctionEnd
+    %f_inner = OpFunction %void None %58
+%local_invocation_index = OpFunctionParameter %uint
+         %62 = OpLabel
+        %idx = OpVariable %_ptr_Function_uint Function %32
+               OpStore %idx %local_invocation_index
+               OpBranch %64
+         %64 = OpLabel
+               OpLoopMerge %65 %66 None
+               OpBranch %67
+         %67 = OpLabel
+         %69 = OpLoad %uint %idx
+         %70 = OpULessThan %bool %69 %uint_4
+         %68 = OpLogicalNot %bool %70
+               OpSelectionMerge %71 None
+               OpBranchConditional %68 %72 %71
+         %72 = OpLabel
+               OpBranch %65
+         %71 = OpLabel
+         %73 = OpLoad %uint %idx
+         %75 = OpAccessChain %_ptr_Workgroup_mat2v3half %w %73
+               OpStore %75 %76
+               OpBranch %66
+         %66 = OpLabel
+         %77 = OpLoad %uint %idx
+         %78 = OpIAdd %uint %77 %uint_1
+               OpStore %idx %78
+               OpBranch %64
+         %65 = OpLabel
+               OpControlBarrier %uint_2 %uint_2 %uint_264
+         %85 = OpAccessChain %_ptr_Uniform__arr_mat2x3_f16_uint_4 %u %uint_0
+         %86 = OpLoad %_arr_mat2x3_f16_uint_4 %85
+         %82 = OpFunctionCall %_arr_mat2v3half_uint_4 %conv_arr4_mat2x3_f16 %86
+               OpStore %w %82
+         %89 = OpAccessChain %_ptr_Workgroup_mat2v3half %w %int_1
+         %92 = OpAccessChain %_ptr_Uniform_mat2x3_f16 %u %uint_0 %uint_2
+         %93 = OpLoad %mat2x3_f16 %92
+         %90 = OpFunctionCall %mat2v3half %conv_mat2x3_f16 %93
+               OpStore %89 %90
+         %96 = OpAccessChain %_ptr_Workgroup_v3half %w %int_1 %94
+         %98 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0 %32 %uint_1
+         %99 = OpLoad %v3half %98
+        %100 = OpVectorShuffle %v3half %99 %99 2 0 1
+               OpStore %96 %100
+        %102 = OpAccessChain %_ptr_Workgroup_half %w %int_1 %94 %uint_0
+        %104 = OpAccessChain %_ptr_Uniform_half %u %uint_0 %32 %uint_1 %32
+        %105 = OpLoad %half %104
+               OpStore %102 %105
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %106
+        %108 = OpLabel
+        %110 = OpLoad %uint %local_invocation_index_1
+        %109 = OpFunctionCall %void %f_inner %110
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..0b15098
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f16/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat2x3<f16>, 4>;
+
+var<workgroup> w : array<mat2x3<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[2];
+  w[1][0] = u[0][1].zxy;
+  w[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/array/mat2x3_f32/dynamic_index_via_ptr.wgsl
new file mode 100644
index 0000000..f50aa0c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/dynamic_index_via_ptr.wgsl
@@ -0,0 +1,15 @@
+@group(0) @binding(0) var<uniform> a : array<mat2x3<f32>, 4>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a       = &a;
+  let p_a_i     = &((*p_a)[i()]);
+  let p_a_i_i   = &((*p_a_i)[i()]);
+
+  let l_a       : array<mat2x3<f32>, 4> = *p_a;
+  let l_a_i     : mat2x3<f32>           = *p_a_i;
+  let l_a_i_i   : vec3<f32>             = *p_a_i_i;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..0533b18
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,37 @@
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[8];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float2x3 tint_symbol_1(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+}
+
+typedef float2x3 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[8], uint offset) {
+  float2x3 arr[4] = (float2x3[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 32u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_i_save = i();
+  const float2x3 l_a[4] = tint_symbol(a, 0u);
+  const float2x3 l_a_i = tint_symbol_1(a, (32u * uint(p_a_i_save)));
+  const uint scalar_offset_2 = (((32u * uint(p_a_i_save)) + (16u * uint(p_a_i_i_save)))) / 4;
+  const float3 l_a_i_i = asfloat(a[scalar_offset_2 / 4].xyz);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..0533b18
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,37 @@
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[8];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float2x3 tint_symbol_1(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+}
+
+typedef float2x3 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[8], uint offset) {
+  float2x3 arr[4] = (float2x3[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 32u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_i_save = i();
+  const float2x3 l_a[4] = tint_symbol(a, 0u);
+  const float2x3 l_a_i = tint_symbol_1(a, (32u * uint(p_a_i_save)));
+  const uint scalar_offset_2 = (((32u * uint(p_a_i_save)) + (16u * uint(p_a_i_i_save)))) / 4;
+  const float3 l_a_i_i = asfloat(a[scalar_offset_2 / 4].xyz);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..7bdae86
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,27 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform a_block_ubo {
+  mat2x3 inner[4];
+} a;
+
+int counter = 0;
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+void f() {
+  int tint_symbol = i();
+  int p_a_i_save = tint_symbol;
+  int tint_symbol_1 = i();
+  int p_a_i_i_save = tint_symbol_1;
+  mat2x3 l_a[4] = a.inner;
+  mat2x3 l_a_i = a.inner[p_a_i_save];
+  vec3 l_a_i_i = a.inner[p_a_i_save][p_a_i_i_save];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..ba4070a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,33 @@
+#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];
+};
+
+int i() {
+  thread int tint_symbol_2 = 0;
+  tint_symbol_2 = as_type<int>((as_type<uint>(tint_symbol_2) + as_type<uint>(1)));
+  return tint_symbol_2;
+}
+
+kernel void f(const constant tint_array<float2x3, 4>* tint_symbol_3 [[buffer(0)]]) {
+  int const tint_symbol = i();
+  int const p_a_i_save = tint_symbol;
+  int const tint_symbol_1 = i();
+  int const p_a_i_i_save = tint_symbol_1;
+  tint_array<float2x3, 4> const l_a = *(tint_symbol_3);
+  float2x3 const l_a_i = (*(tint_symbol_3))[p_a_i_save];
+  float3 const l_a_i_i = (*(tint_symbol_3))[p_a_i_save][p_a_i_i_save];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..53e42b0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,64 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 37
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block "a_block"
+               OpMemberName %a_block 0 "inner"
+               OpName %a "a"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %f "f"
+               OpDecorate %a_block Block
+               OpMemberDecorate %a_block 0 Offset 0
+               OpMemberDecorate %a_block 0 ColMajor
+               OpMemberDecorate %a_block 0 MatrixStride 16
+               OpDecorate %_arr_mat2v3float_uint_4 ArrayStride 32
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat2v3float = OpTypeMatrix %v3float 2
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat2v3float_uint_4 = OpTypeArray %mat2v3float %uint_4
+    %a_block = OpTypeStruct %_arr_mat2v3float_uint_4
+%_ptr_Uniform_a_block = OpTypePointer Uniform %a_block
+          %a = OpVariable %_ptr_Uniform_a_block Uniform
+        %int = OpTypeInt 32 1
+         %11 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %11
+         %14 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+       %void = OpTypeVoid
+         %21 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat2v3float_uint_4 = OpTypePointer Uniform %_arr_mat2v3float_uint_4
+%_ptr_Uniform_mat2v3float = OpTypePointer Uniform %mat2v3float
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+          %i = OpFunction %int None %14
+         %16 = OpLabel
+         %17 = OpLoad %int %counter
+         %19 = OpIAdd %int %17 %int_1
+               OpStore %counter %19
+         %20 = OpLoad %int %counter
+               OpReturnValue %20
+               OpFunctionEnd
+          %f = OpFunction %void None %21
+         %24 = OpLabel
+         %25 = OpFunctionCall %int %i
+         %26 = OpFunctionCall %int %i
+         %29 = OpAccessChain %_ptr_Uniform__arr_mat2v3float_uint_4 %a %uint_0
+         %30 = OpLoad %_arr_mat2v3float_uint_4 %29
+         %32 = OpAccessChain %_ptr_Uniform_mat2v3float %a %uint_0 %25
+         %33 = OpLoad %mat2v3float %32
+         %35 = OpAccessChain %_ptr_Uniform_v3float %a %uint_0 %25 %26
+         %36 = OpLoad %v3float %35
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..afba90a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+@group(0) @binding(0) var<uniform> a : array<mat2x3<f32>, 4>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_i = &((*(p_a))[i()]);
+  let p_a_i_i = &((*(p_a_i))[i()]);
+  let l_a : array<mat2x3<f32>, 4> = *(p_a);
+  let l_a_i : mat2x3<f32> = *(p_a_i);
+  let l_a_i_i : vec3<f32> = *(p_a_i_i);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/array/mat2x3_f32/static_index_via_ptr.wgsl
new file mode 100644
index 0000000..8e1e4087
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/static_index_via_ptr.wgsl
@@ -0,0 +1,12 @@
+@group(0) @binding(0) var<uniform> a : array<mat2x3<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a       = &a;
+  let p_a_2     = &((*p_a)[2]);
+  let p_a_2_1   = &((*p_a_2)[1]);
+
+  let l_a       : array<mat2x3<f32>, 4> = *p_a;
+  let l_a_i     : mat2x3<f32>           = *p_a_2;
+  let l_a_i_i   : vec3<f32>             = *p_a_2_1;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x3_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..a6dcbe4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,28 @@
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[8];
+};
+
+float2x3 tint_symbol_1(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+}
+
+typedef float2x3 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[8], uint offset) {
+  float2x3 arr[4] = (float2x3[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 32u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float2x3 l_a[4] = tint_symbol(a, 0u);
+  const float2x3 l_a_i = tint_symbol_1(a, 64u);
+  const float3 l_a_i_i = asfloat(a[5].xyz);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x3_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..a6dcbe4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,28 @@
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[8];
+};
+
+float2x3 tint_symbol_1(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+}
+
+typedef float2x3 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[8], uint offset) {
+  float2x3 arr[4] = (float2x3[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 32u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float2x3 l_a[4] = tint_symbol(a, 0u);
+  const float2x3 l_a_i = tint_symbol_1(a, 64u);
+  const float3 l_a_i_i = asfloat(a[5].xyz);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat2x3_f32/static_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..5cd53bf
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/static_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,17 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform a_block_ubo {
+  mat2x3 inner[4];
+} a;
+
+void f() {
+  mat2x3 l_a[4] = a.inner;
+  mat2x3 l_a_i = a.inner[2];
+  vec3 l_a_i_i = a.inner[2][1];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat2x3_f32/static_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..87f2879
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/static_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,23 @@
+#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];
+};
+
+kernel void f(const constant tint_array<float2x3, 4>* tint_symbol [[buffer(0)]]) {
+  tint_array<float2x3, 4> const l_a = *(tint_symbol);
+  float2x3 const l_a_i = (*(tint_symbol))[2];
+  float3 const l_a_i_i = (*(tint_symbol))[2][1];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat2x3_f32/static_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..c6340b4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/static_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,49 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 27
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block "a_block"
+               OpMemberName %a_block 0 "inner"
+               OpName %a "a"
+               OpName %f "f"
+               OpDecorate %a_block Block
+               OpMemberDecorate %a_block 0 Offset 0
+               OpMemberDecorate %a_block 0 ColMajor
+               OpMemberDecorate %a_block 0 MatrixStride 16
+               OpDecorate %_arr_mat2v3float_uint_4 ArrayStride 32
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat2v3float = OpTypeMatrix %v3float 2
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat2v3float_uint_4 = OpTypeArray %mat2v3float %uint_4
+    %a_block = OpTypeStruct %_arr_mat2v3float_uint_4
+%_ptr_Uniform_a_block = OpTypePointer Uniform %a_block
+          %a = OpVariable %_ptr_Uniform_a_block Uniform
+       %void = OpTypeVoid
+         %10 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat2v3float_uint_4 = OpTypePointer Uniform %_arr_mat2v3float_uint_4
+        %int = OpTypeInt 32 1
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_mat2v3float = OpTypePointer Uniform %mat2v3float
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+          %f = OpFunction %void None %10
+         %13 = OpLabel
+         %16 = OpAccessChain %_ptr_Uniform__arr_mat2v3float_uint_4 %a %uint_0
+         %17 = OpLoad %_arr_mat2v3float_uint_4 %16
+         %21 = OpAccessChain %_ptr_Uniform_mat2v3float %a %uint_0 %int_2
+         %22 = OpLoad %mat2v3float %21
+         %25 = OpAccessChain %_ptr_Uniform_v3float %a %uint_0 %int_2 %int_1
+         %26 = OpLoad %v3float %25
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat2x3_f32/static_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..44250e7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/static_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> a : array<mat2x3<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_2 = &((*(p_a))[2]);
+  let p_a_2_1 = &((*(p_a_2))[1]);
+  let l_a : array<mat2x3<f32>, 4> = *(p_a);
+  let l_a_i : mat2x3<f32> = *(p_a_2);
+  let l_a_i_i : vec3<f32> = *(p_a_2_1);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_builtin.wgsl b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_builtin.wgsl
new file mode 100644
index 0000000..3aeddf2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_builtin.wgsl
@@ -0,0 +1,8 @@
+@group(0) @binding(0) var<uniform> u : array<mat2x3<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    let t = transpose(u[2]);
+    let l = length(u[0][1].zxy);
+    let a = abs(u[0][1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_builtin.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..3ba88af
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_builtin.wgsl.expected.dxc.hlsl
@@ -0,0 +1,17 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[8];
+};
+
+float2x3 tint_symbol(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float3x2 t = transpose(tint_symbol(u, 64u));
+  const float l = length(asfloat(u[1].xyz).zxy);
+  const float a = abs(asfloat(u[1].xyz).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_builtin.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..3ba88af
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_builtin.wgsl.expected.fxc.hlsl
@@ -0,0 +1,17 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[8];
+};
+
+float2x3 tint_symbol(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float3x2 t = transpose(tint_symbol(u, 64u));
+  const float l = length(asfloat(u[1].xyz).zxy);
+  const float a = abs(asfloat(u[1].xyz).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_builtin.wgsl.expected.glsl
new file mode 100644
index 0000000..a3ae889
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_builtin.wgsl.expected.glsl
@@ -0,0 +1,17 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat2x3 inner[4];
+} u;
+
+void f() {
+  mat3x2 t = transpose(u.inner[2]);
+  float l = length(u.inner[0][1].zxy);
+  float a = abs(u.inner[0][1].zxy.x);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_builtin.wgsl.expected.msl
new file mode 100644
index 0000000..afe9bcc
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_builtin.wgsl.expected.msl
@@ -0,0 +1,23 @@
+#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];
+};
+
+kernel void f(const constant tint_array<float2x3, 4>* tint_symbol [[buffer(0)]]) {
+  float3x2 const t = transpose((*(tint_symbol))[2]);
+  float const l = length(float3((*(tint_symbol))[0][1]).zxy);
+  float const a = fabs(float3((*(tint_symbol))[0][1]).zxy[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_builtin.wgsl.expected.spvasm
new file mode 100644
index 0000000..b70cf36
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_builtin.wgsl.expected.spvasm
@@ -0,0 +1,58 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 36
+; Schema: 0
+               OpCapability Shader
+         %24 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %_arr_mat2v3float_uint_4 ArrayStride 32
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat2v3float = OpTypeMatrix %v3float 2
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat2v3float_uint_4 = OpTypeArray %mat2v3float %uint_4
+    %u_block = OpTypeStruct %_arr_mat2v3float_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+         %10 = OpTypeFunction %void
+    %v2float = OpTypeVector %float 2
+%mat3v2float = OpTypeMatrix %v2float 3
+     %uint_0 = OpConstant %uint 0
+        %int = OpTypeInt 32 1
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_mat2v3float = OpTypePointer Uniform %mat2v3float
+         %25 = OpConstantNull %int
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+          %f = OpFunction %void None %10
+         %13 = OpLabel
+         %21 = OpAccessChain %_ptr_Uniform_mat2v3float %u %uint_0 %int_2
+         %22 = OpLoad %mat2v3float %21
+         %14 = OpTranspose %mat3v2float %22
+         %28 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %25 %int_1
+         %29 = OpLoad %v3float %28
+         %30 = OpVectorShuffle %v3float %29 %29 2 0 1
+         %23 = OpExtInst %float %24 Length %30
+         %32 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %25 %int_1
+         %33 = OpLoad %v3float %32
+         %34 = OpVectorShuffle %v3float %33 %33 2 0 1
+         %35 = OpCompositeExtract %float %34 0
+         %31 = OpExtInst %float %24 FAbs %35
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_builtin.wgsl.expected.wgsl
new file mode 100644
index 0000000..e33a24c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_builtin.wgsl.expected.wgsl
@@ -0,0 +1,8 @@
+@group(0) @binding(0) var<uniform> u : array<mat2x3<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let t = transpose(u[2]);
+  let l = length(u[0][1].zxy);
+  let a = abs(u[0][1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_fn.wgsl b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_fn.wgsl
new file mode 100644
index 0000000..3bfbd27
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_fn.wgsl
@@ -0,0 +1,14 @@
+@group(0) @binding(0) var<uniform> u : array<mat2x3<f32>, 4>;
+
+fn a(a : array<mat2x3<f32>, 4>) {}
+fn b(m : mat2x3<f32>) {}
+fn c(v : vec3<f32>) {}
+fn d(f : f32) {}
+
+@compute @workgroup_size(1)
+fn f() {
+    a(u);
+    b(u[1]);
+    c(u[1][0].zxy);
+    d(u[1][0].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_fn.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..9c293d7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_fn.wgsl.expected.dxc.hlsl
@@ -0,0 +1,41 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[8];
+};
+
+void a(float2x3 a_1[4]) {
+}
+
+void b(float2x3 m) {
+}
+
+void c(float3 v) {
+}
+
+void d(float f_1) {
+}
+
+float2x3 tint_symbol_1(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+}
+
+typedef float2x3 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[8], uint offset) {
+  float2x3 arr[4] = (float2x3[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 32u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 32u));
+  c(asfloat(u[2].xyz).zxy);
+  d(asfloat(u[2].xyz).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_fn.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..9c293d7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_fn.wgsl.expected.fxc.hlsl
@@ -0,0 +1,41 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[8];
+};
+
+void a(float2x3 a_1[4]) {
+}
+
+void b(float2x3 m) {
+}
+
+void c(float3 v) {
+}
+
+void d(float f_1) {
+}
+
+float2x3 tint_symbol_1(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+}
+
+typedef float2x3 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[8], uint offset) {
+  float2x3 arr[4] = (float2x3[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 32u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 32u));
+  c(asfloat(u[2].xyz).zxy);
+  d(asfloat(u[2].xyz).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_fn.wgsl.expected.glsl
new file mode 100644
index 0000000..14132c9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_fn.wgsl.expected.glsl
@@ -0,0 +1,30 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat2x3 inner[4];
+} u;
+
+void a(mat2x3 a_1[4]) {
+}
+
+void b(mat2x3 m) {
+}
+
+void c(vec3 v) {
+}
+
+void d(float f_1) {
+}
+
+void f() {
+  a(u.inner);
+  b(u.inner[1]);
+  c(u.inner[1][0].zxy);
+  d(u.inner[1][0].zxy.x);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_fn.wgsl.expected.msl
new file mode 100644
index 0000000..e15cecf
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_fn.wgsl.expected.msl
@@ -0,0 +1,36 @@
+#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];
+};
+
+void a(tint_array<float2x3, 4> a_1) {
+}
+
+void b(float2x3 m) {
+}
+
+void c(float3 v) {
+}
+
+void d(float f_1) {
+}
+
+kernel void f(const constant tint_array<float2x3, 4>* tint_symbol [[buffer(0)]]) {
+  a(*(tint_symbol));
+  b((*(tint_symbol))[1]);
+  c(float3((*(tint_symbol))[1][0]).zxy);
+  d(float3((*(tint_symbol))[1][0]).zxy[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_fn.wgsl.expected.spvasm
new file mode 100644
index 0000000..f109ca4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_fn.wgsl.expected.spvasm
@@ -0,0 +1,90 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 52
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %a "a"
+               OpName %a_1 "a_1"
+               OpName %b "b"
+               OpName %m "m"
+               OpName %c "c"
+               OpName %v "v"
+               OpName %d "d"
+               OpName %f_1 "f_1"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %_arr_mat2v3float_uint_4 ArrayStride 32
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat2v3float = OpTypeMatrix %v3float 2
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat2v3float_uint_4 = OpTypeArray %mat2v3float %uint_4
+    %u_block = OpTypeStruct %_arr_mat2v3float_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+         %10 = OpTypeFunction %void %_arr_mat2v3float_uint_4
+         %15 = OpTypeFunction %void %mat2v3float
+         %19 = OpTypeFunction %void %v3float
+         %23 = OpTypeFunction %void %float
+         %27 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat2v3float_uint_4 = OpTypePointer Uniform %_arr_mat2v3float_uint_4
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_mat2v3float = OpTypePointer Uniform %mat2v3float
+         %42 = OpConstantNull %int
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+          %a = OpFunction %void None %10
+        %a_1 = OpFunctionParameter %_arr_mat2v3float_uint_4
+         %14 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %b = OpFunction %void None %15
+          %m = OpFunctionParameter %mat2v3float
+         %18 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %c = OpFunction %void None %19
+          %v = OpFunctionParameter %v3float
+         %22 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %d = OpFunction %void None %23
+        %f_1 = OpFunctionParameter %float
+         %26 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %27
+         %29 = OpLabel
+         %33 = OpAccessChain %_ptr_Uniform__arr_mat2v3float_uint_4 %u %uint_0
+         %34 = OpLoad %_arr_mat2v3float_uint_4 %33
+         %30 = OpFunctionCall %void %a %34
+         %39 = OpAccessChain %_ptr_Uniform_mat2v3float %u %uint_0 %int_1
+         %40 = OpLoad %mat2v3float %39
+         %35 = OpFunctionCall %void %b %40
+         %44 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %int_1 %42
+         %45 = OpLoad %v3float %44
+         %46 = OpVectorShuffle %v3float %45 %45 2 0 1
+         %41 = OpFunctionCall %void %c %46
+         %48 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %int_1 %42
+         %49 = OpLoad %v3float %48
+         %50 = OpVectorShuffle %v3float %49 %49 2 0 1
+         %51 = OpCompositeExtract %float %50 0
+         %47 = OpFunctionCall %void %d %51
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_fn.wgsl.expected.wgsl
new file mode 100644
index 0000000..1ff40e4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_fn.wgsl.expected.wgsl
@@ -0,0 +1,21 @@
+@group(0) @binding(0) var<uniform> u : array<mat2x3<f32>, 4>;
+
+fn a(a : array<mat2x3<f32>, 4>) {
+}
+
+fn b(m : mat2x3<f32>) {
+}
+
+fn c(v : vec3<f32>) {
+}
+
+fn d(f : f32) {
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  a(u);
+  b(u[1]);
+  c(u[1][0].zxy);
+  d(u[1][0].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_private.wgsl b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_private.wgsl
new file mode 100644
index 0000000..8918241
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_private.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0) var<uniform> u : array<mat2x3<f32>, 4>;
+var<private> p : array<mat2x3<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[2];
+    p[1][0] = u[0][1].zxy;
+    p[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_private.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..5f9d507
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_private.wgsl.expected.dxc.hlsl
@@ -0,0 +1,30 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[8];
+};
+static float2x3 p[4] = (float2x3[4])0;
+
+float2x3 tint_symbol_1(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+}
+
+typedef float2x3 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[8], uint offset) {
+  float2x3 arr[4] = (float2x3[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 32u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 64u);
+  p[1][0] = asfloat(u[1].xyz).zxy;
+  p[1][0].x = asfloat(u[1].x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_private.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..5f9d507
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_private.wgsl.expected.fxc.hlsl
@@ -0,0 +1,30 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[8];
+};
+static float2x3 p[4] = (float2x3[4])0;
+
+float2x3 tint_symbol_1(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+}
+
+typedef float2x3 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[8], uint offset) {
+  float2x3 arr[4] = (float2x3[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 32u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 64u);
+  p[1][0] = asfloat(u[1].xyz).zxy;
+  p[1][0].x = asfloat(u[1].x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..67f7177
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_private.wgsl.expected.glsl
@@ -0,0 +1,19 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat2x3 inner[4];
+} u;
+
+mat2x3 p[4] = mat2x3[4](mat2x3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat2x3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat2x3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat2x3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
+void f() {
+  p = u.inner;
+  p[1] = u.inner[2];
+  p[1][0] = u.inner[0][1].zxy;
+  p[1][0].x = u.inner[0][1].x;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..4fa5a85
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_private.wgsl.expected.msl
@@ -0,0 +1,25 @@
+#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];
+};
+
+kernel void f(const constant tint_array<float2x3, 4>* tint_symbol_1 [[buffer(0)]]) {
+  thread tint_array<float2x3, 4> tint_symbol = {};
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[2];
+  tint_symbol[1][0] = float3((*(tint_symbol_1))[0][1]).zxy;
+  tint_symbol[1][0][0] = (*(tint_symbol_1))[0][1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_private.wgsl.expected.spvasm
new file mode 100644
index 0000000..ad56275
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_private.wgsl.expected.spvasm
@@ -0,0 +1,68 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 41
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %p "p"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %_arr_mat2v3float_uint_4 ArrayStride 32
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat2v3float = OpTypeMatrix %v3float 2
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat2v3float_uint_4 = OpTypeArray %mat2v3float %uint_4
+    %u_block = OpTypeStruct %_arr_mat2v3float_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_Private__arr_mat2v3float_uint_4 = OpTypePointer Private %_arr_mat2v3float_uint_4
+         %12 = OpConstantNull %_arr_mat2v3float_uint_4
+          %p = OpVariable %_ptr_Private__arr_mat2v3float_uint_4 Private %12
+       %void = OpTypeVoid
+         %13 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat2v3float_uint_4 = OpTypePointer Uniform %_arr_mat2v3float_uint_4
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Private_mat2v3float = OpTypePointer Private %mat2v3float
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_mat2v3float = OpTypePointer Uniform %mat2v3float
+         %29 = OpConstantNull %int
+%_ptr_Private_v3float = OpTypePointer Private %v3float
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+%_ptr_Private_float = OpTypePointer Private %float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+          %f = OpFunction %void None %13
+         %16 = OpLabel
+         %19 = OpAccessChain %_ptr_Uniform__arr_mat2v3float_uint_4 %u %uint_0
+         %20 = OpLoad %_arr_mat2v3float_uint_4 %19
+               OpStore %p %20
+         %24 = OpAccessChain %_ptr_Private_mat2v3float %p %int_1
+         %27 = OpAccessChain %_ptr_Uniform_mat2v3float %u %uint_0 %int_2
+         %28 = OpLoad %mat2v3float %27
+               OpStore %24 %28
+         %31 = OpAccessChain %_ptr_Private_v3float %p %int_1 %29
+         %33 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %29 %int_1
+         %34 = OpLoad %v3float %33
+         %35 = OpVectorShuffle %v3float %34 %34 2 0 1
+               OpStore %31 %35
+         %37 = OpAccessChain %_ptr_Private_float %p %int_1 %29 %uint_0
+         %39 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %29 %int_1 %uint_0
+         %40 = OpLoad %float %39
+               OpStore %37 %40
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..a4230fd
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_private.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> u : array<mat2x3<f32>, 4>;
+
+var<private> p : array<mat2x3<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[2];
+  p[1][0] = u[0][1].zxy;
+  p[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_storage.wgsl b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_storage.wgsl
new file mode 100644
index 0000000..d6b940e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_storage.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0) var<uniform> u : array<mat2x3<f32>, 4>;
+@group(0) @binding(1) var<storage, read_write> s : array<mat2x3<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[2];
+    s[1][0] = u[0][1].zxy;
+    s[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_storage.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..9d1bbf8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_storage.wgsl.expected.dxc.hlsl
@@ -0,0 +1,44 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[8];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, float2x3 value) {
+  buffer.Store3((offset + 0u), asuint(value[0u]));
+  buffer.Store3((offset + 16u), asuint(value[1u]));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, float2x3 value[4]) {
+  float2x3 array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 32u)), array[i]);
+    }
+  }
+}
+
+float2x3 tint_symbol_4(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+}
+
+typedef float2x3 tint_symbol_3_ret[4];
+tint_symbol_3_ret tint_symbol_3(uint4 buffer[8], uint offset) {
+  float2x3 arr[4] = (float2x3[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_4(buffer, (offset + (i_1 * 32u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_3(u, 0u));
+  tint_symbol_1(s, 32u, tint_symbol_4(u, 64u));
+  s.Store3(32u, asuint(asfloat(u[1].xyz).zxy));
+  s.Store(32u, asuint(asfloat(u[1].x)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_storage.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..9d1bbf8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_storage.wgsl.expected.fxc.hlsl
@@ -0,0 +1,44 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[8];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, float2x3 value) {
+  buffer.Store3((offset + 0u), asuint(value[0u]));
+  buffer.Store3((offset + 16u), asuint(value[1u]));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, float2x3 value[4]) {
+  float2x3 array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 32u)), array[i]);
+    }
+  }
+}
+
+float2x3 tint_symbol_4(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+}
+
+typedef float2x3 tint_symbol_3_ret[4];
+tint_symbol_3_ret tint_symbol_3(uint4 buffer[8], uint offset) {
+  float2x3 arr[4] = (float2x3[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_4(buffer, (offset + (i_1 * 32u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_3(u, 0u));
+  tint_symbol_1(s, 32u, tint_symbol_4(u, 64u));
+  s.Store3(32u, asuint(asfloat(u[1].xyz).zxy));
+  s.Store(32u, asuint(asfloat(u[1].x)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..08b531f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_storage.wgsl.expected.glsl
@@ -0,0 +1,22 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat2x3 inner[4];
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  mat2x3 inner[4];
+} s;
+
+void f() {
+  s.inner = u.inner;
+  s.inner[1] = u.inner[2];
+  s.inner[1][0] = u.inner[0][1].zxy;
+  s.inner[1][0].x = u.inner[0][1].x;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..42f3b1d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_storage.wgsl.expected.msl
@@ -0,0 +1,24 @@
+#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];
+};
+
+kernel void f(device tint_array<float2x3, 4>* tint_symbol [[buffer(1)]], const constant tint_array<float2x3, 4>* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
+  (*(tint_symbol))[1][0] = float3((*(tint_symbol_1))[0][1]).zxy;
+  (*(tint_symbol))[1][0][0] = (*(tint_symbol_1))[0][1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_storage.wgsl.expected.spvasm
new file mode 100644
index 0000000..e7e86aa
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_storage.wgsl.expected.spvasm
@@ -0,0 +1,71 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 42
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %s "s"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %_arr_mat2v3float_uint_4 ArrayStride 32
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %s DescriptorSet 0
+               OpDecorate %s Binding 1
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat2v3float = OpTypeMatrix %v3float 2
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat2v3float_uint_4 = OpTypeArray %mat2v3float %uint_4
+    %u_block = OpTypeStruct %_arr_mat2v3float_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
+          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+       %void = OpTypeVoid
+         %12 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer__arr_mat2v3float_uint_4 = OpTypePointer StorageBuffer %_arr_mat2v3float_uint_4
+%_ptr_Uniform__arr_mat2v3float_uint_4 = OpTypePointer Uniform %_arr_mat2v3float_uint_4
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_mat2v3float = OpTypePointer StorageBuffer %mat2v3float
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_mat2v3float = OpTypePointer Uniform %mat2v3float
+         %30 = OpConstantNull %int
+%_ptr_StorageBuffer_v3float = OpTypePointer StorageBuffer %v3float
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+          %f = OpFunction %void None %12
+         %15 = OpLabel
+         %18 = OpAccessChain %_ptr_StorageBuffer__arr_mat2v3float_uint_4 %s %uint_0
+         %20 = OpAccessChain %_ptr_Uniform__arr_mat2v3float_uint_4 %u %uint_0
+         %21 = OpLoad %_arr_mat2v3float_uint_4 %20
+               OpStore %18 %21
+         %25 = OpAccessChain %_ptr_StorageBuffer_mat2v3float %s %uint_0 %int_1
+         %28 = OpAccessChain %_ptr_Uniform_mat2v3float %u %uint_0 %int_2
+         %29 = OpLoad %mat2v3float %28
+               OpStore %25 %29
+         %32 = OpAccessChain %_ptr_StorageBuffer_v3float %s %uint_0 %int_1 %30
+         %34 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %30 %int_1
+         %35 = OpLoad %v3float %34
+         %36 = OpVectorShuffle %v3float %35 %35 2 0 1
+               OpStore %32 %36
+         %38 = OpAccessChain %_ptr_StorageBuffer_float %s %uint_0 %int_1 %30 %uint_0
+         %40 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %30 %int_1 %uint_0
+         %41 = OpLoad %float %40
+               OpStore %38 %41
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..2b23d80
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> u : array<mat2x3<f32>, 4>;
+
+@group(0) @binding(1) var<storage, read_write> s : array<mat2x3<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[2];
+  s[1][0] = u[0][1].zxy;
+  s[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_workgroup.wgsl
new file mode 100644
index 0000000..a79e04a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_workgroup.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0) var<uniform> u : array<mat2x3<f32>, 4>;
+var<workgroup> w : array<mat2x3<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[2];
+    w[1][0] = u[0][1].zxy;
+    w[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_workgroup.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..0b13b88
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_workgroup.wgsl.expected.dxc.hlsl
@@ -0,0 +1,45 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[8];
+};
+groupshared float2x3 w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+float2x3 tint_symbol_3(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+}
+
+typedef float2x3 tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[8], uint offset) {
+  float2x3 arr[4] = (float2x3[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 32u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      w[i] = float2x3((0.0f).xxx, (0.0f).xxx);
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 64u);
+  w[1][0] = asfloat(u[1].xyz).zxy;
+  w[1][0].x = asfloat(u[1].x);
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_workgroup.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..0b13b88
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_workgroup.wgsl.expected.fxc.hlsl
@@ -0,0 +1,45 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[8];
+};
+groupshared float2x3 w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+float2x3 tint_symbol_3(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+}
+
+typedef float2x3 tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[8], uint offset) {
+  float2x3 arr[4] = (float2x3[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 32u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      w[i] = float2x3((0.0f).xxx, (0.0f).xxx);
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 64u);
+  w[1][0] = asfloat(u[1].xyz).zxy;
+  w[1][0].x = asfloat(u[1].x);
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..0c18521
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,26 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat2x3 inner[4];
+} u;
+
+shared mat2x3 w[4];
+void f(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      uint i = idx;
+      w[i] = mat2x3(vec3(0.0f), vec3(0.0f));
+    }
+  }
+  barrier();
+  w = u.inner;
+  w[1] = u.inner[2];
+  w[1][0] = u.inner[0][1].zxy;
+  w[1][0].x = u.inner[0][1].x;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..d63ff3d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,38 @@
+#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_symbol_5 {
+  tint_array<float2x3, 4> w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup tint_array<float2x3, 4>* const tint_symbol, const constant tint_array<float2x3, 4>* const tint_symbol_1) {
+  for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+    uint const i = idx;
+    (*(tint_symbol))[i] = float2x3(float3(0.0f), float3(0.0f));
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
+  (*(tint_symbol))[1][0] = float3((*(tint_symbol_1))[0][1]).zxy;
+  (*(tint_symbol))[1][0][0] = (*(tint_symbol_1))[0][1][0];
+}
+
+kernel void f(const constant tint_array<float2x3, 4>* tint_symbol_4 [[buffer(0)]], threadgroup tint_symbol_5* tint_symbol_3 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup tint_array<float2x3, 4>* const tint_symbol_2 = &((*(tint_symbol_3)).w);
+  f_inner(local_invocation_index, tint_symbol_2, tint_symbol_4);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_workgroup.wgsl.expected.spvasm
new file mode 100644
index 0000000..98ee0ab
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_workgroup.wgsl.expected.spvasm
@@ -0,0 +1,115 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 70
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %local_invocation_index_1 "local_invocation_index_1"
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %w "w"
+               OpName %f_inner "f_inner"
+               OpName %local_invocation_index "local_invocation_index"
+               OpName %idx "idx"
+               OpName %f "f"
+               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %_arr_mat2v3float_uint_4 ArrayStride 32
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat2v3float = OpTypeMatrix %v3float 2
+     %uint_4 = OpConstant %uint 4
+%_arr_mat2v3float_uint_4 = OpTypeArray %mat2v3float %uint_4
+    %u_block = OpTypeStruct %_arr_mat2v3float_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_Workgroup__arr_mat2v3float_uint_4 = OpTypePointer Workgroup %_arr_mat2v3float_uint_4
+          %w = OpVariable %_ptr_Workgroup__arr_mat2v3float_uint_4 Workgroup
+       %void = OpTypeVoid
+         %14 = OpTypeFunction %void %uint
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %21 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Workgroup_mat2v3float = OpTypePointer Workgroup %mat2v3float
+         %35 = OpConstantNull %mat2v3float
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+   %uint_264 = OpConstant %uint 264
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat2v3float_uint_4 = OpTypePointer Uniform %_arr_mat2v3float_uint_4
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_mat2v3float = OpTypePointer Uniform %mat2v3float
+         %53 = OpConstantNull %int
+%_ptr_Workgroup_v3float = OpTypePointer Workgroup %v3float
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+%_ptr_Workgroup_float = OpTypePointer Workgroup %float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+         %65 = OpTypeFunction %void
+    %f_inner = OpFunction %void None %14
+%local_invocation_index = OpFunctionParameter %uint
+         %18 = OpLabel
+        %idx = OpVariable %_ptr_Function_uint Function %21
+               OpStore %idx %local_invocation_index
+               OpBranch %22
+         %22 = OpLabel
+               OpLoopMerge %23 %24 None
+               OpBranch %25
+         %25 = OpLabel
+         %27 = OpLoad %uint %idx
+         %28 = OpULessThan %bool %27 %uint_4
+         %26 = OpLogicalNot %bool %28
+               OpSelectionMerge %30 None
+               OpBranchConditional %26 %31 %30
+         %31 = OpLabel
+               OpBranch %23
+         %30 = OpLabel
+         %32 = OpLoad %uint %idx
+         %34 = OpAccessChain %_ptr_Workgroup_mat2v3float %w %32
+               OpStore %34 %35
+               OpBranch %24
+         %24 = OpLabel
+         %36 = OpLoad %uint %idx
+         %38 = OpIAdd %uint %36 %uint_1
+               OpStore %idx %38
+               OpBranch %22
+         %23 = OpLabel
+               OpControlBarrier %uint_2 %uint_2 %uint_264
+         %44 = OpAccessChain %_ptr_Uniform__arr_mat2v3float_uint_4 %u %uint_0
+         %45 = OpLoad %_arr_mat2v3float_uint_4 %44
+               OpStore %w %45
+         %48 = OpAccessChain %_ptr_Workgroup_mat2v3float %w %int_1
+         %51 = OpAccessChain %_ptr_Uniform_mat2v3float %u %uint_0 %int_2
+         %52 = OpLoad %mat2v3float %51
+               OpStore %48 %52
+         %55 = OpAccessChain %_ptr_Workgroup_v3float %w %int_1 %53
+         %57 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %53 %int_1
+         %58 = OpLoad %v3float %57
+         %59 = OpVectorShuffle %v3float %58 %58 2 0 1
+               OpStore %55 %59
+         %61 = OpAccessChain %_ptr_Workgroup_float %w %int_1 %53 %uint_0
+         %63 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %53 %int_1 %uint_0
+         %64 = OpLoad %float %63
+               OpStore %61 %64
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %65
+         %67 = OpLabel
+         %69 = OpLoad %uint %local_invocation_index_1
+         %68 = OpFunctionCall %void %f_inner %69
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..c34e03b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x3_f32/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> u : array<mat2x3<f32>, 4>;
+
+var<workgroup> w : array<mat2x3<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[2];
+  w[1][0] = u[0][1].zxy;
+  w[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/array/mat2x4_f16/dynamic_index_via_ptr.wgsl
new file mode 100644
index 0000000..0474ac2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/dynamic_index_via_ptr.wgsl
@@ -0,0 +1,17 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> a : array<mat2x4<f16>, 4>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a       = &a;
+  let p_a_i     = &((*p_a)[i()]);
+  let p_a_i_i   = &((*p_a_i)[i()]);
+
+  let l_a       : array<mat2x4<f16>, 4> = *p_a;
+  let l_a_i     : mat2x4<f16>           = *p_a_i;
+  let l_a_i_i   : vec4<f16>             = *p_a_i_i;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..fe06356
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,49 @@
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[4];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 2, 4> tint_symbol_1(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+typedef matrix<float16_t, 2, 4> tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[4], uint offset) {
+  matrix<float16_t, 2, 4> arr[4] = (matrix<float16_t, 2, 4>[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 16u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_i_save = i();
+  const matrix<float16_t, 2, 4> l_a[4] = tint_symbol(a, 0u);
+  const matrix<float16_t, 2, 4> l_a_i = tint_symbol_1(a, (16u * uint(p_a_i_save)));
+  const uint scalar_offset_2 = (((16u * uint(p_a_i_save)) + (8u * uint(p_a_i_i_save)))) / 4;
+  uint4 ubo_load_5 = a[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const vector<float16_t, 4> l_a_i_i = vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..08e7c35
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,54 @@
+SKIP: FAILED
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[4];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 2, 4> tint_symbol_1(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+typedef matrix<float16_t, 2, 4> tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[4], uint offset) {
+  matrix<float16_t, 2, 4> arr[4] = (matrix<float16_t, 2, 4>[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 16u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_i_save = i();
+  const matrix<float16_t, 2, 4> l_a[4] = tint_symbol(a, 0u);
+  const matrix<float16_t, 2, 4> l_a_i = tint_symbol_1(a, (16u * uint(p_a_i_save)));
+  const uint scalar_offset_2 = (((16u * uint(p_a_i_save)) + (8u * uint(p_a_i_i_save)))) / 4;
+  uint4 ubo_load_5 = a[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const vector<float16_t, 4> l_a_i_i = vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000015AD15A89A0(11,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..550a108
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,65 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct mat2x4_f16 {
+  f16vec4 col0;
+  f16vec4 col1;
+};
+
+layout(binding = 0, std140) uniform a_block_std140_ubo {
+  mat2x4_f16 inner[4];
+} a;
+
+int counter = 0;
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+f16mat2x4 conv_mat2x4_f16(mat2x4_f16 val) {
+  return f16mat2x4(val.col0, val.col1);
+}
+
+f16mat2x4[4] conv_arr4_mat2x4_f16(mat2x4_f16 val[4]) {
+  f16mat2x4 arr[4] = f16mat2x4[4](f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat2x4_f16(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16vec4 load_a_inner_p0_p1(uint p0, uint p1) {
+  switch(p1) {
+    case 0u: {
+      return a.inner[p0].col0;
+      break;
+    }
+    case 1u: {
+      return a.inner[p0].col1;
+      break;
+    }
+    default: {
+      return f16vec4(0.0hf);
+      break;
+    }
+  }
+}
+
+void f() {
+  f16mat2x4 p_a[4] = conv_arr4_mat2x4_f16(a.inner);
+  int tint_symbol = i();
+  f16mat2x4 p_a_i = conv_mat2x4_f16(a.inner[tint_symbol]);
+  int tint_symbol_1 = i();
+  f16vec4 p_a_i_i = load_a_inner_p0_p1(uint(tint_symbol), uint(tint_symbol_1));
+  f16mat2x4 l_a[4] = conv_arr4_mat2x4_f16(a.inner);
+  f16mat2x4 l_a_i = conv_mat2x4_f16(a.inner[tint_symbol]);
+  f16vec4 l_a_i_i = load_a_inner_p0_p1(uint(tint_symbol), uint(tint_symbol_1));
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..7ff60c2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,33 @@
+#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];
+};
+
+int i() {
+  thread int tint_symbol_2 = 0;
+  tint_symbol_2 = as_type<int>((as_type<uint>(tint_symbol_2) + as_type<uint>(1)));
+  return tint_symbol_2;
+}
+
+kernel void f(const constant tint_array<half2x4, 4>* tint_symbol_3 [[buffer(0)]]) {
+  int const tint_symbol = i();
+  int const p_a_i_save = tint_symbol;
+  int const tint_symbol_1 = i();
+  int const p_a_i_i_save = tint_symbol_1;
+  tint_array<half2x4, 4> const l_a = *(tint_symbol_3);
+  half2x4 const l_a_i = (*(tint_symbol_3))[p_a_i_save];
+  half4 const l_a_i_i = (*(tint_symbol_3))[p_a_i_save][p_a_i_i_save];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..9ff46e7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,165 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 98
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block_std140 "a_block_std140"
+               OpMemberName %a_block_std140 0 "inner"
+               OpName %mat2x4_f16 "mat2x4_f16"
+               OpMemberName %mat2x4_f16 0 "col0"
+               OpMemberName %mat2x4_f16 1 "col1"
+               OpName %a "a"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %conv_mat2x4_f16 "conv_mat2x4_f16"
+               OpName %val "val"
+               OpName %conv_arr4_mat2x4_f16 "conv_arr4_mat2x4_f16"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i_0 "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_a_inner_p0_p1 "load_a_inner_p0_p1"
+               OpName %p0 "p0"
+               OpName %p1 "p1"
+               OpName %f "f"
+               OpDecorate %a_block_std140 Block
+               OpMemberDecorate %a_block_std140 0 Offset 0
+               OpMemberDecorate %mat2x4_f16 0 Offset 0
+               OpMemberDecorate %mat2x4_f16 1 Offset 8
+               OpDecorate %_arr_mat2x4_f16_uint_4 ArrayStride 16
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+               OpDecorate %_arr_mat2v4half_uint_4 ArrayStride 16
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+ %mat2x4_f16 = OpTypeStruct %v4half %v4half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat2x4_f16_uint_4 = OpTypeArray %mat2x4_f16 %uint_4
+%a_block_std140 = OpTypeStruct %_arr_mat2x4_f16_uint_4
+%_ptr_Uniform_a_block_std140 = OpTypePointer Uniform %a_block_std140
+          %a = OpVariable %_ptr_Uniform_a_block_std140 Uniform
+        %int = OpTypeInt 32 1
+         %11 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %11
+         %14 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+ %mat2v4half = OpTypeMatrix %v4half 2
+         %21 = OpTypeFunction %mat2v4half %mat2x4_f16
+%_arr_mat2v4half_uint_4 = OpTypeArray %mat2v4half %uint_4
+         %29 = OpTypeFunction %_arr_mat2v4half_uint_4 %_arr_mat2x4_f16_uint_4
+%_ptr_Function__arr_mat2v4half_uint_4 = OpTypePointer Function %_arr_mat2v4half_uint_4
+         %36 = OpConstantNull %_arr_mat2v4half_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %39 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_mat2x4_f16_uint_4 = OpTypePointer Function %_arr_mat2x4_f16_uint_4
+         %52 = OpConstantNull %_arr_mat2x4_f16_uint_4
+%_ptr_Function_mat2v4half = OpTypePointer Function %mat2v4half
+%_ptr_Function_mat2x4_f16 = OpTypePointer Function %mat2x4_f16
+     %uint_1 = OpConstant %uint 1
+         %65 = OpTypeFunction %v4half %uint %uint
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+         %80 = OpConstantNull %v4half
+       %void = OpTypeVoid
+         %81 = OpTypeFunction %void
+%_ptr_Uniform__arr_mat2x4_f16_uint_4 = OpTypePointer Uniform %_arr_mat2x4_f16_uint_4
+%_ptr_Uniform_mat2x4_f16 = OpTypePointer Uniform %mat2x4_f16
+          %i = OpFunction %int None %14
+         %16 = OpLabel
+         %17 = OpLoad %int %counter
+         %19 = OpIAdd %int %17 %int_1
+               OpStore %counter %19
+         %20 = OpLoad %int %counter
+               OpReturnValue %20
+               OpFunctionEnd
+%conv_mat2x4_f16 = OpFunction %mat2v4half None %21
+        %val = OpFunctionParameter %mat2x4_f16
+         %25 = OpLabel
+         %26 = OpCompositeExtract %v4half %val 0
+         %27 = OpCompositeExtract %v4half %val 1
+         %28 = OpCompositeConstruct %mat2v4half %26 %27
+               OpReturnValue %28
+               OpFunctionEnd
+%conv_arr4_mat2x4_f16 = OpFunction %_arr_mat2v4half_uint_4 None %29
+      %val_0 = OpFunctionParameter %_arr_mat2x4_f16_uint_4
+         %33 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_mat2v4half_uint_4 Function %36
+        %i_0 = OpVariable %_ptr_Function_uint Function %39
+%var_for_index = OpVariable %_ptr_Function__arr_mat2x4_f16_uint_4 Function %52
+               OpBranch %40
+         %40 = OpLabel
+               OpLoopMerge %41 %42 None
+               OpBranch %43
+         %43 = OpLabel
+         %45 = OpLoad %uint %i_0
+         %46 = OpULessThan %bool %45 %uint_4
+         %44 = OpLogicalNot %bool %46
+               OpSelectionMerge %48 None
+               OpBranchConditional %44 %49 %48
+         %49 = OpLabel
+               OpBranch %41
+         %48 = OpLabel
+               OpStore %var_for_index %val_0
+         %53 = OpLoad %uint %i_0
+         %55 = OpAccessChain %_ptr_Function_mat2v4half %arr %53
+         %57 = OpLoad %uint %i_0
+         %59 = OpAccessChain %_ptr_Function_mat2x4_f16 %var_for_index %57
+         %60 = OpLoad %mat2x4_f16 %59
+         %56 = OpFunctionCall %mat2v4half %conv_mat2x4_f16 %60
+               OpStore %55 %56
+               OpBranch %42
+         %42 = OpLabel
+         %61 = OpLoad %uint %i_0
+         %63 = OpIAdd %uint %61 %uint_1
+               OpStore %i_0 %63
+               OpBranch %40
+         %41 = OpLabel
+         %64 = OpLoad %_arr_mat2v4half_uint_4 %arr
+               OpReturnValue %64
+               OpFunctionEnd
+%load_a_inner_p0_p1 = OpFunction %v4half None %65
+         %p0 = OpFunctionParameter %uint
+         %p1 = OpFunctionParameter %uint
+         %69 = OpLabel
+               OpSelectionMerge %70 None
+               OpSwitch %p1 %71 0 %72 1 %73
+         %72 = OpLabel
+         %76 = OpAccessChain %_ptr_Uniform_v4half %a %uint_0 %p0 %uint_0
+         %77 = OpLoad %v4half %76
+               OpReturnValue %77
+         %73 = OpLabel
+         %78 = OpAccessChain %_ptr_Uniform_v4half %a %uint_0 %p0 %uint_1
+         %79 = OpLoad %v4half %78
+               OpReturnValue %79
+         %71 = OpLabel
+               OpReturnValue %80
+         %70 = OpLabel
+               OpReturnValue %80
+               OpFunctionEnd
+          %f = OpFunction %void None %81
+         %84 = OpLabel
+         %85 = OpFunctionCall %int %i
+         %86 = OpFunctionCall %int %i
+         %89 = OpAccessChain %_ptr_Uniform__arr_mat2x4_f16_uint_4 %a %uint_0
+         %90 = OpLoad %_arr_mat2x4_f16_uint_4 %89
+         %87 = OpFunctionCall %_arr_mat2v4half_uint_4 %conv_arr4_mat2x4_f16 %90
+         %93 = OpAccessChain %_ptr_Uniform_mat2x4_f16 %a %uint_0 %85
+         %94 = OpLoad %mat2x4_f16 %93
+         %91 = OpFunctionCall %mat2v4half %conv_mat2x4_f16 %94
+         %96 = OpBitcast %uint %85
+         %97 = OpBitcast %uint %86
+         %95 = OpFunctionCall %v4half %load_a_inner_p0_p1 %96 %97
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..3593341
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,20 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> a : array<mat2x4<f16>, 4>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_i = &((*(p_a))[i()]);
+  let p_a_i_i = &((*(p_a_i))[i()]);
+  let l_a : array<mat2x4<f16>, 4> = *(p_a);
+  let l_a_i : mat2x4<f16> = *(p_a_i);
+  let l_a_i_i : vec4<f16> = *(p_a_i_i);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/array/mat2x4_f16/static_index_via_ptr.wgsl
new file mode 100644
index 0000000..d3b62e3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/static_index_via_ptr.wgsl
@@ -0,0 +1,14 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> a : array<mat2x4<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a       = &a;
+  let p_a_2     = &((*p_a)[2]);
+  let p_a_2_1   = &((*p_a_2)[1]);
+
+  let l_a       : array<mat2x4<f16>, 4> = *p_a;
+  let l_a_i     : mat2x4<f16>           = *p_a_2;
+  let l_a_i_i   : vec4<f16>             = *p_a_2_1;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x4_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..3632bea
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,39 @@
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[4];
+};
+
+matrix<float16_t, 2, 4> tint_symbol_1(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+typedef matrix<float16_t, 2, 4> tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[4], uint offset) {
+  matrix<float16_t, 2, 4> arr[4] = (matrix<float16_t, 2, 4>[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 16u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 2, 4> l_a[4] = tint_symbol(a, 0u);
+  const matrix<float16_t, 2, 4> l_a_i = tint_symbol_1(a, 32u);
+  uint2 ubo_load_4 = a[2].zw;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const vector<float16_t, 4> l_a_i_i = vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x4_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..d3aaa7e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,44 @@
+SKIP: FAILED
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[4];
+};
+
+matrix<float16_t, 2, 4> tint_symbol_1(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+typedef matrix<float16_t, 2, 4> tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[4], uint offset) {
+  matrix<float16_t, 2, 4> arr[4] = (matrix<float16_t, 2, 4>[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 16u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 2, 4> l_a[4] = tint_symbol(a, 0u);
+  const matrix<float16_t, 2, 4> l_a_i = tint_symbol_1(a, 32u);
+  uint2 ubo_load_4 = a[2].zw;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const vector<float16_t, 4> l_a_i_i = vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x00000192D71EE4C0(5,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat2x4_f16/static_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..4ef2ff5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/static_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,40 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct mat2x4_f16 {
+  f16vec4 col0;
+  f16vec4 col1;
+};
+
+layout(binding = 0, std140) uniform a_block_std140_ubo {
+  mat2x4_f16 inner[4];
+} a;
+
+f16mat2x4 conv_mat2x4_f16(mat2x4_f16 val) {
+  return f16mat2x4(val.col0, val.col1);
+}
+
+f16mat2x4[4] conv_arr4_mat2x4_f16(mat2x4_f16 val[4]) {
+  f16mat2x4 arr[4] = f16mat2x4[4](f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat2x4_f16(val[i]);
+    }
+  }
+  return arr;
+}
+
+void f() {
+  f16mat2x4 p_a[4] = conv_arr4_mat2x4_f16(a.inner);
+  f16mat2x4 p_a_2 = conv_mat2x4_f16(a.inner[2u]);
+  f16vec4 p_a_2_1 = a.inner[2u].col1;
+  f16mat2x4 l_a[4] = conv_arr4_mat2x4_f16(a.inner);
+  f16mat2x4 l_a_i = conv_mat2x4_f16(a.inner[2u]);
+  f16vec4 l_a_i_i = a.inner[2u].col1;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat2x4_f16/static_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..8547394
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/static_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,23 @@
+#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];
+};
+
+kernel void f(const constant tint_array<half2x4, 4>* tint_symbol [[buffer(0)]]) {
+  tint_array<half2x4, 4> const l_a = *(tint_symbol);
+  half2x4 const l_a_i = (*(tint_symbol))[2];
+  half4 const l_a_i_i = (*(tint_symbol))[2][1];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat2x4_f16/static_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..4f7edfd
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/static_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,123 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 71
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block_std140 "a_block_std140"
+               OpMemberName %a_block_std140 0 "inner"
+               OpName %mat2x4_f16 "mat2x4_f16"
+               OpMemberName %mat2x4_f16 0 "col0"
+               OpMemberName %mat2x4_f16 1 "col1"
+               OpName %a "a"
+               OpName %conv_mat2x4_f16 "conv_mat2x4_f16"
+               OpName %val "val"
+               OpName %conv_arr4_mat2x4_f16 "conv_arr4_mat2x4_f16"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %f "f"
+               OpDecorate %a_block_std140 Block
+               OpMemberDecorate %a_block_std140 0 Offset 0
+               OpMemberDecorate %mat2x4_f16 0 Offset 0
+               OpMemberDecorate %mat2x4_f16 1 Offset 8
+               OpDecorate %_arr_mat2x4_f16_uint_4 ArrayStride 16
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+               OpDecorate %_arr_mat2v4half_uint_4 ArrayStride 16
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+ %mat2x4_f16 = OpTypeStruct %v4half %v4half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat2x4_f16_uint_4 = OpTypeArray %mat2x4_f16 %uint_4
+%a_block_std140 = OpTypeStruct %_arr_mat2x4_f16_uint_4
+%_ptr_Uniform_a_block_std140 = OpTypePointer Uniform %a_block_std140
+          %a = OpVariable %_ptr_Uniform_a_block_std140 Uniform
+ %mat2v4half = OpTypeMatrix %v4half 2
+         %10 = OpTypeFunction %mat2v4half %mat2x4_f16
+%_arr_mat2v4half_uint_4 = OpTypeArray %mat2v4half %uint_4
+         %18 = OpTypeFunction %_arr_mat2v4half_uint_4 %_arr_mat2x4_f16_uint_4
+%_ptr_Function__arr_mat2v4half_uint_4 = OpTypePointer Function %_arr_mat2v4half_uint_4
+         %25 = OpConstantNull %_arr_mat2v4half_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %28 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_mat2x4_f16_uint_4 = OpTypePointer Function %_arr_mat2x4_f16_uint_4
+         %41 = OpConstantNull %_arr_mat2x4_f16_uint_4
+%_ptr_Function_mat2v4half = OpTypePointer Function %mat2v4half
+%_ptr_Function_mat2x4_f16 = OpTypePointer Function %mat2x4_f16
+     %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %54 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat2x4_f16_uint_4 = OpTypePointer Uniform %_arr_mat2x4_f16_uint_4
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_mat2x4_f16 = OpTypePointer Uniform %mat2x4_f16
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+%conv_mat2x4_f16 = OpFunction %mat2v4half None %10
+        %val = OpFunctionParameter %mat2x4_f16
+         %14 = OpLabel
+         %15 = OpCompositeExtract %v4half %val 0
+         %16 = OpCompositeExtract %v4half %val 1
+         %17 = OpCompositeConstruct %mat2v4half %15 %16
+               OpReturnValue %17
+               OpFunctionEnd
+%conv_arr4_mat2x4_f16 = OpFunction %_arr_mat2v4half_uint_4 None %18
+      %val_0 = OpFunctionParameter %_arr_mat2x4_f16_uint_4
+         %22 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_mat2v4half_uint_4 Function %25
+          %i = OpVariable %_ptr_Function_uint Function %28
+%var_for_index = OpVariable %_ptr_Function__arr_mat2x4_f16_uint_4 Function %41
+               OpBranch %29
+         %29 = OpLabel
+               OpLoopMerge %30 %31 None
+               OpBranch %32
+         %32 = OpLabel
+         %34 = OpLoad %uint %i
+         %35 = OpULessThan %bool %34 %uint_4
+         %33 = OpLogicalNot %bool %35
+               OpSelectionMerge %37 None
+               OpBranchConditional %33 %38 %37
+         %38 = OpLabel
+               OpBranch %30
+         %37 = OpLabel
+               OpStore %var_for_index %val_0
+         %42 = OpLoad %uint %i
+         %44 = OpAccessChain %_ptr_Function_mat2v4half %arr %42
+         %46 = OpLoad %uint %i
+         %48 = OpAccessChain %_ptr_Function_mat2x4_f16 %var_for_index %46
+         %49 = OpLoad %mat2x4_f16 %48
+         %45 = OpFunctionCall %mat2v4half %conv_mat2x4_f16 %49
+               OpStore %44 %45
+               OpBranch %31
+         %31 = OpLabel
+         %50 = OpLoad %uint %i
+         %52 = OpIAdd %uint %50 %uint_1
+               OpStore %i %52
+               OpBranch %29
+         %30 = OpLabel
+         %53 = OpLoad %_arr_mat2v4half_uint_4 %arr
+               OpReturnValue %53
+               OpFunctionEnd
+          %f = OpFunction %void None %54
+         %57 = OpLabel
+         %61 = OpAccessChain %_ptr_Uniform__arr_mat2x4_f16_uint_4 %a %uint_0
+         %62 = OpLoad %_arr_mat2x4_f16_uint_4 %61
+         %58 = OpFunctionCall %_arr_mat2v4half_uint_4 %conv_arr4_mat2x4_f16 %62
+         %66 = OpAccessChain %_ptr_Uniform_mat2x4_f16 %a %uint_0 %uint_2
+         %67 = OpLoad %mat2x4_f16 %66
+         %63 = OpFunctionCall %mat2v4half %conv_mat2x4_f16 %67
+         %69 = OpAccessChain %_ptr_Uniform_v4half %a %uint_0 %uint_2 %uint_1
+         %70 = OpLoad %v4half %69
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat2x4_f16/static_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..902e580
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/static_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> a : array<mat2x4<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_2 = &((*(p_a))[2]);
+  let p_a_2_1 = &((*(p_a_2))[1]);
+  let l_a : array<mat2x4<f16>, 4> = *(p_a);
+  let l_a_i : mat2x4<f16> = *(p_a_2);
+  let l_a_i_i : vec4<f16> = *(p_a_2_1);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_builtin.wgsl b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_builtin.wgsl
new file mode 100644
index 0000000..3da6797
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_builtin.wgsl
@@ -0,0 +1,10 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat2x4<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    let t = transpose(u[2]);
+    let l = length(u[0][1].ywxz);
+    let a = abs(u[0][1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_builtin.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..b6a103e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_builtin.wgsl.expected.dxc.hlsl
@@ -0,0 +1,31 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+
+matrix<float16_t, 2, 4> tint_symbol(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 4, 2> t = transpose(tint_symbol(u, 32u));
+  uint2 ubo_load_4 = u[0].zw;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const float16_t l = length(vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]).ywxz);
+  uint2 ubo_load_5 = u[0].zw;
+  vector<float16_t, 2> ubo_load_5_xz = vector<float16_t, 2>(f16tof32(ubo_load_5 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_5_yw = vector<float16_t, 2>(f16tof32(ubo_load_5 >> 16));
+  const float16_t a = abs(vector<float16_t, 4>(ubo_load_5_xz[0], ubo_load_5_yw[0], ubo_load_5_xz[1], ubo_load_5_yw[1]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_builtin.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..549f1f1
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_builtin.wgsl.expected.fxc.hlsl
@@ -0,0 +1,36 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+
+matrix<float16_t, 2, 4> tint_symbol(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 4, 2> t = transpose(tint_symbol(u, 32u));
+  uint2 ubo_load_4 = u[0].zw;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const float16_t l = length(vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]).ywxz);
+  uint2 ubo_load_5 = u[0].zw;
+  vector<float16_t, 2> ubo_load_5_xz = vector<float16_t, 2>(f16tof32(ubo_load_5 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_5_yw = vector<float16_t, 2>(f16tof32(ubo_load_5 >> 16));
+  const float16_t a = abs(vector<float16_t, 4>(ubo_load_5_xz[0], ubo_load_5_yw[0], ubo_load_5_xz[1], ubo_load_5_yw[1]).ywxz.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x00000268E1507730(5,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_builtin.wgsl.expected.glsl
new file mode 100644
index 0000000..dc144ba
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_builtin.wgsl.expected.glsl
@@ -0,0 +1,27 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct mat2x4_f16 {
+  f16vec4 col0;
+  f16vec4 col1;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  mat2x4_f16 inner[4];
+} u;
+
+f16mat2x4 conv_mat2x4_f16(mat2x4_f16 val) {
+  return f16mat2x4(val.col0, val.col1);
+}
+
+void f() {
+  f16mat4x2 t = transpose(conv_mat2x4_f16(u.inner[2u]));
+  float16_t l = length(u.inner[0u].col1.ywxz);
+  float16_t a = abs(u.inner[0u].col1.ywxz[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_builtin.wgsl.expected.msl
new file mode 100644
index 0000000..d3fc1d4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_builtin.wgsl.expected.msl
@@ -0,0 +1,23 @@
+#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];
+};
+
+kernel void f(const constant tint_array<half2x4, 4>* tint_symbol [[buffer(0)]]) {
+  half4x2 const t = transpose((*(tint_symbol))[2]);
+  half const l = length(half4((*(tint_symbol))[0][1]).ywxz);
+  half const a = fabs(half4((*(tint_symbol))[0][1]).ywxz[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_builtin.wgsl.expected.spvasm
new file mode 100644
index 0000000..3a6cf21
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_builtin.wgsl.expected.spvasm
@@ -0,0 +1,77 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 44
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+         %32 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %mat2x4_f16 "mat2x4_f16"
+               OpMemberName %mat2x4_f16 0 "col0"
+               OpMemberName %mat2x4_f16 1 "col1"
+               OpName %u "u"
+               OpName %conv_mat2x4_f16 "conv_mat2x4_f16"
+               OpName %val "val"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %mat2x4_f16 0 Offset 0
+               OpMemberDecorate %mat2x4_f16 1 Offset 8
+               OpDecorate %_arr_mat2x4_f16_uint_4 ArrayStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+ %mat2x4_f16 = OpTypeStruct %v4half %v4half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat2x4_f16_uint_4 = OpTypeArray %mat2x4_f16 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_mat2x4_f16_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat2v4half = OpTypeMatrix %v4half 2
+         %10 = OpTypeFunction %mat2v4half %mat2x4_f16
+       %void = OpTypeVoid
+         %18 = OpTypeFunction %void
+     %v2half = OpTypeVector %half 2
+ %mat4v2half = OpTypeMatrix %v2half 4
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_mat2x4_f16 = OpTypePointer Uniform %mat2x4_f16
+         %33 = OpConstantNull %uint
+     %uint_1 = OpConstant %uint 1
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+%conv_mat2x4_f16 = OpFunction %mat2v4half None %10
+        %val = OpFunctionParameter %mat2x4_f16
+         %14 = OpLabel
+         %15 = OpCompositeExtract %v4half %val 0
+         %16 = OpCompositeExtract %v4half %val 1
+         %17 = OpCompositeConstruct %mat2v4half %15 %16
+               OpReturnValue %17
+               OpFunctionEnd
+          %f = OpFunction %void None %18
+         %21 = OpLabel
+         %29 = OpAccessChain %_ptr_Uniform_mat2x4_f16 %u %uint_0 %uint_2
+         %30 = OpLoad %mat2x4_f16 %29
+         %25 = OpFunctionCall %mat2v4half %conv_mat2x4_f16 %30
+         %22 = OpTranspose %mat4v2half %25
+         %36 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0 %33 %uint_1
+         %37 = OpLoad %v4half %36
+         %38 = OpVectorShuffle %v4half %37 %37 1 3 0 2
+         %31 = OpExtInst %half %32 Length %38
+         %40 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0 %33 %uint_1
+         %41 = OpLoad %v4half %40
+         %42 = OpVectorShuffle %v4half %41 %41 1 3 0 2
+         %43 = OpCompositeExtract %half %42 0
+         %39 = OpExtInst %half %32 FAbs %43
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_builtin.wgsl.expected.wgsl
new file mode 100644
index 0000000..981ed12
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_builtin.wgsl.expected.wgsl
@@ -0,0 +1,10 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat2x4<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let t = transpose(u[2]);
+  let l = length(u[0][1].ywxz);
+  let a = abs(u[0][1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_fn.wgsl b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_fn.wgsl
new file mode 100644
index 0000000..41ad327
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_fn.wgsl
@@ -0,0 +1,16 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat2x4<f16>, 4>;
+
+fn a(a : array<mat2x4<f16>, 4>) {}
+fn b(m : mat2x4<f16>) {}
+fn c(v : vec4<f16>) {}
+fn d(f : f16) {}
+
+@compute @workgroup_size(1)
+fn f() {
+    a(u);
+    b(u[1]);
+    c(u[1][0].ywxz);
+    d(u[1][0].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_fn.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..f249b86
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_fn.wgsl.expected.dxc.hlsl
@@ -0,0 +1,55 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+
+void a(matrix<float16_t, 2, 4> a_1[4]) {
+}
+
+void b(matrix<float16_t, 2, 4> m) {
+}
+
+void c(vector<float16_t, 4> v) {
+}
+
+void d(float16_t f_1) {
+}
+
+matrix<float16_t, 2, 4> tint_symbol_1(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+typedef matrix<float16_t, 2, 4> tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[4], uint offset) {
+  matrix<float16_t, 2, 4> arr[4] = (matrix<float16_t, 2, 4>[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 16u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 16u));
+  uint2 ubo_load_4 = u[1].xy;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  c(vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]).ywxz);
+  uint2 ubo_load_5 = u[1].xy;
+  vector<float16_t, 2> ubo_load_5_xz = vector<float16_t, 2>(f16tof32(ubo_load_5 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_5_yw = vector<float16_t, 2>(f16tof32(ubo_load_5 >> 16));
+  d(vector<float16_t, 4>(ubo_load_5_xz[0], ubo_load_5_yw[0], ubo_load_5_xz[1], ubo_load_5_yw[1]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_fn.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..8cd4d42
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_fn.wgsl.expected.fxc.hlsl
@@ -0,0 +1,63 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+
+void a(matrix<float16_t, 2, 4> a_1[4]) {
+}
+
+void b(matrix<float16_t, 2, 4> m) {
+}
+
+void c(vector<float16_t, 4> v) {
+}
+
+void d(float16_t f_1) {
+}
+
+matrix<float16_t, 2, 4> tint_symbol_1(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+typedef matrix<float16_t, 2, 4> tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[4], uint offset) {
+  matrix<float16_t, 2, 4> arr[4] = (matrix<float16_t, 2, 4>[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 16u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 16u));
+  uint2 ubo_load_4 = u[1].xy;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  c(vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]).ywxz);
+  uint2 ubo_load_5 = u[1].xy;
+  vector<float16_t, 2> ubo_load_5_xz = vector<float16_t, 2>(f16tof32(ubo_load_5 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_5_yw = vector<float16_t, 2>(f16tof32(ubo_load_5 >> 16));
+  d(vector<float16_t, 4>(ubo_load_5_xz[0], ubo_load_5_yw[0], ubo_load_5_xz[1], ubo_load_5_yw[1]).ywxz.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001E7EB824620(5,15-23): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001E7EB824620(8,15-23): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001E7EB824620(11,15-23): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001E7EB824620(14,8-16): error X3000: unrecognized identifier 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_fn.wgsl.expected.glsl
new file mode 100644
index 0000000..4d6ba80
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_fn.wgsl.expected.glsl
@@ -0,0 +1,50 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct mat2x4_f16 {
+  f16vec4 col0;
+  f16vec4 col1;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  mat2x4_f16 inner[4];
+} u;
+
+void a(f16mat2x4 a_1[4]) {
+}
+
+void b(f16mat2x4 m) {
+}
+
+void c(f16vec4 v) {
+}
+
+void d(float16_t f_1) {
+}
+
+f16mat2x4 conv_mat2x4_f16(mat2x4_f16 val) {
+  return f16mat2x4(val.col0, val.col1);
+}
+
+f16mat2x4[4] conv_arr4_mat2x4_f16(mat2x4_f16 val[4]) {
+  f16mat2x4 arr[4] = f16mat2x4[4](f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat2x4_f16(val[i]);
+    }
+  }
+  return arr;
+}
+
+void f() {
+  a(conv_arr4_mat2x4_f16(u.inner));
+  b(conv_mat2x4_f16(u.inner[1u]));
+  c(u.inner[1u].col0.ywxz);
+  d(u.inner[1u].col0.ywxz[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_fn.wgsl.expected.msl
new file mode 100644
index 0000000..c5b42bf
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_fn.wgsl.expected.msl
@@ -0,0 +1,36 @@
+#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];
+};
+
+void a(tint_array<half2x4, 4> a_1) {
+}
+
+void b(half2x4 m) {
+}
+
+void c(half4 v) {
+}
+
+void d(half f_1) {
+}
+
+kernel void f(const constant tint_array<half2x4, 4>* tint_symbol [[buffer(0)]]) {
+  a(*(tint_symbol));
+  b((*(tint_symbol))[1]);
+  c(half4((*(tint_symbol))[1][0]).ywxz);
+  d(half4((*(tint_symbol))[1][0]).ywxz[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_fn.wgsl.expected.spvasm
new file mode 100644
index 0000000..a69ffdf
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_fn.wgsl.expected.spvasm
@@ -0,0 +1,163 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 95
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %mat2x4_f16 "mat2x4_f16"
+               OpMemberName %mat2x4_f16 0 "col0"
+               OpMemberName %mat2x4_f16 1 "col1"
+               OpName %u "u"
+               OpName %a "a"
+               OpName %a_1 "a_1"
+               OpName %b "b"
+               OpName %m "m"
+               OpName %c "c"
+               OpName %v "v"
+               OpName %d "d"
+               OpName %f_1 "f_1"
+               OpName %conv_mat2x4_f16 "conv_mat2x4_f16"
+               OpName %val "val"
+               OpName %conv_arr4_mat2x4_f16 "conv_arr4_mat2x4_f16"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %mat2x4_f16 0 Offset 0
+               OpMemberDecorate %mat2x4_f16 1 Offset 8
+               OpDecorate %_arr_mat2x4_f16_uint_4 ArrayStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %_arr_mat2v4half_uint_4 ArrayStride 16
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+ %mat2x4_f16 = OpTypeStruct %v4half %v4half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat2x4_f16_uint_4 = OpTypeArray %mat2x4_f16 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_mat2x4_f16_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+       %void = OpTypeVoid
+ %mat2v4half = OpTypeMatrix %v4half 2
+%_arr_mat2v4half_uint_4 = OpTypeArray %mat2v4half %uint_4
+         %10 = OpTypeFunction %void %_arr_mat2v4half_uint_4
+         %17 = OpTypeFunction %void %mat2v4half
+         %21 = OpTypeFunction %void %v4half
+         %25 = OpTypeFunction %void %half
+         %29 = OpTypeFunction %mat2v4half %mat2x4_f16
+         %36 = OpTypeFunction %_arr_mat2v4half_uint_4 %_arr_mat2x4_f16_uint_4
+%_ptr_Function__arr_mat2v4half_uint_4 = OpTypePointer Function %_arr_mat2v4half_uint_4
+         %42 = OpConstantNull %_arr_mat2v4half_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %45 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_mat2x4_f16_uint_4 = OpTypePointer Function %_arr_mat2x4_f16_uint_4
+         %58 = OpConstantNull %_arr_mat2x4_f16_uint_4
+%_ptr_Function_mat2v4half = OpTypePointer Function %mat2v4half
+%_ptr_Function_mat2x4_f16 = OpTypePointer Function %mat2x4_f16
+     %uint_1 = OpConstant %uint 1
+         %71 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat2x4_f16_uint_4 = OpTypePointer Uniform %_arr_mat2x4_f16_uint_4
+%_ptr_Uniform_mat2x4_f16 = OpTypePointer Uniform %mat2x4_f16
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+          %a = OpFunction %void None %10
+        %a_1 = OpFunctionParameter %_arr_mat2v4half_uint_4
+         %16 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %b = OpFunction %void None %17
+          %m = OpFunctionParameter %mat2v4half
+         %20 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %c = OpFunction %void None %21
+          %v = OpFunctionParameter %v4half
+         %24 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %d = OpFunction %void None %25
+        %f_1 = OpFunctionParameter %half
+         %28 = OpLabel
+               OpReturn
+               OpFunctionEnd
+%conv_mat2x4_f16 = OpFunction %mat2v4half None %29
+        %val = OpFunctionParameter %mat2x4_f16
+         %32 = OpLabel
+         %33 = OpCompositeExtract %v4half %val 0
+         %34 = OpCompositeExtract %v4half %val 1
+         %35 = OpCompositeConstruct %mat2v4half %33 %34
+               OpReturnValue %35
+               OpFunctionEnd
+%conv_arr4_mat2x4_f16 = OpFunction %_arr_mat2v4half_uint_4 None %36
+      %val_0 = OpFunctionParameter %_arr_mat2x4_f16_uint_4
+         %39 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_mat2v4half_uint_4 Function %42
+          %i = OpVariable %_ptr_Function_uint Function %45
+%var_for_index = OpVariable %_ptr_Function__arr_mat2x4_f16_uint_4 Function %58
+               OpBranch %46
+         %46 = OpLabel
+               OpLoopMerge %47 %48 None
+               OpBranch %49
+         %49 = OpLabel
+         %51 = OpLoad %uint %i
+         %52 = OpULessThan %bool %51 %uint_4
+         %50 = OpLogicalNot %bool %52
+               OpSelectionMerge %54 None
+               OpBranchConditional %50 %55 %54
+         %55 = OpLabel
+               OpBranch %47
+         %54 = OpLabel
+               OpStore %var_for_index %val_0
+         %59 = OpLoad %uint %i
+         %61 = OpAccessChain %_ptr_Function_mat2v4half %arr %59
+         %63 = OpLoad %uint %i
+         %65 = OpAccessChain %_ptr_Function_mat2x4_f16 %var_for_index %63
+         %66 = OpLoad %mat2x4_f16 %65
+         %62 = OpFunctionCall %mat2v4half %conv_mat2x4_f16 %66
+               OpStore %61 %62
+               OpBranch %48
+         %48 = OpLabel
+         %67 = OpLoad %uint %i
+         %69 = OpIAdd %uint %67 %uint_1
+               OpStore %i %69
+               OpBranch %46
+         %47 = OpLabel
+         %70 = OpLoad %_arr_mat2v4half_uint_4 %arr
+               OpReturnValue %70
+               OpFunctionEnd
+          %f = OpFunction %void None %71
+         %73 = OpLabel
+         %78 = OpAccessChain %_ptr_Uniform__arr_mat2x4_f16_uint_4 %u %uint_0
+         %79 = OpLoad %_arr_mat2x4_f16_uint_4 %78
+         %75 = OpFunctionCall %_arr_mat2v4half_uint_4 %conv_arr4_mat2x4_f16 %79
+         %74 = OpFunctionCall %void %a %75
+         %83 = OpAccessChain %_ptr_Uniform_mat2x4_f16 %u %uint_0 %uint_1
+         %84 = OpLoad %mat2x4_f16 %83
+         %81 = OpFunctionCall %mat2v4half %conv_mat2x4_f16 %84
+         %80 = OpFunctionCall %void %b %81
+         %87 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0 %uint_1 %uint_0
+         %88 = OpLoad %v4half %87
+         %89 = OpVectorShuffle %v4half %88 %88 1 3 0 2
+         %85 = OpFunctionCall %void %c %89
+         %91 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0 %uint_1 %uint_0
+         %92 = OpLoad %v4half %91
+         %93 = OpVectorShuffle %v4half %92 %92 1 3 0 2
+         %94 = OpCompositeExtract %half %93 0
+         %90 = OpFunctionCall %void %d %94
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_fn.wgsl.expected.wgsl
new file mode 100644
index 0000000..fc4ec28
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_fn.wgsl.expected.wgsl
@@ -0,0 +1,23 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat2x4<f16>, 4>;
+
+fn a(a : array<mat2x4<f16>, 4>) {
+}
+
+fn b(m : mat2x4<f16>) {
+}
+
+fn c(v : vec4<f16>) {
+}
+
+fn d(f : f16) {
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  a(u);
+  b(u[1]);
+  c(u[1][0].ywxz);
+  d(u[1][0].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_private.wgsl b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_private.wgsl
new file mode 100644
index 0000000..7da57a0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_private.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat2x4<f16>, 4>;
+var<private> p : array<mat2x4<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[2];
+    p[1][0] = u[0][1].ywxz;
+    p[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_private.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..245b619
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_private.wgsl.expected.dxc.hlsl
@@ -0,0 +1,41 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+static matrix<float16_t, 2, 4> p[4] = (matrix<float16_t, 2, 4>[4])0;
+
+matrix<float16_t, 2, 4> tint_symbol_1(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+typedef matrix<float16_t, 2, 4> tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[4], uint offset) {
+  matrix<float16_t, 2, 4> arr[4] = (matrix<float16_t, 2, 4>[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 16u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 32u);
+  uint2 ubo_load_4 = u[0].zw;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  p[1][0] = vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]).ywxz;
+  p[1][0].x = float16_t(f16tof32(((u[0].z) & 0xFFFF)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_private.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..db51daf
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_private.wgsl.expected.fxc.hlsl
@@ -0,0 +1,46 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+static matrix<float16_t, 2, 4> p[4] = (matrix<float16_t, 2, 4>[4])0;
+
+matrix<float16_t, 2, 4> tint_symbol_1(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+typedef matrix<float16_t, 2, 4> tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[4], uint offset) {
+  matrix<float16_t, 2, 4> arr[4] = (matrix<float16_t, 2, 4>[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 16u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 32u);
+  uint2 ubo_load_4 = u[0].zw;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  p[1][0] = vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]).ywxz;
+  p[1][0].x = float16_t(f16tof32(((u[0].z) & 0xFFFF)));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000022CF2B4B400(4,15-23): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..5fc6402
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_private.wgsl.expected.glsl
@@ -0,0 +1,39 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct mat2x4_f16 {
+  f16vec4 col0;
+  f16vec4 col1;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  mat2x4_f16 inner[4];
+} u;
+
+f16mat2x4 p[4] = f16mat2x4[4](f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf));
+f16mat2x4 conv_mat2x4_f16(mat2x4_f16 val) {
+  return f16mat2x4(val.col0, val.col1);
+}
+
+f16mat2x4[4] conv_arr4_mat2x4_f16(mat2x4_f16 val[4]) {
+  f16mat2x4 arr[4] = f16mat2x4[4](f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat2x4_f16(val[i]);
+    }
+  }
+  return arr;
+}
+
+void f() {
+  p = conv_arr4_mat2x4_f16(u.inner);
+  p[1] = conv_mat2x4_f16(u.inner[2u]);
+  p[1][0] = u.inner[0u].col1.ywxz;
+  p[1][0].x = u.inner[0u].col1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..2ebeac8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_private.wgsl.expected.msl
@@ -0,0 +1,25 @@
+#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];
+};
+
+kernel void f(const constant tint_array<half2x4, 4>* tint_symbol_1 [[buffer(0)]]) {
+  thread tint_array<half2x4, 4> tint_symbol = {};
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[2];
+  tint_symbol[1][0] = half4((*(tint_symbol_1))[0][1]).ywxz;
+  tint_symbol[1][0][0] = (*(tint_symbol_1))[0][1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_private.wgsl.expected.spvasm
new file mode 100644
index 0000000..e7366e1
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_private.wgsl.expected.spvasm
@@ -0,0 +1,143 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 86
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %mat2x4_f16 "mat2x4_f16"
+               OpMemberName %mat2x4_f16 0 "col0"
+               OpMemberName %mat2x4_f16 1 "col1"
+               OpName %u "u"
+               OpName %p "p"
+               OpName %conv_mat2x4_f16 "conv_mat2x4_f16"
+               OpName %val "val"
+               OpName %conv_arr4_mat2x4_f16 "conv_arr4_mat2x4_f16"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %mat2x4_f16 0 Offset 0
+               OpMemberDecorate %mat2x4_f16 1 Offset 8
+               OpDecorate %_arr_mat2x4_f16_uint_4 ArrayStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %_arr_mat2v4half_uint_4 ArrayStride 16
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+ %mat2x4_f16 = OpTypeStruct %v4half %v4half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat2x4_f16_uint_4 = OpTypeArray %mat2x4_f16 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_mat2x4_f16_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat2v4half = OpTypeMatrix %v4half 2
+%_arr_mat2v4half_uint_4 = OpTypeArray %mat2v4half %uint_4
+%_ptr_Private__arr_mat2v4half_uint_4 = OpTypePointer Private %_arr_mat2v4half_uint_4
+         %14 = OpConstantNull %_arr_mat2v4half_uint_4
+          %p = OpVariable %_ptr_Private__arr_mat2v4half_uint_4 Private %14
+         %15 = OpTypeFunction %mat2v4half %mat2x4_f16
+         %22 = OpTypeFunction %_arr_mat2v4half_uint_4 %_arr_mat2x4_f16_uint_4
+%_ptr_Function__arr_mat2v4half_uint_4 = OpTypePointer Function %_arr_mat2v4half_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %30 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_mat2x4_f16_uint_4 = OpTypePointer Function %_arr_mat2x4_f16_uint_4
+         %43 = OpConstantNull %_arr_mat2x4_f16_uint_4
+%_ptr_Function_mat2v4half = OpTypePointer Function %mat2v4half
+%_ptr_Function_mat2x4_f16 = OpTypePointer Function %mat2x4_f16
+     %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %56 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat2x4_f16_uint_4 = OpTypePointer Uniform %_arr_mat2x4_f16_uint_4
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Private_mat2v4half = OpTypePointer Private %mat2v4half
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_mat2x4_f16 = OpTypePointer Uniform %mat2x4_f16
+         %74 = OpConstantNull %int
+%_ptr_Private_v4half = OpTypePointer Private %v4half
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+%_ptr_Private_half = OpTypePointer Private %half
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+%conv_mat2x4_f16 = OpFunction %mat2v4half None %15
+        %val = OpFunctionParameter %mat2x4_f16
+         %18 = OpLabel
+         %19 = OpCompositeExtract %v4half %val 0
+         %20 = OpCompositeExtract %v4half %val 1
+         %21 = OpCompositeConstruct %mat2v4half %19 %20
+               OpReturnValue %21
+               OpFunctionEnd
+%conv_arr4_mat2x4_f16 = OpFunction %_arr_mat2v4half_uint_4 None %22
+      %val_0 = OpFunctionParameter %_arr_mat2x4_f16_uint_4
+         %25 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_mat2v4half_uint_4 Function %14
+          %i = OpVariable %_ptr_Function_uint Function %30
+%var_for_index = OpVariable %_ptr_Function__arr_mat2x4_f16_uint_4 Function %43
+               OpBranch %31
+         %31 = OpLabel
+               OpLoopMerge %32 %33 None
+               OpBranch %34
+         %34 = OpLabel
+         %36 = OpLoad %uint %i
+         %37 = OpULessThan %bool %36 %uint_4
+         %35 = OpLogicalNot %bool %37
+               OpSelectionMerge %39 None
+               OpBranchConditional %35 %40 %39
+         %40 = OpLabel
+               OpBranch %32
+         %39 = OpLabel
+               OpStore %var_for_index %val_0
+         %44 = OpLoad %uint %i
+         %46 = OpAccessChain %_ptr_Function_mat2v4half %arr %44
+         %48 = OpLoad %uint %i
+         %50 = OpAccessChain %_ptr_Function_mat2x4_f16 %var_for_index %48
+         %51 = OpLoad %mat2x4_f16 %50
+         %47 = OpFunctionCall %mat2v4half %conv_mat2x4_f16 %51
+               OpStore %46 %47
+               OpBranch %33
+         %33 = OpLabel
+         %52 = OpLoad %uint %i
+         %54 = OpIAdd %uint %52 %uint_1
+               OpStore %i %54
+               OpBranch %31
+         %32 = OpLabel
+         %55 = OpLoad %_arr_mat2v4half_uint_4 %arr
+               OpReturnValue %55
+               OpFunctionEnd
+          %f = OpFunction %void None %56
+         %59 = OpLabel
+         %63 = OpAccessChain %_ptr_Uniform__arr_mat2x4_f16_uint_4 %u %uint_0
+         %64 = OpLoad %_arr_mat2x4_f16_uint_4 %63
+         %60 = OpFunctionCall %_arr_mat2v4half_uint_4 %conv_arr4_mat2x4_f16 %64
+               OpStore %p %60
+         %68 = OpAccessChain %_ptr_Private_mat2v4half %p %int_1
+         %72 = OpAccessChain %_ptr_Uniform_mat2x4_f16 %u %uint_0 %uint_2
+         %73 = OpLoad %mat2x4_f16 %72
+         %69 = OpFunctionCall %mat2v4half %conv_mat2x4_f16 %73
+               OpStore %68 %69
+         %76 = OpAccessChain %_ptr_Private_v4half %p %int_1 %74
+         %78 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0 %30 %uint_1
+         %79 = OpLoad %v4half %78
+         %80 = OpVectorShuffle %v4half %79 %79 1 3 0 2
+               OpStore %76 %80
+         %82 = OpAccessChain %_ptr_Private_half %p %int_1 %74 %uint_0
+         %84 = OpAccessChain %_ptr_Uniform_half %u %uint_0 %30 %uint_1 %30
+         %85 = OpLoad %half %84
+               OpStore %82 %85
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..2ee6d30
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_private.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat2x4<f16>, 4>;
+
+var<private> p : array<mat2x4<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[2];
+  p[1][0] = u[0][1].ywxz;
+  p[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_storage.wgsl b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_storage.wgsl
new file mode 100644
index 0000000..50bb230
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_storage.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat2x4<f16>, 4>;
+@group(0) @binding(1) var<storage, read_write> s : array<mat2x4<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[2];
+    s[1][0] = u[0][1].ywxz;
+    s[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_storage.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..d519b2e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_storage.wgsl.expected.dxc.hlsl
@@ -0,0 +1,55 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 2, 4> value) {
+  buffer.Store<vector<float16_t, 4> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 8u), value[1u]);
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 2, 4> value[4]) {
+  matrix<float16_t, 2, 4> array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 16u)), array[i]);
+    }
+  }
+}
+
+matrix<float16_t, 2, 4> tint_symbol_4(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+typedef matrix<float16_t, 2, 4> tint_symbol_3_ret[4];
+tint_symbol_3_ret tint_symbol_3(uint4 buffer[4], uint offset) {
+  matrix<float16_t, 2, 4> arr[4] = (matrix<float16_t, 2, 4>[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_4(buffer, (offset + (i_1 * 16u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_3(u, 0u));
+  tint_symbol_1(s, 16u, tint_symbol_4(u, 32u));
+  uint2 ubo_load_4 = u[0].zw;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  s.Store<vector<float16_t, 4> >(16u, vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]).ywxz);
+  s.Store<float16_t>(16u, float16_t(f16tof32(((u[0].z) & 0xFFFF))));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_storage.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..7ea2f14
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_storage.wgsl.expected.fxc.hlsl
@@ -0,0 +1,61 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 2, 4> value) {
+  buffer.Store<vector<float16_t, 4> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 8u), value[1u]);
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 2, 4> value[4]) {
+  matrix<float16_t, 2, 4> array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 16u)), array[i]);
+    }
+  }
+}
+
+matrix<float16_t, 2, 4> tint_symbol_4(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+typedef matrix<float16_t, 2, 4> tint_symbol_3_ret[4];
+tint_symbol_3_ret tint_symbol_3(uint4 buffer[4], uint offset) {
+  matrix<float16_t, 2, 4> arr[4] = (matrix<float16_t, 2, 4>[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_4(buffer, (offset + (i_1 * 16u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_3(u, 0u));
+  tint_symbol_1(s, 16u, tint_symbol_4(u, 32u));
+  uint2 ubo_load_4 = u[0].zw;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  s.Store<vector<float16_t, 4> >(16u, vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]).ywxz);
+  s.Store<float16_t>(16u, float16_t(f16tof32(((u[0].z) & 0xFFFF))));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000028AE9A12030(6,68-76): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000028AE9A12030(7,3-14): error X3018: invalid subscript 'Store'
+
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..48cbfbf
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_storage.wgsl.expected.glsl
@@ -0,0 +1,42 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct mat2x4_f16 {
+  f16vec4 col0;
+  f16vec4 col1;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  mat2x4_f16 inner[4];
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  f16mat2x4 inner[4];
+} s;
+
+f16mat2x4 conv_mat2x4_f16(mat2x4_f16 val) {
+  return f16mat2x4(val.col0, val.col1);
+}
+
+f16mat2x4[4] conv_arr4_mat2x4_f16(mat2x4_f16 val[4]) {
+  f16mat2x4 arr[4] = f16mat2x4[4](f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat2x4_f16(val[i]);
+    }
+  }
+  return arr;
+}
+
+void f() {
+  s.inner = conv_arr4_mat2x4_f16(u.inner);
+  s.inner[1] = conv_mat2x4_f16(u.inner[2u]);
+  s.inner[1][0] = u.inner[0u].col1.ywxz;
+  s.inner[1][0].x = u.inner[0u].col1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..480eb6e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_storage.wgsl.expected.msl
@@ -0,0 +1,24 @@
+#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];
+};
+
+kernel void f(device tint_array<half2x4, 4>* tint_symbol [[buffer(1)]], const constant tint_array<half2x4, 4>* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
+  (*(tint_symbol))[1][0] = half4((*(tint_symbol_1))[0][1]).ywxz;
+  (*(tint_symbol))[1][0][0] = (*(tint_symbol_1))[0][1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_storage.wgsl.expected.spvasm
new file mode 100644
index 0000000..efffc6a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_storage.wgsl.expected.spvasm
@@ -0,0 +1,154 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 89
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %mat2x4_f16 "mat2x4_f16"
+               OpMemberName %mat2x4_f16 0 "col0"
+               OpMemberName %mat2x4_f16 1 "col1"
+               OpName %u "u"
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %s "s"
+               OpName %conv_mat2x4_f16 "conv_mat2x4_f16"
+               OpName %val "val"
+               OpName %conv_arr4_mat2x4_f16 "conv_arr4_mat2x4_f16"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %mat2x4_f16 0 Offset 0
+               OpMemberDecorate %mat2x4_f16 1 Offset 8
+               OpDecorate %_arr_mat2x4_f16_uint_4 ArrayStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 8
+               OpDecorate %_arr_mat2v4half_uint_4 ArrayStride 16
+               OpDecorate %s DescriptorSet 0
+               OpDecorate %s Binding 1
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+ %mat2x4_f16 = OpTypeStruct %v4half %v4half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat2x4_f16_uint_4 = OpTypeArray %mat2x4_f16 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_mat2x4_f16_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat2v4half = OpTypeMatrix %v4half 2
+%_arr_mat2v4half_uint_4 = OpTypeArray %mat2v4half %uint_4
+    %u_block = OpTypeStruct %_arr_mat2v4half_uint_4
+%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
+          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+         %15 = OpTypeFunction %mat2v4half %mat2x4_f16
+         %22 = OpTypeFunction %_arr_mat2v4half_uint_4 %_arr_mat2x4_f16_uint_4
+%_ptr_Function__arr_mat2v4half_uint_4 = OpTypePointer Function %_arr_mat2v4half_uint_4
+         %28 = OpConstantNull %_arr_mat2v4half_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %31 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_mat2x4_f16_uint_4 = OpTypePointer Function %_arr_mat2x4_f16_uint_4
+         %44 = OpConstantNull %_arr_mat2x4_f16_uint_4
+%_ptr_Function_mat2v4half = OpTypePointer Function %mat2v4half
+%_ptr_Function_mat2x4_f16 = OpTypePointer Function %mat2x4_f16
+     %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %57 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer__arr_mat2v4half_uint_4 = OpTypePointer StorageBuffer %_arr_mat2v4half_uint_4
+%_ptr_Uniform__arr_mat2x4_f16_uint_4 = OpTypePointer Uniform %_arr_mat2x4_f16_uint_4
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_mat2v4half = OpTypePointer StorageBuffer %mat2v4half
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_mat2x4_f16 = OpTypePointer Uniform %mat2x4_f16
+         %77 = OpConstantNull %int
+%_ptr_StorageBuffer_v4half = OpTypePointer StorageBuffer %v4half
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+%_ptr_StorageBuffer_half = OpTypePointer StorageBuffer %half
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+%conv_mat2x4_f16 = OpFunction %mat2v4half None %15
+        %val = OpFunctionParameter %mat2x4_f16
+         %18 = OpLabel
+         %19 = OpCompositeExtract %v4half %val 0
+         %20 = OpCompositeExtract %v4half %val 1
+         %21 = OpCompositeConstruct %mat2v4half %19 %20
+               OpReturnValue %21
+               OpFunctionEnd
+%conv_arr4_mat2x4_f16 = OpFunction %_arr_mat2v4half_uint_4 None %22
+      %val_0 = OpFunctionParameter %_arr_mat2x4_f16_uint_4
+         %25 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_mat2v4half_uint_4 Function %28
+          %i = OpVariable %_ptr_Function_uint Function %31
+%var_for_index = OpVariable %_ptr_Function__arr_mat2x4_f16_uint_4 Function %44
+               OpBranch %32
+         %32 = OpLabel
+               OpLoopMerge %33 %34 None
+               OpBranch %35
+         %35 = OpLabel
+         %37 = OpLoad %uint %i
+         %38 = OpULessThan %bool %37 %uint_4
+         %36 = OpLogicalNot %bool %38
+               OpSelectionMerge %40 None
+               OpBranchConditional %36 %41 %40
+         %41 = OpLabel
+               OpBranch %33
+         %40 = OpLabel
+               OpStore %var_for_index %val_0
+         %45 = OpLoad %uint %i
+         %47 = OpAccessChain %_ptr_Function_mat2v4half %arr %45
+         %49 = OpLoad %uint %i
+         %51 = OpAccessChain %_ptr_Function_mat2x4_f16 %var_for_index %49
+         %52 = OpLoad %mat2x4_f16 %51
+         %48 = OpFunctionCall %mat2v4half %conv_mat2x4_f16 %52
+               OpStore %47 %48
+               OpBranch %34
+         %34 = OpLabel
+         %53 = OpLoad %uint %i
+         %55 = OpIAdd %uint %53 %uint_1
+               OpStore %i %55
+               OpBranch %32
+         %33 = OpLabel
+         %56 = OpLoad %_arr_mat2v4half_uint_4 %arr
+               OpReturnValue %56
+               OpFunctionEnd
+          %f = OpFunction %void None %57
+         %60 = OpLabel
+         %63 = OpAccessChain %_ptr_StorageBuffer__arr_mat2v4half_uint_4 %s %uint_0
+         %66 = OpAccessChain %_ptr_Uniform__arr_mat2x4_f16_uint_4 %u %uint_0
+         %67 = OpLoad %_arr_mat2x4_f16_uint_4 %66
+         %64 = OpFunctionCall %_arr_mat2v4half_uint_4 %conv_arr4_mat2x4_f16 %67
+               OpStore %63 %64
+         %71 = OpAccessChain %_ptr_StorageBuffer_mat2v4half %s %uint_0 %int_1
+         %75 = OpAccessChain %_ptr_Uniform_mat2x4_f16 %u %uint_0 %uint_2
+         %76 = OpLoad %mat2x4_f16 %75
+         %72 = OpFunctionCall %mat2v4half %conv_mat2x4_f16 %76
+               OpStore %71 %72
+         %79 = OpAccessChain %_ptr_StorageBuffer_v4half %s %uint_0 %int_1 %77
+         %81 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0 %31 %uint_1
+         %82 = OpLoad %v4half %81
+         %83 = OpVectorShuffle %v4half %82 %82 1 3 0 2
+               OpStore %79 %83
+         %85 = OpAccessChain %_ptr_StorageBuffer_half %s %uint_0 %int_1 %77 %uint_0
+         %87 = OpAccessChain %_ptr_Uniform_half %u %uint_0 %31 %uint_1 %31
+         %88 = OpLoad %half %87
+               OpStore %85 %88
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..7807cd8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat2x4<f16>, 4>;
+
+@group(0) @binding(1) var<storage, read_write> s : array<mat2x4<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[2];
+  s[1][0] = u[0][1].ywxz;
+  s[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_workgroup.wgsl
new file mode 100644
index 0000000..50ba4da
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_workgroup.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat2x4<f16>, 4>;
+var<workgroup> w : array<mat2x4<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[2];
+    w[1][0] = u[0][1].ywxz;
+    w[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_workgroup.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..2efdd38
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_workgroup.wgsl.expected.dxc.hlsl
@@ -0,0 +1,56 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+groupshared matrix<float16_t, 2, 4> w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 2, 4> tint_symbol_3(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+typedef matrix<float16_t, 2, 4> tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[4], uint offset) {
+  matrix<float16_t, 2, 4> arr[4] = (matrix<float16_t, 2, 4>[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 16u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      w[i] = matrix<float16_t, 2, 4>((float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx);
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 32u);
+  uint2 ubo_load_4 = u[0].zw;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  w[1][0] = vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]).ywxz;
+  w[1][0].x = float16_t(f16tof32(((u[0].z) & 0xFFFF)));
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_workgroup.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..ffeeb95
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_workgroup.wgsl.expected.fxc.hlsl
@@ -0,0 +1,61 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+groupshared matrix<float16_t, 2, 4> w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 2, 4> tint_symbol_3(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+typedef matrix<float16_t, 2, 4> tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[4], uint offset) {
+  matrix<float16_t, 2, 4> arr[4] = (matrix<float16_t, 2, 4>[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 16u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      w[i] = matrix<float16_t, 2, 4>((float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx);
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 32u);
+  uint2 ubo_load_4 = u[0].zw;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  w[1][0] = vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]).ywxz;
+  w[1][0].x = float16_t(f16tof32(((u[0].z) & 0xFFFF)));
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001E5C5F5C8E0(4,20-28): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..7c842fe
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,46 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct mat2x4_f16 {
+  f16vec4 col0;
+  f16vec4 col1;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  mat2x4_f16 inner[4];
+} u;
+
+shared f16mat2x4 w[4];
+f16mat2x4 conv_mat2x4_f16(mat2x4_f16 val) {
+  return f16mat2x4(val.col0, val.col1);
+}
+
+f16mat2x4[4] conv_arr4_mat2x4_f16(mat2x4_f16 val[4]) {
+  f16mat2x4 arr[4] = f16mat2x4[4](f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat2x4_f16(val[i]);
+    }
+  }
+  return arr;
+}
+
+void f(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      uint i = idx;
+      w[i] = f16mat2x4(f16vec4(0.0hf), f16vec4(0.0hf));
+    }
+  }
+  barrier();
+  w = conv_arr4_mat2x4_f16(u.inner);
+  w[1] = conv_mat2x4_f16(u.inner[2u]);
+  w[1][0] = u.inner[0u].col1.ywxz;
+  w[1][0].x = u.inner[0u].col1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..3f9f184
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,38 @@
+#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_symbol_5 {
+  tint_array<half2x4, 4> w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup tint_array<half2x4, 4>* const tint_symbol, const constant tint_array<half2x4, 4>* const tint_symbol_1) {
+  for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+    uint const i = idx;
+    (*(tint_symbol))[i] = half2x4(half4(0.0h), half4(0.0h));
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
+  (*(tint_symbol))[1][0] = half4((*(tint_symbol_1))[0][1]).ywxz;
+  (*(tint_symbol))[1][0][0] = (*(tint_symbol_1))[0][1][0];
+}
+
+kernel void f(const constant tint_array<half2x4, 4>* tint_symbol_4 [[buffer(0)]], threadgroup tint_symbol_5* tint_symbol_3 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup tint_array<half2x4, 4>* const tint_symbol_2 = &((*(tint_symbol_3)).w);
+  f_inner(local_invocation_index, tint_symbol_2, tint_symbol_4);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_workgroup.wgsl.expected.spvasm
new file mode 100644
index 0000000..487a96d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_workgroup.wgsl.expected.spvasm
@@ -0,0 +1,186 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 111
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %local_invocation_index_1 "local_invocation_index_1"
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %mat2x4_f16 "mat2x4_f16"
+               OpMemberName %mat2x4_f16 0 "col0"
+               OpMemberName %mat2x4_f16 1 "col1"
+               OpName %u "u"
+               OpName %w "w"
+               OpName %conv_mat2x4_f16 "conv_mat2x4_f16"
+               OpName %val "val"
+               OpName %conv_arr4_mat2x4_f16 "conv_arr4_mat2x4_f16"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %f_inner "f_inner"
+               OpName %local_invocation_index "local_invocation_index"
+               OpName %idx "idx"
+               OpName %f "f"
+               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %mat2x4_f16 0 Offset 0
+               OpMemberDecorate %mat2x4_f16 1 Offset 8
+               OpDecorate %_arr_mat2x4_f16_uint_4 ArrayStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %_arr_mat2v4half_uint_4 ArrayStride 16
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+ %mat2x4_f16 = OpTypeStruct %v4half %v4half
+     %uint_4 = OpConstant %uint 4
+%_arr_mat2x4_f16_uint_4 = OpTypeArray %mat2x4_f16 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_mat2x4_f16_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat2v4half = OpTypeMatrix %v4half 2
+%_arr_mat2v4half_uint_4 = OpTypeArray %mat2v4half %uint_4
+%_ptr_Workgroup__arr_mat2v4half_uint_4 = OpTypePointer Workgroup %_arr_mat2v4half_uint_4
+          %w = OpVariable %_ptr_Workgroup__arr_mat2v4half_uint_4 Workgroup
+         %16 = OpTypeFunction %mat2v4half %mat2x4_f16
+         %23 = OpTypeFunction %_arr_mat2v4half_uint_4 %_arr_mat2x4_f16_uint_4
+%_ptr_Function__arr_mat2v4half_uint_4 = OpTypePointer Function %_arr_mat2v4half_uint_4
+         %29 = OpConstantNull %_arr_mat2v4half_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %32 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_mat2x4_f16_uint_4 = OpTypePointer Function %_arr_mat2x4_f16_uint_4
+         %45 = OpConstantNull %_arr_mat2x4_f16_uint_4
+%_ptr_Function_mat2v4half = OpTypePointer Function %mat2v4half
+%_ptr_Function_mat2x4_f16 = OpTypePointer Function %mat2x4_f16
+     %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %58 = OpTypeFunction %void %uint
+%_ptr_Workgroup_mat2v4half = OpTypePointer Workgroup %mat2v4half
+         %76 = OpConstantNull %mat2v4half
+     %uint_2 = OpConstant %uint 2
+   %uint_264 = OpConstant %uint 264
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat2x4_f16_uint_4 = OpTypePointer Uniform %_arr_mat2x4_f16_uint_4
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_mat2x4_f16 = OpTypePointer Uniform %mat2x4_f16
+         %94 = OpConstantNull %int
+%_ptr_Workgroup_v4half = OpTypePointer Workgroup %v4half
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+%_ptr_Workgroup_half = OpTypePointer Workgroup %half
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+        %106 = OpTypeFunction %void
+%conv_mat2x4_f16 = OpFunction %mat2v4half None %16
+        %val = OpFunctionParameter %mat2x4_f16
+         %19 = OpLabel
+         %20 = OpCompositeExtract %v4half %val 0
+         %21 = OpCompositeExtract %v4half %val 1
+         %22 = OpCompositeConstruct %mat2v4half %20 %21
+               OpReturnValue %22
+               OpFunctionEnd
+%conv_arr4_mat2x4_f16 = OpFunction %_arr_mat2v4half_uint_4 None %23
+      %val_0 = OpFunctionParameter %_arr_mat2x4_f16_uint_4
+         %26 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_mat2v4half_uint_4 Function %29
+          %i = OpVariable %_ptr_Function_uint Function %32
+%var_for_index = OpVariable %_ptr_Function__arr_mat2x4_f16_uint_4 Function %45
+               OpBranch %33
+         %33 = OpLabel
+               OpLoopMerge %34 %35 None
+               OpBranch %36
+         %36 = OpLabel
+         %38 = OpLoad %uint %i
+         %39 = OpULessThan %bool %38 %uint_4
+         %37 = OpLogicalNot %bool %39
+               OpSelectionMerge %41 None
+               OpBranchConditional %37 %42 %41
+         %42 = OpLabel
+               OpBranch %34
+         %41 = OpLabel
+               OpStore %var_for_index %val_0
+         %46 = OpLoad %uint %i
+         %48 = OpAccessChain %_ptr_Function_mat2v4half %arr %46
+         %50 = OpLoad %uint %i
+         %52 = OpAccessChain %_ptr_Function_mat2x4_f16 %var_for_index %50
+         %53 = OpLoad %mat2x4_f16 %52
+         %49 = OpFunctionCall %mat2v4half %conv_mat2x4_f16 %53
+               OpStore %48 %49
+               OpBranch %35
+         %35 = OpLabel
+         %54 = OpLoad %uint %i
+         %56 = OpIAdd %uint %54 %uint_1
+               OpStore %i %56
+               OpBranch %33
+         %34 = OpLabel
+         %57 = OpLoad %_arr_mat2v4half_uint_4 %arr
+               OpReturnValue %57
+               OpFunctionEnd
+    %f_inner = OpFunction %void None %58
+%local_invocation_index = OpFunctionParameter %uint
+         %62 = OpLabel
+        %idx = OpVariable %_ptr_Function_uint Function %32
+               OpStore %idx %local_invocation_index
+               OpBranch %64
+         %64 = OpLabel
+               OpLoopMerge %65 %66 None
+               OpBranch %67
+         %67 = OpLabel
+         %69 = OpLoad %uint %idx
+         %70 = OpULessThan %bool %69 %uint_4
+         %68 = OpLogicalNot %bool %70
+               OpSelectionMerge %71 None
+               OpBranchConditional %68 %72 %71
+         %72 = OpLabel
+               OpBranch %65
+         %71 = OpLabel
+         %73 = OpLoad %uint %idx
+         %75 = OpAccessChain %_ptr_Workgroup_mat2v4half %w %73
+               OpStore %75 %76
+               OpBranch %66
+         %66 = OpLabel
+         %77 = OpLoad %uint %idx
+         %78 = OpIAdd %uint %77 %uint_1
+               OpStore %idx %78
+               OpBranch %64
+         %65 = OpLabel
+               OpControlBarrier %uint_2 %uint_2 %uint_264
+         %85 = OpAccessChain %_ptr_Uniform__arr_mat2x4_f16_uint_4 %u %uint_0
+         %86 = OpLoad %_arr_mat2x4_f16_uint_4 %85
+         %82 = OpFunctionCall %_arr_mat2v4half_uint_4 %conv_arr4_mat2x4_f16 %86
+               OpStore %w %82
+         %89 = OpAccessChain %_ptr_Workgroup_mat2v4half %w %int_1
+         %92 = OpAccessChain %_ptr_Uniform_mat2x4_f16 %u %uint_0 %uint_2
+         %93 = OpLoad %mat2x4_f16 %92
+         %90 = OpFunctionCall %mat2v4half %conv_mat2x4_f16 %93
+               OpStore %89 %90
+         %96 = OpAccessChain %_ptr_Workgroup_v4half %w %int_1 %94
+         %98 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0 %32 %uint_1
+         %99 = OpLoad %v4half %98
+        %100 = OpVectorShuffle %v4half %99 %99 1 3 0 2
+               OpStore %96 %100
+        %102 = OpAccessChain %_ptr_Workgroup_half %w %int_1 %94 %uint_0
+        %104 = OpAccessChain %_ptr_Uniform_half %u %uint_0 %32 %uint_1 %32
+        %105 = OpLoad %half %104
+               OpStore %102 %105
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %106
+        %108 = OpLabel
+        %110 = OpLoad %uint %local_invocation_index_1
+        %109 = OpFunctionCall %void %f_inner %110
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..cbd73df
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f16/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat2x4<f16>, 4>;
+
+var<workgroup> w : array<mat2x4<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[2];
+  w[1][0] = u[0][1].ywxz;
+  w[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/array/mat2x4_f32/dynamic_index_via_ptr.wgsl
new file mode 100644
index 0000000..c833d93
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/dynamic_index_via_ptr.wgsl
@@ -0,0 +1,15 @@
+@group(0) @binding(0) var<uniform> a : array<mat2x4<f32>, 4>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a       = &a;
+  let p_a_i     = &((*p_a)[i()]);
+  let p_a_i_i   = &((*p_a_i)[i()]);
+
+  let l_a       : array<mat2x4<f32>, 4> = *p_a;
+  let l_a_i     : mat2x4<f32>           = *p_a_i;
+  let l_a_i_i   : vec4<f32>             = *p_a_i_i;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..2f907f8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,37 @@
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[8];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float2x4 tint_symbol_1(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+typedef float2x4 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[8], uint offset) {
+  float2x4 arr[4] = (float2x4[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 32u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_i_save = i();
+  const float2x4 l_a[4] = tint_symbol(a, 0u);
+  const float2x4 l_a_i = tint_symbol_1(a, (32u * uint(p_a_i_save)));
+  const uint scalar_offset_2 = (((32u * uint(p_a_i_save)) + (16u * uint(p_a_i_i_save)))) / 4;
+  const float4 l_a_i_i = asfloat(a[scalar_offset_2 / 4]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..2f907f8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,37 @@
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[8];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float2x4 tint_symbol_1(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+typedef float2x4 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[8], uint offset) {
+  float2x4 arr[4] = (float2x4[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 32u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_i_save = i();
+  const float2x4 l_a[4] = tint_symbol(a, 0u);
+  const float2x4 l_a_i = tint_symbol_1(a, (32u * uint(p_a_i_save)));
+  const uint scalar_offset_2 = (((32u * uint(p_a_i_save)) + (16u * uint(p_a_i_i_save)))) / 4;
+  const float4 l_a_i_i = asfloat(a[scalar_offset_2 / 4]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..29484d7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,27 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform a_block_ubo {
+  mat2x4 inner[4];
+} a;
+
+int counter = 0;
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+void f() {
+  int tint_symbol = i();
+  int p_a_i_save = tint_symbol;
+  int tint_symbol_1 = i();
+  int p_a_i_i_save = tint_symbol_1;
+  mat2x4 l_a[4] = a.inner;
+  mat2x4 l_a_i = a.inner[p_a_i_save];
+  vec4 l_a_i_i = a.inner[p_a_i_save][p_a_i_i_save];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..5566a8c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,33 @@
+#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];
+};
+
+int i() {
+  thread int tint_symbol_2 = 0;
+  tint_symbol_2 = as_type<int>((as_type<uint>(tint_symbol_2) + as_type<uint>(1)));
+  return tint_symbol_2;
+}
+
+kernel void f(const constant tint_array<float2x4, 4>* tint_symbol_3 [[buffer(0)]]) {
+  int const tint_symbol = i();
+  int const p_a_i_save = tint_symbol;
+  int const tint_symbol_1 = i();
+  int const p_a_i_i_save = tint_symbol_1;
+  tint_array<float2x4, 4> const l_a = *(tint_symbol_3);
+  float2x4 const l_a_i = (*(tint_symbol_3))[p_a_i_save];
+  float4 const l_a_i_i = (*(tint_symbol_3))[p_a_i_save][p_a_i_i_save];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..be98ce5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,64 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 37
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block "a_block"
+               OpMemberName %a_block 0 "inner"
+               OpName %a "a"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %f "f"
+               OpDecorate %a_block Block
+               OpMemberDecorate %a_block 0 Offset 0
+               OpMemberDecorate %a_block 0 ColMajor
+               OpMemberDecorate %a_block 0 MatrixStride 16
+               OpDecorate %_arr_mat2v4float_uint_4 ArrayStride 32
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat2v4float = OpTypeMatrix %v4float 2
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat2v4float_uint_4 = OpTypeArray %mat2v4float %uint_4
+    %a_block = OpTypeStruct %_arr_mat2v4float_uint_4
+%_ptr_Uniform_a_block = OpTypePointer Uniform %a_block
+          %a = OpVariable %_ptr_Uniform_a_block Uniform
+        %int = OpTypeInt 32 1
+         %11 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %11
+         %14 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+       %void = OpTypeVoid
+         %21 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat2v4float_uint_4 = OpTypePointer Uniform %_arr_mat2v4float_uint_4
+%_ptr_Uniform_mat2v4float = OpTypePointer Uniform %mat2v4float
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+          %i = OpFunction %int None %14
+         %16 = OpLabel
+         %17 = OpLoad %int %counter
+         %19 = OpIAdd %int %17 %int_1
+               OpStore %counter %19
+         %20 = OpLoad %int %counter
+               OpReturnValue %20
+               OpFunctionEnd
+          %f = OpFunction %void None %21
+         %24 = OpLabel
+         %25 = OpFunctionCall %int %i
+         %26 = OpFunctionCall %int %i
+         %29 = OpAccessChain %_ptr_Uniform__arr_mat2v4float_uint_4 %a %uint_0
+         %30 = OpLoad %_arr_mat2v4float_uint_4 %29
+         %32 = OpAccessChain %_ptr_Uniform_mat2v4float %a %uint_0 %25
+         %33 = OpLoad %mat2v4float %32
+         %35 = OpAccessChain %_ptr_Uniform_v4float %a %uint_0 %25 %26
+         %36 = OpLoad %v4float %35
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..823c9af
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+@group(0) @binding(0) var<uniform> a : array<mat2x4<f32>, 4>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_i = &((*(p_a))[i()]);
+  let p_a_i_i = &((*(p_a_i))[i()]);
+  let l_a : array<mat2x4<f32>, 4> = *(p_a);
+  let l_a_i : mat2x4<f32> = *(p_a_i);
+  let l_a_i_i : vec4<f32> = *(p_a_i_i);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/array/mat2x4_f32/static_index_via_ptr.wgsl
new file mode 100644
index 0000000..e71c4d7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/static_index_via_ptr.wgsl
@@ -0,0 +1,12 @@
+@group(0) @binding(0) var<uniform> a : array<mat2x4<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a       = &a;
+  let p_a_2     = &((*p_a)[2]);
+  let p_a_2_1   = &((*p_a_2)[1]);
+
+  let l_a       : array<mat2x4<f32>, 4> = *p_a;
+  let l_a_i     : mat2x4<f32>           = *p_a_2;
+  let l_a_i_i   : vec4<f32>             = *p_a_2_1;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x4_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..89fd887
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,28 @@
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[8];
+};
+
+float2x4 tint_symbol_1(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+typedef float2x4 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[8], uint offset) {
+  float2x4 arr[4] = (float2x4[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 32u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float2x4 l_a[4] = tint_symbol(a, 0u);
+  const float2x4 l_a_i = tint_symbol_1(a, 64u);
+  const float4 l_a_i_i = asfloat(a[5]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x4_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..89fd887
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,28 @@
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[8];
+};
+
+float2x4 tint_symbol_1(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+typedef float2x4 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[8], uint offset) {
+  float2x4 arr[4] = (float2x4[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 32u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float2x4 l_a[4] = tint_symbol(a, 0u);
+  const float2x4 l_a_i = tint_symbol_1(a, 64u);
+  const float4 l_a_i_i = asfloat(a[5]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat2x4_f32/static_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..008e51a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/static_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,17 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform a_block_ubo {
+  mat2x4 inner[4];
+} a;
+
+void f() {
+  mat2x4 l_a[4] = a.inner;
+  mat2x4 l_a_i = a.inner[2];
+  vec4 l_a_i_i = a.inner[2][1];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat2x4_f32/static_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..2cfad92
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/static_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,23 @@
+#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];
+};
+
+kernel void f(const constant tint_array<float2x4, 4>* tint_symbol [[buffer(0)]]) {
+  tint_array<float2x4, 4> const l_a = *(tint_symbol);
+  float2x4 const l_a_i = (*(tint_symbol))[2];
+  float4 const l_a_i_i = (*(tint_symbol))[2][1];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat2x4_f32/static_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..09f63f8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/static_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,49 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 27
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block "a_block"
+               OpMemberName %a_block 0 "inner"
+               OpName %a "a"
+               OpName %f "f"
+               OpDecorate %a_block Block
+               OpMemberDecorate %a_block 0 Offset 0
+               OpMemberDecorate %a_block 0 ColMajor
+               OpMemberDecorate %a_block 0 MatrixStride 16
+               OpDecorate %_arr_mat2v4float_uint_4 ArrayStride 32
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat2v4float = OpTypeMatrix %v4float 2
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat2v4float_uint_4 = OpTypeArray %mat2v4float %uint_4
+    %a_block = OpTypeStruct %_arr_mat2v4float_uint_4
+%_ptr_Uniform_a_block = OpTypePointer Uniform %a_block
+          %a = OpVariable %_ptr_Uniform_a_block Uniform
+       %void = OpTypeVoid
+         %10 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat2v4float_uint_4 = OpTypePointer Uniform %_arr_mat2v4float_uint_4
+        %int = OpTypeInt 32 1
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_mat2v4float = OpTypePointer Uniform %mat2v4float
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+          %f = OpFunction %void None %10
+         %13 = OpLabel
+         %16 = OpAccessChain %_ptr_Uniform__arr_mat2v4float_uint_4 %a %uint_0
+         %17 = OpLoad %_arr_mat2v4float_uint_4 %16
+         %21 = OpAccessChain %_ptr_Uniform_mat2v4float %a %uint_0 %int_2
+         %22 = OpLoad %mat2v4float %21
+         %25 = OpAccessChain %_ptr_Uniform_v4float %a %uint_0 %int_2 %int_1
+         %26 = OpLoad %v4float %25
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat2x4_f32/static_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..e68d299
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/static_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> a : array<mat2x4<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_2 = &((*(p_a))[2]);
+  let p_a_2_1 = &((*(p_a_2))[1]);
+  let l_a : array<mat2x4<f32>, 4> = *(p_a);
+  let l_a_i : mat2x4<f32> = *(p_a_2);
+  let l_a_i_i : vec4<f32> = *(p_a_2_1);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_builtin.wgsl b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_builtin.wgsl
new file mode 100644
index 0000000..617ab23
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_builtin.wgsl
@@ -0,0 +1,8 @@
+@group(0) @binding(0) var<uniform> u : array<mat2x4<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    let t = transpose(u[2]);
+    let l = length(u[0][1].ywxz);
+    let a = abs(u[0][1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_builtin.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..e5ed937
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_builtin.wgsl.expected.dxc.hlsl
@@ -0,0 +1,17 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[8];
+};
+
+float2x4 tint_symbol(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float4x2 t = transpose(tint_symbol(u, 64u));
+  const float l = length(asfloat(u[1]).ywxz);
+  const float a = abs(asfloat(u[1]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_builtin.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..e5ed937
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_builtin.wgsl.expected.fxc.hlsl
@@ -0,0 +1,17 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[8];
+};
+
+float2x4 tint_symbol(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float4x2 t = transpose(tint_symbol(u, 64u));
+  const float l = length(asfloat(u[1]).ywxz);
+  const float a = abs(asfloat(u[1]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_builtin.wgsl.expected.glsl
new file mode 100644
index 0000000..13fd457
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_builtin.wgsl.expected.glsl
@@ -0,0 +1,17 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat2x4 inner[4];
+} u;
+
+void f() {
+  mat4x2 t = transpose(u.inner[2]);
+  float l = length(u.inner[0][1].ywxz);
+  float a = abs(u.inner[0][1].ywxz.x);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_builtin.wgsl.expected.msl
new file mode 100644
index 0000000..28b3230
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_builtin.wgsl.expected.msl
@@ -0,0 +1,23 @@
+#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];
+};
+
+kernel void f(const constant tint_array<float2x4, 4>* tint_symbol [[buffer(0)]]) {
+  float4x2 const t = transpose((*(tint_symbol))[2]);
+  float const l = length(float4((*(tint_symbol))[0][1]).ywxz);
+  float const a = fabs(float4((*(tint_symbol))[0][1]).ywxz[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_builtin.wgsl.expected.spvasm
new file mode 100644
index 0000000..17e8232
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_builtin.wgsl.expected.spvasm
@@ -0,0 +1,58 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 36
+; Schema: 0
+               OpCapability Shader
+         %24 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %_arr_mat2v4float_uint_4 ArrayStride 32
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat2v4float = OpTypeMatrix %v4float 2
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat2v4float_uint_4 = OpTypeArray %mat2v4float %uint_4
+    %u_block = OpTypeStruct %_arr_mat2v4float_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+         %10 = OpTypeFunction %void
+    %v2float = OpTypeVector %float 2
+%mat4v2float = OpTypeMatrix %v2float 4
+     %uint_0 = OpConstant %uint 0
+        %int = OpTypeInt 32 1
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_mat2v4float = OpTypePointer Uniform %mat2v4float
+         %25 = OpConstantNull %int
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+          %f = OpFunction %void None %10
+         %13 = OpLabel
+         %21 = OpAccessChain %_ptr_Uniform_mat2v4float %u %uint_0 %int_2
+         %22 = OpLoad %mat2v4float %21
+         %14 = OpTranspose %mat4v2float %22
+         %28 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %25 %int_1
+         %29 = OpLoad %v4float %28
+         %30 = OpVectorShuffle %v4float %29 %29 1 3 0 2
+         %23 = OpExtInst %float %24 Length %30
+         %32 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %25 %int_1
+         %33 = OpLoad %v4float %32
+         %34 = OpVectorShuffle %v4float %33 %33 1 3 0 2
+         %35 = OpCompositeExtract %float %34 0
+         %31 = OpExtInst %float %24 FAbs %35
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_builtin.wgsl.expected.wgsl
new file mode 100644
index 0000000..dd05e4a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_builtin.wgsl.expected.wgsl
@@ -0,0 +1,8 @@
+@group(0) @binding(0) var<uniform> u : array<mat2x4<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let t = transpose(u[2]);
+  let l = length(u[0][1].ywxz);
+  let a = abs(u[0][1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_fn.wgsl b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_fn.wgsl
new file mode 100644
index 0000000..397bcf3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_fn.wgsl
@@ -0,0 +1,14 @@
+@group(0) @binding(0) var<uniform> u : array<mat2x4<f32>, 4>;
+
+fn a(a : array<mat2x4<f32>, 4>) {}
+fn b(m : mat2x4<f32>) {}
+fn c(v : vec4<f32>) {}
+fn d(f : f32) {}
+
+@compute @workgroup_size(1)
+fn f() {
+    a(u);
+    b(u[1]);
+    c(u[1][0].ywxz);
+    d(u[1][0].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_fn.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..ea9471a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_fn.wgsl.expected.dxc.hlsl
@@ -0,0 +1,41 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[8];
+};
+
+void a(float2x4 a_1[4]) {
+}
+
+void b(float2x4 m) {
+}
+
+void c(float4 v) {
+}
+
+void d(float f_1) {
+}
+
+float2x4 tint_symbol_1(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+typedef float2x4 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[8], uint offset) {
+  float2x4 arr[4] = (float2x4[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 32u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 32u));
+  c(asfloat(u[2]).ywxz);
+  d(asfloat(u[2]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_fn.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..ea9471a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_fn.wgsl.expected.fxc.hlsl
@@ -0,0 +1,41 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[8];
+};
+
+void a(float2x4 a_1[4]) {
+}
+
+void b(float2x4 m) {
+}
+
+void c(float4 v) {
+}
+
+void d(float f_1) {
+}
+
+float2x4 tint_symbol_1(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+typedef float2x4 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[8], uint offset) {
+  float2x4 arr[4] = (float2x4[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 32u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 32u));
+  c(asfloat(u[2]).ywxz);
+  d(asfloat(u[2]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_fn.wgsl.expected.glsl
new file mode 100644
index 0000000..24562db
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_fn.wgsl.expected.glsl
@@ -0,0 +1,30 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat2x4 inner[4];
+} u;
+
+void a(mat2x4 a_1[4]) {
+}
+
+void b(mat2x4 m) {
+}
+
+void c(vec4 v) {
+}
+
+void d(float f_1) {
+}
+
+void f() {
+  a(u.inner);
+  b(u.inner[1]);
+  c(u.inner[1][0].ywxz);
+  d(u.inner[1][0].ywxz.x);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_fn.wgsl.expected.msl
new file mode 100644
index 0000000..4280139
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_fn.wgsl.expected.msl
@@ -0,0 +1,36 @@
+#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];
+};
+
+void a(tint_array<float2x4, 4> a_1) {
+}
+
+void b(float2x4 m) {
+}
+
+void c(float4 v) {
+}
+
+void d(float f_1) {
+}
+
+kernel void f(const constant tint_array<float2x4, 4>* tint_symbol [[buffer(0)]]) {
+  a(*(tint_symbol));
+  b((*(tint_symbol))[1]);
+  c(float4((*(tint_symbol))[1][0]).ywxz);
+  d(float4((*(tint_symbol))[1][0]).ywxz[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_fn.wgsl.expected.spvasm
new file mode 100644
index 0000000..f7ee0d9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_fn.wgsl.expected.spvasm
@@ -0,0 +1,90 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 52
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %a "a"
+               OpName %a_1 "a_1"
+               OpName %b "b"
+               OpName %m "m"
+               OpName %c "c"
+               OpName %v "v"
+               OpName %d "d"
+               OpName %f_1 "f_1"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %_arr_mat2v4float_uint_4 ArrayStride 32
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat2v4float = OpTypeMatrix %v4float 2
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat2v4float_uint_4 = OpTypeArray %mat2v4float %uint_4
+    %u_block = OpTypeStruct %_arr_mat2v4float_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+         %10 = OpTypeFunction %void %_arr_mat2v4float_uint_4
+         %15 = OpTypeFunction %void %mat2v4float
+         %19 = OpTypeFunction %void %v4float
+         %23 = OpTypeFunction %void %float
+         %27 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat2v4float_uint_4 = OpTypePointer Uniform %_arr_mat2v4float_uint_4
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_mat2v4float = OpTypePointer Uniform %mat2v4float
+         %42 = OpConstantNull %int
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+          %a = OpFunction %void None %10
+        %a_1 = OpFunctionParameter %_arr_mat2v4float_uint_4
+         %14 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %b = OpFunction %void None %15
+          %m = OpFunctionParameter %mat2v4float
+         %18 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %c = OpFunction %void None %19
+          %v = OpFunctionParameter %v4float
+         %22 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %d = OpFunction %void None %23
+        %f_1 = OpFunctionParameter %float
+         %26 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %27
+         %29 = OpLabel
+         %33 = OpAccessChain %_ptr_Uniform__arr_mat2v4float_uint_4 %u %uint_0
+         %34 = OpLoad %_arr_mat2v4float_uint_4 %33
+         %30 = OpFunctionCall %void %a %34
+         %39 = OpAccessChain %_ptr_Uniform_mat2v4float %u %uint_0 %int_1
+         %40 = OpLoad %mat2v4float %39
+         %35 = OpFunctionCall %void %b %40
+         %44 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %int_1 %42
+         %45 = OpLoad %v4float %44
+         %46 = OpVectorShuffle %v4float %45 %45 1 3 0 2
+         %41 = OpFunctionCall %void %c %46
+         %48 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %int_1 %42
+         %49 = OpLoad %v4float %48
+         %50 = OpVectorShuffle %v4float %49 %49 1 3 0 2
+         %51 = OpCompositeExtract %float %50 0
+         %47 = OpFunctionCall %void %d %51
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_fn.wgsl.expected.wgsl
new file mode 100644
index 0000000..5b6e18d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_fn.wgsl.expected.wgsl
@@ -0,0 +1,21 @@
+@group(0) @binding(0) var<uniform> u : array<mat2x4<f32>, 4>;
+
+fn a(a : array<mat2x4<f32>, 4>) {
+}
+
+fn b(m : mat2x4<f32>) {
+}
+
+fn c(v : vec4<f32>) {
+}
+
+fn d(f : f32) {
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  a(u);
+  b(u[1]);
+  c(u[1][0].ywxz);
+  d(u[1][0].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_private.wgsl b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_private.wgsl
new file mode 100644
index 0000000..1ff3c55
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_private.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0) var<uniform> u : array<mat2x4<f32>, 4>;
+var<private> p : array<mat2x4<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[2];
+    p[1][0] = u[0][1].ywxz;
+    p[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_private.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..ba81ce8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_private.wgsl.expected.dxc.hlsl
@@ -0,0 +1,30 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[8];
+};
+static float2x4 p[4] = (float2x4[4])0;
+
+float2x4 tint_symbol_1(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+typedef float2x4 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[8], uint offset) {
+  float2x4 arr[4] = (float2x4[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 32u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 64u);
+  p[1][0] = asfloat(u[1]).ywxz;
+  p[1][0].x = asfloat(u[1].x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_private.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..ba81ce8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_private.wgsl.expected.fxc.hlsl
@@ -0,0 +1,30 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[8];
+};
+static float2x4 p[4] = (float2x4[4])0;
+
+float2x4 tint_symbol_1(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+typedef float2x4 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[8], uint offset) {
+  float2x4 arr[4] = (float2x4[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 32u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 64u);
+  p[1][0] = asfloat(u[1]).ywxz;
+  p[1][0].x = asfloat(u[1].x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..79b73d4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_private.wgsl.expected.glsl
@@ -0,0 +1,19 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat2x4 inner[4];
+} u;
+
+mat2x4 p[4] = mat2x4[4](mat2x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat2x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat2x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat2x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
+void f() {
+  p = u.inner;
+  p[1] = u.inner[2];
+  p[1][0] = u.inner[0][1].ywxz;
+  p[1][0].x = u.inner[0][1].x;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..f28eca1
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_private.wgsl.expected.msl
@@ -0,0 +1,25 @@
+#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];
+};
+
+kernel void f(const constant tint_array<float2x4, 4>* tint_symbol_1 [[buffer(0)]]) {
+  thread tint_array<float2x4, 4> tint_symbol = {};
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[2];
+  tint_symbol[1][0] = float4((*(tint_symbol_1))[0][1]).ywxz;
+  tint_symbol[1][0][0] = (*(tint_symbol_1))[0][1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_private.wgsl.expected.spvasm
new file mode 100644
index 0000000..a2c2daa
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_private.wgsl.expected.spvasm
@@ -0,0 +1,68 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 41
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %p "p"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %_arr_mat2v4float_uint_4 ArrayStride 32
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat2v4float = OpTypeMatrix %v4float 2
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat2v4float_uint_4 = OpTypeArray %mat2v4float %uint_4
+    %u_block = OpTypeStruct %_arr_mat2v4float_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_Private__arr_mat2v4float_uint_4 = OpTypePointer Private %_arr_mat2v4float_uint_4
+         %12 = OpConstantNull %_arr_mat2v4float_uint_4
+          %p = OpVariable %_ptr_Private__arr_mat2v4float_uint_4 Private %12
+       %void = OpTypeVoid
+         %13 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat2v4float_uint_4 = OpTypePointer Uniform %_arr_mat2v4float_uint_4
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Private_mat2v4float = OpTypePointer Private %mat2v4float
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_mat2v4float = OpTypePointer Uniform %mat2v4float
+         %29 = OpConstantNull %int
+%_ptr_Private_v4float = OpTypePointer Private %v4float
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+%_ptr_Private_float = OpTypePointer Private %float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+          %f = OpFunction %void None %13
+         %16 = OpLabel
+         %19 = OpAccessChain %_ptr_Uniform__arr_mat2v4float_uint_4 %u %uint_0
+         %20 = OpLoad %_arr_mat2v4float_uint_4 %19
+               OpStore %p %20
+         %24 = OpAccessChain %_ptr_Private_mat2v4float %p %int_1
+         %27 = OpAccessChain %_ptr_Uniform_mat2v4float %u %uint_0 %int_2
+         %28 = OpLoad %mat2v4float %27
+               OpStore %24 %28
+         %31 = OpAccessChain %_ptr_Private_v4float %p %int_1 %29
+         %33 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %29 %int_1
+         %34 = OpLoad %v4float %33
+         %35 = OpVectorShuffle %v4float %34 %34 1 3 0 2
+               OpStore %31 %35
+         %37 = OpAccessChain %_ptr_Private_float %p %int_1 %29 %uint_0
+         %39 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %29 %int_1 %uint_0
+         %40 = OpLoad %float %39
+               OpStore %37 %40
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..e503c8e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_private.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> u : array<mat2x4<f32>, 4>;
+
+var<private> p : array<mat2x4<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[2];
+  p[1][0] = u[0][1].ywxz;
+  p[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_storage.wgsl b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_storage.wgsl
new file mode 100644
index 0000000..9968162
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_storage.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0) var<uniform> u : array<mat2x4<f32>, 4>;
+@group(0) @binding(1) var<storage, read_write> s : array<mat2x4<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[2];
+    s[1][0] = u[0][1].ywxz;
+    s[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_storage.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..747c20a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_storage.wgsl.expected.dxc.hlsl
@@ -0,0 +1,44 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[8];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, float2x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, float2x4 value[4]) {
+  float2x4 array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 32u)), array[i]);
+    }
+  }
+}
+
+float2x4 tint_symbol_4(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+typedef float2x4 tint_symbol_3_ret[4];
+tint_symbol_3_ret tint_symbol_3(uint4 buffer[8], uint offset) {
+  float2x4 arr[4] = (float2x4[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_4(buffer, (offset + (i_1 * 32u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_3(u, 0u));
+  tint_symbol_1(s, 32u, tint_symbol_4(u, 64u));
+  s.Store4(32u, asuint(asfloat(u[1]).ywxz));
+  s.Store(32u, asuint(asfloat(u[1].x)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_storage.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..747c20a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_storage.wgsl.expected.fxc.hlsl
@@ -0,0 +1,44 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[8];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, float2x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, float2x4 value[4]) {
+  float2x4 array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 32u)), array[i]);
+    }
+  }
+}
+
+float2x4 tint_symbol_4(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+typedef float2x4 tint_symbol_3_ret[4];
+tint_symbol_3_ret tint_symbol_3(uint4 buffer[8], uint offset) {
+  float2x4 arr[4] = (float2x4[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_4(buffer, (offset + (i_1 * 32u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_3(u, 0u));
+  tint_symbol_1(s, 32u, tint_symbol_4(u, 64u));
+  s.Store4(32u, asuint(asfloat(u[1]).ywxz));
+  s.Store(32u, asuint(asfloat(u[1].x)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..ac0b6a2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_storage.wgsl.expected.glsl
@@ -0,0 +1,22 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat2x4 inner[4];
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  mat2x4 inner[4];
+} s;
+
+void f() {
+  s.inner = u.inner;
+  s.inner[1] = u.inner[2];
+  s.inner[1][0] = u.inner[0][1].ywxz;
+  s.inner[1][0].x = u.inner[0][1].x;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..859f287
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_storage.wgsl.expected.msl
@@ -0,0 +1,24 @@
+#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];
+};
+
+kernel void f(device tint_array<float2x4, 4>* tint_symbol [[buffer(1)]], const constant tint_array<float2x4, 4>* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
+  (*(tint_symbol))[1][0] = float4((*(tint_symbol_1))[0][1]).ywxz;
+  (*(tint_symbol))[1][0][0] = (*(tint_symbol_1))[0][1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_storage.wgsl.expected.spvasm
new file mode 100644
index 0000000..5e773dd
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_storage.wgsl.expected.spvasm
@@ -0,0 +1,71 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 42
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %s "s"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %_arr_mat2v4float_uint_4 ArrayStride 32
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %s DescriptorSet 0
+               OpDecorate %s Binding 1
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat2v4float = OpTypeMatrix %v4float 2
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat2v4float_uint_4 = OpTypeArray %mat2v4float %uint_4
+    %u_block = OpTypeStruct %_arr_mat2v4float_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
+          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+       %void = OpTypeVoid
+         %12 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer__arr_mat2v4float_uint_4 = OpTypePointer StorageBuffer %_arr_mat2v4float_uint_4
+%_ptr_Uniform__arr_mat2v4float_uint_4 = OpTypePointer Uniform %_arr_mat2v4float_uint_4
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_mat2v4float = OpTypePointer StorageBuffer %mat2v4float
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_mat2v4float = OpTypePointer Uniform %mat2v4float
+         %30 = OpConstantNull %int
+%_ptr_StorageBuffer_v4float = OpTypePointer StorageBuffer %v4float
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+          %f = OpFunction %void None %12
+         %15 = OpLabel
+         %18 = OpAccessChain %_ptr_StorageBuffer__arr_mat2v4float_uint_4 %s %uint_0
+         %20 = OpAccessChain %_ptr_Uniform__arr_mat2v4float_uint_4 %u %uint_0
+         %21 = OpLoad %_arr_mat2v4float_uint_4 %20
+               OpStore %18 %21
+         %25 = OpAccessChain %_ptr_StorageBuffer_mat2v4float %s %uint_0 %int_1
+         %28 = OpAccessChain %_ptr_Uniform_mat2v4float %u %uint_0 %int_2
+         %29 = OpLoad %mat2v4float %28
+               OpStore %25 %29
+         %32 = OpAccessChain %_ptr_StorageBuffer_v4float %s %uint_0 %int_1 %30
+         %34 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %30 %int_1
+         %35 = OpLoad %v4float %34
+         %36 = OpVectorShuffle %v4float %35 %35 1 3 0 2
+               OpStore %32 %36
+         %38 = OpAccessChain %_ptr_StorageBuffer_float %s %uint_0 %int_1 %30 %uint_0
+         %40 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %30 %int_1 %uint_0
+         %41 = OpLoad %float %40
+               OpStore %38 %41
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..48a709b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> u : array<mat2x4<f32>, 4>;
+
+@group(0) @binding(1) var<storage, read_write> s : array<mat2x4<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[2];
+  s[1][0] = u[0][1].ywxz;
+  s[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_workgroup.wgsl
new file mode 100644
index 0000000..39402fe
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_workgroup.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0) var<uniform> u : array<mat2x4<f32>, 4>;
+var<workgroup> w : array<mat2x4<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[2];
+    w[1][0] = u[0][1].ywxz;
+    w[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_workgroup.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..963cbf8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_workgroup.wgsl.expected.dxc.hlsl
@@ -0,0 +1,45 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[8];
+};
+groupshared float2x4 w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+float2x4 tint_symbol_3(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+typedef float2x4 tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[8], uint offset) {
+  float2x4 arr[4] = (float2x4[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 32u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      w[i] = float2x4((0.0f).xxxx, (0.0f).xxxx);
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 64u);
+  w[1][0] = asfloat(u[1]).ywxz;
+  w[1][0].x = asfloat(u[1].x);
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_workgroup.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..963cbf8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_workgroup.wgsl.expected.fxc.hlsl
@@ -0,0 +1,45 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[8];
+};
+groupshared float2x4 w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+float2x4 tint_symbol_3(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+typedef float2x4 tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[8], uint offset) {
+  float2x4 arr[4] = (float2x4[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 32u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      w[i] = float2x4((0.0f).xxxx, (0.0f).xxxx);
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 64u);
+  w[1][0] = asfloat(u[1]).ywxz;
+  w[1][0].x = asfloat(u[1].x);
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..e20f9d4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,26 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat2x4 inner[4];
+} u;
+
+shared mat2x4 w[4];
+void f(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      uint i = idx;
+      w[i] = mat2x4(vec4(0.0f), vec4(0.0f));
+    }
+  }
+  barrier();
+  w = u.inner;
+  w[1] = u.inner[2];
+  w[1][0] = u.inner[0][1].ywxz;
+  w[1][0].x = u.inner[0][1].x;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..d84ba92
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,38 @@
+#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_symbol_5 {
+  tint_array<float2x4, 4> w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup tint_array<float2x4, 4>* const tint_symbol, const constant tint_array<float2x4, 4>* const tint_symbol_1) {
+  for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+    uint const i = idx;
+    (*(tint_symbol))[i] = float2x4(float4(0.0f), float4(0.0f));
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
+  (*(tint_symbol))[1][0] = float4((*(tint_symbol_1))[0][1]).ywxz;
+  (*(tint_symbol))[1][0][0] = (*(tint_symbol_1))[0][1][0];
+}
+
+kernel void f(const constant tint_array<float2x4, 4>* tint_symbol_4 [[buffer(0)]], threadgroup tint_symbol_5* tint_symbol_3 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup tint_array<float2x4, 4>* const tint_symbol_2 = &((*(tint_symbol_3)).w);
+  f_inner(local_invocation_index, tint_symbol_2, tint_symbol_4);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_workgroup.wgsl.expected.spvasm
new file mode 100644
index 0000000..809115b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_workgroup.wgsl.expected.spvasm
@@ -0,0 +1,115 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 70
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %local_invocation_index_1 "local_invocation_index_1"
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %w "w"
+               OpName %f_inner "f_inner"
+               OpName %local_invocation_index "local_invocation_index"
+               OpName %idx "idx"
+               OpName %f "f"
+               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %_arr_mat2v4float_uint_4 ArrayStride 32
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat2v4float = OpTypeMatrix %v4float 2
+     %uint_4 = OpConstant %uint 4
+%_arr_mat2v4float_uint_4 = OpTypeArray %mat2v4float %uint_4
+    %u_block = OpTypeStruct %_arr_mat2v4float_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_Workgroup__arr_mat2v4float_uint_4 = OpTypePointer Workgroup %_arr_mat2v4float_uint_4
+          %w = OpVariable %_ptr_Workgroup__arr_mat2v4float_uint_4 Workgroup
+       %void = OpTypeVoid
+         %14 = OpTypeFunction %void %uint
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %21 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Workgroup_mat2v4float = OpTypePointer Workgroup %mat2v4float
+         %35 = OpConstantNull %mat2v4float
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+   %uint_264 = OpConstant %uint 264
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat2v4float_uint_4 = OpTypePointer Uniform %_arr_mat2v4float_uint_4
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_mat2v4float = OpTypePointer Uniform %mat2v4float
+         %53 = OpConstantNull %int
+%_ptr_Workgroup_v4float = OpTypePointer Workgroup %v4float
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+%_ptr_Workgroup_float = OpTypePointer Workgroup %float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+         %65 = OpTypeFunction %void
+    %f_inner = OpFunction %void None %14
+%local_invocation_index = OpFunctionParameter %uint
+         %18 = OpLabel
+        %idx = OpVariable %_ptr_Function_uint Function %21
+               OpStore %idx %local_invocation_index
+               OpBranch %22
+         %22 = OpLabel
+               OpLoopMerge %23 %24 None
+               OpBranch %25
+         %25 = OpLabel
+         %27 = OpLoad %uint %idx
+         %28 = OpULessThan %bool %27 %uint_4
+         %26 = OpLogicalNot %bool %28
+               OpSelectionMerge %30 None
+               OpBranchConditional %26 %31 %30
+         %31 = OpLabel
+               OpBranch %23
+         %30 = OpLabel
+         %32 = OpLoad %uint %idx
+         %34 = OpAccessChain %_ptr_Workgroup_mat2v4float %w %32
+               OpStore %34 %35
+               OpBranch %24
+         %24 = OpLabel
+         %36 = OpLoad %uint %idx
+         %38 = OpIAdd %uint %36 %uint_1
+               OpStore %idx %38
+               OpBranch %22
+         %23 = OpLabel
+               OpControlBarrier %uint_2 %uint_2 %uint_264
+         %44 = OpAccessChain %_ptr_Uniform__arr_mat2v4float_uint_4 %u %uint_0
+         %45 = OpLoad %_arr_mat2v4float_uint_4 %44
+               OpStore %w %45
+         %48 = OpAccessChain %_ptr_Workgroup_mat2v4float %w %int_1
+         %51 = OpAccessChain %_ptr_Uniform_mat2v4float %u %uint_0 %int_2
+         %52 = OpLoad %mat2v4float %51
+               OpStore %48 %52
+         %55 = OpAccessChain %_ptr_Workgroup_v4float %w %int_1 %53
+         %57 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %53 %int_1
+         %58 = OpLoad %v4float %57
+         %59 = OpVectorShuffle %v4float %58 %58 1 3 0 2
+               OpStore %55 %59
+         %61 = OpAccessChain %_ptr_Workgroup_float %w %int_1 %53 %uint_0
+         %63 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %53 %int_1 %uint_0
+         %64 = OpLoad %float %63
+               OpStore %61 %64
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %65
+         %67 = OpLabel
+         %69 = OpLoad %uint %local_invocation_index_1
+         %68 = OpFunctionCall %void %f_inner %69
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..d4f0827
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat2x4_f32/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> u : array<mat2x4<f32>, 4>;
+
+var<workgroup> w : array<mat2x4<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[2];
+  w[1][0] = u[0][1].ywxz;
+  w[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/array/mat3x3_f32/dynamic_index_via_ptr.wgsl
new file mode 100644
index 0000000..36e3407
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/dynamic_index_via_ptr.wgsl
@@ -0,0 +1,15 @@
+@group(0) @binding(0) var<uniform> a : array<mat3x3<f32>, 4>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a       = &a;
+  let p_a_i     = &((*p_a)[i()]);
+  let p_a_i_i   = &((*p_a_i)[i()]);
+
+  let l_a       : array<mat3x3<f32>, 4> = *p_a;
+  let l_a_i     : mat3x3<f32>           = *p_a_i;
+  let l_a_i_i   : vec3<f32>             = *p_a_i_i;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..ec7bba0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,38 @@
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[12];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float3x3 tint_symbol_1(uint4 buffer[12], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+}
+
+typedef float3x3 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[12], uint offset) {
+  float3x3 arr[4] = (float3x3[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 48u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_i_save = i();
+  const float3x3 l_a[4] = tint_symbol(a, 0u);
+  const float3x3 l_a_i = tint_symbol_1(a, (48u * uint(p_a_i_save)));
+  const uint scalar_offset_3 = (((48u * uint(p_a_i_save)) + (16u * uint(p_a_i_i_save)))) / 4;
+  const float3 l_a_i_i = asfloat(a[scalar_offset_3 / 4].xyz);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..ec7bba0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,38 @@
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[12];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float3x3 tint_symbol_1(uint4 buffer[12], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+}
+
+typedef float3x3 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[12], uint offset) {
+  float3x3 arr[4] = (float3x3[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 48u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_i_save = i();
+  const float3x3 l_a[4] = tint_symbol(a, 0u);
+  const float3x3 l_a_i = tint_symbol_1(a, (48u * uint(p_a_i_save)));
+  const uint scalar_offset_3 = (((48u * uint(p_a_i_save)) + (16u * uint(p_a_i_i_save)))) / 4;
+  const float3 l_a_i_i = asfloat(a[scalar_offset_3 / 4].xyz);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..dfafea6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,27 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform a_block_ubo {
+  mat3 inner[4];
+} a;
+
+int counter = 0;
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+void f() {
+  int tint_symbol = i();
+  int p_a_i_save = tint_symbol;
+  int tint_symbol_1 = i();
+  int p_a_i_i_save = tint_symbol_1;
+  mat3 l_a[4] = a.inner;
+  mat3 l_a_i = a.inner[p_a_i_save];
+  vec3 l_a_i_i = a.inner[p_a_i_save][p_a_i_i_save];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..33dacb2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,33 @@
+#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];
+};
+
+int i() {
+  thread int tint_symbol_2 = 0;
+  tint_symbol_2 = as_type<int>((as_type<uint>(tint_symbol_2) + as_type<uint>(1)));
+  return tint_symbol_2;
+}
+
+kernel void f(const constant tint_array<float3x3, 4>* tint_symbol_3 [[buffer(0)]]) {
+  int const tint_symbol = i();
+  int const p_a_i_save = tint_symbol;
+  int const tint_symbol_1 = i();
+  int const p_a_i_i_save = tint_symbol_1;
+  tint_array<float3x3, 4> const l_a = *(tint_symbol_3);
+  float3x3 const l_a_i = (*(tint_symbol_3))[p_a_i_save];
+  float3 const l_a_i_i = (*(tint_symbol_3))[p_a_i_save][p_a_i_i_save];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..8e7e1f9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,64 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 37
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block "a_block"
+               OpMemberName %a_block 0 "inner"
+               OpName %a "a"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %f "f"
+               OpDecorate %a_block Block
+               OpMemberDecorate %a_block 0 Offset 0
+               OpMemberDecorate %a_block 0 ColMajor
+               OpMemberDecorate %a_block 0 MatrixStride 16
+               OpDecorate %_arr_mat3v3float_uint_4 ArrayStride 48
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat3v3float_uint_4 = OpTypeArray %mat3v3float %uint_4
+    %a_block = OpTypeStruct %_arr_mat3v3float_uint_4
+%_ptr_Uniform_a_block = OpTypePointer Uniform %a_block
+          %a = OpVariable %_ptr_Uniform_a_block Uniform
+        %int = OpTypeInt 32 1
+         %11 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %11
+         %14 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+       %void = OpTypeVoid
+         %21 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat3v3float_uint_4 = OpTypePointer Uniform %_arr_mat3v3float_uint_4
+%_ptr_Uniform_mat3v3float = OpTypePointer Uniform %mat3v3float
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+          %i = OpFunction %int None %14
+         %16 = OpLabel
+         %17 = OpLoad %int %counter
+         %19 = OpIAdd %int %17 %int_1
+               OpStore %counter %19
+         %20 = OpLoad %int %counter
+               OpReturnValue %20
+               OpFunctionEnd
+          %f = OpFunction %void None %21
+         %24 = OpLabel
+         %25 = OpFunctionCall %int %i
+         %26 = OpFunctionCall %int %i
+         %29 = OpAccessChain %_ptr_Uniform__arr_mat3v3float_uint_4 %a %uint_0
+         %30 = OpLoad %_arr_mat3v3float_uint_4 %29
+         %32 = OpAccessChain %_ptr_Uniform_mat3v3float %a %uint_0 %25
+         %33 = OpLoad %mat3v3float %32
+         %35 = OpAccessChain %_ptr_Uniform_v3float %a %uint_0 %25 %26
+         %36 = OpLoad %v3float %35
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..8523c51
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+@group(0) @binding(0) var<uniform> a : array<mat3x3<f32>, 4>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_i = &((*(p_a))[i()]);
+  let p_a_i_i = &((*(p_a_i))[i()]);
+  let l_a : array<mat3x3<f32>, 4> = *(p_a);
+  let l_a_i : mat3x3<f32> = *(p_a_i);
+  let l_a_i_i : vec3<f32> = *(p_a_i_i);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/array/mat3x3_f32/static_index_via_ptr.wgsl
new file mode 100644
index 0000000..4d868b4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/static_index_via_ptr.wgsl
@@ -0,0 +1,12 @@
+@group(0) @binding(0) var<uniform> a : array<mat3x3<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a       = &a;
+  let p_a_2     = &((*p_a)[2]);
+  let p_a_2_1   = &((*p_a_2)[1]);
+
+  let l_a       : array<mat3x3<f32>, 4> = *p_a;
+  let l_a_i     : mat3x3<f32>           = *p_a_2;
+  let l_a_i_i   : vec3<f32>             = *p_a_2_1;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat3x3_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..ac8182a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,29 @@
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[12];
+};
+
+float3x3 tint_symbol_1(uint4 buffer[12], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+}
+
+typedef float3x3 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[12], uint offset) {
+  float3x3 arr[4] = (float3x3[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 48u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float3x3 l_a[4] = tint_symbol(a, 0u);
+  const float3x3 l_a_i = tint_symbol_1(a, 96u);
+  const float3 l_a_i_i = asfloat(a[7].xyz);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat3x3_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..ac8182a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,29 @@
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[12];
+};
+
+float3x3 tint_symbol_1(uint4 buffer[12], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+}
+
+typedef float3x3 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[12], uint offset) {
+  float3x3 arr[4] = (float3x3[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 48u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float3x3 l_a[4] = tint_symbol(a, 0u);
+  const float3x3 l_a_i = tint_symbol_1(a, 96u);
+  const float3 l_a_i_i = asfloat(a[7].xyz);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat3x3_f32/static_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..926acda
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/static_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,17 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform a_block_ubo {
+  mat3 inner[4];
+} a;
+
+void f() {
+  mat3 l_a[4] = a.inner;
+  mat3 l_a_i = a.inner[2];
+  vec3 l_a_i_i = a.inner[2][1];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat3x3_f32/static_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..05a9ea9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/static_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,23 @@
+#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];
+};
+
+kernel void f(const constant tint_array<float3x3, 4>* tint_symbol [[buffer(0)]]) {
+  tint_array<float3x3, 4> const l_a = *(tint_symbol);
+  float3x3 const l_a_i = (*(tint_symbol))[2];
+  float3 const l_a_i_i = (*(tint_symbol))[2][1];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat3x3_f32/static_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..97cff3e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/static_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,49 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 27
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block "a_block"
+               OpMemberName %a_block 0 "inner"
+               OpName %a "a"
+               OpName %f "f"
+               OpDecorate %a_block Block
+               OpMemberDecorate %a_block 0 Offset 0
+               OpMemberDecorate %a_block 0 ColMajor
+               OpMemberDecorate %a_block 0 MatrixStride 16
+               OpDecorate %_arr_mat3v3float_uint_4 ArrayStride 48
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat3v3float_uint_4 = OpTypeArray %mat3v3float %uint_4
+    %a_block = OpTypeStruct %_arr_mat3v3float_uint_4
+%_ptr_Uniform_a_block = OpTypePointer Uniform %a_block
+          %a = OpVariable %_ptr_Uniform_a_block Uniform
+       %void = OpTypeVoid
+         %10 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat3v3float_uint_4 = OpTypePointer Uniform %_arr_mat3v3float_uint_4
+        %int = OpTypeInt 32 1
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_mat3v3float = OpTypePointer Uniform %mat3v3float
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+          %f = OpFunction %void None %10
+         %13 = OpLabel
+         %16 = OpAccessChain %_ptr_Uniform__arr_mat3v3float_uint_4 %a %uint_0
+         %17 = OpLoad %_arr_mat3v3float_uint_4 %16
+         %21 = OpAccessChain %_ptr_Uniform_mat3v3float %a %uint_0 %int_2
+         %22 = OpLoad %mat3v3float %21
+         %25 = OpAccessChain %_ptr_Uniform_v3float %a %uint_0 %int_2 %int_1
+         %26 = OpLoad %v3float %25
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat3x3_f32/static_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..f147611
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/static_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> a : array<mat3x3<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_2 = &((*(p_a))[2]);
+  let p_a_2_1 = &((*(p_a_2))[1]);
+  let l_a : array<mat3x3<f32>, 4> = *(p_a);
+  let l_a_i : mat3x3<f32> = *(p_a_2);
+  let l_a_i_i : vec3<f32> = *(p_a_2_1);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_builtin.wgsl b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_builtin.wgsl
new file mode 100644
index 0000000..ac6fec7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_builtin.wgsl
@@ -0,0 +1,8 @@
+@group(0) @binding(0) var<uniform> u : array<mat3x3<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    let t = transpose(u[2]);
+    let l = length(u[0][1].zxy);
+    let a = abs(u[0][1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_builtin.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..6bf5247
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_builtin.wgsl.expected.dxc.hlsl
@@ -0,0 +1,18 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[12];
+};
+
+float3x3 tint_symbol(uint4 buffer[12], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float3x3 t = transpose(tint_symbol(u, 96u));
+  const float l = length(asfloat(u[1].xyz).zxy);
+  const float a = abs(asfloat(u[1].xyz).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_builtin.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..6bf5247
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_builtin.wgsl.expected.fxc.hlsl
@@ -0,0 +1,18 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[12];
+};
+
+float3x3 tint_symbol(uint4 buffer[12], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float3x3 t = transpose(tint_symbol(u, 96u));
+  const float l = length(asfloat(u[1].xyz).zxy);
+  const float a = abs(asfloat(u[1].xyz).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_builtin.wgsl.expected.glsl
new file mode 100644
index 0000000..c6be6eb
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_builtin.wgsl.expected.glsl
@@ -0,0 +1,17 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat3 inner[4];
+} u;
+
+void f() {
+  mat3 t = transpose(u.inner[2]);
+  float l = length(u.inner[0][1].zxy);
+  float a = abs(u.inner[0][1].zxy.x);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_builtin.wgsl.expected.msl
new file mode 100644
index 0000000..16b5d79
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_builtin.wgsl.expected.msl
@@ -0,0 +1,23 @@
+#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];
+};
+
+kernel void f(const constant tint_array<float3x3, 4>* tint_symbol [[buffer(0)]]) {
+  float3x3 const t = transpose((*(tint_symbol))[2]);
+  float const l = length(float3((*(tint_symbol))[0][1]).zxy);
+  float const a = fabs(float3((*(tint_symbol))[0][1]).zxy[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_builtin.wgsl.expected.spvasm
new file mode 100644
index 0000000..5c1e625
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_builtin.wgsl.expected.spvasm
@@ -0,0 +1,56 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 34
+; Schema: 0
+               OpCapability Shader
+         %22 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %_arr_mat3v3float_uint_4 ArrayStride 48
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat3v3float_uint_4 = OpTypeArray %mat3v3float %uint_4
+    %u_block = OpTypeStruct %_arr_mat3v3float_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+         %10 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+        %int = OpTypeInt 32 1
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_mat3v3float = OpTypePointer Uniform %mat3v3float
+         %23 = OpConstantNull %int
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+          %f = OpFunction %void None %10
+         %13 = OpLabel
+         %19 = OpAccessChain %_ptr_Uniform_mat3v3float %u %uint_0 %int_2
+         %20 = OpLoad %mat3v3float %19
+         %14 = OpTranspose %mat3v3float %20
+         %26 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %23 %int_1
+         %27 = OpLoad %v3float %26
+         %28 = OpVectorShuffle %v3float %27 %27 2 0 1
+         %21 = OpExtInst %float %22 Length %28
+         %30 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %23 %int_1
+         %31 = OpLoad %v3float %30
+         %32 = OpVectorShuffle %v3float %31 %31 2 0 1
+         %33 = OpCompositeExtract %float %32 0
+         %29 = OpExtInst %float %22 FAbs %33
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_builtin.wgsl.expected.wgsl
new file mode 100644
index 0000000..5a0760d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_builtin.wgsl.expected.wgsl
@@ -0,0 +1,8 @@
+@group(0) @binding(0) var<uniform> u : array<mat3x3<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let t = transpose(u[2]);
+  let l = length(u[0][1].zxy);
+  let a = abs(u[0][1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_fn.wgsl b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_fn.wgsl
new file mode 100644
index 0000000..b35b784
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_fn.wgsl
@@ -0,0 +1,14 @@
+@group(0) @binding(0) var<uniform> u : array<mat3x3<f32>, 4>;
+
+fn a(a : array<mat3x3<f32>, 4>) {}
+fn b(m : mat3x3<f32>) {}
+fn c(v : vec3<f32>) {}
+fn d(f : f32) {}
+
+@compute @workgroup_size(1)
+fn f() {
+    a(u);
+    b(u[1]);
+    c(u[1][0].zxy);
+    d(u[1][0].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_fn.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..3251692
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_fn.wgsl.expected.dxc.hlsl
@@ -0,0 +1,42 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[12];
+};
+
+void a(float3x3 a_1[4]) {
+}
+
+void b(float3x3 m) {
+}
+
+void c(float3 v) {
+}
+
+void d(float f_1) {
+}
+
+float3x3 tint_symbol_1(uint4 buffer[12], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+}
+
+typedef float3x3 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[12], uint offset) {
+  float3x3 arr[4] = (float3x3[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 48u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 48u));
+  c(asfloat(u[3].xyz).zxy);
+  d(asfloat(u[3].xyz).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_fn.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..3251692
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_fn.wgsl.expected.fxc.hlsl
@@ -0,0 +1,42 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[12];
+};
+
+void a(float3x3 a_1[4]) {
+}
+
+void b(float3x3 m) {
+}
+
+void c(float3 v) {
+}
+
+void d(float f_1) {
+}
+
+float3x3 tint_symbol_1(uint4 buffer[12], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+}
+
+typedef float3x3 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[12], uint offset) {
+  float3x3 arr[4] = (float3x3[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 48u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 48u));
+  c(asfloat(u[3].xyz).zxy);
+  d(asfloat(u[3].xyz).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_fn.wgsl.expected.glsl
new file mode 100644
index 0000000..d6e73ff
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_fn.wgsl.expected.glsl
@@ -0,0 +1,30 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat3 inner[4];
+} u;
+
+void a(mat3 a_1[4]) {
+}
+
+void b(mat3 m) {
+}
+
+void c(vec3 v) {
+}
+
+void d(float f_1) {
+}
+
+void f() {
+  a(u.inner);
+  b(u.inner[1]);
+  c(u.inner[1][0].zxy);
+  d(u.inner[1][0].zxy.x);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_fn.wgsl.expected.msl
new file mode 100644
index 0000000..15297bd
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_fn.wgsl.expected.msl
@@ -0,0 +1,36 @@
+#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];
+};
+
+void a(tint_array<float3x3, 4> a_1) {
+}
+
+void b(float3x3 m) {
+}
+
+void c(float3 v) {
+}
+
+void d(float f_1) {
+}
+
+kernel void f(const constant tint_array<float3x3, 4>* tint_symbol [[buffer(0)]]) {
+  a(*(tint_symbol));
+  b((*(tint_symbol))[1]);
+  c(float3((*(tint_symbol))[1][0]).zxy);
+  d(float3((*(tint_symbol))[1][0]).zxy[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_fn.wgsl.expected.spvasm
new file mode 100644
index 0000000..3cdc026
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_fn.wgsl.expected.spvasm
@@ -0,0 +1,90 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 52
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %a "a"
+               OpName %a_1 "a_1"
+               OpName %b "b"
+               OpName %m "m"
+               OpName %c "c"
+               OpName %v "v"
+               OpName %d "d"
+               OpName %f_1 "f_1"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %_arr_mat3v3float_uint_4 ArrayStride 48
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat3v3float_uint_4 = OpTypeArray %mat3v3float %uint_4
+    %u_block = OpTypeStruct %_arr_mat3v3float_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+         %10 = OpTypeFunction %void %_arr_mat3v3float_uint_4
+         %15 = OpTypeFunction %void %mat3v3float
+         %19 = OpTypeFunction %void %v3float
+         %23 = OpTypeFunction %void %float
+         %27 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat3v3float_uint_4 = OpTypePointer Uniform %_arr_mat3v3float_uint_4
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_mat3v3float = OpTypePointer Uniform %mat3v3float
+         %42 = OpConstantNull %int
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+          %a = OpFunction %void None %10
+        %a_1 = OpFunctionParameter %_arr_mat3v3float_uint_4
+         %14 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %b = OpFunction %void None %15
+          %m = OpFunctionParameter %mat3v3float
+         %18 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %c = OpFunction %void None %19
+          %v = OpFunctionParameter %v3float
+         %22 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %d = OpFunction %void None %23
+        %f_1 = OpFunctionParameter %float
+         %26 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %27
+         %29 = OpLabel
+         %33 = OpAccessChain %_ptr_Uniform__arr_mat3v3float_uint_4 %u %uint_0
+         %34 = OpLoad %_arr_mat3v3float_uint_4 %33
+         %30 = OpFunctionCall %void %a %34
+         %39 = OpAccessChain %_ptr_Uniform_mat3v3float %u %uint_0 %int_1
+         %40 = OpLoad %mat3v3float %39
+         %35 = OpFunctionCall %void %b %40
+         %44 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %int_1 %42
+         %45 = OpLoad %v3float %44
+         %46 = OpVectorShuffle %v3float %45 %45 2 0 1
+         %41 = OpFunctionCall %void %c %46
+         %48 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %int_1 %42
+         %49 = OpLoad %v3float %48
+         %50 = OpVectorShuffle %v3float %49 %49 2 0 1
+         %51 = OpCompositeExtract %float %50 0
+         %47 = OpFunctionCall %void %d %51
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_fn.wgsl.expected.wgsl
new file mode 100644
index 0000000..a78c8c9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_fn.wgsl.expected.wgsl
@@ -0,0 +1,21 @@
+@group(0) @binding(0) var<uniform> u : array<mat3x3<f32>, 4>;
+
+fn a(a : array<mat3x3<f32>, 4>) {
+}
+
+fn b(m : mat3x3<f32>) {
+}
+
+fn c(v : vec3<f32>) {
+}
+
+fn d(f : f32) {
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  a(u);
+  b(u[1]);
+  c(u[1][0].zxy);
+  d(u[1][0].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_private.wgsl b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_private.wgsl
new file mode 100644
index 0000000..133e0e5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_private.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0) var<uniform> u : array<mat3x3<f32>, 4>;
+var<private> p : array<mat3x3<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[2];
+    p[1][0] = u[0][1].zxy;
+    p[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_private.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..4bf04e7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_private.wgsl.expected.dxc.hlsl
@@ -0,0 +1,31 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[12];
+};
+static float3x3 p[4] = (float3x3[4])0;
+
+float3x3 tint_symbol_1(uint4 buffer[12], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+}
+
+typedef float3x3 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[12], uint offset) {
+  float3x3 arr[4] = (float3x3[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 48u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 96u);
+  p[1][0] = asfloat(u[1].xyz).zxy;
+  p[1][0].x = asfloat(u[1].x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_private.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..4bf04e7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_private.wgsl.expected.fxc.hlsl
@@ -0,0 +1,31 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[12];
+};
+static float3x3 p[4] = (float3x3[4])0;
+
+float3x3 tint_symbol_1(uint4 buffer[12], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+}
+
+typedef float3x3 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[12], uint offset) {
+  float3x3 arr[4] = (float3x3[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 48u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 96u);
+  p[1][0] = asfloat(u[1].xyz).zxy;
+  p[1][0].x = asfloat(u[1].x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..3aac30a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_private.wgsl.expected.glsl
@@ -0,0 +1,19 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat3 inner[4];
+} u;
+
+mat3 p[4] = mat3[4](mat3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
+void f() {
+  p = u.inner;
+  p[1] = u.inner[2];
+  p[1][0] = u.inner[0][1].zxy;
+  p[1][0].x = u.inner[0][1].x;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..0c7a2db
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_private.wgsl.expected.msl
@@ -0,0 +1,25 @@
+#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];
+};
+
+kernel void f(const constant tint_array<float3x3, 4>* tint_symbol_1 [[buffer(0)]]) {
+  thread tint_array<float3x3, 4> tint_symbol = {};
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[2];
+  tint_symbol[1][0] = float3((*(tint_symbol_1))[0][1]).zxy;
+  tint_symbol[1][0][0] = (*(tint_symbol_1))[0][1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_private.wgsl.expected.spvasm
new file mode 100644
index 0000000..e3b8dae
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_private.wgsl.expected.spvasm
@@ -0,0 +1,68 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 41
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %p "p"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %_arr_mat3v3float_uint_4 ArrayStride 48
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat3v3float_uint_4 = OpTypeArray %mat3v3float %uint_4
+    %u_block = OpTypeStruct %_arr_mat3v3float_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_Private__arr_mat3v3float_uint_4 = OpTypePointer Private %_arr_mat3v3float_uint_4
+         %12 = OpConstantNull %_arr_mat3v3float_uint_4
+          %p = OpVariable %_ptr_Private__arr_mat3v3float_uint_4 Private %12
+       %void = OpTypeVoid
+         %13 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat3v3float_uint_4 = OpTypePointer Uniform %_arr_mat3v3float_uint_4
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Private_mat3v3float = OpTypePointer Private %mat3v3float
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_mat3v3float = OpTypePointer Uniform %mat3v3float
+         %29 = OpConstantNull %int
+%_ptr_Private_v3float = OpTypePointer Private %v3float
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+%_ptr_Private_float = OpTypePointer Private %float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+          %f = OpFunction %void None %13
+         %16 = OpLabel
+         %19 = OpAccessChain %_ptr_Uniform__arr_mat3v3float_uint_4 %u %uint_0
+         %20 = OpLoad %_arr_mat3v3float_uint_4 %19
+               OpStore %p %20
+         %24 = OpAccessChain %_ptr_Private_mat3v3float %p %int_1
+         %27 = OpAccessChain %_ptr_Uniform_mat3v3float %u %uint_0 %int_2
+         %28 = OpLoad %mat3v3float %27
+               OpStore %24 %28
+         %31 = OpAccessChain %_ptr_Private_v3float %p %int_1 %29
+         %33 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %29 %int_1
+         %34 = OpLoad %v3float %33
+         %35 = OpVectorShuffle %v3float %34 %34 2 0 1
+               OpStore %31 %35
+         %37 = OpAccessChain %_ptr_Private_float %p %int_1 %29 %uint_0
+         %39 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %29 %int_1 %uint_0
+         %40 = OpLoad %float %39
+               OpStore %37 %40
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..59b72cf
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_private.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> u : array<mat3x3<f32>, 4>;
+
+var<private> p : array<mat3x3<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[2];
+  p[1][0] = u[0][1].zxy;
+  p[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_storage.wgsl b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_storage.wgsl
new file mode 100644
index 0000000..cc5a3f1
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_storage.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0) var<uniform> u : array<mat3x3<f32>, 4>;
+@group(0) @binding(1) var<storage, read_write> s : array<mat3x3<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[2];
+    s[1][0] = u[0][1].zxy;
+    s[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_storage.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..6dc59a8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_storage.wgsl.expected.dxc.hlsl
@@ -0,0 +1,46 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[12];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, float3x3 value) {
+  buffer.Store3((offset + 0u), asuint(value[0u]));
+  buffer.Store3((offset + 16u), asuint(value[1u]));
+  buffer.Store3((offset + 32u), asuint(value[2u]));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, float3x3 value[4]) {
+  float3x3 array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 48u)), array[i]);
+    }
+  }
+}
+
+float3x3 tint_symbol_4(uint4 buffer[12], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+}
+
+typedef float3x3 tint_symbol_3_ret[4];
+tint_symbol_3_ret tint_symbol_3(uint4 buffer[12], uint offset) {
+  float3x3 arr[4] = (float3x3[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_4(buffer, (offset + (i_1 * 48u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_3(u, 0u));
+  tint_symbol_1(s, 48u, tint_symbol_4(u, 96u));
+  s.Store3(48u, asuint(asfloat(u[1].xyz).zxy));
+  s.Store(48u, asuint(asfloat(u[1].x)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_storage.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..6dc59a8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_storage.wgsl.expected.fxc.hlsl
@@ -0,0 +1,46 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[12];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, float3x3 value) {
+  buffer.Store3((offset + 0u), asuint(value[0u]));
+  buffer.Store3((offset + 16u), asuint(value[1u]));
+  buffer.Store3((offset + 32u), asuint(value[2u]));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, float3x3 value[4]) {
+  float3x3 array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 48u)), array[i]);
+    }
+  }
+}
+
+float3x3 tint_symbol_4(uint4 buffer[12], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+}
+
+typedef float3x3 tint_symbol_3_ret[4];
+tint_symbol_3_ret tint_symbol_3(uint4 buffer[12], uint offset) {
+  float3x3 arr[4] = (float3x3[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_4(buffer, (offset + (i_1 * 48u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_3(u, 0u));
+  tint_symbol_1(s, 48u, tint_symbol_4(u, 96u));
+  s.Store3(48u, asuint(asfloat(u[1].xyz).zxy));
+  s.Store(48u, asuint(asfloat(u[1].x)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..9105811
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_storage.wgsl.expected.glsl
@@ -0,0 +1,22 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat3 inner[4];
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  mat3 inner[4];
+} s;
+
+void f() {
+  s.inner = u.inner;
+  s.inner[1] = u.inner[2];
+  s.inner[1][0] = u.inner[0][1].zxy;
+  s.inner[1][0].x = u.inner[0][1].x;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..048579a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_storage.wgsl.expected.msl
@@ -0,0 +1,24 @@
+#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];
+};
+
+kernel void f(device tint_array<float3x3, 4>* tint_symbol [[buffer(1)]], const constant tint_array<float3x3, 4>* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
+  (*(tint_symbol))[1][0] = float3((*(tint_symbol_1))[0][1]).zxy;
+  (*(tint_symbol))[1][0][0] = (*(tint_symbol_1))[0][1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_storage.wgsl.expected.spvasm
new file mode 100644
index 0000000..2dd00c0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_storage.wgsl.expected.spvasm
@@ -0,0 +1,71 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 42
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %s "s"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %_arr_mat3v3float_uint_4 ArrayStride 48
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %s DescriptorSet 0
+               OpDecorate %s Binding 1
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat3v3float_uint_4 = OpTypeArray %mat3v3float %uint_4
+    %u_block = OpTypeStruct %_arr_mat3v3float_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
+          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+       %void = OpTypeVoid
+         %12 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer__arr_mat3v3float_uint_4 = OpTypePointer StorageBuffer %_arr_mat3v3float_uint_4
+%_ptr_Uniform__arr_mat3v3float_uint_4 = OpTypePointer Uniform %_arr_mat3v3float_uint_4
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_mat3v3float = OpTypePointer StorageBuffer %mat3v3float
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_mat3v3float = OpTypePointer Uniform %mat3v3float
+         %30 = OpConstantNull %int
+%_ptr_StorageBuffer_v3float = OpTypePointer StorageBuffer %v3float
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+          %f = OpFunction %void None %12
+         %15 = OpLabel
+         %18 = OpAccessChain %_ptr_StorageBuffer__arr_mat3v3float_uint_4 %s %uint_0
+         %20 = OpAccessChain %_ptr_Uniform__arr_mat3v3float_uint_4 %u %uint_0
+         %21 = OpLoad %_arr_mat3v3float_uint_4 %20
+               OpStore %18 %21
+         %25 = OpAccessChain %_ptr_StorageBuffer_mat3v3float %s %uint_0 %int_1
+         %28 = OpAccessChain %_ptr_Uniform_mat3v3float %u %uint_0 %int_2
+         %29 = OpLoad %mat3v3float %28
+               OpStore %25 %29
+         %32 = OpAccessChain %_ptr_StorageBuffer_v3float %s %uint_0 %int_1 %30
+         %34 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %30 %int_1
+         %35 = OpLoad %v3float %34
+         %36 = OpVectorShuffle %v3float %35 %35 2 0 1
+               OpStore %32 %36
+         %38 = OpAccessChain %_ptr_StorageBuffer_float %s %uint_0 %int_1 %30 %uint_0
+         %40 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %30 %int_1 %uint_0
+         %41 = OpLoad %float %40
+               OpStore %38 %41
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..a4f9263
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> u : array<mat3x3<f32>, 4>;
+
+@group(0) @binding(1) var<storage, read_write> s : array<mat3x3<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[2];
+  s[1][0] = u[0][1].zxy;
+  s[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_workgroup.wgsl
new file mode 100644
index 0000000..8f011e3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_workgroup.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0) var<uniform> u : array<mat3x3<f32>, 4>;
+var<workgroup> w : array<mat3x3<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[2];
+    w[1][0] = u[0][1].zxy;
+    w[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_workgroup.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..1751886
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_workgroup.wgsl.expected.dxc.hlsl
@@ -0,0 +1,46 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[12];
+};
+groupshared float3x3 w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+float3x3 tint_symbol_3(uint4 buffer[12], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+}
+
+typedef float3x3 tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[12], uint offset) {
+  float3x3 arr[4] = (float3x3[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 48u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      w[i] = float3x3((0.0f).xxx, (0.0f).xxx, (0.0f).xxx);
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 96u);
+  w[1][0] = asfloat(u[1].xyz).zxy;
+  w[1][0].x = asfloat(u[1].x);
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_workgroup.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..1751886
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_workgroup.wgsl.expected.fxc.hlsl
@@ -0,0 +1,46 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[12];
+};
+groupshared float3x3 w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+float3x3 tint_symbol_3(uint4 buffer[12], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+}
+
+typedef float3x3 tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[12], uint offset) {
+  float3x3 arr[4] = (float3x3[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 48u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      w[i] = float3x3((0.0f).xxx, (0.0f).xxx, (0.0f).xxx);
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 96u);
+  w[1][0] = asfloat(u[1].xyz).zxy;
+  w[1][0].x = asfloat(u[1].x);
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..0670f59
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,26 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat3 inner[4];
+} u;
+
+shared mat3 w[4];
+void f(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      uint i = idx;
+      w[i] = mat3(vec3(0.0f), vec3(0.0f), vec3(0.0f));
+    }
+  }
+  barrier();
+  w = u.inner;
+  w[1] = u.inner[2];
+  w[1][0] = u.inner[0][1].zxy;
+  w[1][0].x = u.inner[0][1].x;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..d1bf3a7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,38 @@
+#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_symbol_5 {
+  tint_array<float3x3, 4> w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup tint_array<float3x3, 4>* const tint_symbol, const constant tint_array<float3x3, 4>* const tint_symbol_1) {
+  for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+    uint const i = idx;
+    (*(tint_symbol))[i] = float3x3(float3(0.0f), float3(0.0f), float3(0.0f));
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
+  (*(tint_symbol))[1][0] = float3((*(tint_symbol_1))[0][1]).zxy;
+  (*(tint_symbol))[1][0][0] = (*(tint_symbol_1))[0][1][0];
+}
+
+kernel void f(const constant tint_array<float3x3, 4>* tint_symbol_4 [[buffer(0)]], threadgroup tint_symbol_5* tint_symbol_3 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup tint_array<float3x3, 4>* const tint_symbol_2 = &((*(tint_symbol_3)).w);
+  f_inner(local_invocation_index, tint_symbol_2, tint_symbol_4);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_workgroup.wgsl.expected.spvasm
new file mode 100644
index 0000000..309d2ed
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_workgroup.wgsl.expected.spvasm
@@ -0,0 +1,115 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 70
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %local_invocation_index_1 "local_invocation_index_1"
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %w "w"
+               OpName %f_inner "f_inner"
+               OpName %local_invocation_index "local_invocation_index"
+               OpName %idx "idx"
+               OpName %f "f"
+               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %_arr_mat3v3float_uint_4 ArrayStride 48
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+     %uint_4 = OpConstant %uint 4
+%_arr_mat3v3float_uint_4 = OpTypeArray %mat3v3float %uint_4
+    %u_block = OpTypeStruct %_arr_mat3v3float_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_Workgroup__arr_mat3v3float_uint_4 = OpTypePointer Workgroup %_arr_mat3v3float_uint_4
+          %w = OpVariable %_ptr_Workgroup__arr_mat3v3float_uint_4 Workgroup
+       %void = OpTypeVoid
+         %14 = OpTypeFunction %void %uint
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %21 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Workgroup_mat3v3float = OpTypePointer Workgroup %mat3v3float
+         %35 = OpConstantNull %mat3v3float
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+   %uint_264 = OpConstant %uint 264
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat3v3float_uint_4 = OpTypePointer Uniform %_arr_mat3v3float_uint_4
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_mat3v3float = OpTypePointer Uniform %mat3v3float
+         %53 = OpConstantNull %int
+%_ptr_Workgroup_v3float = OpTypePointer Workgroup %v3float
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+%_ptr_Workgroup_float = OpTypePointer Workgroup %float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+         %65 = OpTypeFunction %void
+    %f_inner = OpFunction %void None %14
+%local_invocation_index = OpFunctionParameter %uint
+         %18 = OpLabel
+        %idx = OpVariable %_ptr_Function_uint Function %21
+               OpStore %idx %local_invocation_index
+               OpBranch %22
+         %22 = OpLabel
+               OpLoopMerge %23 %24 None
+               OpBranch %25
+         %25 = OpLabel
+         %27 = OpLoad %uint %idx
+         %28 = OpULessThan %bool %27 %uint_4
+         %26 = OpLogicalNot %bool %28
+               OpSelectionMerge %30 None
+               OpBranchConditional %26 %31 %30
+         %31 = OpLabel
+               OpBranch %23
+         %30 = OpLabel
+         %32 = OpLoad %uint %idx
+         %34 = OpAccessChain %_ptr_Workgroup_mat3v3float %w %32
+               OpStore %34 %35
+               OpBranch %24
+         %24 = OpLabel
+         %36 = OpLoad %uint %idx
+         %38 = OpIAdd %uint %36 %uint_1
+               OpStore %idx %38
+               OpBranch %22
+         %23 = OpLabel
+               OpControlBarrier %uint_2 %uint_2 %uint_264
+         %44 = OpAccessChain %_ptr_Uniform__arr_mat3v3float_uint_4 %u %uint_0
+         %45 = OpLoad %_arr_mat3v3float_uint_4 %44
+               OpStore %w %45
+         %48 = OpAccessChain %_ptr_Workgroup_mat3v3float %w %int_1
+         %51 = OpAccessChain %_ptr_Uniform_mat3v3float %u %uint_0 %int_2
+         %52 = OpLoad %mat3v3float %51
+               OpStore %48 %52
+         %55 = OpAccessChain %_ptr_Workgroup_v3float %w %int_1 %53
+         %57 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %53 %int_1
+         %58 = OpLoad %v3float %57
+         %59 = OpVectorShuffle %v3float %58 %58 2 0 1
+               OpStore %55 %59
+         %61 = OpAccessChain %_ptr_Workgroup_float %w %int_1 %53 %uint_0
+         %63 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %53 %int_1 %uint_0
+         %64 = OpLoad %float %63
+               OpStore %61 %64
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %65
+         %67 = OpLabel
+         %69 = OpLoad %uint %local_invocation_index_1
+         %68 = OpFunctionCall %void %f_inner %69
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..8e7202f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x3_f32/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> u : array<mat3x3<f32>, 4>;
+
+var<workgroup> w : array<mat3x3<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[2];
+  w[1][0] = u[0][1].zxy;
+  w[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/array/mat3x4_f32/dynamic_index_via_ptr.wgsl
new file mode 100644
index 0000000..8a601d4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/dynamic_index_via_ptr.wgsl
@@ -0,0 +1,15 @@
+@group(0) @binding(0) var<uniform> a : array<mat3x4<f32>, 4>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a       = &a;
+  let p_a_i     = &((*p_a)[i()]);
+  let p_a_i_i   = &((*p_a_i)[i()]);
+
+  let l_a       : array<mat3x4<f32>, 4> = *p_a;
+  let l_a_i     : mat3x4<f32>           = *p_a_i;
+  let l_a_i_i   : vec4<f32>             = *p_a_i_i;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..89cb90f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,38 @@
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[12];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float3x4 tint_symbol_1(uint4 buffer[12], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+}
+
+typedef float3x4 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[12], uint offset) {
+  float3x4 arr[4] = (float3x4[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 48u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_i_save = i();
+  const float3x4 l_a[4] = tint_symbol(a, 0u);
+  const float3x4 l_a_i = tint_symbol_1(a, (48u * uint(p_a_i_save)));
+  const uint scalar_offset_3 = (((48u * uint(p_a_i_save)) + (16u * uint(p_a_i_i_save)))) / 4;
+  const float4 l_a_i_i = asfloat(a[scalar_offset_3 / 4]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..89cb90f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,38 @@
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[12];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float3x4 tint_symbol_1(uint4 buffer[12], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+}
+
+typedef float3x4 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[12], uint offset) {
+  float3x4 arr[4] = (float3x4[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 48u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_i_save = i();
+  const float3x4 l_a[4] = tint_symbol(a, 0u);
+  const float3x4 l_a_i = tint_symbol_1(a, (48u * uint(p_a_i_save)));
+  const uint scalar_offset_3 = (((48u * uint(p_a_i_save)) + (16u * uint(p_a_i_i_save)))) / 4;
+  const float4 l_a_i_i = asfloat(a[scalar_offset_3 / 4]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..3abf919
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,27 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform a_block_ubo {
+  mat3x4 inner[4];
+} a;
+
+int counter = 0;
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+void f() {
+  int tint_symbol = i();
+  int p_a_i_save = tint_symbol;
+  int tint_symbol_1 = i();
+  int p_a_i_i_save = tint_symbol_1;
+  mat3x4 l_a[4] = a.inner;
+  mat3x4 l_a_i = a.inner[p_a_i_save];
+  vec4 l_a_i_i = a.inner[p_a_i_save][p_a_i_i_save];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..fccba32
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,33 @@
+#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];
+};
+
+int i() {
+  thread int tint_symbol_2 = 0;
+  tint_symbol_2 = as_type<int>((as_type<uint>(tint_symbol_2) + as_type<uint>(1)));
+  return tint_symbol_2;
+}
+
+kernel void f(const constant tint_array<float3x4, 4>* tint_symbol_3 [[buffer(0)]]) {
+  int const tint_symbol = i();
+  int const p_a_i_save = tint_symbol;
+  int const tint_symbol_1 = i();
+  int const p_a_i_i_save = tint_symbol_1;
+  tint_array<float3x4, 4> const l_a = *(tint_symbol_3);
+  float3x4 const l_a_i = (*(tint_symbol_3))[p_a_i_save];
+  float4 const l_a_i_i = (*(tint_symbol_3))[p_a_i_save][p_a_i_i_save];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..44c91f2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,64 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 37
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block "a_block"
+               OpMemberName %a_block 0 "inner"
+               OpName %a "a"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %f "f"
+               OpDecorate %a_block Block
+               OpMemberDecorate %a_block 0 Offset 0
+               OpMemberDecorate %a_block 0 ColMajor
+               OpMemberDecorate %a_block 0 MatrixStride 16
+               OpDecorate %_arr_mat3v4float_uint_4 ArrayStride 48
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat3v4float = OpTypeMatrix %v4float 3
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat3v4float_uint_4 = OpTypeArray %mat3v4float %uint_4
+    %a_block = OpTypeStruct %_arr_mat3v4float_uint_4
+%_ptr_Uniform_a_block = OpTypePointer Uniform %a_block
+          %a = OpVariable %_ptr_Uniform_a_block Uniform
+        %int = OpTypeInt 32 1
+         %11 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %11
+         %14 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+       %void = OpTypeVoid
+         %21 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat3v4float_uint_4 = OpTypePointer Uniform %_arr_mat3v4float_uint_4
+%_ptr_Uniform_mat3v4float = OpTypePointer Uniform %mat3v4float
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+          %i = OpFunction %int None %14
+         %16 = OpLabel
+         %17 = OpLoad %int %counter
+         %19 = OpIAdd %int %17 %int_1
+               OpStore %counter %19
+         %20 = OpLoad %int %counter
+               OpReturnValue %20
+               OpFunctionEnd
+          %f = OpFunction %void None %21
+         %24 = OpLabel
+         %25 = OpFunctionCall %int %i
+         %26 = OpFunctionCall %int %i
+         %29 = OpAccessChain %_ptr_Uniform__arr_mat3v4float_uint_4 %a %uint_0
+         %30 = OpLoad %_arr_mat3v4float_uint_4 %29
+         %32 = OpAccessChain %_ptr_Uniform_mat3v4float %a %uint_0 %25
+         %33 = OpLoad %mat3v4float %32
+         %35 = OpAccessChain %_ptr_Uniform_v4float %a %uint_0 %25 %26
+         %36 = OpLoad %v4float %35
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..35174c9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+@group(0) @binding(0) var<uniform> a : array<mat3x4<f32>, 4>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_i = &((*(p_a))[i()]);
+  let p_a_i_i = &((*(p_a_i))[i()]);
+  let l_a : array<mat3x4<f32>, 4> = *(p_a);
+  let l_a_i : mat3x4<f32> = *(p_a_i);
+  let l_a_i_i : vec4<f32> = *(p_a_i_i);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/array/mat3x4_f32/static_index_via_ptr.wgsl
new file mode 100644
index 0000000..1cdf69f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/static_index_via_ptr.wgsl
@@ -0,0 +1,12 @@
+@group(0) @binding(0) var<uniform> a : array<mat3x4<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a       = &a;
+  let p_a_2     = &((*p_a)[2]);
+  let p_a_2_1   = &((*p_a_2)[1]);
+
+  let l_a       : array<mat3x4<f32>, 4> = *p_a;
+  let l_a_i     : mat3x4<f32>           = *p_a_2;
+  let l_a_i_i   : vec4<f32>             = *p_a_2_1;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat3x4_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..ebb5252
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,29 @@
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[12];
+};
+
+float3x4 tint_symbol_1(uint4 buffer[12], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+}
+
+typedef float3x4 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[12], uint offset) {
+  float3x4 arr[4] = (float3x4[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 48u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float3x4 l_a[4] = tint_symbol(a, 0u);
+  const float3x4 l_a_i = tint_symbol_1(a, 96u);
+  const float4 l_a_i_i = asfloat(a[7]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat3x4_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..ebb5252
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,29 @@
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[12];
+};
+
+float3x4 tint_symbol_1(uint4 buffer[12], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+}
+
+typedef float3x4 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[12], uint offset) {
+  float3x4 arr[4] = (float3x4[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 48u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float3x4 l_a[4] = tint_symbol(a, 0u);
+  const float3x4 l_a_i = tint_symbol_1(a, 96u);
+  const float4 l_a_i_i = asfloat(a[7]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat3x4_f32/static_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..97d3721
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/static_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,17 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform a_block_ubo {
+  mat3x4 inner[4];
+} a;
+
+void f() {
+  mat3x4 l_a[4] = a.inner;
+  mat3x4 l_a_i = a.inner[2];
+  vec4 l_a_i_i = a.inner[2][1];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat3x4_f32/static_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..94022a0b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/static_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,23 @@
+#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];
+};
+
+kernel void f(const constant tint_array<float3x4, 4>* tint_symbol [[buffer(0)]]) {
+  tint_array<float3x4, 4> const l_a = *(tint_symbol);
+  float3x4 const l_a_i = (*(tint_symbol))[2];
+  float4 const l_a_i_i = (*(tint_symbol))[2][1];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat3x4_f32/static_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..bc3f5fa
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/static_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,49 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 27
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block "a_block"
+               OpMemberName %a_block 0 "inner"
+               OpName %a "a"
+               OpName %f "f"
+               OpDecorate %a_block Block
+               OpMemberDecorate %a_block 0 Offset 0
+               OpMemberDecorate %a_block 0 ColMajor
+               OpMemberDecorate %a_block 0 MatrixStride 16
+               OpDecorate %_arr_mat3v4float_uint_4 ArrayStride 48
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat3v4float = OpTypeMatrix %v4float 3
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat3v4float_uint_4 = OpTypeArray %mat3v4float %uint_4
+    %a_block = OpTypeStruct %_arr_mat3v4float_uint_4
+%_ptr_Uniform_a_block = OpTypePointer Uniform %a_block
+          %a = OpVariable %_ptr_Uniform_a_block Uniform
+       %void = OpTypeVoid
+         %10 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat3v4float_uint_4 = OpTypePointer Uniform %_arr_mat3v4float_uint_4
+        %int = OpTypeInt 32 1
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_mat3v4float = OpTypePointer Uniform %mat3v4float
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+          %f = OpFunction %void None %10
+         %13 = OpLabel
+         %16 = OpAccessChain %_ptr_Uniform__arr_mat3v4float_uint_4 %a %uint_0
+         %17 = OpLoad %_arr_mat3v4float_uint_4 %16
+         %21 = OpAccessChain %_ptr_Uniform_mat3v4float %a %uint_0 %int_2
+         %22 = OpLoad %mat3v4float %21
+         %25 = OpAccessChain %_ptr_Uniform_v4float %a %uint_0 %int_2 %int_1
+         %26 = OpLoad %v4float %25
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat3x4_f32/static_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..70df08d4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/static_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> a : array<mat3x4<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_2 = &((*(p_a))[2]);
+  let p_a_2_1 = &((*(p_a_2))[1]);
+  let l_a : array<mat3x4<f32>, 4> = *(p_a);
+  let l_a_i : mat3x4<f32> = *(p_a_2);
+  let l_a_i_i : vec4<f32> = *(p_a_2_1);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_builtin.wgsl b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_builtin.wgsl
new file mode 100644
index 0000000..e5fd1b6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_builtin.wgsl
@@ -0,0 +1,8 @@
+@group(0) @binding(0) var<uniform> u : array<mat3x4<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    let t = transpose(u[2]);
+    let l = length(u[0][1].ywxz);
+    let a = abs(u[0][1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_builtin.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..e9ab804
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_builtin.wgsl.expected.dxc.hlsl
@@ -0,0 +1,18 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[12];
+};
+
+float3x4 tint_symbol(uint4 buffer[12], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float4x3 t = transpose(tint_symbol(u, 96u));
+  const float l = length(asfloat(u[1]).ywxz);
+  const float a = abs(asfloat(u[1]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_builtin.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..e9ab804
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_builtin.wgsl.expected.fxc.hlsl
@@ -0,0 +1,18 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[12];
+};
+
+float3x4 tint_symbol(uint4 buffer[12], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float4x3 t = transpose(tint_symbol(u, 96u));
+  const float l = length(asfloat(u[1]).ywxz);
+  const float a = abs(asfloat(u[1]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_builtin.wgsl.expected.glsl
new file mode 100644
index 0000000..1281049
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_builtin.wgsl.expected.glsl
@@ -0,0 +1,17 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat3x4 inner[4];
+} u;
+
+void f() {
+  mat4x3 t = transpose(u.inner[2]);
+  float l = length(u.inner[0][1].ywxz);
+  float a = abs(u.inner[0][1].ywxz.x);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_builtin.wgsl.expected.msl
new file mode 100644
index 0000000..e7f5cd5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_builtin.wgsl.expected.msl
@@ -0,0 +1,23 @@
+#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];
+};
+
+kernel void f(const constant tint_array<float3x4, 4>* tint_symbol [[buffer(0)]]) {
+  float4x3 const t = transpose((*(tint_symbol))[2]);
+  float const l = length(float4((*(tint_symbol))[0][1]).ywxz);
+  float const a = fabs(float4((*(tint_symbol))[0][1]).ywxz[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_builtin.wgsl.expected.spvasm
new file mode 100644
index 0000000..a7c1bcd
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_builtin.wgsl.expected.spvasm
@@ -0,0 +1,58 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 36
+; Schema: 0
+               OpCapability Shader
+         %24 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %_arr_mat3v4float_uint_4 ArrayStride 48
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat3v4float = OpTypeMatrix %v4float 3
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat3v4float_uint_4 = OpTypeArray %mat3v4float %uint_4
+    %u_block = OpTypeStruct %_arr_mat3v4float_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+         %10 = OpTypeFunction %void
+    %v3float = OpTypeVector %float 3
+%mat4v3float = OpTypeMatrix %v3float 4
+     %uint_0 = OpConstant %uint 0
+        %int = OpTypeInt 32 1
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_mat3v4float = OpTypePointer Uniform %mat3v4float
+         %25 = OpConstantNull %int
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+          %f = OpFunction %void None %10
+         %13 = OpLabel
+         %21 = OpAccessChain %_ptr_Uniform_mat3v4float %u %uint_0 %int_2
+         %22 = OpLoad %mat3v4float %21
+         %14 = OpTranspose %mat4v3float %22
+         %28 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %25 %int_1
+         %29 = OpLoad %v4float %28
+         %30 = OpVectorShuffle %v4float %29 %29 1 3 0 2
+         %23 = OpExtInst %float %24 Length %30
+         %32 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %25 %int_1
+         %33 = OpLoad %v4float %32
+         %34 = OpVectorShuffle %v4float %33 %33 1 3 0 2
+         %35 = OpCompositeExtract %float %34 0
+         %31 = OpExtInst %float %24 FAbs %35
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_builtin.wgsl.expected.wgsl
new file mode 100644
index 0000000..57abc4a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_builtin.wgsl.expected.wgsl
@@ -0,0 +1,8 @@
+@group(0) @binding(0) var<uniform> u : array<mat3x4<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let t = transpose(u[2]);
+  let l = length(u[0][1].ywxz);
+  let a = abs(u[0][1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_fn.wgsl b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_fn.wgsl
new file mode 100644
index 0000000..cc37dd7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_fn.wgsl
@@ -0,0 +1,14 @@
+@group(0) @binding(0) var<uniform> u : array<mat3x4<f32>, 4>;
+
+fn a(a : array<mat3x4<f32>, 4>) {}
+fn b(m : mat3x4<f32>) {}
+fn c(v : vec4<f32>) {}
+fn d(f : f32) {}
+
+@compute @workgroup_size(1)
+fn f() {
+    a(u);
+    b(u[1]);
+    c(u[1][0].ywxz);
+    d(u[1][0].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_fn.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..a16dec7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_fn.wgsl.expected.dxc.hlsl
@@ -0,0 +1,42 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[12];
+};
+
+void a(float3x4 a_1[4]) {
+}
+
+void b(float3x4 m) {
+}
+
+void c(float4 v) {
+}
+
+void d(float f_1) {
+}
+
+float3x4 tint_symbol_1(uint4 buffer[12], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+}
+
+typedef float3x4 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[12], uint offset) {
+  float3x4 arr[4] = (float3x4[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 48u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 48u));
+  c(asfloat(u[3]).ywxz);
+  d(asfloat(u[3]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_fn.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..a16dec7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_fn.wgsl.expected.fxc.hlsl
@@ -0,0 +1,42 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[12];
+};
+
+void a(float3x4 a_1[4]) {
+}
+
+void b(float3x4 m) {
+}
+
+void c(float4 v) {
+}
+
+void d(float f_1) {
+}
+
+float3x4 tint_symbol_1(uint4 buffer[12], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+}
+
+typedef float3x4 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[12], uint offset) {
+  float3x4 arr[4] = (float3x4[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 48u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 48u));
+  c(asfloat(u[3]).ywxz);
+  d(asfloat(u[3]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_fn.wgsl.expected.glsl
new file mode 100644
index 0000000..866be189
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_fn.wgsl.expected.glsl
@@ -0,0 +1,30 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat3x4 inner[4];
+} u;
+
+void a(mat3x4 a_1[4]) {
+}
+
+void b(mat3x4 m) {
+}
+
+void c(vec4 v) {
+}
+
+void d(float f_1) {
+}
+
+void f() {
+  a(u.inner);
+  b(u.inner[1]);
+  c(u.inner[1][0].ywxz);
+  d(u.inner[1][0].ywxz.x);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_fn.wgsl.expected.msl
new file mode 100644
index 0000000..cc6a3b7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_fn.wgsl.expected.msl
@@ -0,0 +1,36 @@
+#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];
+};
+
+void a(tint_array<float3x4, 4> a_1) {
+}
+
+void b(float3x4 m) {
+}
+
+void c(float4 v) {
+}
+
+void d(float f_1) {
+}
+
+kernel void f(const constant tint_array<float3x4, 4>* tint_symbol [[buffer(0)]]) {
+  a(*(tint_symbol));
+  b((*(tint_symbol))[1]);
+  c(float4((*(tint_symbol))[1][0]).ywxz);
+  d(float4((*(tint_symbol))[1][0]).ywxz[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_fn.wgsl.expected.spvasm
new file mode 100644
index 0000000..807fe1f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_fn.wgsl.expected.spvasm
@@ -0,0 +1,90 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 52
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %a "a"
+               OpName %a_1 "a_1"
+               OpName %b "b"
+               OpName %m "m"
+               OpName %c "c"
+               OpName %v "v"
+               OpName %d "d"
+               OpName %f_1 "f_1"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %_arr_mat3v4float_uint_4 ArrayStride 48
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat3v4float = OpTypeMatrix %v4float 3
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat3v4float_uint_4 = OpTypeArray %mat3v4float %uint_4
+    %u_block = OpTypeStruct %_arr_mat3v4float_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+         %10 = OpTypeFunction %void %_arr_mat3v4float_uint_4
+         %15 = OpTypeFunction %void %mat3v4float
+         %19 = OpTypeFunction %void %v4float
+         %23 = OpTypeFunction %void %float
+         %27 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat3v4float_uint_4 = OpTypePointer Uniform %_arr_mat3v4float_uint_4
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_mat3v4float = OpTypePointer Uniform %mat3v4float
+         %42 = OpConstantNull %int
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+          %a = OpFunction %void None %10
+        %a_1 = OpFunctionParameter %_arr_mat3v4float_uint_4
+         %14 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %b = OpFunction %void None %15
+          %m = OpFunctionParameter %mat3v4float
+         %18 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %c = OpFunction %void None %19
+          %v = OpFunctionParameter %v4float
+         %22 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %d = OpFunction %void None %23
+        %f_1 = OpFunctionParameter %float
+         %26 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %27
+         %29 = OpLabel
+         %33 = OpAccessChain %_ptr_Uniform__arr_mat3v4float_uint_4 %u %uint_0
+         %34 = OpLoad %_arr_mat3v4float_uint_4 %33
+         %30 = OpFunctionCall %void %a %34
+         %39 = OpAccessChain %_ptr_Uniform_mat3v4float %u %uint_0 %int_1
+         %40 = OpLoad %mat3v4float %39
+         %35 = OpFunctionCall %void %b %40
+         %44 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %int_1 %42
+         %45 = OpLoad %v4float %44
+         %46 = OpVectorShuffle %v4float %45 %45 1 3 0 2
+         %41 = OpFunctionCall %void %c %46
+         %48 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %int_1 %42
+         %49 = OpLoad %v4float %48
+         %50 = OpVectorShuffle %v4float %49 %49 1 3 0 2
+         %51 = OpCompositeExtract %float %50 0
+         %47 = OpFunctionCall %void %d %51
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_fn.wgsl.expected.wgsl
new file mode 100644
index 0000000..813ff50
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_fn.wgsl.expected.wgsl
@@ -0,0 +1,21 @@
+@group(0) @binding(0) var<uniform> u : array<mat3x4<f32>, 4>;
+
+fn a(a : array<mat3x4<f32>, 4>) {
+}
+
+fn b(m : mat3x4<f32>) {
+}
+
+fn c(v : vec4<f32>) {
+}
+
+fn d(f : f32) {
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  a(u);
+  b(u[1]);
+  c(u[1][0].ywxz);
+  d(u[1][0].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_private.wgsl b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_private.wgsl
new file mode 100644
index 0000000..db89fff
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_private.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0) var<uniform> u : array<mat3x4<f32>, 4>;
+var<private> p : array<mat3x4<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[2];
+    p[1][0] = u[0][1].ywxz;
+    p[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_private.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..b708074
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_private.wgsl.expected.dxc.hlsl
@@ -0,0 +1,31 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[12];
+};
+static float3x4 p[4] = (float3x4[4])0;
+
+float3x4 tint_symbol_1(uint4 buffer[12], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+}
+
+typedef float3x4 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[12], uint offset) {
+  float3x4 arr[4] = (float3x4[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 48u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 96u);
+  p[1][0] = asfloat(u[1]).ywxz;
+  p[1][0].x = asfloat(u[1].x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_private.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..b708074
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_private.wgsl.expected.fxc.hlsl
@@ -0,0 +1,31 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[12];
+};
+static float3x4 p[4] = (float3x4[4])0;
+
+float3x4 tint_symbol_1(uint4 buffer[12], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+}
+
+typedef float3x4 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[12], uint offset) {
+  float3x4 arr[4] = (float3x4[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 48u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 96u);
+  p[1][0] = asfloat(u[1]).ywxz;
+  p[1][0].x = asfloat(u[1].x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..e4bd6a7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_private.wgsl.expected.glsl
@@ -0,0 +1,19 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat3x4 inner[4];
+} u;
+
+mat3x4 p[4] = mat3x4[4](mat3x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat3x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat3x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat3x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
+void f() {
+  p = u.inner;
+  p[1] = u.inner[2];
+  p[1][0] = u.inner[0][1].ywxz;
+  p[1][0].x = u.inner[0][1].x;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..478a68e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_private.wgsl.expected.msl
@@ -0,0 +1,25 @@
+#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];
+};
+
+kernel void f(const constant tint_array<float3x4, 4>* tint_symbol_1 [[buffer(0)]]) {
+  thread tint_array<float3x4, 4> tint_symbol = {};
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[2];
+  tint_symbol[1][0] = float4((*(tint_symbol_1))[0][1]).ywxz;
+  tint_symbol[1][0][0] = (*(tint_symbol_1))[0][1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_private.wgsl.expected.spvasm
new file mode 100644
index 0000000..edf4aae
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_private.wgsl.expected.spvasm
@@ -0,0 +1,68 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 41
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %p "p"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %_arr_mat3v4float_uint_4 ArrayStride 48
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat3v4float = OpTypeMatrix %v4float 3
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat3v4float_uint_4 = OpTypeArray %mat3v4float %uint_4
+    %u_block = OpTypeStruct %_arr_mat3v4float_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_Private__arr_mat3v4float_uint_4 = OpTypePointer Private %_arr_mat3v4float_uint_4
+         %12 = OpConstantNull %_arr_mat3v4float_uint_4
+          %p = OpVariable %_ptr_Private__arr_mat3v4float_uint_4 Private %12
+       %void = OpTypeVoid
+         %13 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat3v4float_uint_4 = OpTypePointer Uniform %_arr_mat3v4float_uint_4
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Private_mat3v4float = OpTypePointer Private %mat3v4float
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_mat3v4float = OpTypePointer Uniform %mat3v4float
+         %29 = OpConstantNull %int
+%_ptr_Private_v4float = OpTypePointer Private %v4float
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+%_ptr_Private_float = OpTypePointer Private %float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+          %f = OpFunction %void None %13
+         %16 = OpLabel
+         %19 = OpAccessChain %_ptr_Uniform__arr_mat3v4float_uint_4 %u %uint_0
+         %20 = OpLoad %_arr_mat3v4float_uint_4 %19
+               OpStore %p %20
+         %24 = OpAccessChain %_ptr_Private_mat3v4float %p %int_1
+         %27 = OpAccessChain %_ptr_Uniform_mat3v4float %u %uint_0 %int_2
+         %28 = OpLoad %mat3v4float %27
+               OpStore %24 %28
+         %31 = OpAccessChain %_ptr_Private_v4float %p %int_1 %29
+         %33 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %29 %int_1
+         %34 = OpLoad %v4float %33
+         %35 = OpVectorShuffle %v4float %34 %34 1 3 0 2
+               OpStore %31 %35
+         %37 = OpAccessChain %_ptr_Private_float %p %int_1 %29 %uint_0
+         %39 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %29 %int_1 %uint_0
+         %40 = OpLoad %float %39
+               OpStore %37 %40
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..65e268e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_private.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> u : array<mat3x4<f32>, 4>;
+
+var<private> p : array<mat3x4<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[2];
+  p[1][0] = u[0][1].ywxz;
+  p[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_storage.wgsl b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_storage.wgsl
new file mode 100644
index 0000000..908c09b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_storage.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0) var<uniform> u : array<mat3x4<f32>, 4>;
+@group(0) @binding(1) var<storage, read_write> s : array<mat3x4<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[2];
+    s[1][0] = u[0][1].ywxz;
+    s[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_storage.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..b82dc9c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_storage.wgsl.expected.dxc.hlsl
@@ -0,0 +1,46 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[12];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, float3x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+  buffer.Store4((offset + 32u), asuint(value[2u]));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, float3x4 value[4]) {
+  float3x4 array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 48u)), array[i]);
+    }
+  }
+}
+
+float3x4 tint_symbol_4(uint4 buffer[12], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+}
+
+typedef float3x4 tint_symbol_3_ret[4];
+tint_symbol_3_ret tint_symbol_3(uint4 buffer[12], uint offset) {
+  float3x4 arr[4] = (float3x4[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_4(buffer, (offset + (i_1 * 48u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_3(u, 0u));
+  tint_symbol_1(s, 48u, tint_symbol_4(u, 96u));
+  s.Store4(48u, asuint(asfloat(u[1]).ywxz));
+  s.Store(48u, asuint(asfloat(u[1].x)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_storage.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..b82dc9c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_storage.wgsl.expected.fxc.hlsl
@@ -0,0 +1,46 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[12];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, float3x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+  buffer.Store4((offset + 32u), asuint(value[2u]));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, float3x4 value[4]) {
+  float3x4 array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 48u)), array[i]);
+    }
+  }
+}
+
+float3x4 tint_symbol_4(uint4 buffer[12], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+}
+
+typedef float3x4 tint_symbol_3_ret[4];
+tint_symbol_3_ret tint_symbol_3(uint4 buffer[12], uint offset) {
+  float3x4 arr[4] = (float3x4[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_4(buffer, (offset + (i_1 * 48u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_3(u, 0u));
+  tint_symbol_1(s, 48u, tint_symbol_4(u, 96u));
+  s.Store4(48u, asuint(asfloat(u[1]).ywxz));
+  s.Store(48u, asuint(asfloat(u[1].x)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..b366851
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_storage.wgsl.expected.glsl
@@ -0,0 +1,22 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat3x4 inner[4];
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  mat3x4 inner[4];
+} s;
+
+void f() {
+  s.inner = u.inner;
+  s.inner[1] = u.inner[2];
+  s.inner[1][0] = u.inner[0][1].ywxz;
+  s.inner[1][0].x = u.inner[0][1].x;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..d659b7b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_storage.wgsl.expected.msl
@@ -0,0 +1,24 @@
+#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];
+};
+
+kernel void f(device tint_array<float3x4, 4>* tint_symbol [[buffer(1)]], const constant tint_array<float3x4, 4>* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
+  (*(tint_symbol))[1][0] = float4((*(tint_symbol_1))[0][1]).ywxz;
+  (*(tint_symbol))[1][0][0] = (*(tint_symbol_1))[0][1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_storage.wgsl.expected.spvasm
new file mode 100644
index 0000000..ea80ea1
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_storage.wgsl.expected.spvasm
@@ -0,0 +1,71 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 42
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %s "s"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %_arr_mat3v4float_uint_4 ArrayStride 48
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %s DescriptorSet 0
+               OpDecorate %s Binding 1
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat3v4float = OpTypeMatrix %v4float 3
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat3v4float_uint_4 = OpTypeArray %mat3v4float %uint_4
+    %u_block = OpTypeStruct %_arr_mat3v4float_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
+          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+       %void = OpTypeVoid
+         %12 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer__arr_mat3v4float_uint_4 = OpTypePointer StorageBuffer %_arr_mat3v4float_uint_4
+%_ptr_Uniform__arr_mat3v4float_uint_4 = OpTypePointer Uniform %_arr_mat3v4float_uint_4
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_mat3v4float = OpTypePointer StorageBuffer %mat3v4float
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_mat3v4float = OpTypePointer Uniform %mat3v4float
+         %30 = OpConstantNull %int
+%_ptr_StorageBuffer_v4float = OpTypePointer StorageBuffer %v4float
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+          %f = OpFunction %void None %12
+         %15 = OpLabel
+         %18 = OpAccessChain %_ptr_StorageBuffer__arr_mat3v4float_uint_4 %s %uint_0
+         %20 = OpAccessChain %_ptr_Uniform__arr_mat3v4float_uint_4 %u %uint_0
+         %21 = OpLoad %_arr_mat3v4float_uint_4 %20
+               OpStore %18 %21
+         %25 = OpAccessChain %_ptr_StorageBuffer_mat3v4float %s %uint_0 %int_1
+         %28 = OpAccessChain %_ptr_Uniform_mat3v4float %u %uint_0 %int_2
+         %29 = OpLoad %mat3v4float %28
+               OpStore %25 %29
+         %32 = OpAccessChain %_ptr_StorageBuffer_v4float %s %uint_0 %int_1 %30
+         %34 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %30 %int_1
+         %35 = OpLoad %v4float %34
+         %36 = OpVectorShuffle %v4float %35 %35 1 3 0 2
+               OpStore %32 %36
+         %38 = OpAccessChain %_ptr_StorageBuffer_float %s %uint_0 %int_1 %30 %uint_0
+         %40 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %30 %int_1 %uint_0
+         %41 = OpLoad %float %40
+               OpStore %38 %41
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..12a5b2b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> u : array<mat3x4<f32>, 4>;
+
+@group(0) @binding(1) var<storage, read_write> s : array<mat3x4<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[2];
+  s[1][0] = u[0][1].ywxz;
+  s[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_workgroup.wgsl
new file mode 100644
index 0000000..bf1ee70
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_workgroup.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0) var<uniform> u : array<mat3x4<f32>, 4>;
+var<workgroup> w : array<mat3x4<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[2];
+    w[1][0] = u[0][1].ywxz;
+    w[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_workgroup.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..b27032e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_workgroup.wgsl.expected.dxc.hlsl
@@ -0,0 +1,46 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[12];
+};
+groupshared float3x4 w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+float3x4 tint_symbol_3(uint4 buffer[12], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+}
+
+typedef float3x4 tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[12], uint offset) {
+  float3x4 arr[4] = (float3x4[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 48u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      w[i] = float3x4((0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx);
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 96u);
+  w[1][0] = asfloat(u[1]).ywxz;
+  w[1][0].x = asfloat(u[1].x);
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_workgroup.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..b27032e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_workgroup.wgsl.expected.fxc.hlsl
@@ -0,0 +1,46 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[12];
+};
+groupshared float3x4 w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+float3x4 tint_symbol_3(uint4 buffer[12], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+}
+
+typedef float3x4 tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[12], uint offset) {
+  float3x4 arr[4] = (float3x4[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 48u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      w[i] = float3x4((0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx);
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 96u);
+  w[1][0] = asfloat(u[1]).ywxz;
+  w[1][0].x = asfloat(u[1].x);
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..79d7797
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,26 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat3x4 inner[4];
+} u;
+
+shared mat3x4 w[4];
+void f(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      uint i = idx;
+      w[i] = mat3x4(vec4(0.0f), vec4(0.0f), vec4(0.0f));
+    }
+  }
+  barrier();
+  w = u.inner;
+  w[1] = u.inner[2];
+  w[1][0] = u.inner[0][1].ywxz;
+  w[1][0].x = u.inner[0][1].x;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..f955a90
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,38 @@
+#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_symbol_5 {
+  tint_array<float3x4, 4> w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup tint_array<float3x4, 4>* const tint_symbol, const constant tint_array<float3x4, 4>* const tint_symbol_1) {
+  for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+    uint const i = idx;
+    (*(tint_symbol))[i] = float3x4(float4(0.0f), float4(0.0f), float4(0.0f));
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
+  (*(tint_symbol))[1][0] = float4((*(tint_symbol_1))[0][1]).ywxz;
+  (*(tint_symbol))[1][0][0] = (*(tint_symbol_1))[0][1][0];
+}
+
+kernel void f(const constant tint_array<float3x4, 4>* tint_symbol_4 [[buffer(0)]], threadgroup tint_symbol_5* tint_symbol_3 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup tint_array<float3x4, 4>* const tint_symbol_2 = &((*(tint_symbol_3)).w);
+  f_inner(local_invocation_index, tint_symbol_2, tint_symbol_4);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_workgroup.wgsl.expected.spvasm
new file mode 100644
index 0000000..fb19eed
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_workgroup.wgsl.expected.spvasm
@@ -0,0 +1,115 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 70
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %local_invocation_index_1 "local_invocation_index_1"
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %w "w"
+               OpName %f_inner "f_inner"
+               OpName %local_invocation_index "local_invocation_index"
+               OpName %idx "idx"
+               OpName %f "f"
+               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %_arr_mat3v4float_uint_4 ArrayStride 48
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat3v4float = OpTypeMatrix %v4float 3
+     %uint_4 = OpConstant %uint 4
+%_arr_mat3v4float_uint_4 = OpTypeArray %mat3v4float %uint_4
+    %u_block = OpTypeStruct %_arr_mat3v4float_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_Workgroup__arr_mat3v4float_uint_4 = OpTypePointer Workgroup %_arr_mat3v4float_uint_4
+          %w = OpVariable %_ptr_Workgroup__arr_mat3v4float_uint_4 Workgroup
+       %void = OpTypeVoid
+         %14 = OpTypeFunction %void %uint
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %21 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Workgroup_mat3v4float = OpTypePointer Workgroup %mat3v4float
+         %35 = OpConstantNull %mat3v4float
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+   %uint_264 = OpConstant %uint 264
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat3v4float_uint_4 = OpTypePointer Uniform %_arr_mat3v4float_uint_4
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_mat3v4float = OpTypePointer Uniform %mat3v4float
+         %53 = OpConstantNull %int
+%_ptr_Workgroup_v4float = OpTypePointer Workgroup %v4float
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+%_ptr_Workgroup_float = OpTypePointer Workgroup %float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+         %65 = OpTypeFunction %void
+    %f_inner = OpFunction %void None %14
+%local_invocation_index = OpFunctionParameter %uint
+         %18 = OpLabel
+        %idx = OpVariable %_ptr_Function_uint Function %21
+               OpStore %idx %local_invocation_index
+               OpBranch %22
+         %22 = OpLabel
+               OpLoopMerge %23 %24 None
+               OpBranch %25
+         %25 = OpLabel
+         %27 = OpLoad %uint %idx
+         %28 = OpULessThan %bool %27 %uint_4
+         %26 = OpLogicalNot %bool %28
+               OpSelectionMerge %30 None
+               OpBranchConditional %26 %31 %30
+         %31 = OpLabel
+               OpBranch %23
+         %30 = OpLabel
+         %32 = OpLoad %uint %idx
+         %34 = OpAccessChain %_ptr_Workgroup_mat3v4float %w %32
+               OpStore %34 %35
+               OpBranch %24
+         %24 = OpLabel
+         %36 = OpLoad %uint %idx
+         %38 = OpIAdd %uint %36 %uint_1
+               OpStore %idx %38
+               OpBranch %22
+         %23 = OpLabel
+               OpControlBarrier %uint_2 %uint_2 %uint_264
+         %44 = OpAccessChain %_ptr_Uniform__arr_mat3v4float_uint_4 %u %uint_0
+         %45 = OpLoad %_arr_mat3v4float_uint_4 %44
+               OpStore %w %45
+         %48 = OpAccessChain %_ptr_Workgroup_mat3v4float %w %int_1
+         %51 = OpAccessChain %_ptr_Uniform_mat3v4float %u %uint_0 %int_2
+         %52 = OpLoad %mat3v4float %51
+               OpStore %48 %52
+         %55 = OpAccessChain %_ptr_Workgroup_v4float %w %int_1 %53
+         %57 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %53 %int_1
+         %58 = OpLoad %v4float %57
+         %59 = OpVectorShuffle %v4float %58 %58 1 3 0 2
+               OpStore %55 %59
+         %61 = OpAccessChain %_ptr_Workgroup_float %w %int_1 %53 %uint_0
+         %63 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %53 %int_1 %uint_0
+         %64 = OpLoad %float %63
+               OpStore %61 %64
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %65
+         %67 = OpLabel
+         %69 = OpLoad %uint %local_invocation_index_1
+         %68 = OpFunctionCall %void %f_inner %69
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..da91f6b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat3x4_f32/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> u : array<mat3x4<f32>, 4>;
+
+var<workgroup> w : array<mat3x4<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[2];
+  w[1][0] = u[0][1].ywxz;
+  w[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/to_private.wgsl b/test/tint/buffer/uniform/std140/array/mat4x2/to_private.wgsl
deleted file mode 100644
index 618416a..0000000
--- a/test/tint/buffer/uniform/std140/array/mat4x2/to_private.wgsl
+++ /dev/null
@@ -1,16 +0,0 @@
-struct S {
-  before : i32,
-  m : mat4x2<f32>,
-  after : i32,
-}
-
-@group(0) @binding(0) var<uniform> u : array<mat4x2<f32>, 4>;
-var<private> p : array<mat4x2<f32>, 4>;
-
-@compute @workgroup_size(1)
-fn f() {
-    p = u;
-    p[1] = u[2];
-    p[1][0] = u[0][1].yx;
-    p[1][0].x = u[0][1].x;
-}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x2/to_private.wgsl.expected.glsl
deleted file mode 100644
index 01b3ece..0000000
--- a/test/tint/buffer/uniform/std140/array/mat4x2/to_private.wgsl.expected.glsl
+++ /dev/null
@@ -1,46 +0,0 @@
-#version 310 es
-
-struct mat4x2_f32 {
-  vec2 col0;
-  vec2 col1;
-  vec2 col2;
-  vec2 col3;
-};
-
-struct S {
-  int before;
-  mat4x2 m;
-  int after;
-};
-
-layout(binding = 0, std140) uniform u_block_std140_ubo {
-  mat4x2_f32 inner[4];
-} u;
-
-mat4x2 p[4] = mat4x2[4](mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
-mat4x2 conv_mat4x2_f32(mat4x2_f32 val) {
-  return mat4x2(val.col0, val.col1, val.col2, val.col3);
-}
-
-mat4x2[4] conv_arr4_mat4x2_f32(mat4x2_f32 val[4]) {
-  mat4x2 arr[4] = mat4x2[4](mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      arr[i] = conv_mat4x2_f32(val[i]);
-    }
-  }
-  return arr;
-}
-
-void f() {
-  p = conv_arr4_mat4x2_f32(u.inner);
-  p[1] = conv_mat4x2_f32(u.inner[2u]);
-  p[1][0] = u.inner[0u].col1.yx;
-  p[1][0].x = u.inner[0u].col1[0u];
-}
-
-layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
-void main() {
-  f();
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat4x2/to_private.wgsl.expected.msl
deleted file mode 100644
index cd97f91..0000000
--- a/test/tint/buffer/uniform/std140/array/mat4x2/to_private.wgsl.expected.msl
+++ /dev/null
@@ -1,31 +0,0 @@
-#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 S {
-  int before;
-  float4x2 m;
-  int after;
-};
-
-kernel void f(const constant tint_array<float4x2, 4>* tint_symbol_1 [[buffer(0)]]) {
-  thread tint_array<float4x2, 4> tint_symbol = {};
-  tint_symbol = *(tint_symbol_1);
-  tint_symbol[1] = (*(tint_symbol_1))[2];
-  tint_symbol[1][0] = float2((*(tint_symbol_1))[0][1]).yx;
-  tint_symbol[1][0][0] = (*(tint_symbol_1))[0][1][0];
-  return;
-}
-
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat4x2/to_private.wgsl.expected.wgsl
deleted file mode 100644
index 04780dc..0000000
--- a/test/tint/buffer/uniform/std140/array/mat4x2/to_private.wgsl.expected.wgsl
+++ /dev/null
@@ -1,17 +0,0 @@
-struct S {
-  before : i32,
-  m : mat4x2<f32>,
-  after : i32,
-}
-
-@group(0) @binding(0) var<uniform> u : array<mat4x2<f32>, 4>;
-
-var<private> p : array<mat4x2<f32>, 4>;
-
-@compute @workgroup_size(1)
-fn f() {
-  p = u;
-  p[1] = u[2];
-  p[1][0] = u[0][1].yx;
-  p[1][0].x = u[0][1].x;
-}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/to_storage.wgsl b/test/tint/buffer/uniform/std140/array/mat4x2/to_storage.wgsl
deleted file mode 100644
index fcea4e7..0000000
--- a/test/tint/buffer/uniform/std140/array/mat4x2/to_storage.wgsl
+++ /dev/null
@@ -1,16 +0,0 @@
-struct S {
-  before : i32,
-  m : mat4x2<f32>,
-  after : i32,
-}
-
-@group(0) @binding(0) var<uniform> u : array<mat4x2<f32>, 4>;
-@group(0) @binding(1) var<storage, read_write> s : array<mat4x2<f32>, 4>;
-
-@compute @workgroup_size(1)
-fn f() {
-    s = u;
-    s[1] = u[2];
-    s[1][0] = u[0][1].yx;
-    s[1][0].x = u[0][1].x;
-}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x2/to_storage.wgsl.expected.glsl
deleted file mode 100644
index b7e9977..0000000
--- a/test/tint/buffer/uniform/std140/array/mat4x2/to_storage.wgsl.expected.glsl
+++ /dev/null
@@ -1,49 +0,0 @@
-#version 310 es
-
-struct mat4x2_f32 {
-  vec2 col0;
-  vec2 col1;
-  vec2 col2;
-  vec2 col3;
-};
-
-struct S {
-  int before;
-  mat4x2 m;
-  int after;
-};
-
-layout(binding = 0, std140) uniform u_block_std140_ubo {
-  mat4x2_f32 inner[4];
-} u;
-
-layout(binding = 1, std430) buffer u_block_ssbo {
-  mat4x2 inner[4];
-} s;
-
-mat4x2 conv_mat4x2_f32(mat4x2_f32 val) {
-  return mat4x2(val.col0, val.col1, val.col2, val.col3);
-}
-
-mat4x2[4] conv_arr4_mat4x2_f32(mat4x2_f32 val[4]) {
-  mat4x2 arr[4] = mat4x2[4](mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      arr[i] = conv_mat4x2_f32(val[i]);
-    }
-  }
-  return arr;
-}
-
-void f() {
-  s.inner = conv_arr4_mat4x2_f32(u.inner);
-  s.inner[1] = conv_mat4x2_f32(u.inner[2u]);
-  s.inner[1][0] = u.inner[0u].col1.yx;
-  s.inner[1][0].x = u.inner[0u].col1[0u];
-}
-
-layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
-void main() {
-  f();
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat4x2/to_storage.wgsl.expected.msl
deleted file mode 100644
index abded74..0000000
--- a/test/tint/buffer/uniform/std140/array/mat4x2/to_storage.wgsl.expected.msl
+++ /dev/null
@@ -1,30 +0,0 @@
-#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 S {
-  int before;
-  float4x2 m;
-  int after;
-};
-
-kernel void f(device tint_array<float4x2, 4>* tint_symbol [[buffer(1)]], const constant tint_array<float4x2, 4>* tint_symbol_1 [[buffer(0)]]) {
-  *(tint_symbol) = *(tint_symbol_1);
-  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
-  (*(tint_symbol))[1][0] = float2((*(tint_symbol_1))[0][1]).yx;
-  (*(tint_symbol))[1][0][0] = (*(tint_symbol_1))[0][1][0];
-  return;
-}
-
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat4x2/to_storage.wgsl.expected.wgsl
deleted file mode 100644
index d32f228..0000000
--- a/test/tint/buffer/uniform/std140/array/mat4x2/to_storage.wgsl.expected.wgsl
+++ /dev/null
@@ -1,17 +0,0 @@
-struct S {
-  before : i32,
-  m : mat4x2<f32>,
-  after : i32,
-}
-
-@group(0) @binding(0) var<uniform> u : array<mat4x2<f32>, 4>;
-
-@group(0) @binding(1) var<storage, read_write> s : array<mat4x2<f32>, 4>;
-
-@compute @workgroup_size(1)
-fn f() {
-  s = u;
-  s[1] = u[2];
-  s[1][0] = u[0][1].yx;
-  s[1][0].x = u[0][1].x;
-}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/array/mat4x2/to_workgroup.wgsl
deleted file mode 100644
index b1368c8..0000000
--- a/test/tint/buffer/uniform/std140/array/mat4x2/to_workgroup.wgsl
+++ /dev/null
@@ -1,16 +0,0 @@
-struct S {
-  before : i32,
-  m : mat4x2<f32>,
-  after : i32,
-}
-
-@group(0) @binding(0) var<uniform> u : array<mat4x2<f32>, 4>;
-var<workgroup> w : array<mat4x2<f32>, 4>;
-
-@compute @workgroup_size(1)
-fn f() {
-    w = u;
-    w[1] = u[2];
-    w[1][0] = u[0][1].yx;
-    w[1][0].x = u[0][1].x;
-}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x2/to_workgroup.wgsl.expected.glsl
deleted file mode 100644
index df52a3b..0000000
--- a/test/tint/buffer/uniform/std140/array/mat4x2/to_workgroup.wgsl.expected.glsl
+++ /dev/null
@@ -1,53 +0,0 @@
-#version 310 es
-
-struct mat4x2_f32 {
-  vec2 col0;
-  vec2 col1;
-  vec2 col2;
-  vec2 col3;
-};
-
-struct S {
-  int before;
-  mat4x2 m;
-  int after;
-};
-
-layout(binding = 0, std140) uniform u_block_std140_ubo {
-  mat4x2_f32 inner[4];
-} u;
-
-shared mat4x2 w[4];
-mat4x2 conv_mat4x2_f32(mat4x2_f32 val) {
-  return mat4x2(val.col0, val.col1, val.col2, val.col3);
-}
-
-mat4x2[4] conv_arr4_mat4x2_f32(mat4x2_f32 val[4]) {
-  mat4x2 arr[4] = mat4x2[4](mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      arr[i] = conv_mat4x2_f32(val[i]);
-    }
-  }
-  return arr;
-}
-
-void f(uint local_invocation_index) {
-  {
-    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
-      uint i = idx;
-      w[i] = mat4x2(vec2(0.0f), vec2(0.0f), vec2(0.0f), vec2(0.0f));
-    }
-  }
-  barrier();
-  w = conv_arr4_mat4x2_f32(u.inner);
-  w[1] = conv_mat4x2_f32(u.inner[2u]);
-  w[1][0] = u.inner[0u].col1.yx;
-  w[1][0].x = u.inner[0u].col1[0u];
-}
-
-layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
-void main() {
-  f(gl_LocalInvocationIndex);
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat4x2/to_workgroup.wgsl.expected.msl
deleted file mode 100644
index e4001f3..0000000
--- a/test/tint/buffer/uniform/std140/array/mat4x2/to_workgroup.wgsl.expected.msl
+++ /dev/null
@@ -1,44 +0,0 @@
-#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_symbol_5 {
-  tint_array<float4x2, 4> w;
-};
-
-struct S {
-  int before;
-  float4x2 m;
-  int after;
-};
-
-void f_inner(uint local_invocation_index, threadgroup tint_array<float4x2, 4>* const tint_symbol, const constant tint_array<float4x2, 4>* const tint_symbol_1) {
-  for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
-    uint const i = idx;
-    (*(tint_symbol))[i] = float4x2(float2(0.0f), float2(0.0f), float2(0.0f), float2(0.0f));
-  }
-  threadgroup_barrier(mem_flags::mem_threadgroup);
-  *(tint_symbol) = *(tint_symbol_1);
-  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
-  (*(tint_symbol))[1][0] = float2((*(tint_symbol_1))[0][1]).yx;
-  (*(tint_symbol))[1][0][0] = (*(tint_symbol_1))[0][1][0];
-}
-
-kernel void f(const constant tint_array<float4x2, 4>* tint_symbol_4 [[buffer(0)]], threadgroup tint_symbol_5* tint_symbol_3 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
-  threadgroup tint_array<float4x2, 4>* const tint_symbol_2 = &((*(tint_symbol_3)).w);
-  f_inner(local_invocation_index, tint_symbol_2, tint_symbol_4);
-  return;
-}
-
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat4x2/to_workgroup.wgsl.expected.wgsl
deleted file mode 100644
index 9948855..0000000
--- a/test/tint/buffer/uniform/std140/array/mat4x2/to_workgroup.wgsl.expected.wgsl
+++ /dev/null
@@ -1,17 +0,0 @@
-struct S {
-  before : i32,
-  m : mat4x2<f32>,
-  after : i32,
-}
-
-@group(0) @binding(0) var<uniform> u : array<mat4x2<f32>, 4>;
-
-var<workgroup> w : array<mat4x2<f32>, 4>;
-
-@compute @workgroup_size(1)
-fn f() {
-  w = u;
-  w[1] = u[2];
-  w[1][0] = u[0][1].yx;
-  w[1][0].x = u[0][1].x;
-}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/array/mat4x2_f16/dynamic_index_via_ptr.wgsl
new file mode 100644
index 0000000..54a275a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/dynamic_index_via_ptr.wgsl
@@ -0,0 +1,17 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> a : array<mat4x2<f16>, 4>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a       = &a;
+  let p_a_i     = &((*p_a)[i()]);
+  let p_a_i_i   = &((*p_a_i)[i()]);
+
+  let l_a       : array<mat4x2<f16>, 4> = *p_a;
+  let l_a_i     : mat4x2<f16>           = *p_a_i;
+  let l_a_i_i   : vec2<f16>             = *p_a_i_i;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..c5d26b1
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,44 @@
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[4];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 4, 2> tint_symbol_1(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const uint scalar_offset_3 = ((offset + 12u)) / 4;
+  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+}
+
+typedef matrix<float16_t, 4, 2> tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[4], uint offset) {
+  matrix<float16_t, 4, 2> arr[4] = (matrix<float16_t, 4, 2>[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 16u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_i_save = i();
+  const matrix<float16_t, 4, 2> l_a[4] = tint_symbol(a, 0u);
+  const matrix<float16_t, 4, 2> l_a_i = tint_symbol_1(a, (16u * uint(p_a_i_save)));
+  const uint scalar_offset_4 = (((16u * uint(p_a_i_save)) + (4u * uint(p_a_i_i_save)))) / 4;
+  uint ubo_load_4 = a[scalar_offset_4 / 4][scalar_offset_4 % 4];
+  const vector<float16_t, 2> l_a_i_i = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..101f0c8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,49 @@
+SKIP: FAILED
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[4];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 4, 2> tint_symbol_1(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const uint scalar_offset_3 = ((offset + 12u)) / 4;
+  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+}
+
+typedef matrix<float16_t, 4, 2> tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[4], uint offset) {
+  matrix<float16_t, 4, 2> arr[4] = (matrix<float16_t, 4, 2>[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 16u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_i_save = i();
+  const matrix<float16_t, 4, 2> l_a[4] = tint_symbol(a, 0u);
+  const matrix<float16_t, 4, 2> l_a_i = tint_symbol_1(a, (16u * uint(p_a_i_save)));
+  const uint scalar_offset_4 = (((16u * uint(p_a_i_save)) + (4u * uint(p_a_i_i_save)))) / 4;
+  uint ubo_load_4 = a[scalar_offset_4 / 4][scalar_offset_4 % 4];
+  const vector<float16_t, 2> l_a_i_i = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16)));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x00000252EDBAA7F0(11,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..fdbb9a7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,75 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct mat4x2_f16 {
+  f16vec2 col0;
+  f16vec2 col1;
+  f16vec2 col2;
+  f16vec2 col3;
+};
+
+layout(binding = 0, std140) uniform a_block_std140_ubo {
+  mat4x2_f16 inner[4];
+} a;
+
+int counter = 0;
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+f16mat4x2 conv_mat4x2_f16(mat4x2_f16 val) {
+  return f16mat4x2(val.col0, val.col1, val.col2, val.col3);
+}
+
+f16mat4x2[4] conv_arr4_mat4x2_f16(mat4x2_f16 val[4]) {
+  f16mat4x2 arr[4] = f16mat4x2[4](f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat4x2_f16(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16vec2 load_a_inner_p0_p1(uint p0, uint p1) {
+  switch(p1) {
+    case 0u: {
+      return a.inner[p0].col0;
+      break;
+    }
+    case 1u: {
+      return a.inner[p0].col1;
+      break;
+    }
+    case 2u: {
+      return a.inner[p0].col2;
+      break;
+    }
+    case 3u: {
+      return a.inner[p0].col3;
+      break;
+    }
+    default: {
+      return f16vec2(0.0hf);
+      break;
+    }
+  }
+}
+
+void f() {
+  f16mat4x2 p_a[4] = conv_arr4_mat4x2_f16(a.inner);
+  int tint_symbol = i();
+  f16mat4x2 p_a_i = conv_mat4x2_f16(a.inner[tint_symbol]);
+  int tint_symbol_1 = i();
+  f16vec2 p_a_i_i = load_a_inner_p0_p1(uint(tint_symbol), uint(tint_symbol_1));
+  f16mat4x2 l_a[4] = conv_arr4_mat4x2_f16(a.inner);
+  f16mat4x2 l_a_i = conv_mat4x2_f16(a.inner[tint_symbol]);
+  f16vec2 l_a_i_i = load_a_inner_p0_p1(uint(tint_symbol), uint(tint_symbol_1));
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..f850ce9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,33 @@
+#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];
+};
+
+int i() {
+  thread int tint_symbol_2 = 0;
+  tint_symbol_2 = as_type<int>((as_type<uint>(tint_symbol_2) + as_type<uint>(1)));
+  return tint_symbol_2;
+}
+
+kernel void f(const constant tint_array<half4x2, 4>* tint_symbol_3 [[buffer(0)]]) {
+  int const tint_symbol = i();
+  int const p_a_i_save = tint_symbol;
+  int const tint_symbol_1 = i();
+  int const p_a_i_i_save = tint_symbol_1;
+  tint_array<half4x2, 4> const l_a = *(tint_symbol_3);
+  half4x2 const l_a_i = (*(tint_symbol_3))[p_a_i_save];
+  half2 const l_a_i_i = (*(tint_symbol_3))[p_a_i_save][p_a_i_i_save];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..a141530
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,181 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 108
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block_std140 "a_block_std140"
+               OpMemberName %a_block_std140 0 "inner"
+               OpName %mat4x2_f16 "mat4x2_f16"
+               OpMemberName %mat4x2_f16 0 "col0"
+               OpMemberName %mat4x2_f16 1 "col1"
+               OpMemberName %mat4x2_f16 2 "col2"
+               OpMemberName %mat4x2_f16 3 "col3"
+               OpName %a "a"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %conv_mat4x2_f16 "conv_mat4x2_f16"
+               OpName %val "val"
+               OpName %conv_arr4_mat4x2_f16 "conv_arr4_mat4x2_f16"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i_0 "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_a_inner_p0_p1 "load_a_inner_p0_p1"
+               OpName %p0 "p0"
+               OpName %p1 "p1"
+               OpName %f "f"
+               OpDecorate %a_block_std140 Block
+               OpMemberDecorate %a_block_std140 0 Offset 0
+               OpMemberDecorate %mat4x2_f16 0 Offset 0
+               OpMemberDecorate %mat4x2_f16 1 Offset 4
+               OpMemberDecorate %mat4x2_f16 2 Offset 8
+               OpMemberDecorate %mat4x2_f16 3 Offset 12
+               OpDecorate %_arr_mat4x2_f16_uint_4 ArrayStride 16
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+               OpDecorate %_arr_mat4v2half_uint_4 ArrayStride 16
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+ %mat4x2_f16 = OpTypeStruct %v2half %v2half %v2half %v2half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat4x2_f16_uint_4 = OpTypeArray %mat4x2_f16 %uint_4
+%a_block_std140 = OpTypeStruct %_arr_mat4x2_f16_uint_4
+%_ptr_Uniform_a_block_std140 = OpTypePointer Uniform %a_block_std140
+          %a = OpVariable %_ptr_Uniform_a_block_std140 Uniform
+        %int = OpTypeInt 32 1
+         %11 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %11
+         %14 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+ %mat4v2half = OpTypeMatrix %v2half 4
+         %21 = OpTypeFunction %mat4v2half %mat4x2_f16
+%_arr_mat4v2half_uint_4 = OpTypeArray %mat4v2half %uint_4
+         %31 = OpTypeFunction %_arr_mat4v2half_uint_4 %_arr_mat4x2_f16_uint_4
+%_ptr_Function__arr_mat4v2half_uint_4 = OpTypePointer Function %_arr_mat4v2half_uint_4
+         %38 = OpConstantNull %_arr_mat4v2half_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %41 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_mat4x2_f16_uint_4 = OpTypePointer Function %_arr_mat4x2_f16_uint_4
+         %54 = OpConstantNull %_arr_mat4x2_f16_uint_4
+%_ptr_Function_mat4v2half = OpTypePointer Function %mat4v2half
+%_ptr_Function_mat4x2_f16 = OpTypePointer Function %mat4x2_f16
+     %uint_1 = OpConstant %uint 1
+         %67 = OpTypeFunction %v2half %uint %uint
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+         %90 = OpConstantNull %v2half
+       %void = OpTypeVoid
+         %91 = OpTypeFunction %void
+%_ptr_Uniform__arr_mat4x2_f16_uint_4 = OpTypePointer Uniform %_arr_mat4x2_f16_uint_4
+%_ptr_Uniform_mat4x2_f16 = OpTypePointer Uniform %mat4x2_f16
+          %i = OpFunction %int None %14
+         %16 = OpLabel
+         %17 = OpLoad %int %counter
+         %19 = OpIAdd %int %17 %int_1
+               OpStore %counter %19
+         %20 = OpLoad %int %counter
+               OpReturnValue %20
+               OpFunctionEnd
+%conv_mat4x2_f16 = OpFunction %mat4v2half None %21
+        %val = OpFunctionParameter %mat4x2_f16
+         %25 = OpLabel
+         %26 = OpCompositeExtract %v2half %val 0
+         %27 = OpCompositeExtract %v2half %val 1
+         %28 = OpCompositeExtract %v2half %val 2
+         %29 = OpCompositeExtract %v2half %val 3
+         %30 = OpCompositeConstruct %mat4v2half %26 %27 %28 %29
+               OpReturnValue %30
+               OpFunctionEnd
+%conv_arr4_mat4x2_f16 = OpFunction %_arr_mat4v2half_uint_4 None %31
+      %val_0 = OpFunctionParameter %_arr_mat4x2_f16_uint_4
+         %35 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_mat4v2half_uint_4 Function %38
+        %i_0 = OpVariable %_ptr_Function_uint Function %41
+%var_for_index = OpVariable %_ptr_Function__arr_mat4x2_f16_uint_4 Function %54
+               OpBranch %42
+         %42 = OpLabel
+               OpLoopMerge %43 %44 None
+               OpBranch %45
+         %45 = OpLabel
+         %47 = OpLoad %uint %i_0
+         %48 = OpULessThan %bool %47 %uint_4
+         %46 = OpLogicalNot %bool %48
+               OpSelectionMerge %50 None
+               OpBranchConditional %46 %51 %50
+         %51 = OpLabel
+               OpBranch %43
+         %50 = OpLabel
+               OpStore %var_for_index %val_0
+         %55 = OpLoad %uint %i_0
+         %57 = OpAccessChain %_ptr_Function_mat4v2half %arr %55
+         %59 = OpLoad %uint %i_0
+         %61 = OpAccessChain %_ptr_Function_mat4x2_f16 %var_for_index %59
+         %62 = OpLoad %mat4x2_f16 %61
+         %58 = OpFunctionCall %mat4v2half %conv_mat4x2_f16 %62
+               OpStore %57 %58
+               OpBranch %44
+         %44 = OpLabel
+         %63 = OpLoad %uint %i_0
+         %65 = OpIAdd %uint %63 %uint_1
+               OpStore %i_0 %65
+               OpBranch %42
+         %43 = OpLabel
+         %66 = OpLoad %_arr_mat4v2half_uint_4 %arr
+               OpReturnValue %66
+               OpFunctionEnd
+%load_a_inner_p0_p1 = OpFunction %v2half None %67
+         %p0 = OpFunctionParameter %uint
+         %p1 = OpFunctionParameter %uint
+         %71 = OpLabel
+               OpSelectionMerge %72 None
+               OpSwitch %p1 %73 0 %74 1 %75 2 %76 3 %77
+         %74 = OpLabel
+         %80 = OpAccessChain %_ptr_Uniform_v2half %a %uint_0 %p0 %uint_0
+         %81 = OpLoad %v2half %80
+               OpReturnValue %81
+         %75 = OpLabel
+         %82 = OpAccessChain %_ptr_Uniform_v2half %a %uint_0 %p0 %uint_1
+         %83 = OpLoad %v2half %82
+               OpReturnValue %83
+         %76 = OpLabel
+         %85 = OpAccessChain %_ptr_Uniform_v2half %a %uint_0 %p0 %uint_2
+         %86 = OpLoad %v2half %85
+               OpReturnValue %86
+         %77 = OpLabel
+         %88 = OpAccessChain %_ptr_Uniform_v2half %a %uint_0 %p0 %uint_3
+         %89 = OpLoad %v2half %88
+               OpReturnValue %89
+         %73 = OpLabel
+               OpReturnValue %90
+         %72 = OpLabel
+               OpReturnValue %90
+               OpFunctionEnd
+          %f = OpFunction %void None %91
+         %94 = OpLabel
+         %95 = OpFunctionCall %int %i
+         %96 = OpFunctionCall %int %i
+         %99 = OpAccessChain %_ptr_Uniform__arr_mat4x2_f16_uint_4 %a %uint_0
+        %100 = OpLoad %_arr_mat4x2_f16_uint_4 %99
+         %97 = OpFunctionCall %_arr_mat4v2half_uint_4 %conv_arr4_mat4x2_f16 %100
+        %103 = OpAccessChain %_ptr_Uniform_mat4x2_f16 %a %uint_0 %95
+        %104 = OpLoad %mat4x2_f16 %103
+        %101 = OpFunctionCall %mat4v2half %conv_mat4x2_f16 %104
+        %106 = OpBitcast %uint %95
+        %107 = OpBitcast %uint %96
+        %105 = OpFunctionCall %v2half %load_a_inner_p0_p1 %106 %107
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..d888ce9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,20 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> a : array<mat4x2<f16>, 4>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_i = &((*(p_a))[i()]);
+  let p_a_i_i = &((*(p_a_i))[i()]);
+  let l_a : array<mat4x2<f16>, 4> = *(p_a);
+  let l_a_i : mat4x2<f16> = *(p_a_i);
+  let l_a_i_i : vec2<f16> = *(p_a_i_i);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/array/mat4x2_f16/static_index_via_ptr.wgsl
new file mode 100644
index 0000000..c4faaa8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/static_index_via_ptr.wgsl
@@ -0,0 +1,14 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> a : array<mat4x2<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a       = &a;
+  let p_a_2     = &((*p_a)[2]);
+  let p_a_2_1   = &((*p_a_2)[1]);
+
+  let l_a       : array<mat4x2<f16>, 4> = *p_a;
+  let l_a_i     : mat4x2<f16>           = *p_a_2;
+  let l_a_i_i   : vec2<f16>             = *p_a_2_1;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x2_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..0ffe38c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,35 @@
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[4];
+};
+
+matrix<float16_t, 4, 2> tint_symbol_1(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const uint scalar_offset_3 = ((offset + 12u)) / 4;
+  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+}
+
+typedef matrix<float16_t, 4, 2> tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[4], uint offset) {
+  matrix<float16_t, 4, 2> arr[4] = (matrix<float16_t, 4, 2>[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 16u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 4, 2> l_a[4] = tint_symbol(a, 0u);
+  const matrix<float16_t, 4, 2> l_a_i = tint_symbol_1(a, 32u);
+  uint ubo_load_4 = a[2].y;
+  const vector<float16_t, 2> l_a_i_i = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x2_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..1a318b5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,40 @@
+SKIP: FAILED
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[4];
+};
+
+matrix<float16_t, 4, 2> tint_symbol_1(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const uint scalar_offset_3 = ((offset + 12u)) / 4;
+  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+}
+
+typedef matrix<float16_t, 4, 2> tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[4], uint offset) {
+  matrix<float16_t, 4, 2> arr[4] = (matrix<float16_t, 4, 2>[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 16u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 4, 2> l_a[4] = tint_symbol(a, 0u);
+  const matrix<float16_t, 4, 2> l_a_i = tint_symbol_1(a, 32u);
+  uint ubo_load_4 = a[2].y;
+  const vector<float16_t, 2> l_a_i_i = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16)));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000014EAAC1C520(5,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x2_f16/static_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..1f206c5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/static_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,42 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct mat4x2_f16 {
+  f16vec2 col0;
+  f16vec2 col1;
+  f16vec2 col2;
+  f16vec2 col3;
+};
+
+layout(binding = 0, std140) uniform a_block_std140_ubo {
+  mat4x2_f16 inner[4];
+} a;
+
+f16mat4x2 conv_mat4x2_f16(mat4x2_f16 val) {
+  return f16mat4x2(val.col0, val.col1, val.col2, val.col3);
+}
+
+f16mat4x2[4] conv_arr4_mat4x2_f16(mat4x2_f16 val[4]) {
+  f16mat4x2 arr[4] = f16mat4x2[4](f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat4x2_f16(val[i]);
+    }
+  }
+  return arr;
+}
+
+void f() {
+  f16mat4x2 p_a[4] = conv_arr4_mat4x2_f16(a.inner);
+  f16mat4x2 p_a_2 = conv_mat4x2_f16(a.inner[2u]);
+  f16vec2 p_a_2_1 = a.inner[2u].col1;
+  f16mat4x2 l_a[4] = conv_arr4_mat4x2_f16(a.inner);
+  f16mat4x2 l_a_i = conv_mat4x2_f16(a.inner[2u]);
+  f16vec2 l_a_i_i = a.inner[2u].col1;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat4x2_f16/static_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..b804719
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/static_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,23 @@
+#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];
+};
+
+kernel void f(const constant tint_array<half4x2, 4>* tint_symbol [[buffer(0)]]) {
+  tint_array<half4x2, 4> const l_a = *(tint_symbol);
+  half4x2 const l_a_i = (*(tint_symbol))[2];
+  half2 const l_a_i_i = (*(tint_symbol))[2][1];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x2_f16/static_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..03a69bc
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/static_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,129 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 73
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block_std140 "a_block_std140"
+               OpMemberName %a_block_std140 0 "inner"
+               OpName %mat4x2_f16 "mat4x2_f16"
+               OpMemberName %mat4x2_f16 0 "col0"
+               OpMemberName %mat4x2_f16 1 "col1"
+               OpMemberName %mat4x2_f16 2 "col2"
+               OpMemberName %mat4x2_f16 3 "col3"
+               OpName %a "a"
+               OpName %conv_mat4x2_f16 "conv_mat4x2_f16"
+               OpName %val "val"
+               OpName %conv_arr4_mat4x2_f16 "conv_arr4_mat4x2_f16"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %f "f"
+               OpDecorate %a_block_std140 Block
+               OpMemberDecorate %a_block_std140 0 Offset 0
+               OpMemberDecorate %mat4x2_f16 0 Offset 0
+               OpMemberDecorate %mat4x2_f16 1 Offset 4
+               OpMemberDecorate %mat4x2_f16 2 Offset 8
+               OpMemberDecorate %mat4x2_f16 3 Offset 12
+               OpDecorate %_arr_mat4x2_f16_uint_4 ArrayStride 16
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+               OpDecorate %_arr_mat4v2half_uint_4 ArrayStride 16
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+ %mat4x2_f16 = OpTypeStruct %v2half %v2half %v2half %v2half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat4x2_f16_uint_4 = OpTypeArray %mat4x2_f16 %uint_4
+%a_block_std140 = OpTypeStruct %_arr_mat4x2_f16_uint_4
+%_ptr_Uniform_a_block_std140 = OpTypePointer Uniform %a_block_std140
+          %a = OpVariable %_ptr_Uniform_a_block_std140 Uniform
+ %mat4v2half = OpTypeMatrix %v2half 4
+         %10 = OpTypeFunction %mat4v2half %mat4x2_f16
+%_arr_mat4v2half_uint_4 = OpTypeArray %mat4v2half %uint_4
+         %20 = OpTypeFunction %_arr_mat4v2half_uint_4 %_arr_mat4x2_f16_uint_4
+%_ptr_Function__arr_mat4v2half_uint_4 = OpTypePointer Function %_arr_mat4v2half_uint_4
+         %27 = OpConstantNull %_arr_mat4v2half_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %30 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_mat4x2_f16_uint_4 = OpTypePointer Function %_arr_mat4x2_f16_uint_4
+         %43 = OpConstantNull %_arr_mat4x2_f16_uint_4
+%_ptr_Function_mat4v2half = OpTypePointer Function %mat4v2half
+%_ptr_Function_mat4x2_f16 = OpTypePointer Function %mat4x2_f16
+     %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %56 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat4x2_f16_uint_4 = OpTypePointer Uniform %_arr_mat4x2_f16_uint_4
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_mat4x2_f16 = OpTypePointer Uniform %mat4x2_f16
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+%conv_mat4x2_f16 = OpFunction %mat4v2half None %10
+        %val = OpFunctionParameter %mat4x2_f16
+         %14 = OpLabel
+         %15 = OpCompositeExtract %v2half %val 0
+         %16 = OpCompositeExtract %v2half %val 1
+         %17 = OpCompositeExtract %v2half %val 2
+         %18 = OpCompositeExtract %v2half %val 3
+         %19 = OpCompositeConstruct %mat4v2half %15 %16 %17 %18
+               OpReturnValue %19
+               OpFunctionEnd
+%conv_arr4_mat4x2_f16 = OpFunction %_arr_mat4v2half_uint_4 None %20
+      %val_0 = OpFunctionParameter %_arr_mat4x2_f16_uint_4
+         %24 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_mat4v2half_uint_4 Function %27
+          %i = OpVariable %_ptr_Function_uint Function %30
+%var_for_index = OpVariable %_ptr_Function__arr_mat4x2_f16_uint_4 Function %43
+               OpBranch %31
+         %31 = OpLabel
+               OpLoopMerge %32 %33 None
+               OpBranch %34
+         %34 = OpLabel
+         %36 = OpLoad %uint %i
+         %37 = OpULessThan %bool %36 %uint_4
+         %35 = OpLogicalNot %bool %37
+               OpSelectionMerge %39 None
+               OpBranchConditional %35 %40 %39
+         %40 = OpLabel
+               OpBranch %32
+         %39 = OpLabel
+               OpStore %var_for_index %val_0
+         %44 = OpLoad %uint %i
+         %46 = OpAccessChain %_ptr_Function_mat4v2half %arr %44
+         %48 = OpLoad %uint %i
+         %50 = OpAccessChain %_ptr_Function_mat4x2_f16 %var_for_index %48
+         %51 = OpLoad %mat4x2_f16 %50
+         %47 = OpFunctionCall %mat4v2half %conv_mat4x2_f16 %51
+               OpStore %46 %47
+               OpBranch %33
+         %33 = OpLabel
+         %52 = OpLoad %uint %i
+         %54 = OpIAdd %uint %52 %uint_1
+               OpStore %i %54
+               OpBranch %31
+         %32 = OpLabel
+         %55 = OpLoad %_arr_mat4v2half_uint_4 %arr
+               OpReturnValue %55
+               OpFunctionEnd
+          %f = OpFunction %void None %56
+         %59 = OpLabel
+         %63 = OpAccessChain %_ptr_Uniform__arr_mat4x2_f16_uint_4 %a %uint_0
+         %64 = OpLoad %_arr_mat4x2_f16_uint_4 %63
+         %60 = OpFunctionCall %_arr_mat4v2half_uint_4 %conv_arr4_mat4x2_f16 %64
+         %68 = OpAccessChain %_ptr_Uniform_mat4x2_f16 %a %uint_0 %uint_2
+         %69 = OpLoad %mat4x2_f16 %68
+         %65 = OpFunctionCall %mat4v2half %conv_mat4x2_f16 %69
+         %71 = OpAccessChain %_ptr_Uniform_v2half %a %uint_0 %uint_2 %uint_1
+         %72 = OpLoad %v2half %71
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat4x2_f16/static_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..cbfb856
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/static_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> a : array<mat4x2<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_2 = &((*(p_a))[2]);
+  let p_a_2_1 = &((*(p_a_2))[1]);
+  let l_a : array<mat4x2<f16>, 4> = *(p_a);
+  let l_a_i : mat4x2<f16> = *(p_a_2);
+  let l_a_i_i : vec2<f16> = *(p_a_2_1);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_builtin.wgsl b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_builtin.wgsl
new file mode 100644
index 0000000..ff810e1
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_builtin.wgsl
@@ -0,0 +1,10 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat4x2<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    let t = transpose(u[2]);
+    let l = length(u[0][1].yx);
+    let a = abs(u[0][1].yx.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_builtin.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..cddeb05
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_builtin.wgsl.expected.dxc.hlsl
@@ -0,0 +1,25 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+
+matrix<float16_t, 4, 2> tint_symbol(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const uint scalar_offset_3 = ((offset + 12u)) / 4;
+  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 2, 4> t = transpose(tint_symbol(u, 32u));
+  uint ubo_load_4 = u[0].y;
+  const float16_t l = length(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16))).yx);
+  uint ubo_load_5 = u[0].y;
+  const float16_t a = abs(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_5 & 0xFFFF)), float16_t(f16tof32(ubo_load_5 >> 16))).yx.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_builtin.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..5531d39
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_builtin.wgsl.expected.fxc.hlsl
@@ -0,0 +1,30 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+
+matrix<float16_t, 4, 2> tint_symbol(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const uint scalar_offset_3 = ((offset + 12u)) / 4;
+  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 2, 4> t = transpose(tint_symbol(u, 32u));
+  uint ubo_load_4 = u[0].y;
+  const float16_t l = length(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16))).yx);
+  uint ubo_load_5 = u[0].y;
+  const float16_t a = abs(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_5 & 0xFFFF)), float16_t(f16tof32(ubo_load_5 >> 16))).yx.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000025103259540(5,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_builtin.wgsl.expected.glsl
new file mode 100644
index 0000000..36a1082
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_builtin.wgsl.expected.glsl
@@ -0,0 +1,29 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct mat4x2_f16 {
+  f16vec2 col0;
+  f16vec2 col1;
+  f16vec2 col2;
+  f16vec2 col3;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  mat4x2_f16 inner[4];
+} u;
+
+f16mat4x2 conv_mat4x2_f16(mat4x2_f16 val) {
+  return f16mat4x2(val.col0, val.col1, val.col2, val.col3);
+}
+
+void f() {
+  f16mat2x4 t = transpose(conv_mat4x2_f16(u.inner[2u]));
+  float16_t l = length(u.inner[0u].col1.yx);
+  float16_t a = abs(u.inner[0u].col1.yx[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_builtin.wgsl.expected.msl
new file mode 100644
index 0000000..58f8a98
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_builtin.wgsl.expected.msl
@@ -0,0 +1,23 @@
+#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];
+};
+
+kernel void f(const constant tint_array<half4x2, 4>* tint_symbol [[buffer(0)]]) {
+  half2x4 const t = transpose((*(tint_symbol))[2]);
+  half const l = length(half2((*(tint_symbol))[0][1]).yx);
+  half const a = fabs(half2((*(tint_symbol))[0][1]).yx[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_builtin.wgsl.expected.spvasm
new file mode 100644
index 0000000..78be241
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_builtin.wgsl.expected.spvasm
@@ -0,0 +1,83 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 46
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+         %34 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %mat4x2_f16 "mat4x2_f16"
+               OpMemberName %mat4x2_f16 0 "col0"
+               OpMemberName %mat4x2_f16 1 "col1"
+               OpMemberName %mat4x2_f16 2 "col2"
+               OpMemberName %mat4x2_f16 3 "col3"
+               OpName %u "u"
+               OpName %conv_mat4x2_f16 "conv_mat4x2_f16"
+               OpName %val "val"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %mat4x2_f16 0 Offset 0
+               OpMemberDecorate %mat4x2_f16 1 Offset 4
+               OpMemberDecorate %mat4x2_f16 2 Offset 8
+               OpMemberDecorate %mat4x2_f16 3 Offset 12
+               OpDecorate %_arr_mat4x2_f16_uint_4 ArrayStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+ %mat4x2_f16 = OpTypeStruct %v2half %v2half %v2half %v2half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat4x2_f16_uint_4 = OpTypeArray %mat4x2_f16 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_mat4x2_f16_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat4v2half = OpTypeMatrix %v2half 4
+         %10 = OpTypeFunction %mat4v2half %mat4x2_f16
+       %void = OpTypeVoid
+         %20 = OpTypeFunction %void
+     %v4half = OpTypeVector %half 4
+ %mat2v4half = OpTypeMatrix %v4half 2
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_mat4x2_f16 = OpTypePointer Uniform %mat4x2_f16
+         %35 = OpConstantNull %uint
+     %uint_1 = OpConstant %uint 1
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+%conv_mat4x2_f16 = OpFunction %mat4v2half None %10
+        %val = OpFunctionParameter %mat4x2_f16
+         %14 = OpLabel
+         %15 = OpCompositeExtract %v2half %val 0
+         %16 = OpCompositeExtract %v2half %val 1
+         %17 = OpCompositeExtract %v2half %val 2
+         %18 = OpCompositeExtract %v2half %val 3
+         %19 = OpCompositeConstruct %mat4v2half %15 %16 %17 %18
+               OpReturnValue %19
+               OpFunctionEnd
+          %f = OpFunction %void None %20
+         %23 = OpLabel
+         %31 = OpAccessChain %_ptr_Uniform_mat4x2_f16 %u %uint_0 %uint_2
+         %32 = OpLoad %mat4x2_f16 %31
+         %27 = OpFunctionCall %mat4v2half %conv_mat4x2_f16 %32
+         %24 = OpTranspose %mat2v4half %27
+         %38 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0 %35 %uint_1
+         %39 = OpLoad %v2half %38
+         %40 = OpVectorShuffle %v2half %39 %39 1 0
+         %33 = OpExtInst %half %34 Length %40
+         %42 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0 %35 %uint_1
+         %43 = OpLoad %v2half %42
+         %44 = OpVectorShuffle %v2half %43 %43 1 0
+         %45 = OpCompositeExtract %half %44 0
+         %41 = OpExtInst %half %34 FAbs %45
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_builtin.wgsl.expected.wgsl
new file mode 100644
index 0000000..de84569
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_builtin.wgsl.expected.wgsl
@@ -0,0 +1,10 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat4x2<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let t = transpose(u[2]);
+  let l = length(u[0][1].yx);
+  let a = abs(u[0][1].yx.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_fn.wgsl b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_fn.wgsl
new file mode 100644
index 0000000..09c953b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_fn.wgsl
@@ -0,0 +1,16 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat4x2<f16>, 4>;
+
+fn a(a : array<mat4x2<f16>, 4>) {}
+fn b(m : mat4x2<f16>) {}
+fn c(v : vec2<f16>) {}
+fn d(f : f16) {}
+
+@compute @workgroup_size(1)
+fn f() {
+    a(u);
+    b(u[1]);
+    c(u[1][0].yx);
+    d(u[1][0].yx.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_fn.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..3895e31
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_fn.wgsl.expected.dxc.hlsl
@@ -0,0 +1,49 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+
+void a(matrix<float16_t, 4, 2> a_1[4]) {
+}
+
+void b(matrix<float16_t, 4, 2> m) {
+}
+
+void c(vector<float16_t, 2> v) {
+}
+
+void d(float16_t f_1) {
+}
+
+matrix<float16_t, 4, 2> tint_symbol_1(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const uint scalar_offset_3 = ((offset + 12u)) / 4;
+  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+}
+
+typedef matrix<float16_t, 4, 2> tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[4], uint offset) {
+  matrix<float16_t, 4, 2> arr[4] = (matrix<float16_t, 4, 2>[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 16u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 16u));
+  uint ubo_load_4 = u[1].x;
+  c(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16))).yx);
+  uint ubo_load_5 = u[1].x;
+  d(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_5 & 0xFFFF)), float16_t(f16tof32(ubo_load_5 >> 16))).yx.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_fn.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..3a1afc5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_fn.wgsl.expected.fxc.hlsl
@@ -0,0 +1,57 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+
+void a(matrix<float16_t, 4, 2> a_1[4]) {
+}
+
+void b(matrix<float16_t, 4, 2> m) {
+}
+
+void c(vector<float16_t, 2> v) {
+}
+
+void d(float16_t f_1) {
+}
+
+matrix<float16_t, 4, 2> tint_symbol_1(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const uint scalar_offset_3 = ((offset + 12u)) / 4;
+  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+}
+
+typedef matrix<float16_t, 4, 2> tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[4], uint offset) {
+  matrix<float16_t, 4, 2> arr[4] = (matrix<float16_t, 4, 2>[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 16u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 16u));
+  uint ubo_load_4 = u[1].x;
+  c(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16))).yx);
+  uint ubo_load_5 = u[1].x;
+  d(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_5 & 0xFFFF)), float16_t(f16tof32(ubo_load_5 >> 16))).yx.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000029B724CE850(5,15-23): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000029B724CE850(8,15-23): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000029B724CE850(11,15-23): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000029B724CE850(14,8-16): error X3000: unrecognized identifier 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_fn.wgsl.expected.glsl
new file mode 100644
index 0000000..df1283c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_fn.wgsl.expected.glsl
@@ -0,0 +1,52 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct mat4x2_f16 {
+  f16vec2 col0;
+  f16vec2 col1;
+  f16vec2 col2;
+  f16vec2 col3;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  mat4x2_f16 inner[4];
+} u;
+
+void a(f16mat4x2 a_1[4]) {
+}
+
+void b(f16mat4x2 m) {
+}
+
+void c(f16vec2 v) {
+}
+
+void d(float16_t f_1) {
+}
+
+f16mat4x2 conv_mat4x2_f16(mat4x2_f16 val) {
+  return f16mat4x2(val.col0, val.col1, val.col2, val.col3);
+}
+
+f16mat4x2[4] conv_arr4_mat4x2_f16(mat4x2_f16 val[4]) {
+  f16mat4x2 arr[4] = f16mat4x2[4](f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat4x2_f16(val[i]);
+    }
+  }
+  return arr;
+}
+
+void f() {
+  a(conv_arr4_mat4x2_f16(u.inner));
+  b(conv_mat4x2_f16(u.inner[1u]));
+  c(u.inner[1u].col0.yx);
+  d(u.inner[1u].col0.yx[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_fn.wgsl.expected.msl
new file mode 100644
index 0000000..66b4cf5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_fn.wgsl.expected.msl
@@ -0,0 +1,36 @@
+#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];
+};
+
+void a(tint_array<half4x2, 4> a_1) {
+}
+
+void b(half4x2 m) {
+}
+
+void c(half2 v) {
+}
+
+void d(half f_1) {
+}
+
+kernel void f(const constant tint_array<half4x2, 4>* tint_symbol [[buffer(0)]]) {
+  a(*(tint_symbol));
+  b((*(tint_symbol))[1]);
+  c(half2((*(tint_symbol))[1][0]).yx);
+  d(half2((*(tint_symbol))[1][0]).yx[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_fn.wgsl.expected.spvasm
new file mode 100644
index 0000000..ee9bd13
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_fn.wgsl.expected.spvasm
@@ -0,0 +1,169 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 97
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %mat4x2_f16 "mat4x2_f16"
+               OpMemberName %mat4x2_f16 0 "col0"
+               OpMemberName %mat4x2_f16 1 "col1"
+               OpMemberName %mat4x2_f16 2 "col2"
+               OpMemberName %mat4x2_f16 3 "col3"
+               OpName %u "u"
+               OpName %a "a"
+               OpName %a_1 "a_1"
+               OpName %b "b"
+               OpName %m "m"
+               OpName %c "c"
+               OpName %v "v"
+               OpName %d "d"
+               OpName %f_1 "f_1"
+               OpName %conv_mat4x2_f16 "conv_mat4x2_f16"
+               OpName %val "val"
+               OpName %conv_arr4_mat4x2_f16 "conv_arr4_mat4x2_f16"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %mat4x2_f16 0 Offset 0
+               OpMemberDecorate %mat4x2_f16 1 Offset 4
+               OpMemberDecorate %mat4x2_f16 2 Offset 8
+               OpMemberDecorate %mat4x2_f16 3 Offset 12
+               OpDecorate %_arr_mat4x2_f16_uint_4 ArrayStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %_arr_mat4v2half_uint_4 ArrayStride 16
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+ %mat4x2_f16 = OpTypeStruct %v2half %v2half %v2half %v2half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat4x2_f16_uint_4 = OpTypeArray %mat4x2_f16 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_mat4x2_f16_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+       %void = OpTypeVoid
+ %mat4v2half = OpTypeMatrix %v2half 4
+%_arr_mat4v2half_uint_4 = OpTypeArray %mat4v2half %uint_4
+         %10 = OpTypeFunction %void %_arr_mat4v2half_uint_4
+         %17 = OpTypeFunction %void %mat4v2half
+         %21 = OpTypeFunction %void %v2half
+         %25 = OpTypeFunction %void %half
+         %29 = OpTypeFunction %mat4v2half %mat4x2_f16
+         %38 = OpTypeFunction %_arr_mat4v2half_uint_4 %_arr_mat4x2_f16_uint_4
+%_ptr_Function__arr_mat4v2half_uint_4 = OpTypePointer Function %_arr_mat4v2half_uint_4
+         %44 = OpConstantNull %_arr_mat4v2half_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %47 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_mat4x2_f16_uint_4 = OpTypePointer Function %_arr_mat4x2_f16_uint_4
+         %60 = OpConstantNull %_arr_mat4x2_f16_uint_4
+%_ptr_Function_mat4v2half = OpTypePointer Function %mat4v2half
+%_ptr_Function_mat4x2_f16 = OpTypePointer Function %mat4x2_f16
+     %uint_1 = OpConstant %uint 1
+         %73 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat4x2_f16_uint_4 = OpTypePointer Uniform %_arr_mat4x2_f16_uint_4
+%_ptr_Uniform_mat4x2_f16 = OpTypePointer Uniform %mat4x2_f16
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+          %a = OpFunction %void None %10
+        %a_1 = OpFunctionParameter %_arr_mat4v2half_uint_4
+         %16 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %b = OpFunction %void None %17
+          %m = OpFunctionParameter %mat4v2half
+         %20 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %c = OpFunction %void None %21
+          %v = OpFunctionParameter %v2half
+         %24 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %d = OpFunction %void None %25
+        %f_1 = OpFunctionParameter %half
+         %28 = OpLabel
+               OpReturn
+               OpFunctionEnd
+%conv_mat4x2_f16 = OpFunction %mat4v2half None %29
+        %val = OpFunctionParameter %mat4x2_f16
+         %32 = OpLabel
+         %33 = OpCompositeExtract %v2half %val 0
+         %34 = OpCompositeExtract %v2half %val 1
+         %35 = OpCompositeExtract %v2half %val 2
+         %36 = OpCompositeExtract %v2half %val 3
+         %37 = OpCompositeConstruct %mat4v2half %33 %34 %35 %36
+               OpReturnValue %37
+               OpFunctionEnd
+%conv_arr4_mat4x2_f16 = OpFunction %_arr_mat4v2half_uint_4 None %38
+      %val_0 = OpFunctionParameter %_arr_mat4x2_f16_uint_4
+         %41 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_mat4v2half_uint_4 Function %44
+          %i = OpVariable %_ptr_Function_uint Function %47
+%var_for_index = OpVariable %_ptr_Function__arr_mat4x2_f16_uint_4 Function %60
+               OpBranch %48
+         %48 = OpLabel
+               OpLoopMerge %49 %50 None
+               OpBranch %51
+         %51 = OpLabel
+         %53 = OpLoad %uint %i
+         %54 = OpULessThan %bool %53 %uint_4
+         %52 = OpLogicalNot %bool %54
+               OpSelectionMerge %56 None
+               OpBranchConditional %52 %57 %56
+         %57 = OpLabel
+               OpBranch %49
+         %56 = OpLabel
+               OpStore %var_for_index %val_0
+         %61 = OpLoad %uint %i
+         %63 = OpAccessChain %_ptr_Function_mat4v2half %arr %61
+         %65 = OpLoad %uint %i
+         %67 = OpAccessChain %_ptr_Function_mat4x2_f16 %var_for_index %65
+         %68 = OpLoad %mat4x2_f16 %67
+         %64 = OpFunctionCall %mat4v2half %conv_mat4x2_f16 %68
+               OpStore %63 %64
+               OpBranch %50
+         %50 = OpLabel
+         %69 = OpLoad %uint %i
+         %71 = OpIAdd %uint %69 %uint_1
+               OpStore %i %71
+               OpBranch %48
+         %49 = OpLabel
+         %72 = OpLoad %_arr_mat4v2half_uint_4 %arr
+               OpReturnValue %72
+               OpFunctionEnd
+          %f = OpFunction %void None %73
+         %75 = OpLabel
+         %80 = OpAccessChain %_ptr_Uniform__arr_mat4x2_f16_uint_4 %u %uint_0
+         %81 = OpLoad %_arr_mat4x2_f16_uint_4 %80
+         %77 = OpFunctionCall %_arr_mat4v2half_uint_4 %conv_arr4_mat4x2_f16 %81
+         %76 = OpFunctionCall %void %a %77
+         %85 = OpAccessChain %_ptr_Uniform_mat4x2_f16 %u %uint_0 %uint_1
+         %86 = OpLoad %mat4x2_f16 %85
+         %83 = OpFunctionCall %mat4v2half %conv_mat4x2_f16 %86
+         %82 = OpFunctionCall %void %b %83
+         %89 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0 %uint_1 %uint_0
+         %90 = OpLoad %v2half %89
+         %91 = OpVectorShuffle %v2half %90 %90 1 0
+         %87 = OpFunctionCall %void %c %91
+         %93 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0 %uint_1 %uint_0
+         %94 = OpLoad %v2half %93
+         %95 = OpVectorShuffle %v2half %94 %94 1 0
+         %96 = OpCompositeExtract %half %95 0
+         %92 = OpFunctionCall %void %d %96
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_fn.wgsl.expected.wgsl
new file mode 100644
index 0000000..3d5ca68
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_fn.wgsl.expected.wgsl
@@ -0,0 +1,23 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat4x2<f16>, 4>;
+
+fn a(a : array<mat4x2<f16>, 4>) {
+}
+
+fn b(m : mat4x2<f16>) {
+}
+
+fn c(v : vec2<f16>) {
+}
+
+fn d(f : f16) {
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  a(u);
+  b(u[1]);
+  c(u[1][0].yx);
+  d(u[1][0].yx.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_private.wgsl b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_private.wgsl
new file mode 100644
index 0000000..54d8d8f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_private.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat4x2<f16>, 4>;
+var<private> p : array<mat4x2<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[2];
+    p[1][0] = u[0][1].yx;
+    p[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_private.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..f9a1fc80
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_private.wgsl.expected.dxc.hlsl
@@ -0,0 +1,37 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+static matrix<float16_t, 4, 2> p[4] = (matrix<float16_t, 4, 2>[4])0;
+
+matrix<float16_t, 4, 2> tint_symbol_1(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const uint scalar_offset_3 = ((offset + 12u)) / 4;
+  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+}
+
+typedef matrix<float16_t, 4, 2> tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[4], uint offset) {
+  matrix<float16_t, 4, 2> arr[4] = (matrix<float16_t, 4, 2>[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 16u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 32u);
+  uint ubo_load_4 = u[0].y;
+  p[1][0] = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16))).yx;
+  p[1][0].x = float16_t(f16tof32(((u[0].y) & 0xFFFF)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_private.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..e57ed87
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_private.wgsl.expected.fxc.hlsl
@@ -0,0 +1,42 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+static matrix<float16_t, 4, 2> p[4] = (matrix<float16_t, 4, 2>[4])0;
+
+matrix<float16_t, 4, 2> tint_symbol_1(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const uint scalar_offset_3 = ((offset + 12u)) / 4;
+  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+}
+
+typedef matrix<float16_t, 4, 2> tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[4], uint offset) {
+  matrix<float16_t, 4, 2> arr[4] = (matrix<float16_t, 4, 2>[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 16u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 32u);
+  uint ubo_load_4 = u[0].y;
+  p[1][0] = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16))).yx;
+  p[1][0].x = float16_t(f16tof32(((u[0].y) & 0xFFFF)));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000015CB4D295E0(4,15-23): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..d842b0e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_private.wgsl.expected.glsl
@@ -0,0 +1,41 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct mat4x2_f16 {
+  f16vec2 col0;
+  f16vec2 col1;
+  f16vec2 col2;
+  f16vec2 col3;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  mat4x2_f16 inner[4];
+} u;
+
+f16mat4x2 p[4] = f16mat4x2[4](f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf));
+f16mat4x2 conv_mat4x2_f16(mat4x2_f16 val) {
+  return f16mat4x2(val.col0, val.col1, val.col2, val.col3);
+}
+
+f16mat4x2[4] conv_arr4_mat4x2_f16(mat4x2_f16 val[4]) {
+  f16mat4x2 arr[4] = f16mat4x2[4](f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat4x2_f16(val[i]);
+    }
+  }
+  return arr;
+}
+
+void f() {
+  p = conv_arr4_mat4x2_f16(u.inner);
+  p[1] = conv_mat4x2_f16(u.inner[2u]);
+  p[1][0] = u.inner[0u].col1.yx;
+  p[1][0].x = u.inner[0u].col1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..0b1f07b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_private.wgsl.expected.msl
@@ -0,0 +1,25 @@
+#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];
+};
+
+kernel void f(const constant tint_array<half4x2, 4>* tint_symbol_1 [[buffer(0)]]) {
+  thread tint_array<half4x2, 4> tint_symbol = {};
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[2];
+  tint_symbol[1][0] = half2((*(tint_symbol_1))[0][1]).yx;
+  tint_symbol[1][0][0] = (*(tint_symbol_1))[0][1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_private.wgsl.expected.spvasm
new file mode 100644
index 0000000..415b8aa
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_private.wgsl.expected.spvasm
@@ -0,0 +1,149 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 88
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %mat4x2_f16 "mat4x2_f16"
+               OpMemberName %mat4x2_f16 0 "col0"
+               OpMemberName %mat4x2_f16 1 "col1"
+               OpMemberName %mat4x2_f16 2 "col2"
+               OpMemberName %mat4x2_f16 3 "col3"
+               OpName %u "u"
+               OpName %p "p"
+               OpName %conv_mat4x2_f16 "conv_mat4x2_f16"
+               OpName %val "val"
+               OpName %conv_arr4_mat4x2_f16 "conv_arr4_mat4x2_f16"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %mat4x2_f16 0 Offset 0
+               OpMemberDecorate %mat4x2_f16 1 Offset 4
+               OpMemberDecorate %mat4x2_f16 2 Offset 8
+               OpMemberDecorate %mat4x2_f16 3 Offset 12
+               OpDecorate %_arr_mat4x2_f16_uint_4 ArrayStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %_arr_mat4v2half_uint_4 ArrayStride 16
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+ %mat4x2_f16 = OpTypeStruct %v2half %v2half %v2half %v2half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat4x2_f16_uint_4 = OpTypeArray %mat4x2_f16 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_mat4x2_f16_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat4v2half = OpTypeMatrix %v2half 4
+%_arr_mat4v2half_uint_4 = OpTypeArray %mat4v2half %uint_4
+%_ptr_Private__arr_mat4v2half_uint_4 = OpTypePointer Private %_arr_mat4v2half_uint_4
+         %14 = OpConstantNull %_arr_mat4v2half_uint_4
+          %p = OpVariable %_ptr_Private__arr_mat4v2half_uint_4 Private %14
+         %15 = OpTypeFunction %mat4v2half %mat4x2_f16
+         %24 = OpTypeFunction %_arr_mat4v2half_uint_4 %_arr_mat4x2_f16_uint_4
+%_ptr_Function__arr_mat4v2half_uint_4 = OpTypePointer Function %_arr_mat4v2half_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %32 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_mat4x2_f16_uint_4 = OpTypePointer Function %_arr_mat4x2_f16_uint_4
+         %45 = OpConstantNull %_arr_mat4x2_f16_uint_4
+%_ptr_Function_mat4v2half = OpTypePointer Function %mat4v2half
+%_ptr_Function_mat4x2_f16 = OpTypePointer Function %mat4x2_f16
+     %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %58 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat4x2_f16_uint_4 = OpTypePointer Uniform %_arr_mat4x2_f16_uint_4
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Private_mat4v2half = OpTypePointer Private %mat4v2half
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_mat4x2_f16 = OpTypePointer Uniform %mat4x2_f16
+         %76 = OpConstantNull %int
+%_ptr_Private_v2half = OpTypePointer Private %v2half
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+%_ptr_Private_half = OpTypePointer Private %half
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+%conv_mat4x2_f16 = OpFunction %mat4v2half None %15
+        %val = OpFunctionParameter %mat4x2_f16
+         %18 = OpLabel
+         %19 = OpCompositeExtract %v2half %val 0
+         %20 = OpCompositeExtract %v2half %val 1
+         %21 = OpCompositeExtract %v2half %val 2
+         %22 = OpCompositeExtract %v2half %val 3
+         %23 = OpCompositeConstruct %mat4v2half %19 %20 %21 %22
+               OpReturnValue %23
+               OpFunctionEnd
+%conv_arr4_mat4x2_f16 = OpFunction %_arr_mat4v2half_uint_4 None %24
+      %val_0 = OpFunctionParameter %_arr_mat4x2_f16_uint_4
+         %27 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_mat4v2half_uint_4 Function %14
+          %i = OpVariable %_ptr_Function_uint Function %32
+%var_for_index = OpVariable %_ptr_Function__arr_mat4x2_f16_uint_4 Function %45
+               OpBranch %33
+         %33 = OpLabel
+               OpLoopMerge %34 %35 None
+               OpBranch %36
+         %36 = OpLabel
+         %38 = OpLoad %uint %i
+         %39 = OpULessThan %bool %38 %uint_4
+         %37 = OpLogicalNot %bool %39
+               OpSelectionMerge %41 None
+               OpBranchConditional %37 %42 %41
+         %42 = OpLabel
+               OpBranch %34
+         %41 = OpLabel
+               OpStore %var_for_index %val_0
+         %46 = OpLoad %uint %i
+         %48 = OpAccessChain %_ptr_Function_mat4v2half %arr %46
+         %50 = OpLoad %uint %i
+         %52 = OpAccessChain %_ptr_Function_mat4x2_f16 %var_for_index %50
+         %53 = OpLoad %mat4x2_f16 %52
+         %49 = OpFunctionCall %mat4v2half %conv_mat4x2_f16 %53
+               OpStore %48 %49
+               OpBranch %35
+         %35 = OpLabel
+         %54 = OpLoad %uint %i
+         %56 = OpIAdd %uint %54 %uint_1
+               OpStore %i %56
+               OpBranch %33
+         %34 = OpLabel
+         %57 = OpLoad %_arr_mat4v2half_uint_4 %arr
+               OpReturnValue %57
+               OpFunctionEnd
+          %f = OpFunction %void None %58
+         %61 = OpLabel
+         %65 = OpAccessChain %_ptr_Uniform__arr_mat4x2_f16_uint_4 %u %uint_0
+         %66 = OpLoad %_arr_mat4x2_f16_uint_4 %65
+         %62 = OpFunctionCall %_arr_mat4v2half_uint_4 %conv_arr4_mat4x2_f16 %66
+               OpStore %p %62
+         %70 = OpAccessChain %_ptr_Private_mat4v2half %p %int_1
+         %74 = OpAccessChain %_ptr_Uniform_mat4x2_f16 %u %uint_0 %uint_2
+         %75 = OpLoad %mat4x2_f16 %74
+         %71 = OpFunctionCall %mat4v2half %conv_mat4x2_f16 %75
+               OpStore %70 %71
+         %78 = OpAccessChain %_ptr_Private_v2half %p %int_1 %76
+         %80 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0 %32 %uint_1
+         %81 = OpLoad %v2half %80
+         %82 = OpVectorShuffle %v2half %81 %81 1 0
+               OpStore %78 %82
+         %84 = OpAccessChain %_ptr_Private_half %p %int_1 %76 %uint_0
+         %86 = OpAccessChain %_ptr_Uniform_half %u %uint_0 %32 %uint_1 %32
+         %87 = OpLoad %half %86
+               OpStore %84 %87
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..e59b04b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_private.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat4x2<f16>, 4>;
+
+var<private> p : array<mat4x2<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[2];
+  p[1][0] = u[0][1].yx;
+  p[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_storage.wgsl b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_storage.wgsl
new file mode 100644
index 0000000..05a7730
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_storage.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat4x2<f16>, 4>;
+@group(0) @binding(1) var<storage, read_write> s : array<mat4x2<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[2];
+    s[1][0] = u[0][1].yx;
+    s[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_storage.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..8097133
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_storage.wgsl.expected.dxc.hlsl
@@ -0,0 +1,53 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 2> value) {
+  buffer.Store<vector<float16_t, 2> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 4u), value[1u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 8u), value[2u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 12u), value[3u]);
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 2> value[4]) {
+  matrix<float16_t, 4, 2> array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 16u)), array[i]);
+    }
+  }
+}
+
+matrix<float16_t, 4, 2> tint_symbol_4(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const uint scalar_offset_3 = ((offset + 12u)) / 4;
+  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+}
+
+typedef matrix<float16_t, 4, 2> tint_symbol_3_ret[4];
+tint_symbol_3_ret tint_symbol_3(uint4 buffer[4], uint offset) {
+  matrix<float16_t, 4, 2> arr[4] = (matrix<float16_t, 4, 2>[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_4(buffer, (offset + (i_1 * 16u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_3(u, 0u));
+  tint_symbol_1(s, 16u, tint_symbol_4(u, 32u));
+  uint ubo_load_4 = u[0].y;
+  s.Store<vector<float16_t, 2> >(16u, vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16))).yx);
+  s.Store<float16_t>(16u, float16_t(f16tof32(((u[0].y) & 0xFFFF))));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_storage.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..489bfd1
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_storage.wgsl.expected.fxc.hlsl
@@ -0,0 +1,59 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 2> value) {
+  buffer.Store<vector<float16_t, 2> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 4u), value[1u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 8u), value[2u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 12u), value[3u]);
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 2> value[4]) {
+  matrix<float16_t, 4, 2> array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 16u)), array[i]);
+    }
+  }
+}
+
+matrix<float16_t, 4, 2> tint_symbol_4(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const uint scalar_offset_3 = ((offset + 12u)) / 4;
+  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+}
+
+typedef matrix<float16_t, 4, 2> tint_symbol_3_ret[4];
+tint_symbol_3_ret tint_symbol_3(uint4 buffer[4], uint offset) {
+  matrix<float16_t, 4, 2> arr[4] = (matrix<float16_t, 4, 2>[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_4(buffer, (offset + (i_1 * 16u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_3(u, 0u));
+  tint_symbol_1(s, 16u, tint_symbol_4(u, 32u));
+  uint ubo_load_4 = u[0].y;
+  s.Store<vector<float16_t, 2> >(16u, vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16))).yx);
+  s.Store<float16_t>(16u, float16_t(f16tof32(((u[0].y) & 0xFFFF))));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001F88B180520(6,68-76): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001F88B180520(7,3-14): error X3018: invalid subscript 'Store'
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..8913fc4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_storage.wgsl.expected.glsl
@@ -0,0 +1,44 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct mat4x2_f16 {
+  f16vec2 col0;
+  f16vec2 col1;
+  f16vec2 col2;
+  f16vec2 col3;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  mat4x2_f16 inner[4];
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  f16mat4x2 inner[4];
+} s;
+
+f16mat4x2 conv_mat4x2_f16(mat4x2_f16 val) {
+  return f16mat4x2(val.col0, val.col1, val.col2, val.col3);
+}
+
+f16mat4x2[4] conv_arr4_mat4x2_f16(mat4x2_f16 val[4]) {
+  f16mat4x2 arr[4] = f16mat4x2[4](f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat4x2_f16(val[i]);
+    }
+  }
+  return arr;
+}
+
+void f() {
+  s.inner = conv_arr4_mat4x2_f16(u.inner);
+  s.inner[1] = conv_mat4x2_f16(u.inner[2u]);
+  s.inner[1][0] = u.inner[0u].col1.yx;
+  s.inner[1][0].x = u.inner[0u].col1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..2b7f2a2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_storage.wgsl.expected.msl
@@ -0,0 +1,24 @@
+#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];
+};
+
+kernel void f(device tint_array<half4x2, 4>* tint_symbol [[buffer(1)]], const constant tint_array<half4x2, 4>* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
+  (*(tint_symbol))[1][0] = half2((*(tint_symbol_1))[0][1]).yx;
+  (*(tint_symbol))[1][0][0] = (*(tint_symbol_1))[0][1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_storage.wgsl.expected.spvasm
new file mode 100644
index 0000000..0981e80
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_storage.wgsl.expected.spvasm
@@ -0,0 +1,160 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 91
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %mat4x2_f16 "mat4x2_f16"
+               OpMemberName %mat4x2_f16 0 "col0"
+               OpMemberName %mat4x2_f16 1 "col1"
+               OpMemberName %mat4x2_f16 2 "col2"
+               OpMemberName %mat4x2_f16 3 "col3"
+               OpName %u "u"
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %s "s"
+               OpName %conv_mat4x2_f16 "conv_mat4x2_f16"
+               OpName %val "val"
+               OpName %conv_arr4_mat4x2_f16 "conv_arr4_mat4x2_f16"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %mat4x2_f16 0 Offset 0
+               OpMemberDecorate %mat4x2_f16 1 Offset 4
+               OpMemberDecorate %mat4x2_f16 2 Offset 8
+               OpMemberDecorate %mat4x2_f16 3 Offset 12
+               OpDecorate %_arr_mat4x2_f16_uint_4 ArrayStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 4
+               OpDecorate %_arr_mat4v2half_uint_4 ArrayStride 16
+               OpDecorate %s DescriptorSet 0
+               OpDecorate %s Binding 1
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+ %mat4x2_f16 = OpTypeStruct %v2half %v2half %v2half %v2half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat4x2_f16_uint_4 = OpTypeArray %mat4x2_f16 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_mat4x2_f16_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat4v2half = OpTypeMatrix %v2half 4
+%_arr_mat4v2half_uint_4 = OpTypeArray %mat4v2half %uint_4
+    %u_block = OpTypeStruct %_arr_mat4v2half_uint_4
+%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
+          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+         %15 = OpTypeFunction %mat4v2half %mat4x2_f16
+         %24 = OpTypeFunction %_arr_mat4v2half_uint_4 %_arr_mat4x2_f16_uint_4
+%_ptr_Function__arr_mat4v2half_uint_4 = OpTypePointer Function %_arr_mat4v2half_uint_4
+         %30 = OpConstantNull %_arr_mat4v2half_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %33 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_mat4x2_f16_uint_4 = OpTypePointer Function %_arr_mat4x2_f16_uint_4
+         %46 = OpConstantNull %_arr_mat4x2_f16_uint_4
+%_ptr_Function_mat4v2half = OpTypePointer Function %mat4v2half
+%_ptr_Function_mat4x2_f16 = OpTypePointer Function %mat4x2_f16
+     %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %59 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer__arr_mat4v2half_uint_4 = OpTypePointer StorageBuffer %_arr_mat4v2half_uint_4
+%_ptr_Uniform__arr_mat4x2_f16_uint_4 = OpTypePointer Uniform %_arr_mat4x2_f16_uint_4
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_mat4v2half = OpTypePointer StorageBuffer %mat4v2half
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_mat4x2_f16 = OpTypePointer Uniform %mat4x2_f16
+         %79 = OpConstantNull %int
+%_ptr_StorageBuffer_v2half = OpTypePointer StorageBuffer %v2half
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+%_ptr_StorageBuffer_half = OpTypePointer StorageBuffer %half
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+%conv_mat4x2_f16 = OpFunction %mat4v2half None %15
+        %val = OpFunctionParameter %mat4x2_f16
+         %18 = OpLabel
+         %19 = OpCompositeExtract %v2half %val 0
+         %20 = OpCompositeExtract %v2half %val 1
+         %21 = OpCompositeExtract %v2half %val 2
+         %22 = OpCompositeExtract %v2half %val 3
+         %23 = OpCompositeConstruct %mat4v2half %19 %20 %21 %22
+               OpReturnValue %23
+               OpFunctionEnd
+%conv_arr4_mat4x2_f16 = OpFunction %_arr_mat4v2half_uint_4 None %24
+      %val_0 = OpFunctionParameter %_arr_mat4x2_f16_uint_4
+         %27 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_mat4v2half_uint_4 Function %30
+          %i = OpVariable %_ptr_Function_uint Function %33
+%var_for_index = OpVariable %_ptr_Function__arr_mat4x2_f16_uint_4 Function %46
+               OpBranch %34
+         %34 = OpLabel
+               OpLoopMerge %35 %36 None
+               OpBranch %37
+         %37 = OpLabel
+         %39 = OpLoad %uint %i
+         %40 = OpULessThan %bool %39 %uint_4
+         %38 = OpLogicalNot %bool %40
+               OpSelectionMerge %42 None
+               OpBranchConditional %38 %43 %42
+         %43 = OpLabel
+               OpBranch %35
+         %42 = OpLabel
+               OpStore %var_for_index %val_0
+         %47 = OpLoad %uint %i
+         %49 = OpAccessChain %_ptr_Function_mat4v2half %arr %47
+         %51 = OpLoad %uint %i
+         %53 = OpAccessChain %_ptr_Function_mat4x2_f16 %var_for_index %51
+         %54 = OpLoad %mat4x2_f16 %53
+         %50 = OpFunctionCall %mat4v2half %conv_mat4x2_f16 %54
+               OpStore %49 %50
+               OpBranch %36
+         %36 = OpLabel
+         %55 = OpLoad %uint %i
+         %57 = OpIAdd %uint %55 %uint_1
+               OpStore %i %57
+               OpBranch %34
+         %35 = OpLabel
+         %58 = OpLoad %_arr_mat4v2half_uint_4 %arr
+               OpReturnValue %58
+               OpFunctionEnd
+          %f = OpFunction %void None %59
+         %62 = OpLabel
+         %65 = OpAccessChain %_ptr_StorageBuffer__arr_mat4v2half_uint_4 %s %uint_0
+         %68 = OpAccessChain %_ptr_Uniform__arr_mat4x2_f16_uint_4 %u %uint_0
+         %69 = OpLoad %_arr_mat4x2_f16_uint_4 %68
+         %66 = OpFunctionCall %_arr_mat4v2half_uint_4 %conv_arr4_mat4x2_f16 %69
+               OpStore %65 %66
+         %73 = OpAccessChain %_ptr_StorageBuffer_mat4v2half %s %uint_0 %int_1
+         %77 = OpAccessChain %_ptr_Uniform_mat4x2_f16 %u %uint_0 %uint_2
+         %78 = OpLoad %mat4x2_f16 %77
+         %74 = OpFunctionCall %mat4v2half %conv_mat4x2_f16 %78
+               OpStore %73 %74
+         %81 = OpAccessChain %_ptr_StorageBuffer_v2half %s %uint_0 %int_1 %79
+         %83 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0 %33 %uint_1
+         %84 = OpLoad %v2half %83
+         %85 = OpVectorShuffle %v2half %84 %84 1 0
+               OpStore %81 %85
+         %87 = OpAccessChain %_ptr_StorageBuffer_half %s %uint_0 %int_1 %79 %uint_0
+         %89 = OpAccessChain %_ptr_Uniform_half %u %uint_0 %33 %uint_1 %33
+         %90 = OpLoad %half %89
+               OpStore %87 %90
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..c80638d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat4x2<f16>, 4>;
+
+@group(0) @binding(1) var<storage, read_write> s : array<mat4x2<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[2];
+  s[1][0] = u[0][1].yx;
+  s[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_workgroup.wgsl
new file mode 100644
index 0000000..7b129e0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_workgroup.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat4x2<f16>, 4>;
+var<workgroup> w : array<mat4x2<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[2];
+    w[1][0] = u[0][1].yx;
+    w[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_workgroup.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..f67e431
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_workgroup.wgsl.expected.dxc.hlsl
@@ -0,0 +1,52 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+groupshared matrix<float16_t, 4, 2> w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 4, 2> tint_symbol_3(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const uint scalar_offset_3 = ((offset + 12u)) / 4;
+  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+}
+
+typedef matrix<float16_t, 4, 2> tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[4], uint offset) {
+  matrix<float16_t, 4, 2> arr[4] = (matrix<float16_t, 4, 2>[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 16u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      w[i] = matrix<float16_t, 4, 2>((float16_t(0.0h)).xx, (float16_t(0.0h)).xx, (float16_t(0.0h)).xx, (float16_t(0.0h)).xx);
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 32u);
+  uint ubo_load_4 = u[0].y;
+  w[1][0] = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16))).yx;
+  w[1][0].x = float16_t(f16tof32(((u[0].y) & 0xFFFF)));
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_workgroup.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..03d7569
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_workgroup.wgsl.expected.fxc.hlsl
@@ -0,0 +1,57 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+groupshared matrix<float16_t, 4, 2> w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 4, 2> tint_symbol_3(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const uint scalar_offset_3 = ((offset + 12u)) / 4;
+  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+}
+
+typedef matrix<float16_t, 4, 2> tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[4], uint offset) {
+  matrix<float16_t, 4, 2> arr[4] = (matrix<float16_t, 4, 2>[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 16u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      w[i] = matrix<float16_t, 4, 2>((float16_t(0.0h)).xx, (float16_t(0.0h)).xx, (float16_t(0.0h)).xx, (float16_t(0.0h)).xx);
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 32u);
+  uint ubo_load_4 = u[0].y;
+  w[1][0] = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16))).yx;
+  w[1][0].x = float16_t(f16tof32(((u[0].y) & 0xFFFF)));
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000020D4DFDDE90(4,20-28): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..b0b1940
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,48 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct mat4x2_f16 {
+  f16vec2 col0;
+  f16vec2 col1;
+  f16vec2 col2;
+  f16vec2 col3;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  mat4x2_f16 inner[4];
+} u;
+
+shared f16mat4x2 w[4];
+f16mat4x2 conv_mat4x2_f16(mat4x2_f16 val) {
+  return f16mat4x2(val.col0, val.col1, val.col2, val.col3);
+}
+
+f16mat4x2[4] conv_arr4_mat4x2_f16(mat4x2_f16 val[4]) {
+  f16mat4x2 arr[4] = f16mat4x2[4](f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat4x2_f16(val[i]);
+    }
+  }
+  return arr;
+}
+
+void f(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      uint i = idx;
+      w[i] = f16mat4x2(f16vec2(0.0hf), f16vec2(0.0hf), f16vec2(0.0hf), f16vec2(0.0hf));
+    }
+  }
+  barrier();
+  w = conv_arr4_mat4x2_f16(u.inner);
+  w[1] = conv_mat4x2_f16(u.inner[2u]);
+  w[1][0] = u.inner[0u].col1.yx;
+  w[1][0].x = u.inner[0u].col1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..2fe9b38
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,38 @@
+#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_symbol_5 {
+  tint_array<half4x2, 4> w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup tint_array<half4x2, 4>* const tint_symbol, const constant tint_array<half4x2, 4>* const tint_symbol_1) {
+  for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+    uint const i = idx;
+    (*(tint_symbol))[i] = half4x2(half2(0.0h), half2(0.0h), half2(0.0h), half2(0.0h));
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
+  (*(tint_symbol))[1][0] = half2((*(tint_symbol_1))[0][1]).yx;
+  (*(tint_symbol))[1][0][0] = (*(tint_symbol_1))[0][1][0];
+}
+
+kernel void f(const constant tint_array<half4x2, 4>* tint_symbol_4 [[buffer(0)]], threadgroup tint_symbol_5* tint_symbol_3 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup tint_array<half4x2, 4>* const tint_symbol_2 = &((*(tint_symbol_3)).w);
+  f_inner(local_invocation_index, tint_symbol_2, tint_symbol_4);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_workgroup.wgsl.expected.spvasm
new file mode 100644
index 0000000..dfe569a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_workgroup.wgsl.expected.spvasm
@@ -0,0 +1,192 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 113
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %local_invocation_index_1 "local_invocation_index_1"
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %mat4x2_f16 "mat4x2_f16"
+               OpMemberName %mat4x2_f16 0 "col0"
+               OpMemberName %mat4x2_f16 1 "col1"
+               OpMemberName %mat4x2_f16 2 "col2"
+               OpMemberName %mat4x2_f16 3 "col3"
+               OpName %u "u"
+               OpName %w "w"
+               OpName %conv_mat4x2_f16 "conv_mat4x2_f16"
+               OpName %val "val"
+               OpName %conv_arr4_mat4x2_f16 "conv_arr4_mat4x2_f16"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %f_inner "f_inner"
+               OpName %local_invocation_index "local_invocation_index"
+               OpName %idx "idx"
+               OpName %f "f"
+               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %mat4x2_f16 0 Offset 0
+               OpMemberDecorate %mat4x2_f16 1 Offset 4
+               OpMemberDecorate %mat4x2_f16 2 Offset 8
+               OpMemberDecorate %mat4x2_f16 3 Offset 12
+               OpDecorate %_arr_mat4x2_f16_uint_4 ArrayStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %_arr_mat4v2half_uint_4 ArrayStride 16
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+ %mat4x2_f16 = OpTypeStruct %v2half %v2half %v2half %v2half
+     %uint_4 = OpConstant %uint 4
+%_arr_mat4x2_f16_uint_4 = OpTypeArray %mat4x2_f16 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_mat4x2_f16_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat4v2half = OpTypeMatrix %v2half 4
+%_arr_mat4v2half_uint_4 = OpTypeArray %mat4v2half %uint_4
+%_ptr_Workgroup__arr_mat4v2half_uint_4 = OpTypePointer Workgroup %_arr_mat4v2half_uint_4
+          %w = OpVariable %_ptr_Workgroup__arr_mat4v2half_uint_4 Workgroup
+         %16 = OpTypeFunction %mat4v2half %mat4x2_f16
+         %25 = OpTypeFunction %_arr_mat4v2half_uint_4 %_arr_mat4x2_f16_uint_4
+%_ptr_Function__arr_mat4v2half_uint_4 = OpTypePointer Function %_arr_mat4v2half_uint_4
+         %31 = OpConstantNull %_arr_mat4v2half_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %34 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_mat4x2_f16_uint_4 = OpTypePointer Function %_arr_mat4x2_f16_uint_4
+         %47 = OpConstantNull %_arr_mat4x2_f16_uint_4
+%_ptr_Function_mat4v2half = OpTypePointer Function %mat4v2half
+%_ptr_Function_mat4x2_f16 = OpTypePointer Function %mat4x2_f16
+     %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %60 = OpTypeFunction %void %uint
+%_ptr_Workgroup_mat4v2half = OpTypePointer Workgroup %mat4v2half
+         %78 = OpConstantNull %mat4v2half
+     %uint_2 = OpConstant %uint 2
+   %uint_264 = OpConstant %uint 264
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat4x2_f16_uint_4 = OpTypePointer Uniform %_arr_mat4x2_f16_uint_4
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_mat4x2_f16 = OpTypePointer Uniform %mat4x2_f16
+         %96 = OpConstantNull %int
+%_ptr_Workgroup_v2half = OpTypePointer Workgroup %v2half
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+%_ptr_Workgroup_half = OpTypePointer Workgroup %half
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+        %108 = OpTypeFunction %void
+%conv_mat4x2_f16 = OpFunction %mat4v2half None %16
+        %val = OpFunctionParameter %mat4x2_f16
+         %19 = OpLabel
+         %20 = OpCompositeExtract %v2half %val 0
+         %21 = OpCompositeExtract %v2half %val 1
+         %22 = OpCompositeExtract %v2half %val 2
+         %23 = OpCompositeExtract %v2half %val 3
+         %24 = OpCompositeConstruct %mat4v2half %20 %21 %22 %23
+               OpReturnValue %24
+               OpFunctionEnd
+%conv_arr4_mat4x2_f16 = OpFunction %_arr_mat4v2half_uint_4 None %25
+      %val_0 = OpFunctionParameter %_arr_mat4x2_f16_uint_4
+         %28 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_mat4v2half_uint_4 Function %31
+          %i = OpVariable %_ptr_Function_uint Function %34
+%var_for_index = OpVariable %_ptr_Function__arr_mat4x2_f16_uint_4 Function %47
+               OpBranch %35
+         %35 = OpLabel
+               OpLoopMerge %36 %37 None
+               OpBranch %38
+         %38 = OpLabel
+         %40 = OpLoad %uint %i
+         %41 = OpULessThan %bool %40 %uint_4
+         %39 = OpLogicalNot %bool %41
+               OpSelectionMerge %43 None
+               OpBranchConditional %39 %44 %43
+         %44 = OpLabel
+               OpBranch %36
+         %43 = OpLabel
+               OpStore %var_for_index %val_0
+         %48 = OpLoad %uint %i
+         %50 = OpAccessChain %_ptr_Function_mat4v2half %arr %48
+         %52 = OpLoad %uint %i
+         %54 = OpAccessChain %_ptr_Function_mat4x2_f16 %var_for_index %52
+         %55 = OpLoad %mat4x2_f16 %54
+         %51 = OpFunctionCall %mat4v2half %conv_mat4x2_f16 %55
+               OpStore %50 %51
+               OpBranch %37
+         %37 = OpLabel
+         %56 = OpLoad %uint %i
+         %58 = OpIAdd %uint %56 %uint_1
+               OpStore %i %58
+               OpBranch %35
+         %36 = OpLabel
+         %59 = OpLoad %_arr_mat4v2half_uint_4 %arr
+               OpReturnValue %59
+               OpFunctionEnd
+    %f_inner = OpFunction %void None %60
+%local_invocation_index = OpFunctionParameter %uint
+         %64 = OpLabel
+        %idx = OpVariable %_ptr_Function_uint Function %34
+               OpStore %idx %local_invocation_index
+               OpBranch %66
+         %66 = OpLabel
+               OpLoopMerge %67 %68 None
+               OpBranch %69
+         %69 = OpLabel
+         %71 = OpLoad %uint %idx
+         %72 = OpULessThan %bool %71 %uint_4
+         %70 = OpLogicalNot %bool %72
+               OpSelectionMerge %73 None
+               OpBranchConditional %70 %74 %73
+         %74 = OpLabel
+               OpBranch %67
+         %73 = OpLabel
+         %75 = OpLoad %uint %idx
+         %77 = OpAccessChain %_ptr_Workgroup_mat4v2half %w %75
+               OpStore %77 %78
+               OpBranch %68
+         %68 = OpLabel
+         %79 = OpLoad %uint %idx
+         %80 = OpIAdd %uint %79 %uint_1
+               OpStore %idx %80
+               OpBranch %66
+         %67 = OpLabel
+               OpControlBarrier %uint_2 %uint_2 %uint_264
+         %87 = OpAccessChain %_ptr_Uniform__arr_mat4x2_f16_uint_4 %u %uint_0
+         %88 = OpLoad %_arr_mat4x2_f16_uint_4 %87
+         %84 = OpFunctionCall %_arr_mat4v2half_uint_4 %conv_arr4_mat4x2_f16 %88
+               OpStore %w %84
+         %91 = OpAccessChain %_ptr_Workgroup_mat4v2half %w %int_1
+         %94 = OpAccessChain %_ptr_Uniform_mat4x2_f16 %u %uint_0 %uint_2
+         %95 = OpLoad %mat4x2_f16 %94
+         %92 = OpFunctionCall %mat4v2half %conv_mat4x2_f16 %95
+               OpStore %91 %92
+         %98 = OpAccessChain %_ptr_Workgroup_v2half %w %int_1 %96
+        %100 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0 %34 %uint_1
+        %101 = OpLoad %v2half %100
+        %102 = OpVectorShuffle %v2half %101 %101 1 0
+               OpStore %98 %102
+        %104 = OpAccessChain %_ptr_Workgroup_half %w %int_1 %96 %uint_0
+        %106 = OpAccessChain %_ptr_Uniform_half %u %uint_0 %34 %uint_1 %34
+        %107 = OpLoad %half %106
+               OpStore %104 %107
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %108
+        %110 = OpLabel
+        %112 = OpLoad %uint %local_invocation_index_1
+        %111 = OpFunctionCall %void %f_inner %112
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..811c638
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f16/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat4x2<f16>, 4>;
+
+var<workgroup> w : array<mat4x2<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[2];
+  w[1][0] = u[0][1].yx;
+  w[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/array/mat4x2_f32/dynamic_index_via_ptr.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat4x2/dynamic_index_via_ptr.wgsl
rename to test/tint/buffer/uniform/std140/array/mat4x2_f32/dynamic_index_via_ptr.wgsl
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x2_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat4x2/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/uniform/std140/array/mat4x2_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x2_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat4x2/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/uniform/std140/array/mat4x2_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x2_f32/dynamic_index_via_ptr.wgsl.expected.glsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat4x2/dynamic_index_via_ptr.wgsl.expected.glsl
rename to test/tint/buffer/uniform/std140/array/mat4x2_f32/dynamic_index_via_ptr.wgsl.expected.glsl
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat4x2_f32/dynamic_index_via_ptr.wgsl.expected.msl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat4x2/dynamic_index_via_ptr.wgsl.expected.msl
rename to test/tint/buffer/uniform/std140/array/mat4x2_f32/dynamic_index_via_ptr.wgsl.expected.msl
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x2_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat4x2/dynamic_index_via_ptr.wgsl.expected.spvasm
rename to test/tint/buffer/uniform/std140/array/mat4x2_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat4x2_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat4x2/dynamic_index_via_ptr.wgsl.expected.wgsl
rename to test/tint/buffer/uniform/std140/array/mat4x2_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/array/mat4x2_f32/static_index_via_ptr.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat4x2/static_index_via_ptr.wgsl
rename to test/tint/buffer/uniform/std140/array/mat4x2_f32/static_index_via_ptr.wgsl
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x2_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat4x2/static_index_via_ptr.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/uniform/std140/array/mat4x2_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x2_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat4x2/static_index_via_ptr.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/uniform/std140/array/mat4x2_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x2_f32/static_index_via_ptr.wgsl.expected.glsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat4x2/static_index_via_ptr.wgsl.expected.glsl
rename to test/tint/buffer/uniform/std140/array/mat4x2_f32/static_index_via_ptr.wgsl.expected.glsl
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat4x2_f32/static_index_via_ptr.wgsl.expected.msl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat4x2/static_index_via_ptr.wgsl.expected.msl
rename to test/tint/buffer/uniform/std140/array/mat4x2_f32/static_index_via_ptr.wgsl.expected.msl
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x2_f32/static_index_via_ptr.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat4x2/static_index_via_ptr.wgsl.expected.spvasm
rename to test/tint/buffer/uniform/std140/array/mat4x2_f32/static_index_via_ptr.wgsl.expected.spvasm
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat4x2_f32/static_index_via_ptr.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat4x2/static_index_via_ptr.wgsl.expected.wgsl
rename to test/tint/buffer/uniform/std140/array/mat4x2_f32/static_index_via_ptr.wgsl.expected.wgsl
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_builtin.wgsl b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_builtin.wgsl
new file mode 100644
index 0000000..174ac02
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_builtin.wgsl
@@ -0,0 +1,8 @@
+@group(0) @binding(0) var<uniform> u : array<mat4x2<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    let t = transpose(u[2]);
+    let l = length(u[0][1].yx);
+    let a = abs(u[0][1].yx.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_builtin.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..2e395ab
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_builtin.wgsl.expected.dxc.hlsl
@@ -0,0 +1,23 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[8];
+};
+
+float4x2 tint_symbol(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_3 / 4];
+  return float4x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)), asfloat(((scalar_offset_3 & 2) ? ubo_load_3.zw : ubo_load_3.xy)));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float2x4 t = transpose(tint_symbol(u, 64u));
+  const float l = length(asfloat(u[0].zw).yx);
+  const float a = abs(asfloat(u[0].zw).yx.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_builtin.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..2e395ab
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_builtin.wgsl.expected.fxc.hlsl
@@ -0,0 +1,23 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[8];
+};
+
+float4x2 tint_symbol(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_3 / 4];
+  return float4x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)), asfloat(((scalar_offset_3 & 2) ? ubo_load_3.zw : ubo_load_3.xy)));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float2x4 t = transpose(tint_symbol(u, 64u));
+  const float l = length(asfloat(u[0].zw).yx);
+  const float a = abs(asfloat(u[0].zw).yx.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_builtin.wgsl.expected.glsl
new file mode 100644
index 0000000..df5f137
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_builtin.wgsl.expected.glsl
@@ -0,0 +1,28 @@
+#version 310 es
+
+struct mat4x2_f32 {
+  vec2 col0;
+  vec2 col1;
+  vec2 col2;
+  vec2 col3;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  mat4x2_f32 inner[4];
+} u;
+
+mat4x2 conv_mat4x2_f32(mat4x2_f32 val) {
+  return mat4x2(val.col0, val.col1, val.col2, val.col3);
+}
+
+void f() {
+  mat2x4 t = transpose(conv_mat4x2_f32(u.inner[2u]));
+  float l = length(u.inner[0u].col1.yx);
+  float a = abs(u.inner[0u].col1.yx[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_builtin.wgsl.expected.msl
new file mode 100644
index 0000000..b8aac7e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_builtin.wgsl.expected.msl
@@ -0,0 +1,23 @@
+#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];
+};
+
+kernel void f(const constant tint_array<float4x2, 4>* tint_symbol [[buffer(0)]]) {
+  float2x4 const t = transpose((*(tint_symbol))[2]);
+  float const l = length(float2((*(tint_symbol))[0][1]).yx);
+  float const a = fabs(float2((*(tint_symbol))[0][1]).yx[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_builtin.wgsl.expected.spvasm
new file mode 100644
index 0000000..a8609dc
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_builtin.wgsl.expected.spvasm
@@ -0,0 +1,79 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 46
+; Schema: 0
+               OpCapability Shader
+         %34 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %mat4x2_f32 "mat4x2_f32"
+               OpMemberName %mat4x2_f32 0 "col0"
+               OpMemberName %mat4x2_f32 1 "col1"
+               OpMemberName %mat4x2_f32 2 "col2"
+               OpMemberName %mat4x2_f32 3 "col3"
+               OpName %u "u"
+               OpName %conv_mat4x2_f32 "conv_mat4x2_f32"
+               OpName %val "val"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %mat4x2_f32 0 Offset 0
+               OpMemberDecorate %mat4x2_f32 1 Offset 8
+               OpMemberDecorate %mat4x2_f32 2 Offset 16
+               OpMemberDecorate %mat4x2_f32 3 Offset 24
+               OpDecorate %_arr_mat4x2_f32_uint_4 ArrayStride 32
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+      %float = OpTypeFloat 32
+    %v2float = OpTypeVector %float 2
+ %mat4x2_f32 = OpTypeStruct %v2float %v2float %v2float %v2float
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat4x2_f32_uint_4 = OpTypeArray %mat4x2_f32 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_mat4x2_f32_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+%mat4v2float = OpTypeMatrix %v2float 4
+         %10 = OpTypeFunction %mat4v2float %mat4x2_f32
+       %void = OpTypeVoid
+         %20 = OpTypeFunction %void
+    %v4float = OpTypeVector %float 4
+%mat2v4float = OpTypeMatrix %v4float 2
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_mat4x2_f32 = OpTypePointer Uniform %mat4x2_f32
+         %35 = OpConstantNull %uint
+     %uint_1 = OpConstant %uint 1
+%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
+%conv_mat4x2_f32 = OpFunction %mat4v2float None %10
+        %val = OpFunctionParameter %mat4x2_f32
+         %14 = OpLabel
+         %15 = OpCompositeExtract %v2float %val 0
+         %16 = OpCompositeExtract %v2float %val 1
+         %17 = OpCompositeExtract %v2float %val 2
+         %18 = OpCompositeExtract %v2float %val 3
+         %19 = OpCompositeConstruct %mat4v2float %15 %16 %17 %18
+               OpReturnValue %19
+               OpFunctionEnd
+          %f = OpFunction %void None %20
+         %23 = OpLabel
+         %31 = OpAccessChain %_ptr_Uniform_mat4x2_f32 %u %uint_0 %uint_2
+         %32 = OpLoad %mat4x2_f32 %31
+         %27 = OpFunctionCall %mat4v2float %conv_mat4x2_f32 %32
+         %24 = OpTranspose %mat2v4float %27
+         %38 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %35 %uint_1
+         %39 = OpLoad %v2float %38
+         %40 = OpVectorShuffle %v2float %39 %39 1 0
+         %33 = OpExtInst %float %34 Length %40
+         %42 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %35 %uint_1
+         %43 = OpLoad %v2float %42
+         %44 = OpVectorShuffle %v2float %43 %43 1 0
+         %45 = OpCompositeExtract %float %44 0
+         %41 = OpExtInst %float %34 FAbs %45
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_builtin.wgsl.expected.wgsl
new file mode 100644
index 0000000..67aafb6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_builtin.wgsl.expected.wgsl
@@ -0,0 +1,8 @@
+@group(0) @binding(0) var<uniform> u : array<mat4x2<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let t = transpose(u[2]);
+  let l = length(u[0][1].yx);
+  let a = abs(u[0][1].yx.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/to_fn.wgsl b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_fn.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat4x2/to_fn.wgsl
rename to test/tint/buffer/uniform/std140/array/mat4x2_f32/to_fn.wgsl
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_fn.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat4x2/to_fn.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/uniform/std140/array/mat4x2_f32/to_fn.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_fn.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat4x2/to_fn.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/uniform/std140/array/mat4x2_f32/to_fn.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_fn.wgsl.expected.glsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat4x2/to_fn.wgsl.expected.glsl
rename to test/tint/buffer/uniform/std140/array/mat4x2_f32/to_fn.wgsl.expected.glsl
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_fn.wgsl.expected.msl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat4x2/to_fn.wgsl.expected.msl
rename to test/tint/buffer/uniform/std140/array/mat4x2_f32/to_fn.wgsl.expected.msl
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_fn.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat4x2/to_fn.wgsl.expected.spvasm
rename to test/tint/buffer/uniform/std140/array/mat4x2_f32/to_fn.wgsl.expected.spvasm
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_fn.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat4x2/to_fn.wgsl.expected.wgsl
rename to test/tint/buffer/uniform/std140/array/mat4x2_f32/to_fn.wgsl.expected.wgsl
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_private.wgsl b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_private.wgsl
new file mode 100644
index 0000000..eb36f48
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_private.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0) var<uniform> u : array<mat4x2<f32>, 4>;
+var<private> p : array<mat4x2<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[2];
+    p[1][0] = u[0][1].yx;
+    p[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_private.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat4x2/to_private.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/uniform/std140/array/mat4x2_f32/to_private.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_private.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat4x2/to_private.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/uniform/std140/array/mat4x2_f32/to_private.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..533c5dd
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_private.wgsl.expected.glsl
@@ -0,0 +1,40 @@
+#version 310 es
+
+struct mat4x2_f32 {
+  vec2 col0;
+  vec2 col1;
+  vec2 col2;
+  vec2 col3;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  mat4x2_f32 inner[4];
+} u;
+
+mat4x2 p[4] = mat4x2[4](mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
+mat4x2 conv_mat4x2_f32(mat4x2_f32 val) {
+  return mat4x2(val.col0, val.col1, val.col2, val.col3);
+}
+
+mat4x2[4] conv_arr4_mat4x2_f32(mat4x2_f32 val[4]) {
+  mat4x2 arr[4] = mat4x2[4](mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat4x2_f32(val[i]);
+    }
+  }
+  return arr;
+}
+
+void f() {
+  p = conv_arr4_mat4x2_f32(u.inner);
+  p[1] = conv_mat4x2_f32(u.inner[2u]);
+  p[1][0] = u.inner[0u].col1.yx;
+  p[1][0].x = u.inner[0u].col1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..03a47ff
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_private.wgsl.expected.msl
@@ -0,0 +1,25 @@
+#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];
+};
+
+kernel void f(const constant tint_array<float4x2, 4>* tint_symbol_1 [[buffer(0)]]) {
+  thread tint_array<float4x2, 4> tint_symbol = {};
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[2];
+  tint_symbol[1][0] = float2((*(tint_symbol_1))[0][1]).yx;
+  tint_symbol[1][0][0] = (*(tint_symbol_1))[0][1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_private.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat4x2/to_private.wgsl.expected.spvasm
rename to test/tint/buffer/uniform/std140/array/mat4x2_f32/to_private.wgsl.expected.spvasm
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..01d5033
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_private.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> u : array<mat4x2<f32>, 4>;
+
+var<private> p : array<mat4x2<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[2];
+  p[1][0] = u[0][1].yx;
+  p[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_storage.wgsl b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_storage.wgsl
new file mode 100644
index 0000000..82a1f0b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_storage.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0) var<uniform> u : array<mat4x2<f32>, 4>;
+@group(0) @binding(1) var<storage, read_write> s : array<mat4x2<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[2];
+    s[1][0] = u[0][1].yx;
+    s[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_storage.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat4x2/to_storage.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/uniform/std140/array/mat4x2_f32/to_storage.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_storage.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat4x2/to_storage.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/uniform/std140/array/mat4x2_f32/to_storage.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..d2ac282
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_storage.wgsl.expected.glsl
@@ -0,0 +1,43 @@
+#version 310 es
+
+struct mat4x2_f32 {
+  vec2 col0;
+  vec2 col1;
+  vec2 col2;
+  vec2 col3;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  mat4x2_f32 inner[4];
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  mat4x2 inner[4];
+} s;
+
+mat4x2 conv_mat4x2_f32(mat4x2_f32 val) {
+  return mat4x2(val.col0, val.col1, val.col2, val.col3);
+}
+
+mat4x2[4] conv_arr4_mat4x2_f32(mat4x2_f32 val[4]) {
+  mat4x2 arr[4] = mat4x2[4](mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat4x2_f32(val[i]);
+    }
+  }
+  return arr;
+}
+
+void f() {
+  s.inner = conv_arr4_mat4x2_f32(u.inner);
+  s.inner[1] = conv_mat4x2_f32(u.inner[2u]);
+  s.inner[1][0] = u.inner[0u].col1.yx;
+  s.inner[1][0].x = u.inner[0u].col1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..a3aff13
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_storage.wgsl.expected.msl
@@ -0,0 +1,24 @@
+#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];
+};
+
+kernel void f(device tint_array<float4x2, 4>* tint_symbol [[buffer(1)]], const constant tint_array<float4x2, 4>* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
+  (*(tint_symbol))[1][0] = float2((*(tint_symbol_1))[0][1]).yx;
+  (*(tint_symbol))[1][0][0] = (*(tint_symbol_1))[0][1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_storage.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat4x2/to_storage.wgsl.expected.spvasm
rename to test/tint/buffer/uniform/std140/array/mat4x2_f32/to_storage.wgsl.expected.spvasm
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..b4549c7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> u : array<mat4x2<f32>, 4>;
+
+@group(0) @binding(1) var<storage, read_write> s : array<mat4x2<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[2];
+  s[1][0] = u[0][1].yx;
+  s[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_workgroup.wgsl
new file mode 100644
index 0000000..5d68d23
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_workgroup.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0) var<uniform> u : array<mat4x2<f32>, 4>;
+var<workgroup> w : array<mat4x2<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[2];
+    w[1][0] = u[0][1].yx;
+    w[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_workgroup.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat4x2/to_workgroup.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/uniform/std140/array/mat4x2_f32/to_workgroup.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_workgroup.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat4x2/to_workgroup.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/uniform/std140/array/mat4x2_f32/to_workgroup.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..092559f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,47 @@
+#version 310 es
+
+struct mat4x2_f32 {
+  vec2 col0;
+  vec2 col1;
+  vec2 col2;
+  vec2 col3;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  mat4x2_f32 inner[4];
+} u;
+
+shared mat4x2 w[4];
+mat4x2 conv_mat4x2_f32(mat4x2_f32 val) {
+  return mat4x2(val.col0, val.col1, val.col2, val.col3);
+}
+
+mat4x2[4] conv_arr4_mat4x2_f32(mat4x2_f32 val[4]) {
+  mat4x2 arr[4] = mat4x2[4](mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat4x2_f32(val[i]);
+    }
+  }
+  return arr;
+}
+
+void f(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      uint i = idx;
+      w[i] = mat4x2(vec2(0.0f), vec2(0.0f), vec2(0.0f), vec2(0.0f));
+    }
+  }
+  barrier();
+  w = conv_arr4_mat4x2_f32(u.inner);
+  w[1] = conv_mat4x2_f32(u.inner[2u]);
+  w[1][0] = u.inner[0u].col1.yx;
+  w[1][0].x = u.inner[0u].col1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..9a7cc49
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,38 @@
+#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_symbol_5 {
+  tint_array<float4x2, 4> w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup tint_array<float4x2, 4>* const tint_symbol, const constant tint_array<float4x2, 4>* const tint_symbol_1) {
+  for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+    uint const i = idx;
+    (*(tint_symbol))[i] = float4x2(float2(0.0f), float2(0.0f), float2(0.0f), float2(0.0f));
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
+  (*(tint_symbol))[1][0] = float2((*(tint_symbol_1))[0][1]).yx;
+  (*(tint_symbol))[1][0][0] = (*(tint_symbol_1))[0][1][0];
+}
+
+kernel void f(const constant tint_array<float4x2, 4>* tint_symbol_4 [[buffer(0)]], threadgroup tint_symbol_5* tint_symbol_3 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup tint_array<float4x2, 4>* const tint_symbol_2 = &((*(tint_symbol_3)).w);
+  f_inner(local_invocation_index, tint_symbol_2, tint_symbol_4);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_workgroup.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/uniform/std140/array/mat4x2/to_workgroup.wgsl.expected.spvasm
rename to test/tint/buffer/uniform/std140/array/mat4x2_f32/to_workgroup.wgsl.expected.spvasm
diff --git a/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..f45b673
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x2_f32/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> u : array<mat4x2<f32>, 4>;
+
+var<workgroup> w : array<mat4x2<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[2];
+  w[1][0] = u[0][1].yx;
+  w[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/array/mat4x3_f16/dynamic_index_via_ptr.wgsl
new file mode 100644
index 0000000..4ae7b5b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/dynamic_index_via_ptr.wgsl
@@ -0,0 +1,17 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> a : array<mat4x3<f16>, 4>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a       = &a;
+  let p_a_i     = &((*p_a)[i()]);
+  let p_a_i_i   = &((*p_a_i)[i()]);
+
+  let l_a       : array<mat4x3<f16>, 4> = *p_a;
+  let l_a_i     : mat4x3<f16>           = *p_a_i;
+  let l_a_i_i   : vec3<f16>             = *p_a_i_i;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..87b7680
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,59 @@
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[8];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 4, 3> tint_symbol_1(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+}
+
+typedef matrix<float16_t, 4, 3> tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[8], uint offset) {
+  matrix<float16_t, 4, 3> arr[4] = (matrix<float16_t, 4, 3>[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 32u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_i_save = i();
+  const matrix<float16_t, 4, 3> l_a[4] = tint_symbol(a, 0u);
+  const matrix<float16_t, 4, 3> l_a_i = tint_symbol_1(a, (32u * uint(p_a_i_save)));
+  const uint scalar_offset_4 = (((32u * uint(p_a_i_save)) + (8u * uint(p_a_i_i_save)))) / 4;
+  uint4 ubo_load_9 = a[scalar_offset_4 / 4];
+  uint2 ubo_load_8 = ((scalar_offset_4 & 2) ? ubo_load_9.zw : ubo_load_9.xy);
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  float16_t ubo_load_8_y = f16tof32(ubo_load_8[0] >> 16);
+  const vector<float16_t, 3> l_a_i_i = vector<float16_t, 3>(ubo_load_8_xz[0], ubo_load_8_y, ubo_load_8_xz[1]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..eed8899
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,64 @@
+SKIP: FAILED
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[8];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 4, 3> tint_symbol_1(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+}
+
+typedef matrix<float16_t, 4, 3> tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[8], uint offset) {
+  matrix<float16_t, 4, 3> arr[4] = (matrix<float16_t, 4, 3>[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 32u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_i_save = i();
+  const matrix<float16_t, 4, 3> l_a[4] = tint_symbol(a, 0u);
+  const matrix<float16_t, 4, 3> l_a_i = tint_symbol_1(a, (32u * uint(p_a_i_save)));
+  const uint scalar_offset_4 = (((32u * uint(p_a_i_save)) + (8u * uint(p_a_i_i_save)))) / 4;
+  uint4 ubo_load_9 = a[scalar_offset_4 / 4];
+  uint2 ubo_load_8 = ((scalar_offset_4 & 2) ? ubo_load_9.zw : ubo_load_9.xy);
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  float16_t ubo_load_8_y = f16tof32(ubo_load_8[0] >> 16);
+  const vector<float16_t, 3> l_a_i_i = vector<float16_t, 3>(ubo_load_8_xz[0], ubo_load_8_y, ubo_load_8_xz[1]);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x00000180EC89DCE0(11,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..36f90b4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,75 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct mat4x3_f16 {
+  f16vec3 col0;
+  f16vec3 col1;
+  f16vec3 col2;
+  f16vec3 col3;
+};
+
+layout(binding = 0, std140) uniform a_block_std140_ubo {
+  mat4x3_f16 inner[4];
+} a;
+
+int counter = 0;
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+f16mat4x3 conv_mat4x3_f16(mat4x3_f16 val) {
+  return f16mat4x3(val.col0, val.col1, val.col2, val.col3);
+}
+
+f16mat4x3[4] conv_arr4_mat4x3_f16(mat4x3_f16 val[4]) {
+  f16mat4x3 arr[4] = f16mat4x3[4](f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat4x3_f16(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16vec3 load_a_inner_p0_p1(uint p0, uint p1) {
+  switch(p1) {
+    case 0u: {
+      return a.inner[p0].col0;
+      break;
+    }
+    case 1u: {
+      return a.inner[p0].col1;
+      break;
+    }
+    case 2u: {
+      return a.inner[p0].col2;
+      break;
+    }
+    case 3u: {
+      return a.inner[p0].col3;
+      break;
+    }
+    default: {
+      return f16vec3(0.0hf);
+      break;
+    }
+  }
+}
+
+void f() {
+  f16mat4x3 p_a[4] = conv_arr4_mat4x3_f16(a.inner);
+  int tint_symbol = i();
+  f16mat4x3 p_a_i = conv_mat4x3_f16(a.inner[tint_symbol]);
+  int tint_symbol_1 = i();
+  f16vec3 p_a_i_i = load_a_inner_p0_p1(uint(tint_symbol), uint(tint_symbol_1));
+  f16mat4x3 l_a[4] = conv_arr4_mat4x3_f16(a.inner);
+  f16mat4x3 l_a_i = conv_mat4x3_f16(a.inner[tint_symbol]);
+  f16vec3 l_a_i_i = load_a_inner_p0_p1(uint(tint_symbol), uint(tint_symbol_1));
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..5f57b03
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,33 @@
+#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];
+};
+
+int i() {
+  thread int tint_symbol_2 = 0;
+  tint_symbol_2 = as_type<int>((as_type<uint>(tint_symbol_2) + as_type<uint>(1)));
+  return tint_symbol_2;
+}
+
+kernel void f(const constant tint_array<half4x3, 4>* tint_symbol_3 [[buffer(0)]]) {
+  int const tint_symbol = i();
+  int const p_a_i_save = tint_symbol;
+  int const tint_symbol_1 = i();
+  int const p_a_i_i_save = tint_symbol_1;
+  tint_array<half4x3, 4> const l_a = *(tint_symbol_3);
+  half4x3 const l_a_i = (*(tint_symbol_3))[p_a_i_save];
+  half3 const l_a_i_i = (*(tint_symbol_3))[p_a_i_save][p_a_i_i_save];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..fd218f4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,181 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 108
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block_std140 "a_block_std140"
+               OpMemberName %a_block_std140 0 "inner"
+               OpName %mat4x3_f16 "mat4x3_f16"
+               OpMemberName %mat4x3_f16 0 "col0"
+               OpMemberName %mat4x3_f16 1 "col1"
+               OpMemberName %mat4x3_f16 2 "col2"
+               OpMemberName %mat4x3_f16 3 "col3"
+               OpName %a "a"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %conv_mat4x3_f16 "conv_mat4x3_f16"
+               OpName %val "val"
+               OpName %conv_arr4_mat4x3_f16 "conv_arr4_mat4x3_f16"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i_0 "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_a_inner_p0_p1 "load_a_inner_p0_p1"
+               OpName %p0 "p0"
+               OpName %p1 "p1"
+               OpName %f "f"
+               OpDecorate %a_block_std140 Block
+               OpMemberDecorate %a_block_std140 0 Offset 0
+               OpMemberDecorate %mat4x3_f16 0 Offset 0
+               OpMemberDecorate %mat4x3_f16 1 Offset 8
+               OpMemberDecorate %mat4x3_f16 2 Offset 16
+               OpMemberDecorate %mat4x3_f16 3 Offset 24
+               OpDecorate %_arr_mat4x3_f16_uint_4 ArrayStride 32
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+               OpDecorate %_arr_mat4v3half_uint_4 ArrayStride 32
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+ %mat4x3_f16 = OpTypeStruct %v3half %v3half %v3half %v3half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat4x3_f16_uint_4 = OpTypeArray %mat4x3_f16 %uint_4
+%a_block_std140 = OpTypeStruct %_arr_mat4x3_f16_uint_4
+%_ptr_Uniform_a_block_std140 = OpTypePointer Uniform %a_block_std140
+          %a = OpVariable %_ptr_Uniform_a_block_std140 Uniform
+        %int = OpTypeInt 32 1
+         %11 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %11
+         %14 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+ %mat4v3half = OpTypeMatrix %v3half 4
+         %21 = OpTypeFunction %mat4v3half %mat4x3_f16
+%_arr_mat4v3half_uint_4 = OpTypeArray %mat4v3half %uint_4
+         %31 = OpTypeFunction %_arr_mat4v3half_uint_4 %_arr_mat4x3_f16_uint_4
+%_ptr_Function__arr_mat4v3half_uint_4 = OpTypePointer Function %_arr_mat4v3half_uint_4
+         %38 = OpConstantNull %_arr_mat4v3half_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %41 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_mat4x3_f16_uint_4 = OpTypePointer Function %_arr_mat4x3_f16_uint_4
+         %54 = OpConstantNull %_arr_mat4x3_f16_uint_4
+%_ptr_Function_mat4v3half = OpTypePointer Function %mat4v3half
+%_ptr_Function_mat4x3_f16 = OpTypePointer Function %mat4x3_f16
+     %uint_1 = OpConstant %uint 1
+         %67 = OpTypeFunction %v3half %uint %uint
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+         %90 = OpConstantNull %v3half
+       %void = OpTypeVoid
+         %91 = OpTypeFunction %void
+%_ptr_Uniform__arr_mat4x3_f16_uint_4 = OpTypePointer Uniform %_arr_mat4x3_f16_uint_4
+%_ptr_Uniform_mat4x3_f16 = OpTypePointer Uniform %mat4x3_f16
+          %i = OpFunction %int None %14
+         %16 = OpLabel
+         %17 = OpLoad %int %counter
+         %19 = OpIAdd %int %17 %int_1
+               OpStore %counter %19
+         %20 = OpLoad %int %counter
+               OpReturnValue %20
+               OpFunctionEnd
+%conv_mat4x3_f16 = OpFunction %mat4v3half None %21
+        %val = OpFunctionParameter %mat4x3_f16
+         %25 = OpLabel
+         %26 = OpCompositeExtract %v3half %val 0
+         %27 = OpCompositeExtract %v3half %val 1
+         %28 = OpCompositeExtract %v3half %val 2
+         %29 = OpCompositeExtract %v3half %val 3
+         %30 = OpCompositeConstruct %mat4v3half %26 %27 %28 %29
+               OpReturnValue %30
+               OpFunctionEnd
+%conv_arr4_mat4x3_f16 = OpFunction %_arr_mat4v3half_uint_4 None %31
+      %val_0 = OpFunctionParameter %_arr_mat4x3_f16_uint_4
+         %35 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_mat4v3half_uint_4 Function %38
+        %i_0 = OpVariable %_ptr_Function_uint Function %41
+%var_for_index = OpVariable %_ptr_Function__arr_mat4x3_f16_uint_4 Function %54
+               OpBranch %42
+         %42 = OpLabel
+               OpLoopMerge %43 %44 None
+               OpBranch %45
+         %45 = OpLabel
+         %47 = OpLoad %uint %i_0
+         %48 = OpULessThan %bool %47 %uint_4
+         %46 = OpLogicalNot %bool %48
+               OpSelectionMerge %50 None
+               OpBranchConditional %46 %51 %50
+         %51 = OpLabel
+               OpBranch %43
+         %50 = OpLabel
+               OpStore %var_for_index %val_0
+         %55 = OpLoad %uint %i_0
+         %57 = OpAccessChain %_ptr_Function_mat4v3half %arr %55
+         %59 = OpLoad %uint %i_0
+         %61 = OpAccessChain %_ptr_Function_mat4x3_f16 %var_for_index %59
+         %62 = OpLoad %mat4x3_f16 %61
+         %58 = OpFunctionCall %mat4v3half %conv_mat4x3_f16 %62
+               OpStore %57 %58
+               OpBranch %44
+         %44 = OpLabel
+         %63 = OpLoad %uint %i_0
+         %65 = OpIAdd %uint %63 %uint_1
+               OpStore %i_0 %65
+               OpBranch %42
+         %43 = OpLabel
+         %66 = OpLoad %_arr_mat4v3half_uint_4 %arr
+               OpReturnValue %66
+               OpFunctionEnd
+%load_a_inner_p0_p1 = OpFunction %v3half None %67
+         %p0 = OpFunctionParameter %uint
+         %p1 = OpFunctionParameter %uint
+         %71 = OpLabel
+               OpSelectionMerge %72 None
+               OpSwitch %p1 %73 0 %74 1 %75 2 %76 3 %77
+         %74 = OpLabel
+         %80 = OpAccessChain %_ptr_Uniform_v3half %a %uint_0 %p0 %uint_0
+         %81 = OpLoad %v3half %80
+               OpReturnValue %81
+         %75 = OpLabel
+         %82 = OpAccessChain %_ptr_Uniform_v3half %a %uint_0 %p0 %uint_1
+         %83 = OpLoad %v3half %82
+               OpReturnValue %83
+         %76 = OpLabel
+         %85 = OpAccessChain %_ptr_Uniform_v3half %a %uint_0 %p0 %uint_2
+         %86 = OpLoad %v3half %85
+               OpReturnValue %86
+         %77 = OpLabel
+         %88 = OpAccessChain %_ptr_Uniform_v3half %a %uint_0 %p0 %uint_3
+         %89 = OpLoad %v3half %88
+               OpReturnValue %89
+         %73 = OpLabel
+               OpReturnValue %90
+         %72 = OpLabel
+               OpReturnValue %90
+               OpFunctionEnd
+          %f = OpFunction %void None %91
+         %94 = OpLabel
+         %95 = OpFunctionCall %int %i
+         %96 = OpFunctionCall %int %i
+         %99 = OpAccessChain %_ptr_Uniform__arr_mat4x3_f16_uint_4 %a %uint_0
+        %100 = OpLoad %_arr_mat4x3_f16_uint_4 %99
+         %97 = OpFunctionCall %_arr_mat4v3half_uint_4 %conv_arr4_mat4x3_f16 %100
+        %103 = OpAccessChain %_ptr_Uniform_mat4x3_f16 %a %uint_0 %95
+        %104 = OpLoad %mat4x3_f16 %103
+        %101 = OpFunctionCall %mat4v3half %conv_mat4x3_f16 %104
+        %106 = OpBitcast %uint %95
+        %107 = OpBitcast %uint %96
+        %105 = OpFunctionCall %v3half %load_a_inner_p0_p1 %106 %107
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..c1ce99f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,20 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> a : array<mat4x3<f16>, 4>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_i = &((*(p_a))[i()]);
+  let p_a_i_i = &((*(p_a_i))[i()]);
+  let l_a : array<mat4x3<f16>, 4> = *(p_a);
+  let l_a_i : mat4x3<f16> = *(p_a_i);
+  let l_a_i_i : vec3<f16> = *(p_a_i_i);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/array/mat4x3_f16/static_index_via_ptr.wgsl
new file mode 100644
index 0000000..43527ff
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/static_index_via_ptr.wgsl
@@ -0,0 +1,14 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> a : array<mat4x3<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a       = &a;
+  let p_a_2     = &((*p_a)[2]);
+  let p_a_2_1   = &((*p_a_2)[1]);
+
+  let l_a       : array<mat4x3<f16>, 4> = *p_a;
+  let l_a_i     : mat4x3<f16>           = *p_a_2;
+  let l_a_i_i   : vec3<f16>             = *p_a_2_1;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x3_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..53dc367
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,49 @@
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[8];
+};
+
+matrix<float16_t, 4, 3> tint_symbol_1(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+}
+
+typedef matrix<float16_t, 4, 3> tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[8], uint offset) {
+  matrix<float16_t, 4, 3> arr[4] = (matrix<float16_t, 4, 3>[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 32u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 4, 3> l_a[4] = tint_symbol(a, 0u);
+  const matrix<float16_t, 4, 3> l_a_i = tint_symbol_1(a, 64u);
+  uint2 ubo_load_8 = a[4].zw;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  float16_t ubo_load_8_y = f16tof32(ubo_load_8[0] >> 16);
+  const vector<float16_t, 3> l_a_i_i = vector<float16_t, 3>(ubo_load_8_xz[0], ubo_load_8_y, ubo_load_8_xz[1]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x3_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..acc35b5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,54 @@
+SKIP: FAILED
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[8];
+};
+
+matrix<float16_t, 4, 3> tint_symbol_1(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+}
+
+typedef matrix<float16_t, 4, 3> tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[8], uint offset) {
+  matrix<float16_t, 4, 3> arr[4] = (matrix<float16_t, 4, 3>[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 32u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 4, 3> l_a[4] = tint_symbol(a, 0u);
+  const matrix<float16_t, 4, 3> l_a_i = tint_symbol_1(a, 64u);
+  uint2 ubo_load_8 = a[4].zw;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  float16_t ubo_load_8_y = f16tof32(ubo_load_8[0] >> 16);
+  const vector<float16_t, 3> l_a_i_i = vector<float16_t, 3>(ubo_load_8_xz[0], ubo_load_8_y, ubo_load_8_xz[1]);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000021B182DE800(5,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x3_f16/static_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..41093e5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/static_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,42 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct mat4x3_f16 {
+  f16vec3 col0;
+  f16vec3 col1;
+  f16vec3 col2;
+  f16vec3 col3;
+};
+
+layout(binding = 0, std140) uniform a_block_std140_ubo {
+  mat4x3_f16 inner[4];
+} a;
+
+f16mat4x3 conv_mat4x3_f16(mat4x3_f16 val) {
+  return f16mat4x3(val.col0, val.col1, val.col2, val.col3);
+}
+
+f16mat4x3[4] conv_arr4_mat4x3_f16(mat4x3_f16 val[4]) {
+  f16mat4x3 arr[4] = f16mat4x3[4](f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat4x3_f16(val[i]);
+    }
+  }
+  return arr;
+}
+
+void f() {
+  f16mat4x3 p_a[4] = conv_arr4_mat4x3_f16(a.inner);
+  f16mat4x3 p_a_2 = conv_mat4x3_f16(a.inner[2u]);
+  f16vec3 p_a_2_1 = a.inner[2u].col1;
+  f16mat4x3 l_a[4] = conv_arr4_mat4x3_f16(a.inner);
+  f16mat4x3 l_a_i = conv_mat4x3_f16(a.inner[2u]);
+  f16vec3 l_a_i_i = a.inner[2u].col1;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat4x3_f16/static_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..b7999ab
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/static_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,23 @@
+#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];
+};
+
+kernel void f(const constant tint_array<half4x3, 4>* tint_symbol [[buffer(0)]]) {
+  tint_array<half4x3, 4> const l_a = *(tint_symbol);
+  half4x3 const l_a_i = (*(tint_symbol))[2];
+  half3 const l_a_i_i = (*(tint_symbol))[2][1];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x3_f16/static_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..589a551
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/static_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,129 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 73
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block_std140 "a_block_std140"
+               OpMemberName %a_block_std140 0 "inner"
+               OpName %mat4x3_f16 "mat4x3_f16"
+               OpMemberName %mat4x3_f16 0 "col0"
+               OpMemberName %mat4x3_f16 1 "col1"
+               OpMemberName %mat4x3_f16 2 "col2"
+               OpMemberName %mat4x3_f16 3 "col3"
+               OpName %a "a"
+               OpName %conv_mat4x3_f16 "conv_mat4x3_f16"
+               OpName %val "val"
+               OpName %conv_arr4_mat4x3_f16 "conv_arr4_mat4x3_f16"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %f "f"
+               OpDecorate %a_block_std140 Block
+               OpMemberDecorate %a_block_std140 0 Offset 0
+               OpMemberDecorate %mat4x3_f16 0 Offset 0
+               OpMemberDecorate %mat4x3_f16 1 Offset 8
+               OpMemberDecorate %mat4x3_f16 2 Offset 16
+               OpMemberDecorate %mat4x3_f16 3 Offset 24
+               OpDecorate %_arr_mat4x3_f16_uint_4 ArrayStride 32
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+               OpDecorate %_arr_mat4v3half_uint_4 ArrayStride 32
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+ %mat4x3_f16 = OpTypeStruct %v3half %v3half %v3half %v3half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat4x3_f16_uint_4 = OpTypeArray %mat4x3_f16 %uint_4
+%a_block_std140 = OpTypeStruct %_arr_mat4x3_f16_uint_4
+%_ptr_Uniform_a_block_std140 = OpTypePointer Uniform %a_block_std140
+          %a = OpVariable %_ptr_Uniform_a_block_std140 Uniform
+ %mat4v3half = OpTypeMatrix %v3half 4
+         %10 = OpTypeFunction %mat4v3half %mat4x3_f16
+%_arr_mat4v3half_uint_4 = OpTypeArray %mat4v3half %uint_4
+         %20 = OpTypeFunction %_arr_mat4v3half_uint_4 %_arr_mat4x3_f16_uint_4
+%_ptr_Function__arr_mat4v3half_uint_4 = OpTypePointer Function %_arr_mat4v3half_uint_4
+         %27 = OpConstantNull %_arr_mat4v3half_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %30 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_mat4x3_f16_uint_4 = OpTypePointer Function %_arr_mat4x3_f16_uint_4
+         %43 = OpConstantNull %_arr_mat4x3_f16_uint_4
+%_ptr_Function_mat4v3half = OpTypePointer Function %mat4v3half
+%_ptr_Function_mat4x3_f16 = OpTypePointer Function %mat4x3_f16
+     %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %56 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat4x3_f16_uint_4 = OpTypePointer Uniform %_arr_mat4x3_f16_uint_4
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_mat4x3_f16 = OpTypePointer Uniform %mat4x3_f16
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+%conv_mat4x3_f16 = OpFunction %mat4v3half None %10
+        %val = OpFunctionParameter %mat4x3_f16
+         %14 = OpLabel
+         %15 = OpCompositeExtract %v3half %val 0
+         %16 = OpCompositeExtract %v3half %val 1
+         %17 = OpCompositeExtract %v3half %val 2
+         %18 = OpCompositeExtract %v3half %val 3
+         %19 = OpCompositeConstruct %mat4v3half %15 %16 %17 %18
+               OpReturnValue %19
+               OpFunctionEnd
+%conv_arr4_mat4x3_f16 = OpFunction %_arr_mat4v3half_uint_4 None %20
+      %val_0 = OpFunctionParameter %_arr_mat4x3_f16_uint_4
+         %24 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_mat4v3half_uint_4 Function %27
+          %i = OpVariable %_ptr_Function_uint Function %30
+%var_for_index = OpVariable %_ptr_Function__arr_mat4x3_f16_uint_4 Function %43
+               OpBranch %31
+         %31 = OpLabel
+               OpLoopMerge %32 %33 None
+               OpBranch %34
+         %34 = OpLabel
+         %36 = OpLoad %uint %i
+         %37 = OpULessThan %bool %36 %uint_4
+         %35 = OpLogicalNot %bool %37
+               OpSelectionMerge %39 None
+               OpBranchConditional %35 %40 %39
+         %40 = OpLabel
+               OpBranch %32
+         %39 = OpLabel
+               OpStore %var_for_index %val_0
+         %44 = OpLoad %uint %i
+         %46 = OpAccessChain %_ptr_Function_mat4v3half %arr %44
+         %48 = OpLoad %uint %i
+         %50 = OpAccessChain %_ptr_Function_mat4x3_f16 %var_for_index %48
+         %51 = OpLoad %mat4x3_f16 %50
+         %47 = OpFunctionCall %mat4v3half %conv_mat4x3_f16 %51
+               OpStore %46 %47
+               OpBranch %33
+         %33 = OpLabel
+         %52 = OpLoad %uint %i
+         %54 = OpIAdd %uint %52 %uint_1
+               OpStore %i %54
+               OpBranch %31
+         %32 = OpLabel
+         %55 = OpLoad %_arr_mat4v3half_uint_4 %arr
+               OpReturnValue %55
+               OpFunctionEnd
+          %f = OpFunction %void None %56
+         %59 = OpLabel
+         %63 = OpAccessChain %_ptr_Uniform__arr_mat4x3_f16_uint_4 %a %uint_0
+         %64 = OpLoad %_arr_mat4x3_f16_uint_4 %63
+         %60 = OpFunctionCall %_arr_mat4v3half_uint_4 %conv_arr4_mat4x3_f16 %64
+         %68 = OpAccessChain %_ptr_Uniform_mat4x3_f16 %a %uint_0 %uint_2
+         %69 = OpLoad %mat4x3_f16 %68
+         %65 = OpFunctionCall %mat4v3half %conv_mat4x3_f16 %69
+         %71 = OpAccessChain %_ptr_Uniform_v3half %a %uint_0 %uint_2 %uint_1
+         %72 = OpLoad %v3half %71
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat4x3_f16/static_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..7be7438
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/static_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> a : array<mat4x3<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_2 = &((*(p_a))[2]);
+  let p_a_2_1 = &((*(p_a_2))[1]);
+  let l_a : array<mat4x3<f16>, 4> = *(p_a);
+  let l_a_i : mat4x3<f16> = *(p_a_2);
+  let l_a_i_i : vec3<f16> = *(p_a_2_1);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_builtin.wgsl b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_builtin.wgsl
new file mode 100644
index 0000000..b61759f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_builtin.wgsl
@@ -0,0 +1,10 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat4x3<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    let t = transpose(u[2]);
+    let l = length(u[0][1].zxy);
+    let a = abs(u[0][1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_builtin.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..fe691e9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_builtin.wgsl.expected.dxc.hlsl
@@ -0,0 +1,41 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[8];
+};
+
+matrix<float16_t, 4, 3> tint_symbol(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 3, 4> t = transpose(tint_symbol(u, 64u));
+  uint2 ubo_load_8 = u[0].zw;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  float16_t ubo_load_8_y = f16tof32(ubo_load_8[0] >> 16);
+  const float16_t l = length(vector<float16_t, 3>(ubo_load_8_xz[0], ubo_load_8_y, ubo_load_8_xz[1]).zxy);
+  uint2 ubo_load_9 = u[0].zw;
+  vector<float16_t, 2> ubo_load_9_xz = vector<float16_t, 2>(f16tof32(ubo_load_9 & 0xFFFF));
+  float16_t ubo_load_9_y = f16tof32(ubo_load_9[0] >> 16);
+  const float16_t a = abs(vector<float16_t, 3>(ubo_load_9_xz[0], ubo_load_9_y, ubo_load_9_xz[1]).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_builtin.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..aa2cb40
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_builtin.wgsl.expected.fxc.hlsl
@@ -0,0 +1,46 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[8];
+};
+
+matrix<float16_t, 4, 3> tint_symbol(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 3, 4> t = transpose(tint_symbol(u, 64u));
+  uint2 ubo_load_8 = u[0].zw;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  float16_t ubo_load_8_y = f16tof32(ubo_load_8[0] >> 16);
+  const float16_t l = length(vector<float16_t, 3>(ubo_load_8_xz[0], ubo_load_8_y, ubo_load_8_xz[1]).zxy);
+  uint2 ubo_load_9 = u[0].zw;
+  vector<float16_t, 2> ubo_load_9_xz = vector<float16_t, 2>(f16tof32(ubo_load_9 & 0xFFFF));
+  float16_t ubo_load_9_y = f16tof32(ubo_load_9[0] >> 16);
+  const float16_t a = abs(vector<float16_t, 3>(ubo_load_9_xz[0], ubo_load_9_y, ubo_load_9_xz[1]).zxy.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000002C9B1C5A400(5,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_builtin.wgsl.expected.glsl
new file mode 100644
index 0000000..da81276
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_builtin.wgsl.expected.glsl
@@ -0,0 +1,29 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct mat4x3_f16 {
+  f16vec3 col0;
+  f16vec3 col1;
+  f16vec3 col2;
+  f16vec3 col3;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  mat4x3_f16 inner[4];
+} u;
+
+f16mat4x3 conv_mat4x3_f16(mat4x3_f16 val) {
+  return f16mat4x3(val.col0, val.col1, val.col2, val.col3);
+}
+
+void f() {
+  f16mat3x4 t = transpose(conv_mat4x3_f16(u.inner[2u]));
+  float16_t l = length(u.inner[0u].col1.zxy);
+  float16_t a = abs(u.inner[0u].col1.zxy[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_builtin.wgsl.expected.msl
new file mode 100644
index 0000000..39b9c1c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_builtin.wgsl.expected.msl
@@ -0,0 +1,23 @@
+#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];
+};
+
+kernel void f(const constant tint_array<half4x3, 4>* tint_symbol [[buffer(0)]]) {
+  half3x4 const t = transpose((*(tint_symbol))[2]);
+  half const l = length(half3((*(tint_symbol))[0][1]).zxy);
+  half const a = fabs(half3((*(tint_symbol))[0][1]).zxy[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_builtin.wgsl.expected.spvasm
new file mode 100644
index 0000000..272eab8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_builtin.wgsl.expected.spvasm
@@ -0,0 +1,83 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 46
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+         %34 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %mat4x3_f16 "mat4x3_f16"
+               OpMemberName %mat4x3_f16 0 "col0"
+               OpMemberName %mat4x3_f16 1 "col1"
+               OpMemberName %mat4x3_f16 2 "col2"
+               OpMemberName %mat4x3_f16 3 "col3"
+               OpName %u "u"
+               OpName %conv_mat4x3_f16 "conv_mat4x3_f16"
+               OpName %val "val"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %mat4x3_f16 0 Offset 0
+               OpMemberDecorate %mat4x3_f16 1 Offset 8
+               OpMemberDecorate %mat4x3_f16 2 Offset 16
+               OpMemberDecorate %mat4x3_f16 3 Offset 24
+               OpDecorate %_arr_mat4x3_f16_uint_4 ArrayStride 32
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+ %mat4x3_f16 = OpTypeStruct %v3half %v3half %v3half %v3half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat4x3_f16_uint_4 = OpTypeArray %mat4x3_f16 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_mat4x3_f16_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat4v3half = OpTypeMatrix %v3half 4
+         %10 = OpTypeFunction %mat4v3half %mat4x3_f16
+       %void = OpTypeVoid
+         %20 = OpTypeFunction %void
+     %v4half = OpTypeVector %half 4
+ %mat3v4half = OpTypeMatrix %v4half 3
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_mat4x3_f16 = OpTypePointer Uniform %mat4x3_f16
+         %35 = OpConstantNull %uint
+     %uint_1 = OpConstant %uint 1
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+%conv_mat4x3_f16 = OpFunction %mat4v3half None %10
+        %val = OpFunctionParameter %mat4x3_f16
+         %14 = OpLabel
+         %15 = OpCompositeExtract %v3half %val 0
+         %16 = OpCompositeExtract %v3half %val 1
+         %17 = OpCompositeExtract %v3half %val 2
+         %18 = OpCompositeExtract %v3half %val 3
+         %19 = OpCompositeConstruct %mat4v3half %15 %16 %17 %18
+               OpReturnValue %19
+               OpFunctionEnd
+          %f = OpFunction %void None %20
+         %23 = OpLabel
+         %31 = OpAccessChain %_ptr_Uniform_mat4x3_f16 %u %uint_0 %uint_2
+         %32 = OpLoad %mat4x3_f16 %31
+         %27 = OpFunctionCall %mat4v3half %conv_mat4x3_f16 %32
+         %24 = OpTranspose %mat3v4half %27
+         %38 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0 %35 %uint_1
+         %39 = OpLoad %v3half %38
+         %40 = OpVectorShuffle %v3half %39 %39 2 0 1
+         %33 = OpExtInst %half %34 Length %40
+         %42 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0 %35 %uint_1
+         %43 = OpLoad %v3half %42
+         %44 = OpVectorShuffle %v3half %43 %43 2 0 1
+         %45 = OpCompositeExtract %half %44 0
+         %41 = OpExtInst %half %34 FAbs %45
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_builtin.wgsl.expected.wgsl
new file mode 100644
index 0000000..3be1c07
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_builtin.wgsl.expected.wgsl
@@ -0,0 +1,10 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat4x3<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let t = transpose(u[2]);
+  let l = length(u[0][1].zxy);
+  let a = abs(u[0][1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_fn.wgsl b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_fn.wgsl
new file mode 100644
index 0000000..b66dc37
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_fn.wgsl
@@ -0,0 +1,16 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat4x3<f16>, 4>;
+
+fn a(a : array<mat4x3<f16>, 4>) {}
+fn b(m : mat4x3<f16>) {}
+fn c(v : vec3<f16>) {}
+fn d(f : f16) {}
+
+@compute @workgroup_size(1)
+fn f() {
+    a(u);
+    b(u[1]);
+    c(u[1][0].zxy);
+    d(u[1][0].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_fn.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..2768c99
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_fn.wgsl.expected.dxc.hlsl
@@ -0,0 +1,65 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[8];
+};
+
+void a(matrix<float16_t, 4, 3> a_1[4]) {
+}
+
+void b(matrix<float16_t, 4, 3> m) {
+}
+
+void c(vector<float16_t, 3> v) {
+}
+
+void d(float16_t f_1) {
+}
+
+matrix<float16_t, 4, 3> tint_symbol_1(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+}
+
+typedef matrix<float16_t, 4, 3> tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[8], uint offset) {
+  matrix<float16_t, 4, 3> arr[4] = (matrix<float16_t, 4, 3>[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 32u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 32u));
+  uint2 ubo_load_8 = u[2].xy;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  float16_t ubo_load_8_y = f16tof32(ubo_load_8[0] >> 16);
+  c(vector<float16_t, 3>(ubo_load_8_xz[0], ubo_load_8_y, ubo_load_8_xz[1]).zxy);
+  uint2 ubo_load_9 = u[2].xy;
+  vector<float16_t, 2> ubo_load_9_xz = vector<float16_t, 2>(f16tof32(ubo_load_9 & 0xFFFF));
+  float16_t ubo_load_9_y = f16tof32(ubo_load_9[0] >> 16);
+  d(vector<float16_t, 3>(ubo_load_9_xz[0], ubo_load_9_y, ubo_load_9_xz[1]).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_fn.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..88a9d54
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_fn.wgsl.expected.fxc.hlsl
@@ -0,0 +1,73 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[8];
+};
+
+void a(matrix<float16_t, 4, 3> a_1[4]) {
+}
+
+void b(matrix<float16_t, 4, 3> m) {
+}
+
+void c(vector<float16_t, 3> v) {
+}
+
+void d(float16_t f_1) {
+}
+
+matrix<float16_t, 4, 3> tint_symbol_1(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+}
+
+typedef matrix<float16_t, 4, 3> tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[8], uint offset) {
+  matrix<float16_t, 4, 3> arr[4] = (matrix<float16_t, 4, 3>[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 32u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 32u));
+  uint2 ubo_load_8 = u[2].xy;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  float16_t ubo_load_8_y = f16tof32(ubo_load_8[0] >> 16);
+  c(vector<float16_t, 3>(ubo_load_8_xz[0], ubo_load_8_y, ubo_load_8_xz[1]).zxy);
+  uint2 ubo_load_9 = u[2].xy;
+  vector<float16_t, 2> ubo_load_9_xz = vector<float16_t, 2>(f16tof32(ubo_load_9 & 0xFFFF));
+  float16_t ubo_load_9_y = f16tof32(ubo_load_9[0] >> 16);
+  d(vector<float16_t, 3>(ubo_load_9_xz[0], ubo_load_9_y, ubo_load_9_xz[1]).zxy.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x00000296784C0E70(5,15-23): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x00000296784C0E70(8,15-23): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x00000296784C0E70(11,15-23): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x00000296784C0E70(14,8-16): error X3000: unrecognized identifier 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_fn.wgsl.expected.glsl
new file mode 100644
index 0000000..fee3b35
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_fn.wgsl.expected.glsl
@@ -0,0 +1,52 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct mat4x3_f16 {
+  f16vec3 col0;
+  f16vec3 col1;
+  f16vec3 col2;
+  f16vec3 col3;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  mat4x3_f16 inner[4];
+} u;
+
+void a(f16mat4x3 a_1[4]) {
+}
+
+void b(f16mat4x3 m) {
+}
+
+void c(f16vec3 v) {
+}
+
+void d(float16_t f_1) {
+}
+
+f16mat4x3 conv_mat4x3_f16(mat4x3_f16 val) {
+  return f16mat4x3(val.col0, val.col1, val.col2, val.col3);
+}
+
+f16mat4x3[4] conv_arr4_mat4x3_f16(mat4x3_f16 val[4]) {
+  f16mat4x3 arr[4] = f16mat4x3[4](f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat4x3_f16(val[i]);
+    }
+  }
+  return arr;
+}
+
+void f() {
+  a(conv_arr4_mat4x3_f16(u.inner));
+  b(conv_mat4x3_f16(u.inner[1u]));
+  c(u.inner[1u].col0.zxy);
+  d(u.inner[1u].col0.zxy[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_fn.wgsl.expected.msl
new file mode 100644
index 0000000..ed20c74
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_fn.wgsl.expected.msl
@@ -0,0 +1,36 @@
+#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];
+};
+
+void a(tint_array<half4x3, 4> a_1) {
+}
+
+void b(half4x3 m) {
+}
+
+void c(half3 v) {
+}
+
+void d(half f_1) {
+}
+
+kernel void f(const constant tint_array<half4x3, 4>* tint_symbol [[buffer(0)]]) {
+  a(*(tint_symbol));
+  b((*(tint_symbol))[1]);
+  c(half3((*(tint_symbol))[1][0]).zxy);
+  d(half3((*(tint_symbol))[1][0]).zxy[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_fn.wgsl.expected.spvasm
new file mode 100644
index 0000000..8e4fc69
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_fn.wgsl.expected.spvasm
@@ -0,0 +1,169 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 97
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %mat4x3_f16 "mat4x3_f16"
+               OpMemberName %mat4x3_f16 0 "col0"
+               OpMemberName %mat4x3_f16 1 "col1"
+               OpMemberName %mat4x3_f16 2 "col2"
+               OpMemberName %mat4x3_f16 3 "col3"
+               OpName %u "u"
+               OpName %a "a"
+               OpName %a_1 "a_1"
+               OpName %b "b"
+               OpName %m "m"
+               OpName %c "c"
+               OpName %v "v"
+               OpName %d "d"
+               OpName %f_1 "f_1"
+               OpName %conv_mat4x3_f16 "conv_mat4x3_f16"
+               OpName %val "val"
+               OpName %conv_arr4_mat4x3_f16 "conv_arr4_mat4x3_f16"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %mat4x3_f16 0 Offset 0
+               OpMemberDecorate %mat4x3_f16 1 Offset 8
+               OpMemberDecorate %mat4x3_f16 2 Offset 16
+               OpMemberDecorate %mat4x3_f16 3 Offset 24
+               OpDecorate %_arr_mat4x3_f16_uint_4 ArrayStride 32
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %_arr_mat4v3half_uint_4 ArrayStride 32
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+ %mat4x3_f16 = OpTypeStruct %v3half %v3half %v3half %v3half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat4x3_f16_uint_4 = OpTypeArray %mat4x3_f16 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_mat4x3_f16_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+       %void = OpTypeVoid
+ %mat4v3half = OpTypeMatrix %v3half 4
+%_arr_mat4v3half_uint_4 = OpTypeArray %mat4v3half %uint_4
+         %10 = OpTypeFunction %void %_arr_mat4v3half_uint_4
+         %17 = OpTypeFunction %void %mat4v3half
+         %21 = OpTypeFunction %void %v3half
+         %25 = OpTypeFunction %void %half
+         %29 = OpTypeFunction %mat4v3half %mat4x3_f16
+         %38 = OpTypeFunction %_arr_mat4v3half_uint_4 %_arr_mat4x3_f16_uint_4
+%_ptr_Function__arr_mat4v3half_uint_4 = OpTypePointer Function %_arr_mat4v3half_uint_4
+         %44 = OpConstantNull %_arr_mat4v3half_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %47 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_mat4x3_f16_uint_4 = OpTypePointer Function %_arr_mat4x3_f16_uint_4
+         %60 = OpConstantNull %_arr_mat4x3_f16_uint_4
+%_ptr_Function_mat4v3half = OpTypePointer Function %mat4v3half
+%_ptr_Function_mat4x3_f16 = OpTypePointer Function %mat4x3_f16
+     %uint_1 = OpConstant %uint 1
+         %73 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat4x3_f16_uint_4 = OpTypePointer Uniform %_arr_mat4x3_f16_uint_4
+%_ptr_Uniform_mat4x3_f16 = OpTypePointer Uniform %mat4x3_f16
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+          %a = OpFunction %void None %10
+        %a_1 = OpFunctionParameter %_arr_mat4v3half_uint_4
+         %16 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %b = OpFunction %void None %17
+          %m = OpFunctionParameter %mat4v3half
+         %20 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %c = OpFunction %void None %21
+          %v = OpFunctionParameter %v3half
+         %24 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %d = OpFunction %void None %25
+        %f_1 = OpFunctionParameter %half
+         %28 = OpLabel
+               OpReturn
+               OpFunctionEnd
+%conv_mat4x3_f16 = OpFunction %mat4v3half None %29
+        %val = OpFunctionParameter %mat4x3_f16
+         %32 = OpLabel
+         %33 = OpCompositeExtract %v3half %val 0
+         %34 = OpCompositeExtract %v3half %val 1
+         %35 = OpCompositeExtract %v3half %val 2
+         %36 = OpCompositeExtract %v3half %val 3
+         %37 = OpCompositeConstruct %mat4v3half %33 %34 %35 %36
+               OpReturnValue %37
+               OpFunctionEnd
+%conv_arr4_mat4x3_f16 = OpFunction %_arr_mat4v3half_uint_4 None %38
+      %val_0 = OpFunctionParameter %_arr_mat4x3_f16_uint_4
+         %41 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_mat4v3half_uint_4 Function %44
+          %i = OpVariable %_ptr_Function_uint Function %47
+%var_for_index = OpVariable %_ptr_Function__arr_mat4x3_f16_uint_4 Function %60
+               OpBranch %48
+         %48 = OpLabel
+               OpLoopMerge %49 %50 None
+               OpBranch %51
+         %51 = OpLabel
+         %53 = OpLoad %uint %i
+         %54 = OpULessThan %bool %53 %uint_4
+         %52 = OpLogicalNot %bool %54
+               OpSelectionMerge %56 None
+               OpBranchConditional %52 %57 %56
+         %57 = OpLabel
+               OpBranch %49
+         %56 = OpLabel
+               OpStore %var_for_index %val_0
+         %61 = OpLoad %uint %i
+         %63 = OpAccessChain %_ptr_Function_mat4v3half %arr %61
+         %65 = OpLoad %uint %i
+         %67 = OpAccessChain %_ptr_Function_mat4x3_f16 %var_for_index %65
+         %68 = OpLoad %mat4x3_f16 %67
+         %64 = OpFunctionCall %mat4v3half %conv_mat4x3_f16 %68
+               OpStore %63 %64
+               OpBranch %50
+         %50 = OpLabel
+         %69 = OpLoad %uint %i
+         %71 = OpIAdd %uint %69 %uint_1
+               OpStore %i %71
+               OpBranch %48
+         %49 = OpLabel
+         %72 = OpLoad %_arr_mat4v3half_uint_4 %arr
+               OpReturnValue %72
+               OpFunctionEnd
+          %f = OpFunction %void None %73
+         %75 = OpLabel
+         %80 = OpAccessChain %_ptr_Uniform__arr_mat4x3_f16_uint_4 %u %uint_0
+         %81 = OpLoad %_arr_mat4x3_f16_uint_4 %80
+         %77 = OpFunctionCall %_arr_mat4v3half_uint_4 %conv_arr4_mat4x3_f16 %81
+         %76 = OpFunctionCall %void %a %77
+         %85 = OpAccessChain %_ptr_Uniform_mat4x3_f16 %u %uint_0 %uint_1
+         %86 = OpLoad %mat4x3_f16 %85
+         %83 = OpFunctionCall %mat4v3half %conv_mat4x3_f16 %86
+         %82 = OpFunctionCall %void %b %83
+         %89 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0 %uint_1 %uint_0
+         %90 = OpLoad %v3half %89
+         %91 = OpVectorShuffle %v3half %90 %90 2 0 1
+         %87 = OpFunctionCall %void %c %91
+         %93 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0 %uint_1 %uint_0
+         %94 = OpLoad %v3half %93
+         %95 = OpVectorShuffle %v3half %94 %94 2 0 1
+         %96 = OpCompositeExtract %half %95 0
+         %92 = OpFunctionCall %void %d %96
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_fn.wgsl.expected.wgsl
new file mode 100644
index 0000000..280e923
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_fn.wgsl.expected.wgsl
@@ -0,0 +1,23 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat4x3<f16>, 4>;
+
+fn a(a : array<mat4x3<f16>, 4>) {
+}
+
+fn b(m : mat4x3<f16>) {
+}
+
+fn c(v : vec3<f16>) {
+}
+
+fn d(f : f16) {
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  a(u);
+  b(u[1]);
+  c(u[1][0].zxy);
+  d(u[1][0].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_private.wgsl b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_private.wgsl
new file mode 100644
index 0000000..20e3e86
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_private.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat4x3<f16>, 4>;
+var<private> p : array<mat4x3<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[2];
+    p[1][0] = u[0][1].zxy;
+    p[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_private.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..4b50702
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_private.wgsl.expected.dxc.hlsl
@@ -0,0 +1,51 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[8];
+};
+static matrix<float16_t, 4, 3> p[4] = (matrix<float16_t, 4, 3>[4])0;
+
+matrix<float16_t, 4, 3> tint_symbol_1(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+}
+
+typedef matrix<float16_t, 4, 3> tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[8], uint offset) {
+  matrix<float16_t, 4, 3> arr[4] = (matrix<float16_t, 4, 3>[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 32u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 64u);
+  uint2 ubo_load_8 = u[0].zw;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  float16_t ubo_load_8_y = f16tof32(ubo_load_8[0] >> 16);
+  p[1][0] = vector<float16_t, 3>(ubo_load_8_xz[0], ubo_load_8_y, ubo_load_8_xz[1]).zxy;
+  p[1][0].x = float16_t(f16tof32(((u[0].z) & 0xFFFF)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_private.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..71ba00c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_private.wgsl.expected.fxc.hlsl
@@ -0,0 +1,56 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[8];
+};
+static matrix<float16_t, 4, 3> p[4] = (matrix<float16_t, 4, 3>[4])0;
+
+matrix<float16_t, 4, 3> tint_symbol_1(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+}
+
+typedef matrix<float16_t, 4, 3> tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[8], uint offset) {
+  matrix<float16_t, 4, 3> arr[4] = (matrix<float16_t, 4, 3>[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 32u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 64u);
+  uint2 ubo_load_8 = u[0].zw;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  float16_t ubo_load_8_y = f16tof32(ubo_load_8[0] >> 16);
+  p[1][0] = vector<float16_t, 3>(ubo_load_8_xz[0], ubo_load_8_y, ubo_load_8_xz[1]).zxy;
+  p[1][0].x = float16_t(f16tof32(((u[0].z) & 0xFFFF)));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x00000222F970C590(4,15-23): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..fc3fbc5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_private.wgsl.expected.glsl
@@ -0,0 +1,41 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct mat4x3_f16 {
+  f16vec3 col0;
+  f16vec3 col1;
+  f16vec3 col2;
+  f16vec3 col3;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  mat4x3_f16 inner[4];
+} u;
+
+f16mat4x3 p[4] = f16mat4x3[4](f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf));
+f16mat4x3 conv_mat4x3_f16(mat4x3_f16 val) {
+  return f16mat4x3(val.col0, val.col1, val.col2, val.col3);
+}
+
+f16mat4x3[4] conv_arr4_mat4x3_f16(mat4x3_f16 val[4]) {
+  f16mat4x3 arr[4] = f16mat4x3[4](f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat4x3_f16(val[i]);
+    }
+  }
+  return arr;
+}
+
+void f() {
+  p = conv_arr4_mat4x3_f16(u.inner);
+  p[1] = conv_mat4x3_f16(u.inner[2u]);
+  p[1][0] = u.inner[0u].col1.zxy;
+  p[1][0].x = u.inner[0u].col1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..89c4a04
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_private.wgsl.expected.msl
@@ -0,0 +1,25 @@
+#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];
+};
+
+kernel void f(const constant tint_array<half4x3, 4>* tint_symbol_1 [[buffer(0)]]) {
+  thread tint_array<half4x3, 4> tint_symbol = {};
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[2];
+  tint_symbol[1][0] = half3((*(tint_symbol_1))[0][1]).zxy;
+  tint_symbol[1][0][0] = (*(tint_symbol_1))[0][1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_private.wgsl.expected.spvasm
new file mode 100644
index 0000000..1223488
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_private.wgsl.expected.spvasm
@@ -0,0 +1,149 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 88
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %mat4x3_f16 "mat4x3_f16"
+               OpMemberName %mat4x3_f16 0 "col0"
+               OpMemberName %mat4x3_f16 1 "col1"
+               OpMemberName %mat4x3_f16 2 "col2"
+               OpMemberName %mat4x3_f16 3 "col3"
+               OpName %u "u"
+               OpName %p "p"
+               OpName %conv_mat4x3_f16 "conv_mat4x3_f16"
+               OpName %val "val"
+               OpName %conv_arr4_mat4x3_f16 "conv_arr4_mat4x3_f16"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %mat4x3_f16 0 Offset 0
+               OpMemberDecorate %mat4x3_f16 1 Offset 8
+               OpMemberDecorate %mat4x3_f16 2 Offset 16
+               OpMemberDecorate %mat4x3_f16 3 Offset 24
+               OpDecorate %_arr_mat4x3_f16_uint_4 ArrayStride 32
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %_arr_mat4v3half_uint_4 ArrayStride 32
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+ %mat4x3_f16 = OpTypeStruct %v3half %v3half %v3half %v3half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat4x3_f16_uint_4 = OpTypeArray %mat4x3_f16 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_mat4x3_f16_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat4v3half = OpTypeMatrix %v3half 4
+%_arr_mat4v3half_uint_4 = OpTypeArray %mat4v3half %uint_4
+%_ptr_Private__arr_mat4v3half_uint_4 = OpTypePointer Private %_arr_mat4v3half_uint_4
+         %14 = OpConstantNull %_arr_mat4v3half_uint_4
+          %p = OpVariable %_ptr_Private__arr_mat4v3half_uint_4 Private %14
+         %15 = OpTypeFunction %mat4v3half %mat4x3_f16
+         %24 = OpTypeFunction %_arr_mat4v3half_uint_4 %_arr_mat4x3_f16_uint_4
+%_ptr_Function__arr_mat4v3half_uint_4 = OpTypePointer Function %_arr_mat4v3half_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %32 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_mat4x3_f16_uint_4 = OpTypePointer Function %_arr_mat4x3_f16_uint_4
+         %45 = OpConstantNull %_arr_mat4x3_f16_uint_4
+%_ptr_Function_mat4v3half = OpTypePointer Function %mat4v3half
+%_ptr_Function_mat4x3_f16 = OpTypePointer Function %mat4x3_f16
+     %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %58 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat4x3_f16_uint_4 = OpTypePointer Uniform %_arr_mat4x3_f16_uint_4
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Private_mat4v3half = OpTypePointer Private %mat4v3half
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_mat4x3_f16 = OpTypePointer Uniform %mat4x3_f16
+         %76 = OpConstantNull %int
+%_ptr_Private_v3half = OpTypePointer Private %v3half
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+%_ptr_Private_half = OpTypePointer Private %half
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+%conv_mat4x3_f16 = OpFunction %mat4v3half None %15
+        %val = OpFunctionParameter %mat4x3_f16
+         %18 = OpLabel
+         %19 = OpCompositeExtract %v3half %val 0
+         %20 = OpCompositeExtract %v3half %val 1
+         %21 = OpCompositeExtract %v3half %val 2
+         %22 = OpCompositeExtract %v3half %val 3
+         %23 = OpCompositeConstruct %mat4v3half %19 %20 %21 %22
+               OpReturnValue %23
+               OpFunctionEnd
+%conv_arr4_mat4x3_f16 = OpFunction %_arr_mat4v3half_uint_4 None %24
+      %val_0 = OpFunctionParameter %_arr_mat4x3_f16_uint_4
+         %27 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_mat4v3half_uint_4 Function %14
+          %i = OpVariable %_ptr_Function_uint Function %32
+%var_for_index = OpVariable %_ptr_Function__arr_mat4x3_f16_uint_4 Function %45
+               OpBranch %33
+         %33 = OpLabel
+               OpLoopMerge %34 %35 None
+               OpBranch %36
+         %36 = OpLabel
+         %38 = OpLoad %uint %i
+         %39 = OpULessThan %bool %38 %uint_4
+         %37 = OpLogicalNot %bool %39
+               OpSelectionMerge %41 None
+               OpBranchConditional %37 %42 %41
+         %42 = OpLabel
+               OpBranch %34
+         %41 = OpLabel
+               OpStore %var_for_index %val_0
+         %46 = OpLoad %uint %i
+         %48 = OpAccessChain %_ptr_Function_mat4v3half %arr %46
+         %50 = OpLoad %uint %i
+         %52 = OpAccessChain %_ptr_Function_mat4x3_f16 %var_for_index %50
+         %53 = OpLoad %mat4x3_f16 %52
+         %49 = OpFunctionCall %mat4v3half %conv_mat4x3_f16 %53
+               OpStore %48 %49
+               OpBranch %35
+         %35 = OpLabel
+         %54 = OpLoad %uint %i
+         %56 = OpIAdd %uint %54 %uint_1
+               OpStore %i %56
+               OpBranch %33
+         %34 = OpLabel
+         %57 = OpLoad %_arr_mat4v3half_uint_4 %arr
+               OpReturnValue %57
+               OpFunctionEnd
+          %f = OpFunction %void None %58
+         %61 = OpLabel
+         %65 = OpAccessChain %_ptr_Uniform__arr_mat4x3_f16_uint_4 %u %uint_0
+         %66 = OpLoad %_arr_mat4x3_f16_uint_4 %65
+         %62 = OpFunctionCall %_arr_mat4v3half_uint_4 %conv_arr4_mat4x3_f16 %66
+               OpStore %p %62
+         %70 = OpAccessChain %_ptr_Private_mat4v3half %p %int_1
+         %74 = OpAccessChain %_ptr_Uniform_mat4x3_f16 %u %uint_0 %uint_2
+         %75 = OpLoad %mat4x3_f16 %74
+         %71 = OpFunctionCall %mat4v3half %conv_mat4x3_f16 %75
+               OpStore %70 %71
+         %78 = OpAccessChain %_ptr_Private_v3half %p %int_1 %76
+         %80 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0 %32 %uint_1
+         %81 = OpLoad %v3half %80
+         %82 = OpVectorShuffle %v3half %81 %81 2 0 1
+               OpStore %78 %82
+         %84 = OpAccessChain %_ptr_Private_half %p %int_1 %76 %uint_0
+         %86 = OpAccessChain %_ptr_Uniform_half %u %uint_0 %32 %uint_1 %32
+         %87 = OpLoad %half %86
+               OpStore %84 %87
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..cfa4a46
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_private.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat4x3<f16>, 4>;
+
+var<private> p : array<mat4x3<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[2];
+  p[1][0] = u[0][1].zxy;
+  p[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_storage.wgsl b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_storage.wgsl
new file mode 100644
index 0000000..1858b2a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_storage.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat4x3<f16>, 4>;
+@group(0) @binding(1) var<storage, read_write> s : array<mat4x3<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[2];
+    s[1][0] = u[0][1].zxy;
+    s[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_storage.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..a101585
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_storage.wgsl.expected.dxc.hlsl
@@ -0,0 +1,67 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[8];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 3> value) {
+  buffer.Store<vector<float16_t, 3> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 8u), value[1u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 16u), value[2u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 24u), value[3u]);
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 3> value[4]) {
+  matrix<float16_t, 4, 3> array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 32u)), array[i]);
+    }
+  }
+}
+
+matrix<float16_t, 4, 3> tint_symbol_4(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+}
+
+typedef matrix<float16_t, 4, 3> tint_symbol_3_ret[4];
+tint_symbol_3_ret tint_symbol_3(uint4 buffer[8], uint offset) {
+  matrix<float16_t, 4, 3> arr[4] = (matrix<float16_t, 4, 3>[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_4(buffer, (offset + (i_1 * 32u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_3(u, 0u));
+  tint_symbol_1(s, 32u, tint_symbol_4(u, 64u));
+  uint2 ubo_load_8 = u[0].zw;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  float16_t ubo_load_8_y = f16tof32(ubo_load_8[0] >> 16);
+  s.Store<vector<float16_t, 3> >(32u, vector<float16_t, 3>(ubo_load_8_xz[0], ubo_load_8_y, ubo_load_8_xz[1]).zxy);
+  s.Store<float16_t>(32u, float16_t(f16tof32(((u[0].z) & 0xFFFF))));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_storage.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..567a5eb
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_storage.wgsl.expected.fxc.hlsl
@@ -0,0 +1,73 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[8];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 3> value) {
+  buffer.Store<vector<float16_t, 3> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 8u), value[1u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 16u), value[2u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 24u), value[3u]);
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 3> value[4]) {
+  matrix<float16_t, 4, 3> array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 32u)), array[i]);
+    }
+  }
+}
+
+matrix<float16_t, 4, 3> tint_symbol_4(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+}
+
+typedef matrix<float16_t, 4, 3> tint_symbol_3_ret[4];
+tint_symbol_3_ret tint_symbol_3(uint4 buffer[8], uint offset) {
+  matrix<float16_t, 4, 3> arr[4] = (matrix<float16_t, 4, 3>[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_4(buffer, (offset + (i_1 * 32u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_3(u, 0u));
+  tint_symbol_1(s, 32u, tint_symbol_4(u, 64u));
+  uint2 ubo_load_8 = u[0].zw;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  float16_t ubo_load_8_y = f16tof32(ubo_load_8[0] >> 16);
+  s.Store<vector<float16_t, 3> >(32u, vector<float16_t, 3>(ubo_load_8_xz[0], ubo_load_8_y, ubo_load_8_xz[1]).zxy);
+  s.Store<float16_t>(32u, float16_t(f16tof32(((u[0].z) & 0xFFFF))));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000021F13DB33D0(6,68-76): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000021F13DB33D0(7,3-14): error X3018: invalid subscript 'Store'
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..2bf3e2f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_storage.wgsl.expected.glsl
@@ -0,0 +1,44 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct mat4x3_f16 {
+  f16vec3 col0;
+  f16vec3 col1;
+  f16vec3 col2;
+  f16vec3 col3;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  mat4x3_f16 inner[4];
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  f16mat4x3 inner[4];
+} s;
+
+f16mat4x3 conv_mat4x3_f16(mat4x3_f16 val) {
+  return f16mat4x3(val.col0, val.col1, val.col2, val.col3);
+}
+
+f16mat4x3[4] conv_arr4_mat4x3_f16(mat4x3_f16 val[4]) {
+  f16mat4x3 arr[4] = f16mat4x3[4](f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat4x3_f16(val[i]);
+    }
+  }
+  return arr;
+}
+
+void f() {
+  s.inner = conv_arr4_mat4x3_f16(u.inner);
+  s.inner[1] = conv_mat4x3_f16(u.inner[2u]);
+  s.inner[1][0] = u.inner[0u].col1.zxy;
+  s.inner[1][0].x = u.inner[0u].col1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..7405552
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_storage.wgsl.expected.msl
@@ -0,0 +1,24 @@
+#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];
+};
+
+kernel void f(device tint_array<half4x3, 4>* tint_symbol [[buffer(1)]], const constant tint_array<half4x3, 4>* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
+  (*(tint_symbol))[1][0] = half3((*(tint_symbol_1))[0][1]).zxy;
+  (*(tint_symbol))[1][0][0] = (*(tint_symbol_1))[0][1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_storage.wgsl.expected.spvasm
new file mode 100644
index 0000000..cb52845
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_storage.wgsl.expected.spvasm
@@ -0,0 +1,160 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 91
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %mat4x3_f16 "mat4x3_f16"
+               OpMemberName %mat4x3_f16 0 "col0"
+               OpMemberName %mat4x3_f16 1 "col1"
+               OpMemberName %mat4x3_f16 2 "col2"
+               OpMemberName %mat4x3_f16 3 "col3"
+               OpName %u "u"
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %s "s"
+               OpName %conv_mat4x3_f16 "conv_mat4x3_f16"
+               OpName %val "val"
+               OpName %conv_arr4_mat4x3_f16 "conv_arr4_mat4x3_f16"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %mat4x3_f16 0 Offset 0
+               OpMemberDecorate %mat4x3_f16 1 Offset 8
+               OpMemberDecorate %mat4x3_f16 2 Offset 16
+               OpMemberDecorate %mat4x3_f16 3 Offset 24
+               OpDecorate %_arr_mat4x3_f16_uint_4 ArrayStride 32
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 8
+               OpDecorate %_arr_mat4v3half_uint_4 ArrayStride 32
+               OpDecorate %s DescriptorSet 0
+               OpDecorate %s Binding 1
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+ %mat4x3_f16 = OpTypeStruct %v3half %v3half %v3half %v3half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat4x3_f16_uint_4 = OpTypeArray %mat4x3_f16 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_mat4x3_f16_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat4v3half = OpTypeMatrix %v3half 4
+%_arr_mat4v3half_uint_4 = OpTypeArray %mat4v3half %uint_4
+    %u_block = OpTypeStruct %_arr_mat4v3half_uint_4
+%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
+          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+         %15 = OpTypeFunction %mat4v3half %mat4x3_f16
+         %24 = OpTypeFunction %_arr_mat4v3half_uint_4 %_arr_mat4x3_f16_uint_4
+%_ptr_Function__arr_mat4v3half_uint_4 = OpTypePointer Function %_arr_mat4v3half_uint_4
+         %30 = OpConstantNull %_arr_mat4v3half_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %33 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_mat4x3_f16_uint_4 = OpTypePointer Function %_arr_mat4x3_f16_uint_4
+         %46 = OpConstantNull %_arr_mat4x3_f16_uint_4
+%_ptr_Function_mat4v3half = OpTypePointer Function %mat4v3half
+%_ptr_Function_mat4x3_f16 = OpTypePointer Function %mat4x3_f16
+     %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %59 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer__arr_mat4v3half_uint_4 = OpTypePointer StorageBuffer %_arr_mat4v3half_uint_4
+%_ptr_Uniform__arr_mat4x3_f16_uint_4 = OpTypePointer Uniform %_arr_mat4x3_f16_uint_4
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_mat4v3half = OpTypePointer StorageBuffer %mat4v3half
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_mat4x3_f16 = OpTypePointer Uniform %mat4x3_f16
+         %79 = OpConstantNull %int
+%_ptr_StorageBuffer_v3half = OpTypePointer StorageBuffer %v3half
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+%_ptr_StorageBuffer_half = OpTypePointer StorageBuffer %half
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+%conv_mat4x3_f16 = OpFunction %mat4v3half None %15
+        %val = OpFunctionParameter %mat4x3_f16
+         %18 = OpLabel
+         %19 = OpCompositeExtract %v3half %val 0
+         %20 = OpCompositeExtract %v3half %val 1
+         %21 = OpCompositeExtract %v3half %val 2
+         %22 = OpCompositeExtract %v3half %val 3
+         %23 = OpCompositeConstruct %mat4v3half %19 %20 %21 %22
+               OpReturnValue %23
+               OpFunctionEnd
+%conv_arr4_mat4x3_f16 = OpFunction %_arr_mat4v3half_uint_4 None %24
+      %val_0 = OpFunctionParameter %_arr_mat4x3_f16_uint_4
+         %27 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_mat4v3half_uint_4 Function %30
+          %i = OpVariable %_ptr_Function_uint Function %33
+%var_for_index = OpVariable %_ptr_Function__arr_mat4x3_f16_uint_4 Function %46
+               OpBranch %34
+         %34 = OpLabel
+               OpLoopMerge %35 %36 None
+               OpBranch %37
+         %37 = OpLabel
+         %39 = OpLoad %uint %i
+         %40 = OpULessThan %bool %39 %uint_4
+         %38 = OpLogicalNot %bool %40
+               OpSelectionMerge %42 None
+               OpBranchConditional %38 %43 %42
+         %43 = OpLabel
+               OpBranch %35
+         %42 = OpLabel
+               OpStore %var_for_index %val_0
+         %47 = OpLoad %uint %i
+         %49 = OpAccessChain %_ptr_Function_mat4v3half %arr %47
+         %51 = OpLoad %uint %i
+         %53 = OpAccessChain %_ptr_Function_mat4x3_f16 %var_for_index %51
+         %54 = OpLoad %mat4x3_f16 %53
+         %50 = OpFunctionCall %mat4v3half %conv_mat4x3_f16 %54
+               OpStore %49 %50
+               OpBranch %36
+         %36 = OpLabel
+         %55 = OpLoad %uint %i
+         %57 = OpIAdd %uint %55 %uint_1
+               OpStore %i %57
+               OpBranch %34
+         %35 = OpLabel
+         %58 = OpLoad %_arr_mat4v3half_uint_4 %arr
+               OpReturnValue %58
+               OpFunctionEnd
+          %f = OpFunction %void None %59
+         %62 = OpLabel
+         %65 = OpAccessChain %_ptr_StorageBuffer__arr_mat4v3half_uint_4 %s %uint_0
+         %68 = OpAccessChain %_ptr_Uniform__arr_mat4x3_f16_uint_4 %u %uint_0
+         %69 = OpLoad %_arr_mat4x3_f16_uint_4 %68
+         %66 = OpFunctionCall %_arr_mat4v3half_uint_4 %conv_arr4_mat4x3_f16 %69
+               OpStore %65 %66
+         %73 = OpAccessChain %_ptr_StorageBuffer_mat4v3half %s %uint_0 %int_1
+         %77 = OpAccessChain %_ptr_Uniform_mat4x3_f16 %u %uint_0 %uint_2
+         %78 = OpLoad %mat4x3_f16 %77
+         %74 = OpFunctionCall %mat4v3half %conv_mat4x3_f16 %78
+               OpStore %73 %74
+         %81 = OpAccessChain %_ptr_StorageBuffer_v3half %s %uint_0 %int_1 %79
+         %83 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0 %33 %uint_1
+         %84 = OpLoad %v3half %83
+         %85 = OpVectorShuffle %v3half %84 %84 2 0 1
+               OpStore %81 %85
+         %87 = OpAccessChain %_ptr_StorageBuffer_half %s %uint_0 %int_1 %79 %uint_0
+         %89 = OpAccessChain %_ptr_Uniform_half %u %uint_0 %33 %uint_1 %33
+         %90 = OpLoad %half %89
+               OpStore %87 %90
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..3ff7968
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat4x3<f16>, 4>;
+
+@group(0) @binding(1) var<storage, read_write> s : array<mat4x3<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[2];
+  s[1][0] = u[0][1].zxy;
+  s[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_workgroup.wgsl
new file mode 100644
index 0000000..faaeba5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_workgroup.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat4x3<f16>, 4>;
+var<workgroup> w : array<mat4x3<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[2];
+    w[1][0] = u[0][1].zxy;
+    w[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_workgroup.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..6024dea
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_workgroup.wgsl.expected.dxc.hlsl
@@ -0,0 +1,66 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[8];
+};
+groupshared matrix<float16_t, 4, 3> w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 4, 3> tint_symbol_3(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+}
+
+typedef matrix<float16_t, 4, 3> tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[8], uint offset) {
+  matrix<float16_t, 4, 3> arr[4] = (matrix<float16_t, 4, 3>[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 32u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      w[i] = matrix<float16_t, 4, 3>((float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx);
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 64u);
+  uint2 ubo_load_8 = u[0].zw;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  float16_t ubo_load_8_y = f16tof32(ubo_load_8[0] >> 16);
+  w[1][0] = vector<float16_t, 3>(ubo_load_8_xz[0], ubo_load_8_y, ubo_load_8_xz[1]).zxy;
+  w[1][0].x = float16_t(f16tof32(((u[0].z) & 0xFFFF)));
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_workgroup.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..3f7cf0d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_workgroup.wgsl.expected.fxc.hlsl
@@ -0,0 +1,71 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[8];
+};
+groupshared matrix<float16_t, 4, 3> w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 4, 3> tint_symbol_3(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+}
+
+typedef matrix<float16_t, 4, 3> tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[8], uint offset) {
+  matrix<float16_t, 4, 3> arr[4] = (matrix<float16_t, 4, 3>[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 32u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      w[i] = matrix<float16_t, 4, 3>((float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx);
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 64u);
+  uint2 ubo_load_8 = u[0].zw;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  float16_t ubo_load_8_y = f16tof32(ubo_load_8[0] >> 16);
+  w[1][0] = vector<float16_t, 3>(ubo_load_8_xz[0], ubo_load_8_y, ubo_load_8_xz[1]).zxy;
+  w[1][0].x = float16_t(f16tof32(((u[0].z) & 0xFFFF)));
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001D6F2EDF360(4,20-28): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..ebe86ff
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,48 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct mat4x3_f16 {
+  f16vec3 col0;
+  f16vec3 col1;
+  f16vec3 col2;
+  f16vec3 col3;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  mat4x3_f16 inner[4];
+} u;
+
+shared f16mat4x3 w[4];
+f16mat4x3 conv_mat4x3_f16(mat4x3_f16 val) {
+  return f16mat4x3(val.col0, val.col1, val.col2, val.col3);
+}
+
+f16mat4x3[4] conv_arr4_mat4x3_f16(mat4x3_f16 val[4]) {
+  f16mat4x3 arr[4] = f16mat4x3[4](f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat4x3_f16(val[i]);
+    }
+  }
+  return arr;
+}
+
+void f(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      uint i = idx;
+      w[i] = f16mat4x3(f16vec3(0.0hf), f16vec3(0.0hf), f16vec3(0.0hf), f16vec3(0.0hf));
+    }
+  }
+  barrier();
+  w = conv_arr4_mat4x3_f16(u.inner);
+  w[1] = conv_mat4x3_f16(u.inner[2u]);
+  w[1][0] = u.inner[0u].col1.zxy;
+  w[1][0].x = u.inner[0u].col1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..5db2fda
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,38 @@
+#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_symbol_5 {
+  tint_array<half4x3, 4> w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup tint_array<half4x3, 4>* const tint_symbol, const constant tint_array<half4x3, 4>* const tint_symbol_1) {
+  for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+    uint const i = idx;
+    (*(tint_symbol))[i] = half4x3(half3(0.0h), half3(0.0h), half3(0.0h), half3(0.0h));
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
+  (*(tint_symbol))[1][0] = half3((*(tint_symbol_1))[0][1]).zxy;
+  (*(tint_symbol))[1][0][0] = (*(tint_symbol_1))[0][1][0];
+}
+
+kernel void f(const constant tint_array<half4x3, 4>* tint_symbol_4 [[buffer(0)]], threadgroup tint_symbol_5* tint_symbol_3 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup tint_array<half4x3, 4>* const tint_symbol_2 = &((*(tint_symbol_3)).w);
+  f_inner(local_invocation_index, tint_symbol_2, tint_symbol_4);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_workgroup.wgsl.expected.spvasm
new file mode 100644
index 0000000..335346f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_workgroup.wgsl.expected.spvasm
@@ -0,0 +1,192 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 113
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %local_invocation_index_1 "local_invocation_index_1"
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %mat4x3_f16 "mat4x3_f16"
+               OpMemberName %mat4x3_f16 0 "col0"
+               OpMemberName %mat4x3_f16 1 "col1"
+               OpMemberName %mat4x3_f16 2 "col2"
+               OpMemberName %mat4x3_f16 3 "col3"
+               OpName %u "u"
+               OpName %w "w"
+               OpName %conv_mat4x3_f16 "conv_mat4x3_f16"
+               OpName %val "val"
+               OpName %conv_arr4_mat4x3_f16 "conv_arr4_mat4x3_f16"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %f_inner "f_inner"
+               OpName %local_invocation_index "local_invocation_index"
+               OpName %idx "idx"
+               OpName %f "f"
+               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %mat4x3_f16 0 Offset 0
+               OpMemberDecorate %mat4x3_f16 1 Offset 8
+               OpMemberDecorate %mat4x3_f16 2 Offset 16
+               OpMemberDecorate %mat4x3_f16 3 Offset 24
+               OpDecorate %_arr_mat4x3_f16_uint_4 ArrayStride 32
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %_arr_mat4v3half_uint_4 ArrayStride 32
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+ %mat4x3_f16 = OpTypeStruct %v3half %v3half %v3half %v3half
+     %uint_4 = OpConstant %uint 4
+%_arr_mat4x3_f16_uint_4 = OpTypeArray %mat4x3_f16 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_mat4x3_f16_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat4v3half = OpTypeMatrix %v3half 4
+%_arr_mat4v3half_uint_4 = OpTypeArray %mat4v3half %uint_4
+%_ptr_Workgroup__arr_mat4v3half_uint_4 = OpTypePointer Workgroup %_arr_mat4v3half_uint_4
+          %w = OpVariable %_ptr_Workgroup__arr_mat4v3half_uint_4 Workgroup
+         %16 = OpTypeFunction %mat4v3half %mat4x3_f16
+         %25 = OpTypeFunction %_arr_mat4v3half_uint_4 %_arr_mat4x3_f16_uint_4
+%_ptr_Function__arr_mat4v3half_uint_4 = OpTypePointer Function %_arr_mat4v3half_uint_4
+         %31 = OpConstantNull %_arr_mat4v3half_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %34 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_mat4x3_f16_uint_4 = OpTypePointer Function %_arr_mat4x3_f16_uint_4
+         %47 = OpConstantNull %_arr_mat4x3_f16_uint_4
+%_ptr_Function_mat4v3half = OpTypePointer Function %mat4v3half
+%_ptr_Function_mat4x3_f16 = OpTypePointer Function %mat4x3_f16
+     %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %60 = OpTypeFunction %void %uint
+%_ptr_Workgroup_mat4v3half = OpTypePointer Workgroup %mat4v3half
+         %78 = OpConstantNull %mat4v3half
+     %uint_2 = OpConstant %uint 2
+   %uint_264 = OpConstant %uint 264
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat4x3_f16_uint_4 = OpTypePointer Uniform %_arr_mat4x3_f16_uint_4
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_mat4x3_f16 = OpTypePointer Uniform %mat4x3_f16
+         %96 = OpConstantNull %int
+%_ptr_Workgroup_v3half = OpTypePointer Workgroup %v3half
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+%_ptr_Workgroup_half = OpTypePointer Workgroup %half
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+        %108 = OpTypeFunction %void
+%conv_mat4x3_f16 = OpFunction %mat4v3half None %16
+        %val = OpFunctionParameter %mat4x3_f16
+         %19 = OpLabel
+         %20 = OpCompositeExtract %v3half %val 0
+         %21 = OpCompositeExtract %v3half %val 1
+         %22 = OpCompositeExtract %v3half %val 2
+         %23 = OpCompositeExtract %v3half %val 3
+         %24 = OpCompositeConstruct %mat4v3half %20 %21 %22 %23
+               OpReturnValue %24
+               OpFunctionEnd
+%conv_arr4_mat4x3_f16 = OpFunction %_arr_mat4v3half_uint_4 None %25
+      %val_0 = OpFunctionParameter %_arr_mat4x3_f16_uint_4
+         %28 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_mat4v3half_uint_4 Function %31
+          %i = OpVariable %_ptr_Function_uint Function %34
+%var_for_index = OpVariable %_ptr_Function__arr_mat4x3_f16_uint_4 Function %47
+               OpBranch %35
+         %35 = OpLabel
+               OpLoopMerge %36 %37 None
+               OpBranch %38
+         %38 = OpLabel
+         %40 = OpLoad %uint %i
+         %41 = OpULessThan %bool %40 %uint_4
+         %39 = OpLogicalNot %bool %41
+               OpSelectionMerge %43 None
+               OpBranchConditional %39 %44 %43
+         %44 = OpLabel
+               OpBranch %36
+         %43 = OpLabel
+               OpStore %var_for_index %val_0
+         %48 = OpLoad %uint %i
+         %50 = OpAccessChain %_ptr_Function_mat4v3half %arr %48
+         %52 = OpLoad %uint %i
+         %54 = OpAccessChain %_ptr_Function_mat4x3_f16 %var_for_index %52
+         %55 = OpLoad %mat4x3_f16 %54
+         %51 = OpFunctionCall %mat4v3half %conv_mat4x3_f16 %55
+               OpStore %50 %51
+               OpBranch %37
+         %37 = OpLabel
+         %56 = OpLoad %uint %i
+         %58 = OpIAdd %uint %56 %uint_1
+               OpStore %i %58
+               OpBranch %35
+         %36 = OpLabel
+         %59 = OpLoad %_arr_mat4v3half_uint_4 %arr
+               OpReturnValue %59
+               OpFunctionEnd
+    %f_inner = OpFunction %void None %60
+%local_invocation_index = OpFunctionParameter %uint
+         %64 = OpLabel
+        %idx = OpVariable %_ptr_Function_uint Function %34
+               OpStore %idx %local_invocation_index
+               OpBranch %66
+         %66 = OpLabel
+               OpLoopMerge %67 %68 None
+               OpBranch %69
+         %69 = OpLabel
+         %71 = OpLoad %uint %idx
+         %72 = OpULessThan %bool %71 %uint_4
+         %70 = OpLogicalNot %bool %72
+               OpSelectionMerge %73 None
+               OpBranchConditional %70 %74 %73
+         %74 = OpLabel
+               OpBranch %67
+         %73 = OpLabel
+         %75 = OpLoad %uint %idx
+         %77 = OpAccessChain %_ptr_Workgroup_mat4v3half %w %75
+               OpStore %77 %78
+               OpBranch %68
+         %68 = OpLabel
+         %79 = OpLoad %uint %idx
+         %80 = OpIAdd %uint %79 %uint_1
+               OpStore %idx %80
+               OpBranch %66
+         %67 = OpLabel
+               OpControlBarrier %uint_2 %uint_2 %uint_264
+         %87 = OpAccessChain %_ptr_Uniform__arr_mat4x3_f16_uint_4 %u %uint_0
+         %88 = OpLoad %_arr_mat4x3_f16_uint_4 %87
+         %84 = OpFunctionCall %_arr_mat4v3half_uint_4 %conv_arr4_mat4x3_f16 %88
+               OpStore %w %84
+         %91 = OpAccessChain %_ptr_Workgroup_mat4v3half %w %int_1
+         %94 = OpAccessChain %_ptr_Uniform_mat4x3_f16 %u %uint_0 %uint_2
+         %95 = OpLoad %mat4x3_f16 %94
+         %92 = OpFunctionCall %mat4v3half %conv_mat4x3_f16 %95
+               OpStore %91 %92
+         %98 = OpAccessChain %_ptr_Workgroup_v3half %w %int_1 %96
+        %100 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0 %34 %uint_1
+        %101 = OpLoad %v3half %100
+        %102 = OpVectorShuffle %v3half %101 %101 2 0 1
+               OpStore %98 %102
+        %104 = OpAccessChain %_ptr_Workgroup_half %w %int_1 %96 %uint_0
+        %106 = OpAccessChain %_ptr_Uniform_half %u %uint_0 %34 %uint_1 %34
+        %107 = OpLoad %half %106
+               OpStore %104 %107
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %108
+        %110 = OpLabel
+        %112 = OpLoad %uint %local_invocation_index_1
+        %111 = OpFunctionCall %void %f_inner %112
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..39cd472
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f16/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat4x3<f16>, 4>;
+
+var<workgroup> w : array<mat4x3<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[2];
+  w[1][0] = u[0][1].zxy;
+  w[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/array/mat4x3_f32/dynamic_index_via_ptr.wgsl
new file mode 100644
index 0000000..f1ae5b2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/dynamic_index_via_ptr.wgsl
@@ -0,0 +1,15 @@
+@group(0) @binding(0) var<uniform> a : array<mat4x3<f32>, 4>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a       = &a;
+  let p_a_i     = &((*p_a)[i()]);
+  let p_a_i_i   = &((*p_a_i)[i()]);
+
+  let l_a       : array<mat4x3<f32>, 4> = *p_a;
+  let l_a_i     : mat4x3<f32>           = *p_a_i;
+  let l_a_i_i   : vec3<f32>             = *p_a_i_i;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..0d9daa8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,39 @@
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[16];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float4x3 tint_symbol_1(uint4 buffer[16], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+typedef float4x3 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[16], uint offset) {
+  float4x3 arr[4] = (float4x3[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_i_save = i();
+  const float4x3 l_a[4] = tint_symbol(a, 0u);
+  const float4x3 l_a_i = tint_symbol_1(a, (64u * uint(p_a_i_save)));
+  const uint scalar_offset_4 = (((64u * uint(p_a_i_save)) + (16u * uint(p_a_i_i_save)))) / 4;
+  const float3 l_a_i_i = asfloat(a[scalar_offset_4 / 4].xyz);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..0d9daa8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,39 @@
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[16];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float4x3 tint_symbol_1(uint4 buffer[16], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+typedef float4x3 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[16], uint offset) {
+  float4x3 arr[4] = (float4x3[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_i_save = i();
+  const float4x3 l_a[4] = tint_symbol(a, 0u);
+  const float4x3 l_a_i = tint_symbol_1(a, (64u * uint(p_a_i_save)));
+  const uint scalar_offset_4 = (((64u * uint(p_a_i_save)) + (16u * uint(p_a_i_i_save)))) / 4;
+  const float3 l_a_i_i = asfloat(a[scalar_offset_4 / 4].xyz);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..5a78b8c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,27 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform a_block_ubo {
+  mat4x3 inner[4];
+} a;
+
+int counter = 0;
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+void f() {
+  int tint_symbol = i();
+  int p_a_i_save = tint_symbol;
+  int tint_symbol_1 = i();
+  int p_a_i_i_save = tint_symbol_1;
+  mat4x3 l_a[4] = a.inner;
+  mat4x3 l_a_i = a.inner[p_a_i_save];
+  vec3 l_a_i_i = a.inner[p_a_i_save][p_a_i_i_save];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..0c60210
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,33 @@
+#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];
+};
+
+int i() {
+  thread int tint_symbol_2 = 0;
+  tint_symbol_2 = as_type<int>((as_type<uint>(tint_symbol_2) + as_type<uint>(1)));
+  return tint_symbol_2;
+}
+
+kernel void f(const constant tint_array<float4x3, 4>* tint_symbol_3 [[buffer(0)]]) {
+  int const tint_symbol = i();
+  int const p_a_i_save = tint_symbol;
+  int const tint_symbol_1 = i();
+  int const p_a_i_i_save = tint_symbol_1;
+  tint_array<float4x3, 4> const l_a = *(tint_symbol_3);
+  float4x3 const l_a_i = (*(tint_symbol_3))[p_a_i_save];
+  float3 const l_a_i_i = (*(tint_symbol_3))[p_a_i_save][p_a_i_i_save];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..e1fda42
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,64 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 37
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block "a_block"
+               OpMemberName %a_block 0 "inner"
+               OpName %a "a"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %f "f"
+               OpDecorate %a_block Block
+               OpMemberDecorate %a_block 0 Offset 0
+               OpMemberDecorate %a_block 0 ColMajor
+               OpMemberDecorate %a_block 0 MatrixStride 16
+               OpDecorate %_arr_mat4v3float_uint_4 ArrayStride 64
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat4v3float = OpTypeMatrix %v3float 4
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat4v3float_uint_4 = OpTypeArray %mat4v3float %uint_4
+    %a_block = OpTypeStruct %_arr_mat4v3float_uint_4
+%_ptr_Uniform_a_block = OpTypePointer Uniform %a_block
+          %a = OpVariable %_ptr_Uniform_a_block Uniform
+        %int = OpTypeInt 32 1
+         %11 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %11
+         %14 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+       %void = OpTypeVoid
+         %21 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat4v3float_uint_4 = OpTypePointer Uniform %_arr_mat4v3float_uint_4
+%_ptr_Uniform_mat4v3float = OpTypePointer Uniform %mat4v3float
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+          %i = OpFunction %int None %14
+         %16 = OpLabel
+         %17 = OpLoad %int %counter
+         %19 = OpIAdd %int %17 %int_1
+               OpStore %counter %19
+         %20 = OpLoad %int %counter
+               OpReturnValue %20
+               OpFunctionEnd
+          %f = OpFunction %void None %21
+         %24 = OpLabel
+         %25 = OpFunctionCall %int %i
+         %26 = OpFunctionCall %int %i
+         %29 = OpAccessChain %_ptr_Uniform__arr_mat4v3float_uint_4 %a %uint_0
+         %30 = OpLoad %_arr_mat4v3float_uint_4 %29
+         %32 = OpAccessChain %_ptr_Uniform_mat4v3float %a %uint_0 %25
+         %33 = OpLoad %mat4v3float %32
+         %35 = OpAccessChain %_ptr_Uniform_v3float %a %uint_0 %25 %26
+         %36 = OpLoad %v3float %35
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..aa2b7eb
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+@group(0) @binding(0) var<uniform> a : array<mat4x3<f32>, 4>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_i = &((*(p_a))[i()]);
+  let p_a_i_i = &((*(p_a_i))[i()]);
+  let l_a : array<mat4x3<f32>, 4> = *(p_a);
+  let l_a_i : mat4x3<f32> = *(p_a_i);
+  let l_a_i_i : vec3<f32> = *(p_a_i_i);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/array/mat4x3_f32/static_index_via_ptr.wgsl
new file mode 100644
index 0000000..47ec86d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/static_index_via_ptr.wgsl
@@ -0,0 +1,12 @@
+@group(0) @binding(0) var<uniform> a : array<mat4x3<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a       = &a;
+  let p_a_2     = &((*p_a)[2]);
+  let p_a_2_1   = &((*p_a_2)[1]);
+
+  let l_a       : array<mat4x3<f32>, 4> = *p_a;
+  let l_a_i     : mat4x3<f32>           = *p_a_2;
+  let l_a_i_i   : vec3<f32>             = *p_a_2_1;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x3_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..7b865c6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,30 @@
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[16];
+};
+
+float4x3 tint_symbol_1(uint4 buffer[16], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+typedef float4x3 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[16], uint offset) {
+  float4x3 arr[4] = (float4x3[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float4x3 l_a[4] = tint_symbol(a, 0u);
+  const float4x3 l_a_i = tint_symbol_1(a, 128u);
+  const float3 l_a_i_i = asfloat(a[9].xyz);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x3_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..7b865c6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,30 @@
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[16];
+};
+
+float4x3 tint_symbol_1(uint4 buffer[16], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+typedef float4x3 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[16], uint offset) {
+  float4x3 arr[4] = (float4x3[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float4x3 l_a[4] = tint_symbol(a, 0u);
+  const float4x3 l_a_i = tint_symbol_1(a, 128u);
+  const float3 l_a_i_i = asfloat(a[9].xyz);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x3_f32/static_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..f4c0c5c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/static_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,17 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform a_block_ubo {
+  mat4x3 inner[4];
+} a;
+
+void f() {
+  mat4x3 l_a[4] = a.inner;
+  mat4x3 l_a_i = a.inner[2];
+  vec3 l_a_i_i = a.inner[2][1];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat4x3_f32/static_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..0b5148e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/static_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,23 @@
+#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];
+};
+
+kernel void f(const constant tint_array<float4x3, 4>* tint_symbol [[buffer(0)]]) {
+  tint_array<float4x3, 4> const l_a = *(tint_symbol);
+  float4x3 const l_a_i = (*(tint_symbol))[2];
+  float3 const l_a_i_i = (*(tint_symbol))[2][1];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x3_f32/static_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..d03dc81
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/static_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,49 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 27
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block "a_block"
+               OpMemberName %a_block 0 "inner"
+               OpName %a "a"
+               OpName %f "f"
+               OpDecorate %a_block Block
+               OpMemberDecorate %a_block 0 Offset 0
+               OpMemberDecorate %a_block 0 ColMajor
+               OpMemberDecorate %a_block 0 MatrixStride 16
+               OpDecorate %_arr_mat4v3float_uint_4 ArrayStride 64
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat4v3float = OpTypeMatrix %v3float 4
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat4v3float_uint_4 = OpTypeArray %mat4v3float %uint_4
+    %a_block = OpTypeStruct %_arr_mat4v3float_uint_4
+%_ptr_Uniform_a_block = OpTypePointer Uniform %a_block
+          %a = OpVariable %_ptr_Uniform_a_block Uniform
+       %void = OpTypeVoid
+         %10 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat4v3float_uint_4 = OpTypePointer Uniform %_arr_mat4v3float_uint_4
+        %int = OpTypeInt 32 1
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_mat4v3float = OpTypePointer Uniform %mat4v3float
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+          %f = OpFunction %void None %10
+         %13 = OpLabel
+         %16 = OpAccessChain %_ptr_Uniform__arr_mat4v3float_uint_4 %a %uint_0
+         %17 = OpLoad %_arr_mat4v3float_uint_4 %16
+         %21 = OpAccessChain %_ptr_Uniform_mat4v3float %a %uint_0 %int_2
+         %22 = OpLoad %mat4v3float %21
+         %25 = OpAccessChain %_ptr_Uniform_v3float %a %uint_0 %int_2 %int_1
+         %26 = OpLoad %v3float %25
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat4x3_f32/static_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..bfe8256
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/static_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> a : array<mat4x3<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_2 = &((*(p_a))[2]);
+  let p_a_2_1 = &((*(p_a_2))[1]);
+  let l_a : array<mat4x3<f32>, 4> = *(p_a);
+  let l_a_i : mat4x3<f32> = *(p_a_2);
+  let l_a_i_i : vec3<f32> = *(p_a_2_1);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_builtin.wgsl b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_builtin.wgsl
new file mode 100644
index 0000000..d354ee8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_builtin.wgsl
@@ -0,0 +1,8 @@
+@group(0) @binding(0) var<uniform> u : array<mat4x3<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    let t = transpose(u[2]);
+    let l = length(u[0][1].zxy);
+    let a = abs(u[0][1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_builtin.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..f398365
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_builtin.wgsl.expected.dxc.hlsl
@@ -0,0 +1,19 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[16];
+};
+
+float4x3 tint_symbol(uint4 buffer[16], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float3x4 t = transpose(tint_symbol(u, 128u));
+  const float l = length(asfloat(u[1].xyz).zxy);
+  const float a = abs(asfloat(u[1].xyz).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_builtin.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..f398365
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_builtin.wgsl.expected.fxc.hlsl
@@ -0,0 +1,19 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[16];
+};
+
+float4x3 tint_symbol(uint4 buffer[16], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float3x4 t = transpose(tint_symbol(u, 128u));
+  const float l = length(asfloat(u[1].xyz).zxy);
+  const float a = abs(asfloat(u[1].xyz).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_builtin.wgsl.expected.glsl
new file mode 100644
index 0000000..fb08583
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_builtin.wgsl.expected.glsl
@@ -0,0 +1,17 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat4x3 inner[4];
+} u;
+
+void f() {
+  mat3x4 t = transpose(u.inner[2]);
+  float l = length(u.inner[0][1].zxy);
+  float a = abs(u.inner[0][1].zxy.x);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_builtin.wgsl.expected.msl
new file mode 100644
index 0000000..3edd8e3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_builtin.wgsl.expected.msl
@@ -0,0 +1,23 @@
+#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];
+};
+
+kernel void f(const constant tint_array<float4x3, 4>* tint_symbol [[buffer(0)]]) {
+  float3x4 const t = transpose((*(tint_symbol))[2]);
+  float const l = length(float3((*(tint_symbol))[0][1]).zxy);
+  float const a = fabs(float3((*(tint_symbol))[0][1]).zxy[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_builtin.wgsl.expected.spvasm
new file mode 100644
index 0000000..018984f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_builtin.wgsl.expected.spvasm
@@ -0,0 +1,58 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 36
+; Schema: 0
+               OpCapability Shader
+         %24 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %_arr_mat4v3float_uint_4 ArrayStride 64
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat4v3float = OpTypeMatrix %v3float 4
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat4v3float_uint_4 = OpTypeArray %mat4v3float %uint_4
+    %u_block = OpTypeStruct %_arr_mat4v3float_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+         %10 = OpTypeFunction %void
+    %v4float = OpTypeVector %float 4
+%mat3v4float = OpTypeMatrix %v4float 3
+     %uint_0 = OpConstant %uint 0
+        %int = OpTypeInt 32 1
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_mat4v3float = OpTypePointer Uniform %mat4v3float
+         %25 = OpConstantNull %int
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+          %f = OpFunction %void None %10
+         %13 = OpLabel
+         %21 = OpAccessChain %_ptr_Uniform_mat4v3float %u %uint_0 %int_2
+         %22 = OpLoad %mat4v3float %21
+         %14 = OpTranspose %mat3v4float %22
+         %28 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %25 %int_1
+         %29 = OpLoad %v3float %28
+         %30 = OpVectorShuffle %v3float %29 %29 2 0 1
+         %23 = OpExtInst %float %24 Length %30
+         %32 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %25 %int_1
+         %33 = OpLoad %v3float %32
+         %34 = OpVectorShuffle %v3float %33 %33 2 0 1
+         %35 = OpCompositeExtract %float %34 0
+         %31 = OpExtInst %float %24 FAbs %35
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_builtin.wgsl.expected.wgsl
new file mode 100644
index 0000000..87104e4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_builtin.wgsl.expected.wgsl
@@ -0,0 +1,8 @@
+@group(0) @binding(0) var<uniform> u : array<mat4x3<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let t = transpose(u[2]);
+  let l = length(u[0][1].zxy);
+  let a = abs(u[0][1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_fn.wgsl b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_fn.wgsl
new file mode 100644
index 0000000..59de93c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_fn.wgsl
@@ -0,0 +1,14 @@
+@group(0) @binding(0) var<uniform> u : array<mat4x3<f32>, 4>;
+
+fn a(a : array<mat4x3<f32>, 4>) {}
+fn b(m : mat4x3<f32>) {}
+fn c(v : vec3<f32>) {}
+fn d(f : f32) {}
+
+@compute @workgroup_size(1)
+fn f() {
+    a(u);
+    b(u[1]);
+    c(u[1][0].zxy);
+    d(u[1][0].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_fn.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..c1ac4a6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_fn.wgsl.expected.dxc.hlsl
@@ -0,0 +1,43 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[16];
+};
+
+void a(float4x3 a_1[4]) {
+}
+
+void b(float4x3 m) {
+}
+
+void c(float3 v) {
+}
+
+void d(float f_1) {
+}
+
+float4x3 tint_symbol_1(uint4 buffer[16], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+typedef float4x3 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[16], uint offset) {
+  float4x3 arr[4] = (float4x3[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 64u));
+  c(asfloat(u[4].xyz).zxy);
+  d(asfloat(u[4].xyz).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_fn.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..c1ac4a6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_fn.wgsl.expected.fxc.hlsl
@@ -0,0 +1,43 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[16];
+};
+
+void a(float4x3 a_1[4]) {
+}
+
+void b(float4x3 m) {
+}
+
+void c(float3 v) {
+}
+
+void d(float f_1) {
+}
+
+float4x3 tint_symbol_1(uint4 buffer[16], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+typedef float4x3 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[16], uint offset) {
+  float4x3 arr[4] = (float4x3[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 64u));
+  c(asfloat(u[4].xyz).zxy);
+  d(asfloat(u[4].xyz).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_fn.wgsl.expected.glsl
new file mode 100644
index 0000000..6458ea6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_fn.wgsl.expected.glsl
@@ -0,0 +1,30 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat4x3 inner[4];
+} u;
+
+void a(mat4x3 a_1[4]) {
+}
+
+void b(mat4x3 m) {
+}
+
+void c(vec3 v) {
+}
+
+void d(float f_1) {
+}
+
+void f() {
+  a(u.inner);
+  b(u.inner[1]);
+  c(u.inner[1][0].zxy);
+  d(u.inner[1][0].zxy.x);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_fn.wgsl.expected.msl
new file mode 100644
index 0000000..f2f446e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_fn.wgsl.expected.msl
@@ -0,0 +1,36 @@
+#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];
+};
+
+void a(tint_array<float4x3, 4> a_1) {
+}
+
+void b(float4x3 m) {
+}
+
+void c(float3 v) {
+}
+
+void d(float f_1) {
+}
+
+kernel void f(const constant tint_array<float4x3, 4>* tint_symbol [[buffer(0)]]) {
+  a(*(tint_symbol));
+  b((*(tint_symbol))[1]);
+  c(float3((*(tint_symbol))[1][0]).zxy);
+  d(float3((*(tint_symbol))[1][0]).zxy[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_fn.wgsl.expected.spvasm
new file mode 100644
index 0000000..15aa728
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_fn.wgsl.expected.spvasm
@@ -0,0 +1,90 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 52
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %a "a"
+               OpName %a_1 "a_1"
+               OpName %b "b"
+               OpName %m "m"
+               OpName %c "c"
+               OpName %v "v"
+               OpName %d "d"
+               OpName %f_1 "f_1"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %_arr_mat4v3float_uint_4 ArrayStride 64
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat4v3float = OpTypeMatrix %v3float 4
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat4v3float_uint_4 = OpTypeArray %mat4v3float %uint_4
+    %u_block = OpTypeStruct %_arr_mat4v3float_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+         %10 = OpTypeFunction %void %_arr_mat4v3float_uint_4
+         %15 = OpTypeFunction %void %mat4v3float
+         %19 = OpTypeFunction %void %v3float
+         %23 = OpTypeFunction %void %float
+         %27 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat4v3float_uint_4 = OpTypePointer Uniform %_arr_mat4v3float_uint_4
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_mat4v3float = OpTypePointer Uniform %mat4v3float
+         %42 = OpConstantNull %int
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+          %a = OpFunction %void None %10
+        %a_1 = OpFunctionParameter %_arr_mat4v3float_uint_4
+         %14 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %b = OpFunction %void None %15
+          %m = OpFunctionParameter %mat4v3float
+         %18 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %c = OpFunction %void None %19
+          %v = OpFunctionParameter %v3float
+         %22 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %d = OpFunction %void None %23
+        %f_1 = OpFunctionParameter %float
+         %26 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %27
+         %29 = OpLabel
+         %33 = OpAccessChain %_ptr_Uniform__arr_mat4v3float_uint_4 %u %uint_0
+         %34 = OpLoad %_arr_mat4v3float_uint_4 %33
+         %30 = OpFunctionCall %void %a %34
+         %39 = OpAccessChain %_ptr_Uniform_mat4v3float %u %uint_0 %int_1
+         %40 = OpLoad %mat4v3float %39
+         %35 = OpFunctionCall %void %b %40
+         %44 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %int_1 %42
+         %45 = OpLoad %v3float %44
+         %46 = OpVectorShuffle %v3float %45 %45 2 0 1
+         %41 = OpFunctionCall %void %c %46
+         %48 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %int_1 %42
+         %49 = OpLoad %v3float %48
+         %50 = OpVectorShuffle %v3float %49 %49 2 0 1
+         %51 = OpCompositeExtract %float %50 0
+         %47 = OpFunctionCall %void %d %51
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_fn.wgsl.expected.wgsl
new file mode 100644
index 0000000..db050c9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_fn.wgsl.expected.wgsl
@@ -0,0 +1,21 @@
+@group(0) @binding(0) var<uniform> u : array<mat4x3<f32>, 4>;
+
+fn a(a : array<mat4x3<f32>, 4>) {
+}
+
+fn b(m : mat4x3<f32>) {
+}
+
+fn c(v : vec3<f32>) {
+}
+
+fn d(f : f32) {
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  a(u);
+  b(u[1]);
+  c(u[1][0].zxy);
+  d(u[1][0].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_private.wgsl b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_private.wgsl
new file mode 100644
index 0000000..eab66b0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_private.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0) var<uniform> u : array<mat4x3<f32>, 4>;
+var<private> p : array<mat4x3<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[2];
+    p[1][0] = u[0][1].zxy;
+    p[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_private.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..5236d8f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_private.wgsl.expected.dxc.hlsl
@@ -0,0 +1,32 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[16];
+};
+static float4x3 p[4] = (float4x3[4])0;
+
+float4x3 tint_symbol_1(uint4 buffer[16], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+typedef float4x3 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[16], uint offset) {
+  float4x3 arr[4] = (float4x3[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 128u);
+  p[1][0] = asfloat(u[1].xyz).zxy;
+  p[1][0].x = asfloat(u[1].x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_private.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..5236d8f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_private.wgsl.expected.fxc.hlsl
@@ -0,0 +1,32 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[16];
+};
+static float4x3 p[4] = (float4x3[4])0;
+
+float4x3 tint_symbol_1(uint4 buffer[16], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+typedef float4x3 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[16], uint offset) {
+  float4x3 arr[4] = (float4x3[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 128u);
+  p[1][0] = asfloat(u[1].xyz).zxy;
+  p[1][0].x = asfloat(u[1].x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..6c91e16
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_private.wgsl.expected.glsl
@@ -0,0 +1,19 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat4x3 inner[4];
+} u;
+
+mat4x3 p[4] = mat4x3[4](mat4x3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4x3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
+void f() {
+  p = u.inner;
+  p[1] = u.inner[2];
+  p[1][0] = u.inner[0][1].zxy;
+  p[1][0].x = u.inner[0][1].x;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..cfb8e04
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_private.wgsl.expected.msl
@@ -0,0 +1,25 @@
+#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];
+};
+
+kernel void f(const constant tint_array<float4x3, 4>* tint_symbol_1 [[buffer(0)]]) {
+  thread tint_array<float4x3, 4> tint_symbol = {};
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[2];
+  tint_symbol[1][0] = float3((*(tint_symbol_1))[0][1]).zxy;
+  tint_symbol[1][0][0] = (*(tint_symbol_1))[0][1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_private.wgsl.expected.spvasm
new file mode 100644
index 0000000..aed5708
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_private.wgsl.expected.spvasm
@@ -0,0 +1,68 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 41
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %p "p"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %_arr_mat4v3float_uint_4 ArrayStride 64
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat4v3float = OpTypeMatrix %v3float 4
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat4v3float_uint_4 = OpTypeArray %mat4v3float %uint_4
+    %u_block = OpTypeStruct %_arr_mat4v3float_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_Private__arr_mat4v3float_uint_4 = OpTypePointer Private %_arr_mat4v3float_uint_4
+         %12 = OpConstantNull %_arr_mat4v3float_uint_4
+          %p = OpVariable %_ptr_Private__arr_mat4v3float_uint_4 Private %12
+       %void = OpTypeVoid
+         %13 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat4v3float_uint_4 = OpTypePointer Uniform %_arr_mat4v3float_uint_4
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Private_mat4v3float = OpTypePointer Private %mat4v3float
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_mat4v3float = OpTypePointer Uniform %mat4v3float
+         %29 = OpConstantNull %int
+%_ptr_Private_v3float = OpTypePointer Private %v3float
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+%_ptr_Private_float = OpTypePointer Private %float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+          %f = OpFunction %void None %13
+         %16 = OpLabel
+         %19 = OpAccessChain %_ptr_Uniform__arr_mat4v3float_uint_4 %u %uint_0
+         %20 = OpLoad %_arr_mat4v3float_uint_4 %19
+               OpStore %p %20
+         %24 = OpAccessChain %_ptr_Private_mat4v3float %p %int_1
+         %27 = OpAccessChain %_ptr_Uniform_mat4v3float %u %uint_0 %int_2
+         %28 = OpLoad %mat4v3float %27
+               OpStore %24 %28
+         %31 = OpAccessChain %_ptr_Private_v3float %p %int_1 %29
+         %33 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %29 %int_1
+         %34 = OpLoad %v3float %33
+         %35 = OpVectorShuffle %v3float %34 %34 2 0 1
+               OpStore %31 %35
+         %37 = OpAccessChain %_ptr_Private_float %p %int_1 %29 %uint_0
+         %39 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %29 %int_1 %uint_0
+         %40 = OpLoad %float %39
+               OpStore %37 %40
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..2c89745
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_private.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> u : array<mat4x3<f32>, 4>;
+
+var<private> p : array<mat4x3<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[2];
+  p[1][0] = u[0][1].zxy;
+  p[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_storage.wgsl b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_storage.wgsl
new file mode 100644
index 0000000..2a1f17f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_storage.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0) var<uniform> u : array<mat4x3<f32>, 4>;
+@group(0) @binding(1) var<storage, read_write> s : array<mat4x3<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[2];
+    s[1][0] = u[0][1].zxy;
+    s[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_storage.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..befc57d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_storage.wgsl.expected.dxc.hlsl
@@ -0,0 +1,48 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[16];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, float4x3 value) {
+  buffer.Store3((offset + 0u), asuint(value[0u]));
+  buffer.Store3((offset + 16u), asuint(value[1u]));
+  buffer.Store3((offset + 32u), asuint(value[2u]));
+  buffer.Store3((offset + 48u), asuint(value[3u]));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, float4x3 value[4]) {
+  float4x3 array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 64u)), array[i]);
+    }
+  }
+}
+
+float4x3 tint_symbol_4(uint4 buffer[16], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+typedef float4x3 tint_symbol_3_ret[4];
+tint_symbol_3_ret tint_symbol_3(uint4 buffer[16], uint offset) {
+  float4x3 arr[4] = (float4x3[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_4(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_3(u, 0u));
+  tint_symbol_1(s, 64u, tint_symbol_4(u, 128u));
+  s.Store3(64u, asuint(asfloat(u[1].xyz).zxy));
+  s.Store(64u, asuint(asfloat(u[1].x)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_storage.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..befc57d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_storage.wgsl.expected.fxc.hlsl
@@ -0,0 +1,48 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[16];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, float4x3 value) {
+  buffer.Store3((offset + 0u), asuint(value[0u]));
+  buffer.Store3((offset + 16u), asuint(value[1u]));
+  buffer.Store3((offset + 32u), asuint(value[2u]));
+  buffer.Store3((offset + 48u), asuint(value[3u]));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, float4x3 value[4]) {
+  float4x3 array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 64u)), array[i]);
+    }
+  }
+}
+
+float4x3 tint_symbol_4(uint4 buffer[16], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+typedef float4x3 tint_symbol_3_ret[4];
+tint_symbol_3_ret tint_symbol_3(uint4 buffer[16], uint offset) {
+  float4x3 arr[4] = (float4x3[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_4(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_3(u, 0u));
+  tint_symbol_1(s, 64u, tint_symbol_4(u, 128u));
+  s.Store3(64u, asuint(asfloat(u[1].xyz).zxy));
+  s.Store(64u, asuint(asfloat(u[1].x)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..eb0649d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_storage.wgsl.expected.glsl
@@ -0,0 +1,22 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat4x3 inner[4];
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  mat4x3 inner[4];
+} s;
+
+void f() {
+  s.inner = u.inner;
+  s.inner[1] = u.inner[2];
+  s.inner[1][0] = u.inner[0][1].zxy;
+  s.inner[1][0].x = u.inner[0][1].x;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..05cfa2f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_storage.wgsl.expected.msl
@@ -0,0 +1,24 @@
+#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];
+};
+
+kernel void f(device tint_array<float4x3, 4>* tint_symbol [[buffer(1)]], const constant tint_array<float4x3, 4>* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
+  (*(tint_symbol))[1][0] = float3((*(tint_symbol_1))[0][1]).zxy;
+  (*(tint_symbol))[1][0][0] = (*(tint_symbol_1))[0][1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_storage.wgsl.expected.spvasm
new file mode 100644
index 0000000..061e9a9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_storage.wgsl.expected.spvasm
@@ -0,0 +1,71 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 42
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %s "s"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %_arr_mat4v3float_uint_4 ArrayStride 64
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %s DescriptorSet 0
+               OpDecorate %s Binding 1
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat4v3float = OpTypeMatrix %v3float 4
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat4v3float_uint_4 = OpTypeArray %mat4v3float %uint_4
+    %u_block = OpTypeStruct %_arr_mat4v3float_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
+          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+       %void = OpTypeVoid
+         %12 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer__arr_mat4v3float_uint_4 = OpTypePointer StorageBuffer %_arr_mat4v3float_uint_4
+%_ptr_Uniform__arr_mat4v3float_uint_4 = OpTypePointer Uniform %_arr_mat4v3float_uint_4
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_mat4v3float = OpTypePointer StorageBuffer %mat4v3float
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_mat4v3float = OpTypePointer Uniform %mat4v3float
+         %30 = OpConstantNull %int
+%_ptr_StorageBuffer_v3float = OpTypePointer StorageBuffer %v3float
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+          %f = OpFunction %void None %12
+         %15 = OpLabel
+         %18 = OpAccessChain %_ptr_StorageBuffer__arr_mat4v3float_uint_4 %s %uint_0
+         %20 = OpAccessChain %_ptr_Uniform__arr_mat4v3float_uint_4 %u %uint_0
+         %21 = OpLoad %_arr_mat4v3float_uint_4 %20
+               OpStore %18 %21
+         %25 = OpAccessChain %_ptr_StorageBuffer_mat4v3float %s %uint_0 %int_1
+         %28 = OpAccessChain %_ptr_Uniform_mat4v3float %u %uint_0 %int_2
+         %29 = OpLoad %mat4v3float %28
+               OpStore %25 %29
+         %32 = OpAccessChain %_ptr_StorageBuffer_v3float %s %uint_0 %int_1 %30
+         %34 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %30 %int_1
+         %35 = OpLoad %v3float %34
+         %36 = OpVectorShuffle %v3float %35 %35 2 0 1
+               OpStore %32 %36
+         %38 = OpAccessChain %_ptr_StorageBuffer_float %s %uint_0 %int_1 %30 %uint_0
+         %40 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %30 %int_1 %uint_0
+         %41 = OpLoad %float %40
+               OpStore %38 %41
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..a3b16ba
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> u : array<mat4x3<f32>, 4>;
+
+@group(0) @binding(1) var<storage, read_write> s : array<mat4x3<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[2];
+  s[1][0] = u[0][1].zxy;
+  s[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_workgroup.wgsl
new file mode 100644
index 0000000..6f078c4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_workgroup.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0) var<uniform> u : array<mat4x3<f32>, 4>;
+var<workgroup> w : array<mat4x3<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[2];
+    w[1][0] = u[0][1].zxy;
+    w[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_workgroup.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..1c1745a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_workgroup.wgsl.expected.dxc.hlsl
@@ -0,0 +1,47 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[16];
+};
+groupshared float4x3 w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+float4x3 tint_symbol_3(uint4 buffer[16], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+typedef float4x3 tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[16], uint offset) {
+  float4x3 arr[4] = (float4x3[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      w[i] = float4x3((0.0f).xxx, (0.0f).xxx, (0.0f).xxx, (0.0f).xxx);
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 128u);
+  w[1][0] = asfloat(u[1].xyz).zxy;
+  w[1][0].x = asfloat(u[1].x);
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_workgroup.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..1c1745a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_workgroup.wgsl.expected.fxc.hlsl
@@ -0,0 +1,47 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[16];
+};
+groupshared float4x3 w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+float4x3 tint_symbol_3(uint4 buffer[16], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+typedef float4x3 tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[16], uint offset) {
+  float4x3 arr[4] = (float4x3[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      w[i] = float4x3((0.0f).xxx, (0.0f).xxx, (0.0f).xxx, (0.0f).xxx);
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 128u);
+  w[1][0] = asfloat(u[1].xyz).zxy;
+  w[1][0].x = asfloat(u[1].x);
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..f06a3a3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,26 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat4x3 inner[4];
+} u;
+
+shared mat4x3 w[4];
+void f(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      uint i = idx;
+      w[i] = mat4x3(vec3(0.0f), vec3(0.0f), vec3(0.0f), vec3(0.0f));
+    }
+  }
+  barrier();
+  w = u.inner;
+  w[1] = u.inner[2];
+  w[1][0] = u.inner[0][1].zxy;
+  w[1][0].x = u.inner[0][1].x;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..b6e7f8c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,38 @@
+#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_symbol_5 {
+  tint_array<float4x3, 4> w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup tint_array<float4x3, 4>* const tint_symbol, const constant tint_array<float4x3, 4>* const tint_symbol_1) {
+  for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+    uint const i = idx;
+    (*(tint_symbol))[i] = float4x3(float3(0.0f), float3(0.0f), float3(0.0f), float3(0.0f));
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
+  (*(tint_symbol))[1][0] = float3((*(tint_symbol_1))[0][1]).zxy;
+  (*(tint_symbol))[1][0][0] = (*(tint_symbol_1))[0][1][0];
+}
+
+kernel void f(const constant tint_array<float4x3, 4>* tint_symbol_4 [[buffer(0)]], threadgroup tint_symbol_5* tint_symbol_3 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup tint_array<float4x3, 4>* const tint_symbol_2 = &((*(tint_symbol_3)).w);
+  f_inner(local_invocation_index, tint_symbol_2, tint_symbol_4);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_workgroup.wgsl.expected.spvasm
new file mode 100644
index 0000000..b2a40f3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_workgroup.wgsl.expected.spvasm
@@ -0,0 +1,115 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 70
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %local_invocation_index_1 "local_invocation_index_1"
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %w "w"
+               OpName %f_inner "f_inner"
+               OpName %local_invocation_index "local_invocation_index"
+               OpName %idx "idx"
+               OpName %f "f"
+               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %_arr_mat4v3float_uint_4 ArrayStride 64
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat4v3float = OpTypeMatrix %v3float 4
+     %uint_4 = OpConstant %uint 4
+%_arr_mat4v3float_uint_4 = OpTypeArray %mat4v3float %uint_4
+    %u_block = OpTypeStruct %_arr_mat4v3float_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_Workgroup__arr_mat4v3float_uint_4 = OpTypePointer Workgroup %_arr_mat4v3float_uint_4
+          %w = OpVariable %_ptr_Workgroup__arr_mat4v3float_uint_4 Workgroup
+       %void = OpTypeVoid
+         %14 = OpTypeFunction %void %uint
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %21 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Workgroup_mat4v3float = OpTypePointer Workgroup %mat4v3float
+         %35 = OpConstantNull %mat4v3float
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+   %uint_264 = OpConstant %uint 264
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat4v3float_uint_4 = OpTypePointer Uniform %_arr_mat4v3float_uint_4
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_mat4v3float = OpTypePointer Uniform %mat4v3float
+         %53 = OpConstantNull %int
+%_ptr_Workgroup_v3float = OpTypePointer Workgroup %v3float
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+%_ptr_Workgroup_float = OpTypePointer Workgroup %float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+         %65 = OpTypeFunction %void
+    %f_inner = OpFunction %void None %14
+%local_invocation_index = OpFunctionParameter %uint
+         %18 = OpLabel
+        %idx = OpVariable %_ptr_Function_uint Function %21
+               OpStore %idx %local_invocation_index
+               OpBranch %22
+         %22 = OpLabel
+               OpLoopMerge %23 %24 None
+               OpBranch %25
+         %25 = OpLabel
+         %27 = OpLoad %uint %idx
+         %28 = OpULessThan %bool %27 %uint_4
+         %26 = OpLogicalNot %bool %28
+               OpSelectionMerge %30 None
+               OpBranchConditional %26 %31 %30
+         %31 = OpLabel
+               OpBranch %23
+         %30 = OpLabel
+         %32 = OpLoad %uint %idx
+         %34 = OpAccessChain %_ptr_Workgroup_mat4v3float %w %32
+               OpStore %34 %35
+               OpBranch %24
+         %24 = OpLabel
+         %36 = OpLoad %uint %idx
+         %38 = OpIAdd %uint %36 %uint_1
+               OpStore %idx %38
+               OpBranch %22
+         %23 = OpLabel
+               OpControlBarrier %uint_2 %uint_2 %uint_264
+         %44 = OpAccessChain %_ptr_Uniform__arr_mat4v3float_uint_4 %u %uint_0
+         %45 = OpLoad %_arr_mat4v3float_uint_4 %44
+               OpStore %w %45
+         %48 = OpAccessChain %_ptr_Workgroup_mat4v3float %w %int_1
+         %51 = OpAccessChain %_ptr_Uniform_mat4v3float %u %uint_0 %int_2
+         %52 = OpLoad %mat4v3float %51
+               OpStore %48 %52
+         %55 = OpAccessChain %_ptr_Workgroup_v3float %w %int_1 %53
+         %57 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %53 %int_1
+         %58 = OpLoad %v3float %57
+         %59 = OpVectorShuffle %v3float %58 %58 2 0 1
+               OpStore %55 %59
+         %61 = OpAccessChain %_ptr_Workgroup_float %w %int_1 %53 %uint_0
+         %63 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %53 %int_1 %uint_0
+         %64 = OpLoad %float %63
+               OpStore %61 %64
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %65
+         %67 = OpLabel
+         %69 = OpLoad %uint %local_invocation_index_1
+         %68 = OpFunctionCall %void %f_inner %69
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..3a25aa3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x3_f32/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> u : array<mat4x3<f32>, 4>;
+
+var<workgroup> w : array<mat4x3<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[2];
+  w[1][0] = u[0][1].zxy;
+  w[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/array/mat4x4_f16/dynamic_index_via_ptr.wgsl
new file mode 100644
index 0000000..44fece1
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/dynamic_index_via_ptr.wgsl
@@ -0,0 +1,17 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> a : array<mat4x4<f16>, 4>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a       = &a;
+  let p_a_i     = &((*p_a)[i()]);
+  let p_a_i_i   = &((*p_a_i)[i()]);
+
+  let l_a       : array<mat4x4<f16>, 4> = *p_a;
+  let l_a_i     : mat4x4<f16>           = *p_a_i;
+  let l_a_i_i   : vec4<f16>             = *p_a_i_i;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..59fae52
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,59 @@
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[8];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 4, 4> tint_symbol_1(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+}
+
+typedef matrix<float16_t, 4, 4> tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[8], uint offset) {
+  matrix<float16_t, 4, 4> arr[4] = (matrix<float16_t, 4, 4>[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 32u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_i_save = i();
+  const matrix<float16_t, 4, 4> l_a[4] = tint_symbol(a, 0u);
+  const matrix<float16_t, 4, 4> l_a_i = tint_symbol_1(a, (32u * uint(p_a_i_save)));
+  const uint scalar_offset_4 = (((32u * uint(p_a_i_save)) + (8u * uint(p_a_i_i_save)))) / 4;
+  uint4 ubo_load_9 = a[scalar_offset_4 / 4];
+  uint2 ubo_load_8 = ((scalar_offset_4 & 2) ? ubo_load_9.zw : ubo_load_9.xy);
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_8_yw = vector<float16_t, 2>(f16tof32(ubo_load_8 >> 16));
+  const vector<float16_t, 4> l_a_i_i = vector<float16_t, 4>(ubo_load_8_xz[0], ubo_load_8_yw[0], ubo_load_8_xz[1], ubo_load_8_yw[1]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..c58ef9c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,64 @@
+SKIP: FAILED
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[8];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 4, 4> tint_symbol_1(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+}
+
+typedef matrix<float16_t, 4, 4> tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[8], uint offset) {
+  matrix<float16_t, 4, 4> arr[4] = (matrix<float16_t, 4, 4>[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 32u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_i_save = i();
+  const matrix<float16_t, 4, 4> l_a[4] = tint_symbol(a, 0u);
+  const matrix<float16_t, 4, 4> l_a_i = tint_symbol_1(a, (32u * uint(p_a_i_save)));
+  const uint scalar_offset_4 = (((32u * uint(p_a_i_save)) + (8u * uint(p_a_i_i_save)))) / 4;
+  uint4 ubo_load_9 = a[scalar_offset_4 / 4];
+  uint2 ubo_load_8 = ((scalar_offset_4 & 2) ? ubo_load_9.zw : ubo_load_9.xy);
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_8_yw = vector<float16_t, 2>(f16tof32(ubo_load_8 >> 16));
+  const vector<float16_t, 4> l_a_i_i = vector<float16_t, 4>(ubo_load_8_xz[0], ubo_load_8_yw[0], ubo_load_8_xz[1], ubo_load_8_yw[1]);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001F4B0E9BB50(11,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..1ba2908
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,75 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct mat4x4_f16 {
+  f16vec4 col0;
+  f16vec4 col1;
+  f16vec4 col2;
+  f16vec4 col3;
+};
+
+layout(binding = 0, std140) uniform a_block_std140_ubo {
+  mat4x4_f16 inner[4];
+} a;
+
+int counter = 0;
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+f16mat4 conv_mat4x4_f16(mat4x4_f16 val) {
+  return f16mat4(val.col0, val.col1, val.col2, val.col3);
+}
+
+f16mat4[4] conv_arr4_mat4x4_f16(mat4x4_f16 val[4]) {
+  f16mat4 arr[4] = f16mat4[4](f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat4x4_f16(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16vec4 load_a_inner_p0_p1(uint p0, uint p1) {
+  switch(p1) {
+    case 0u: {
+      return a.inner[p0].col0;
+      break;
+    }
+    case 1u: {
+      return a.inner[p0].col1;
+      break;
+    }
+    case 2u: {
+      return a.inner[p0].col2;
+      break;
+    }
+    case 3u: {
+      return a.inner[p0].col3;
+      break;
+    }
+    default: {
+      return f16vec4(0.0hf);
+      break;
+    }
+  }
+}
+
+void f() {
+  f16mat4 p_a[4] = conv_arr4_mat4x4_f16(a.inner);
+  int tint_symbol = i();
+  f16mat4 p_a_i = conv_mat4x4_f16(a.inner[tint_symbol]);
+  int tint_symbol_1 = i();
+  f16vec4 p_a_i_i = load_a_inner_p0_p1(uint(tint_symbol), uint(tint_symbol_1));
+  f16mat4 l_a[4] = conv_arr4_mat4x4_f16(a.inner);
+  f16mat4 l_a_i = conv_mat4x4_f16(a.inner[tint_symbol]);
+  f16vec4 l_a_i_i = load_a_inner_p0_p1(uint(tint_symbol), uint(tint_symbol_1));
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..c1b59e6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,33 @@
+#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];
+};
+
+int i() {
+  thread int tint_symbol_2 = 0;
+  tint_symbol_2 = as_type<int>((as_type<uint>(tint_symbol_2) + as_type<uint>(1)));
+  return tint_symbol_2;
+}
+
+kernel void f(const constant tint_array<half4x4, 4>* tint_symbol_3 [[buffer(0)]]) {
+  int const tint_symbol = i();
+  int const p_a_i_save = tint_symbol;
+  int const tint_symbol_1 = i();
+  int const p_a_i_i_save = tint_symbol_1;
+  tint_array<half4x4, 4> const l_a = *(tint_symbol_3);
+  half4x4 const l_a_i = (*(tint_symbol_3))[p_a_i_save];
+  half4 const l_a_i_i = (*(tint_symbol_3))[p_a_i_save][p_a_i_i_save];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..575ae9b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,181 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 108
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block_std140 "a_block_std140"
+               OpMemberName %a_block_std140 0 "inner"
+               OpName %mat4x4_f16 "mat4x4_f16"
+               OpMemberName %mat4x4_f16 0 "col0"
+               OpMemberName %mat4x4_f16 1 "col1"
+               OpMemberName %mat4x4_f16 2 "col2"
+               OpMemberName %mat4x4_f16 3 "col3"
+               OpName %a "a"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %conv_mat4x4_f16 "conv_mat4x4_f16"
+               OpName %val "val"
+               OpName %conv_arr4_mat4x4_f16 "conv_arr4_mat4x4_f16"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i_0 "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_a_inner_p0_p1 "load_a_inner_p0_p1"
+               OpName %p0 "p0"
+               OpName %p1 "p1"
+               OpName %f "f"
+               OpDecorate %a_block_std140 Block
+               OpMemberDecorate %a_block_std140 0 Offset 0
+               OpMemberDecorate %mat4x4_f16 0 Offset 0
+               OpMemberDecorate %mat4x4_f16 1 Offset 8
+               OpMemberDecorate %mat4x4_f16 2 Offset 16
+               OpMemberDecorate %mat4x4_f16 3 Offset 24
+               OpDecorate %_arr_mat4x4_f16_uint_4 ArrayStride 32
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+               OpDecorate %_arr_mat4v4half_uint_4 ArrayStride 32
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+ %mat4x4_f16 = OpTypeStruct %v4half %v4half %v4half %v4half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat4x4_f16_uint_4 = OpTypeArray %mat4x4_f16 %uint_4
+%a_block_std140 = OpTypeStruct %_arr_mat4x4_f16_uint_4
+%_ptr_Uniform_a_block_std140 = OpTypePointer Uniform %a_block_std140
+          %a = OpVariable %_ptr_Uniform_a_block_std140 Uniform
+        %int = OpTypeInt 32 1
+         %11 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %11
+         %14 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+ %mat4v4half = OpTypeMatrix %v4half 4
+         %21 = OpTypeFunction %mat4v4half %mat4x4_f16
+%_arr_mat4v4half_uint_4 = OpTypeArray %mat4v4half %uint_4
+         %31 = OpTypeFunction %_arr_mat4v4half_uint_4 %_arr_mat4x4_f16_uint_4
+%_ptr_Function__arr_mat4v4half_uint_4 = OpTypePointer Function %_arr_mat4v4half_uint_4
+         %38 = OpConstantNull %_arr_mat4v4half_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %41 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_mat4x4_f16_uint_4 = OpTypePointer Function %_arr_mat4x4_f16_uint_4
+         %54 = OpConstantNull %_arr_mat4x4_f16_uint_4
+%_ptr_Function_mat4v4half = OpTypePointer Function %mat4v4half
+%_ptr_Function_mat4x4_f16 = OpTypePointer Function %mat4x4_f16
+     %uint_1 = OpConstant %uint 1
+         %67 = OpTypeFunction %v4half %uint %uint
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+         %90 = OpConstantNull %v4half
+       %void = OpTypeVoid
+         %91 = OpTypeFunction %void
+%_ptr_Uniform__arr_mat4x4_f16_uint_4 = OpTypePointer Uniform %_arr_mat4x4_f16_uint_4
+%_ptr_Uniform_mat4x4_f16 = OpTypePointer Uniform %mat4x4_f16
+          %i = OpFunction %int None %14
+         %16 = OpLabel
+         %17 = OpLoad %int %counter
+         %19 = OpIAdd %int %17 %int_1
+               OpStore %counter %19
+         %20 = OpLoad %int %counter
+               OpReturnValue %20
+               OpFunctionEnd
+%conv_mat4x4_f16 = OpFunction %mat4v4half None %21
+        %val = OpFunctionParameter %mat4x4_f16
+         %25 = OpLabel
+         %26 = OpCompositeExtract %v4half %val 0
+         %27 = OpCompositeExtract %v4half %val 1
+         %28 = OpCompositeExtract %v4half %val 2
+         %29 = OpCompositeExtract %v4half %val 3
+         %30 = OpCompositeConstruct %mat4v4half %26 %27 %28 %29
+               OpReturnValue %30
+               OpFunctionEnd
+%conv_arr4_mat4x4_f16 = OpFunction %_arr_mat4v4half_uint_4 None %31
+      %val_0 = OpFunctionParameter %_arr_mat4x4_f16_uint_4
+         %35 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_mat4v4half_uint_4 Function %38
+        %i_0 = OpVariable %_ptr_Function_uint Function %41
+%var_for_index = OpVariable %_ptr_Function__arr_mat4x4_f16_uint_4 Function %54
+               OpBranch %42
+         %42 = OpLabel
+               OpLoopMerge %43 %44 None
+               OpBranch %45
+         %45 = OpLabel
+         %47 = OpLoad %uint %i_0
+         %48 = OpULessThan %bool %47 %uint_4
+         %46 = OpLogicalNot %bool %48
+               OpSelectionMerge %50 None
+               OpBranchConditional %46 %51 %50
+         %51 = OpLabel
+               OpBranch %43
+         %50 = OpLabel
+               OpStore %var_for_index %val_0
+         %55 = OpLoad %uint %i_0
+         %57 = OpAccessChain %_ptr_Function_mat4v4half %arr %55
+         %59 = OpLoad %uint %i_0
+         %61 = OpAccessChain %_ptr_Function_mat4x4_f16 %var_for_index %59
+         %62 = OpLoad %mat4x4_f16 %61
+         %58 = OpFunctionCall %mat4v4half %conv_mat4x4_f16 %62
+               OpStore %57 %58
+               OpBranch %44
+         %44 = OpLabel
+         %63 = OpLoad %uint %i_0
+         %65 = OpIAdd %uint %63 %uint_1
+               OpStore %i_0 %65
+               OpBranch %42
+         %43 = OpLabel
+         %66 = OpLoad %_arr_mat4v4half_uint_4 %arr
+               OpReturnValue %66
+               OpFunctionEnd
+%load_a_inner_p0_p1 = OpFunction %v4half None %67
+         %p0 = OpFunctionParameter %uint
+         %p1 = OpFunctionParameter %uint
+         %71 = OpLabel
+               OpSelectionMerge %72 None
+               OpSwitch %p1 %73 0 %74 1 %75 2 %76 3 %77
+         %74 = OpLabel
+         %80 = OpAccessChain %_ptr_Uniform_v4half %a %uint_0 %p0 %uint_0
+         %81 = OpLoad %v4half %80
+               OpReturnValue %81
+         %75 = OpLabel
+         %82 = OpAccessChain %_ptr_Uniform_v4half %a %uint_0 %p0 %uint_1
+         %83 = OpLoad %v4half %82
+               OpReturnValue %83
+         %76 = OpLabel
+         %85 = OpAccessChain %_ptr_Uniform_v4half %a %uint_0 %p0 %uint_2
+         %86 = OpLoad %v4half %85
+               OpReturnValue %86
+         %77 = OpLabel
+         %88 = OpAccessChain %_ptr_Uniform_v4half %a %uint_0 %p0 %uint_3
+         %89 = OpLoad %v4half %88
+               OpReturnValue %89
+         %73 = OpLabel
+               OpReturnValue %90
+         %72 = OpLabel
+               OpReturnValue %90
+               OpFunctionEnd
+          %f = OpFunction %void None %91
+         %94 = OpLabel
+         %95 = OpFunctionCall %int %i
+         %96 = OpFunctionCall %int %i
+         %99 = OpAccessChain %_ptr_Uniform__arr_mat4x4_f16_uint_4 %a %uint_0
+        %100 = OpLoad %_arr_mat4x4_f16_uint_4 %99
+         %97 = OpFunctionCall %_arr_mat4v4half_uint_4 %conv_arr4_mat4x4_f16 %100
+        %103 = OpAccessChain %_ptr_Uniform_mat4x4_f16 %a %uint_0 %95
+        %104 = OpLoad %mat4x4_f16 %103
+        %101 = OpFunctionCall %mat4v4half %conv_mat4x4_f16 %104
+        %106 = OpBitcast %uint %95
+        %107 = OpBitcast %uint %96
+        %105 = OpFunctionCall %v4half %load_a_inner_p0_p1 %106 %107
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..0d1e24a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,20 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> a : array<mat4x4<f16>, 4>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_i = &((*(p_a))[i()]);
+  let p_a_i_i = &((*(p_a_i))[i()]);
+  let l_a : array<mat4x4<f16>, 4> = *(p_a);
+  let l_a_i : mat4x4<f16> = *(p_a_i);
+  let l_a_i_i : vec4<f16> = *(p_a_i_i);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/array/mat4x4_f16/static_index_via_ptr.wgsl
new file mode 100644
index 0000000..580856f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/static_index_via_ptr.wgsl
@@ -0,0 +1,14 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> a : array<mat4x4<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a       = &a;
+  let p_a_2     = &((*p_a)[2]);
+  let p_a_2_1   = &((*p_a_2)[1]);
+
+  let l_a       : array<mat4x4<f16>, 4> = *p_a;
+  let l_a_i     : mat4x4<f16>           = *p_a_2;
+  let l_a_i_i   : vec4<f16>             = *p_a_2_1;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x4_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..0413807
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,49 @@
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[8];
+};
+
+matrix<float16_t, 4, 4> tint_symbol_1(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+}
+
+typedef matrix<float16_t, 4, 4> tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[8], uint offset) {
+  matrix<float16_t, 4, 4> arr[4] = (matrix<float16_t, 4, 4>[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 32u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 4, 4> l_a[4] = tint_symbol(a, 0u);
+  const matrix<float16_t, 4, 4> l_a_i = tint_symbol_1(a, 64u);
+  uint2 ubo_load_8 = a[4].zw;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_8_yw = vector<float16_t, 2>(f16tof32(ubo_load_8 >> 16));
+  const vector<float16_t, 4> l_a_i_i = vector<float16_t, 4>(ubo_load_8_xz[0], ubo_load_8_yw[0], ubo_load_8_xz[1], ubo_load_8_yw[1]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x4_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..d0b7cb8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,54 @@
+SKIP: FAILED
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[8];
+};
+
+matrix<float16_t, 4, 4> tint_symbol_1(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+}
+
+typedef matrix<float16_t, 4, 4> tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[8], uint offset) {
+  matrix<float16_t, 4, 4> arr[4] = (matrix<float16_t, 4, 4>[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 32u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 4, 4> l_a[4] = tint_symbol(a, 0u);
+  const matrix<float16_t, 4, 4> l_a_i = tint_symbol_1(a, 64u);
+  uint2 ubo_load_8 = a[4].zw;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_8_yw = vector<float16_t, 2>(f16tof32(ubo_load_8 >> 16));
+  const vector<float16_t, 4> l_a_i_i = vector<float16_t, 4>(ubo_load_8_xz[0], ubo_load_8_yw[0], ubo_load_8_xz[1], ubo_load_8_yw[1]);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001586950D8A0(5,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x4_f16/static_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..2e2ba11
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/static_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,42 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct mat4x4_f16 {
+  f16vec4 col0;
+  f16vec4 col1;
+  f16vec4 col2;
+  f16vec4 col3;
+};
+
+layout(binding = 0, std140) uniform a_block_std140_ubo {
+  mat4x4_f16 inner[4];
+} a;
+
+f16mat4 conv_mat4x4_f16(mat4x4_f16 val) {
+  return f16mat4(val.col0, val.col1, val.col2, val.col3);
+}
+
+f16mat4[4] conv_arr4_mat4x4_f16(mat4x4_f16 val[4]) {
+  f16mat4 arr[4] = f16mat4[4](f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat4x4_f16(val[i]);
+    }
+  }
+  return arr;
+}
+
+void f() {
+  f16mat4 p_a[4] = conv_arr4_mat4x4_f16(a.inner);
+  f16mat4 p_a_2 = conv_mat4x4_f16(a.inner[2u]);
+  f16vec4 p_a_2_1 = a.inner[2u].col1;
+  f16mat4 l_a[4] = conv_arr4_mat4x4_f16(a.inner);
+  f16mat4 l_a_i = conv_mat4x4_f16(a.inner[2u]);
+  f16vec4 l_a_i_i = a.inner[2u].col1;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat4x4_f16/static_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..ccd4ec1
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/static_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,23 @@
+#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];
+};
+
+kernel void f(const constant tint_array<half4x4, 4>* tint_symbol [[buffer(0)]]) {
+  tint_array<half4x4, 4> const l_a = *(tint_symbol);
+  half4x4 const l_a_i = (*(tint_symbol))[2];
+  half4 const l_a_i_i = (*(tint_symbol))[2][1];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x4_f16/static_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..a982f07
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/static_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,129 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 73
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block_std140 "a_block_std140"
+               OpMemberName %a_block_std140 0 "inner"
+               OpName %mat4x4_f16 "mat4x4_f16"
+               OpMemberName %mat4x4_f16 0 "col0"
+               OpMemberName %mat4x4_f16 1 "col1"
+               OpMemberName %mat4x4_f16 2 "col2"
+               OpMemberName %mat4x4_f16 3 "col3"
+               OpName %a "a"
+               OpName %conv_mat4x4_f16 "conv_mat4x4_f16"
+               OpName %val "val"
+               OpName %conv_arr4_mat4x4_f16 "conv_arr4_mat4x4_f16"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %f "f"
+               OpDecorate %a_block_std140 Block
+               OpMemberDecorate %a_block_std140 0 Offset 0
+               OpMemberDecorate %mat4x4_f16 0 Offset 0
+               OpMemberDecorate %mat4x4_f16 1 Offset 8
+               OpMemberDecorate %mat4x4_f16 2 Offset 16
+               OpMemberDecorate %mat4x4_f16 3 Offset 24
+               OpDecorate %_arr_mat4x4_f16_uint_4 ArrayStride 32
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+               OpDecorate %_arr_mat4v4half_uint_4 ArrayStride 32
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+ %mat4x4_f16 = OpTypeStruct %v4half %v4half %v4half %v4half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat4x4_f16_uint_4 = OpTypeArray %mat4x4_f16 %uint_4
+%a_block_std140 = OpTypeStruct %_arr_mat4x4_f16_uint_4
+%_ptr_Uniform_a_block_std140 = OpTypePointer Uniform %a_block_std140
+          %a = OpVariable %_ptr_Uniform_a_block_std140 Uniform
+ %mat4v4half = OpTypeMatrix %v4half 4
+         %10 = OpTypeFunction %mat4v4half %mat4x4_f16
+%_arr_mat4v4half_uint_4 = OpTypeArray %mat4v4half %uint_4
+         %20 = OpTypeFunction %_arr_mat4v4half_uint_4 %_arr_mat4x4_f16_uint_4
+%_ptr_Function__arr_mat4v4half_uint_4 = OpTypePointer Function %_arr_mat4v4half_uint_4
+         %27 = OpConstantNull %_arr_mat4v4half_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %30 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_mat4x4_f16_uint_4 = OpTypePointer Function %_arr_mat4x4_f16_uint_4
+         %43 = OpConstantNull %_arr_mat4x4_f16_uint_4
+%_ptr_Function_mat4v4half = OpTypePointer Function %mat4v4half
+%_ptr_Function_mat4x4_f16 = OpTypePointer Function %mat4x4_f16
+     %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %56 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat4x4_f16_uint_4 = OpTypePointer Uniform %_arr_mat4x4_f16_uint_4
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_mat4x4_f16 = OpTypePointer Uniform %mat4x4_f16
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+%conv_mat4x4_f16 = OpFunction %mat4v4half None %10
+        %val = OpFunctionParameter %mat4x4_f16
+         %14 = OpLabel
+         %15 = OpCompositeExtract %v4half %val 0
+         %16 = OpCompositeExtract %v4half %val 1
+         %17 = OpCompositeExtract %v4half %val 2
+         %18 = OpCompositeExtract %v4half %val 3
+         %19 = OpCompositeConstruct %mat4v4half %15 %16 %17 %18
+               OpReturnValue %19
+               OpFunctionEnd
+%conv_arr4_mat4x4_f16 = OpFunction %_arr_mat4v4half_uint_4 None %20
+      %val_0 = OpFunctionParameter %_arr_mat4x4_f16_uint_4
+         %24 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_mat4v4half_uint_4 Function %27
+          %i = OpVariable %_ptr_Function_uint Function %30
+%var_for_index = OpVariable %_ptr_Function__arr_mat4x4_f16_uint_4 Function %43
+               OpBranch %31
+         %31 = OpLabel
+               OpLoopMerge %32 %33 None
+               OpBranch %34
+         %34 = OpLabel
+         %36 = OpLoad %uint %i
+         %37 = OpULessThan %bool %36 %uint_4
+         %35 = OpLogicalNot %bool %37
+               OpSelectionMerge %39 None
+               OpBranchConditional %35 %40 %39
+         %40 = OpLabel
+               OpBranch %32
+         %39 = OpLabel
+               OpStore %var_for_index %val_0
+         %44 = OpLoad %uint %i
+         %46 = OpAccessChain %_ptr_Function_mat4v4half %arr %44
+         %48 = OpLoad %uint %i
+         %50 = OpAccessChain %_ptr_Function_mat4x4_f16 %var_for_index %48
+         %51 = OpLoad %mat4x4_f16 %50
+         %47 = OpFunctionCall %mat4v4half %conv_mat4x4_f16 %51
+               OpStore %46 %47
+               OpBranch %33
+         %33 = OpLabel
+         %52 = OpLoad %uint %i
+         %54 = OpIAdd %uint %52 %uint_1
+               OpStore %i %54
+               OpBranch %31
+         %32 = OpLabel
+         %55 = OpLoad %_arr_mat4v4half_uint_4 %arr
+               OpReturnValue %55
+               OpFunctionEnd
+          %f = OpFunction %void None %56
+         %59 = OpLabel
+         %63 = OpAccessChain %_ptr_Uniform__arr_mat4x4_f16_uint_4 %a %uint_0
+         %64 = OpLoad %_arr_mat4x4_f16_uint_4 %63
+         %60 = OpFunctionCall %_arr_mat4v4half_uint_4 %conv_arr4_mat4x4_f16 %64
+         %68 = OpAccessChain %_ptr_Uniform_mat4x4_f16 %a %uint_0 %uint_2
+         %69 = OpLoad %mat4x4_f16 %68
+         %65 = OpFunctionCall %mat4v4half %conv_mat4x4_f16 %69
+         %71 = OpAccessChain %_ptr_Uniform_v4half %a %uint_0 %uint_2 %uint_1
+         %72 = OpLoad %v4half %71
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat4x4_f16/static_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..c91863f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/static_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> a : array<mat4x4<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_2 = &((*(p_a))[2]);
+  let p_a_2_1 = &((*(p_a_2))[1]);
+  let l_a : array<mat4x4<f16>, 4> = *(p_a);
+  let l_a_i : mat4x4<f16> = *(p_a_2);
+  let l_a_i_i : vec4<f16> = *(p_a_2_1);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_builtin.wgsl b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_builtin.wgsl
new file mode 100644
index 0000000..c2729ec
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_builtin.wgsl
@@ -0,0 +1,10 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat4x4<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    let t = transpose(u[2]);
+    let l = length(u[0][1].ywxz);
+    let a = abs(u[0][1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_builtin.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..3db7f37
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_builtin.wgsl.expected.dxc.hlsl
@@ -0,0 +1,41 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[8];
+};
+
+matrix<float16_t, 4, 4> tint_symbol(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 4, 4> t = transpose(tint_symbol(u, 64u));
+  uint2 ubo_load_8 = u[0].zw;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_8_yw = vector<float16_t, 2>(f16tof32(ubo_load_8 >> 16));
+  const float16_t l = length(vector<float16_t, 4>(ubo_load_8_xz[0], ubo_load_8_yw[0], ubo_load_8_xz[1], ubo_load_8_yw[1]).ywxz);
+  uint2 ubo_load_9 = u[0].zw;
+  vector<float16_t, 2> ubo_load_9_xz = vector<float16_t, 2>(f16tof32(ubo_load_9 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_9_yw = vector<float16_t, 2>(f16tof32(ubo_load_9 >> 16));
+  const float16_t a = abs(vector<float16_t, 4>(ubo_load_9_xz[0], ubo_load_9_yw[0], ubo_load_9_xz[1], ubo_load_9_yw[1]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_builtin.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..dbd9a19
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_builtin.wgsl.expected.fxc.hlsl
@@ -0,0 +1,46 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[8];
+};
+
+matrix<float16_t, 4, 4> tint_symbol(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 4, 4> t = transpose(tint_symbol(u, 64u));
+  uint2 ubo_load_8 = u[0].zw;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_8_yw = vector<float16_t, 2>(f16tof32(ubo_load_8 >> 16));
+  const float16_t l = length(vector<float16_t, 4>(ubo_load_8_xz[0], ubo_load_8_yw[0], ubo_load_8_xz[1], ubo_load_8_yw[1]).ywxz);
+  uint2 ubo_load_9 = u[0].zw;
+  vector<float16_t, 2> ubo_load_9_xz = vector<float16_t, 2>(f16tof32(ubo_load_9 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_9_yw = vector<float16_t, 2>(f16tof32(ubo_load_9 >> 16));
+  const float16_t a = abs(vector<float16_t, 4>(ubo_load_9_xz[0], ubo_load_9_yw[0], ubo_load_9_xz[1], ubo_load_9_yw[1]).ywxz.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000002574E068B20(5,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_builtin.wgsl.expected.glsl
new file mode 100644
index 0000000..24c5493
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_builtin.wgsl.expected.glsl
@@ -0,0 +1,29 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct mat4x4_f16 {
+  f16vec4 col0;
+  f16vec4 col1;
+  f16vec4 col2;
+  f16vec4 col3;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  mat4x4_f16 inner[4];
+} u;
+
+f16mat4 conv_mat4x4_f16(mat4x4_f16 val) {
+  return f16mat4(val.col0, val.col1, val.col2, val.col3);
+}
+
+void f() {
+  f16mat4 t = transpose(conv_mat4x4_f16(u.inner[2u]));
+  float16_t l = length(u.inner[0u].col1.ywxz);
+  float16_t a = abs(u.inner[0u].col1.ywxz[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_builtin.wgsl.expected.msl
new file mode 100644
index 0000000..f1b041d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_builtin.wgsl.expected.msl
@@ -0,0 +1,23 @@
+#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];
+};
+
+kernel void f(const constant tint_array<half4x4, 4>* tint_symbol [[buffer(0)]]) {
+  half4x4 const t = transpose((*(tint_symbol))[2]);
+  half const l = length(half4((*(tint_symbol))[0][1]).ywxz);
+  half const a = fabs(half4((*(tint_symbol))[0][1]).ywxz[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_builtin.wgsl.expected.spvasm
new file mode 100644
index 0000000..4d30027
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_builtin.wgsl.expected.spvasm
@@ -0,0 +1,81 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 44
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+         %32 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %mat4x4_f16 "mat4x4_f16"
+               OpMemberName %mat4x4_f16 0 "col0"
+               OpMemberName %mat4x4_f16 1 "col1"
+               OpMemberName %mat4x4_f16 2 "col2"
+               OpMemberName %mat4x4_f16 3 "col3"
+               OpName %u "u"
+               OpName %conv_mat4x4_f16 "conv_mat4x4_f16"
+               OpName %val "val"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %mat4x4_f16 0 Offset 0
+               OpMemberDecorate %mat4x4_f16 1 Offset 8
+               OpMemberDecorate %mat4x4_f16 2 Offset 16
+               OpMemberDecorate %mat4x4_f16 3 Offset 24
+               OpDecorate %_arr_mat4x4_f16_uint_4 ArrayStride 32
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+ %mat4x4_f16 = OpTypeStruct %v4half %v4half %v4half %v4half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat4x4_f16_uint_4 = OpTypeArray %mat4x4_f16 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_mat4x4_f16_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat4v4half = OpTypeMatrix %v4half 4
+         %10 = OpTypeFunction %mat4v4half %mat4x4_f16
+       %void = OpTypeVoid
+         %20 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_mat4x4_f16 = OpTypePointer Uniform %mat4x4_f16
+         %33 = OpConstantNull %uint
+     %uint_1 = OpConstant %uint 1
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+%conv_mat4x4_f16 = OpFunction %mat4v4half None %10
+        %val = OpFunctionParameter %mat4x4_f16
+         %14 = OpLabel
+         %15 = OpCompositeExtract %v4half %val 0
+         %16 = OpCompositeExtract %v4half %val 1
+         %17 = OpCompositeExtract %v4half %val 2
+         %18 = OpCompositeExtract %v4half %val 3
+         %19 = OpCompositeConstruct %mat4v4half %15 %16 %17 %18
+               OpReturnValue %19
+               OpFunctionEnd
+          %f = OpFunction %void None %20
+         %23 = OpLabel
+         %29 = OpAccessChain %_ptr_Uniform_mat4x4_f16 %u %uint_0 %uint_2
+         %30 = OpLoad %mat4x4_f16 %29
+         %25 = OpFunctionCall %mat4v4half %conv_mat4x4_f16 %30
+         %24 = OpTranspose %mat4v4half %25
+         %36 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0 %33 %uint_1
+         %37 = OpLoad %v4half %36
+         %38 = OpVectorShuffle %v4half %37 %37 1 3 0 2
+         %31 = OpExtInst %half %32 Length %38
+         %40 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0 %33 %uint_1
+         %41 = OpLoad %v4half %40
+         %42 = OpVectorShuffle %v4half %41 %41 1 3 0 2
+         %43 = OpCompositeExtract %half %42 0
+         %39 = OpExtInst %half %32 FAbs %43
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_builtin.wgsl.expected.wgsl
new file mode 100644
index 0000000..d6bd702
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_builtin.wgsl.expected.wgsl
@@ -0,0 +1,10 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat4x4<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let t = transpose(u[2]);
+  let l = length(u[0][1].ywxz);
+  let a = abs(u[0][1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_fn.wgsl b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_fn.wgsl
new file mode 100644
index 0000000..3566b7e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_fn.wgsl
@@ -0,0 +1,16 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat4x4<f16>, 4>;
+
+fn a(a : array<mat4x4<f16>, 4>) {}
+fn b(m : mat4x4<f16>) {}
+fn c(v : vec4<f16>) {}
+fn d(f : f16) {}
+
+@compute @workgroup_size(1)
+fn f() {
+    a(u);
+    b(u[1]);
+    c(u[1][0].ywxz);
+    d(u[1][0].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_fn.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..99d2802
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_fn.wgsl.expected.dxc.hlsl
@@ -0,0 +1,65 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[8];
+};
+
+void a(matrix<float16_t, 4, 4> a_1[4]) {
+}
+
+void b(matrix<float16_t, 4, 4> m) {
+}
+
+void c(vector<float16_t, 4> v) {
+}
+
+void d(float16_t f_1) {
+}
+
+matrix<float16_t, 4, 4> tint_symbol_1(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+}
+
+typedef matrix<float16_t, 4, 4> tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[8], uint offset) {
+  matrix<float16_t, 4, 4> arr[4] = (matrix<float16_t, 4, 4>[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 32u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 32u));
+  uint2 ubo_load_8 = u[2].xy;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_8_yw = vector<float16_t, 2>(f16tof32(ubo_load_8 >> 16));
+  c(vector<float16_t, 4>(ubo_load_8_xz[0], ubo_load_8_yw[0], ubo_load_8_xz[1], ubo_load_8_yw[1]).ywxz);
+  uint2 ubo_load_9 = u[2].xy;
+  vector<float16_t, 2> ubo_load_9_xz = vector<float16_t, 2>(f16tof32(ubo_load_9 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_9_yw = vector<float16_t, 2>(f16tof32(ubo_load_9 >> 16));
+  d(vector<float16_t, 4>(ubo_load_9_xz[0], ubo_load_9_yw[0], ubo_load_9_xz[1], ubo_load_9_yw[1]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_fn.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..62edde6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_fn.wgsl.expected.fxc.hlsl
@@ -0,0 +1,73 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[8];
+};
+
+void a(matrix<float16_t, 4, 4> a_1[4]) {
+}
+
+void b(matrix<float16_t, 4, 4> m) {
+}
+
+void c(vector<float16_t, 4> v) {
+}
+
+void d(float16_t f_1) {
+}
+
+matrix<float16_t, 4, 4> tint_symbol_1(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+}
+
+typedef matrix<float16_t, 4, 4> tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[8], uint offset) {
+  matrix<float16_t, 4, 4> arr[4] = (matrix<float16_t, 4, 4>[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 32u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 32u));
+  uint2 ubo_load_8 = u[2].xy;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_8_yw = vector<float16_t, 2>(f16tof32(ubo_load_8 >> 16));
+  c(vector<float16_t, 4>(ubo_load_8_xz[0], ubo_load_8_yw[0], ubo_load_8_xz[1], ubo_load_8_yw[1]).ywxz);
+  uint2 ubo_load_9 = u[2].xy;
+  vector<float16_t, 2> ubo_load_9_xz = vector<float16_t, 2>(f16tof32(ubo_load_9 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_9_yw = vector<float16_t, 2>(f16tof32(ubo_load_9 >> 16));
+  d(vector<float16_t, 4>(ubo_load_9_xz[0], ubo_load_9_yw[0], ubo_load_9_xz[1], ubo_load_9_yw[1]).ywxz.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001FAC4F2FC00(5,15-23): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001FAC4F2FC00(8,15-23): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001FAC4F2FC00(11,15-23): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001FAC4F2FC00(14,8-16): error X3000: unrecognized identifier 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_fn.wgsl.expected.glsl
new file mode 100644
index 0000000..26fb428
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_fn.wgsl.expected.glsl
@@ -0,0 +1,52 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct mat4x4_f16 {
+  f16vec4 col0;
+  f16vec4 col1;
+  f16vec4 col2;
+  f16vec4 col3;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  mat4x4_f16 inner[4];
+} u;
+
+void a(f16mat4 a_1[4]) {
+}
+
+void b(f16mat4 m) {
+}
+
+void c(f16vec4 v) {
+}
+
+void d(float16_t f_1) {
+}
+
+f16mat4 conv_mat4x4_f16(mat4x4_f16 val) {
+  return f16mat4(val.col0, val.col1, val.col2, val.col3);
+}
+
+f16mat4[4] conv_arr4_mat4x4_f16(mat4x4_f16 val[4]) {
+  f16mat4 arr[4] = f16mat4[4](f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat4x4_f16(val[i]);
+    }
+  }
+  return arr;
+}
+
+void f() {
+  a(conv_arr4_mat4x4_f16(u.inner));
+  b(conv_mat4x4_f16(u.inner[1u]));
+  c(u.inner[1u].col0.ywxz);
+  d(u.inner[1u].col0.ywxz[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_fn.wgsl.expected.msl
new file mode 100644
index 0000000..7824fac
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_fn.wgsl.expected.msl
@@ -0,0 +1,36 @@
+#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];
+};
+
+void a(tint_array<half4x4, 4> a_1) {
+}
+
+void b(half4x4 m) {
+}
+
+void c(half4 v) {
+}
+
+void d(half f_1) {
+}
+
+kernel void f(const constant tint_array<half4x4, 4>* tint_symbol [[buffer(0)]]) {
+  a(*(tint_symbol));
+  b((*(tint_symbol))[1]);
+  c(half4((*(tint_symbol))[1][0]).ywxz);
+  d(half4((*(tint_symbol))[1][0]).ywxz[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_fn.wgsl.expected.spvasm
new file mode 100644
index 0000000..b1b21d5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_fn.wgsl.expected.spvasm
@@ -0,0 +1,169 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 97
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %mat4x4_f16 "mat4x4_f16"
+               OpMemberName %mat4x4_f16 0 "col0"
+               OpMemberName %mat4x4_f16 1 "col1"
+               OpMemberName %mat4x4_f16 2 "col2"
+               OpMemberName %mat4x4_f16 3 "col3"
+               OpName %u "u"
+               OpName %a "a"
+               OpName %a_1 "a_1"
+               OpName %b "b"
+               OpName %m "m"
+               OpName %c "c"
+               OpName %v "v"
+               OpName %d "d"
+               OpName %f_1 "f_1"
+               OpName %conv_mat4x4_f16 "conv_mat4x4_f16"
+               OpName %val "val"
+               OpName %conv_arr4_mat4x4_f16 "conv_arr4_mat4x4_f16"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %mat4x4_f16 0 Offset 0
+               OpMemberDecorate %mat4x4_f16 1 Offset 8
+               OpMemberDecorate %mat4x4_f16 2 Offset 16
+               OpMemberDecorate %mat4x4_f16 3 Offset 24
+               OpDecorate %_arr_mat4x4_f16_uint_4 ArrayStride 32
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %_arr_mat4v4half_uint_4 ArrayStride 32
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+ %mat4x4_f16 = OpTypeStruct %v4half %v4half %v4half %v4half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat4x4_f16_uint_4 = OpTypeArray %mat4x4_f16 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_mat4x4_f16_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+       %void = OpTypeVoid
+ %mat4v4half = OpTypeMatrix %v4half 4
+%_arr_mat4v4half_uint_4 = OpTypeArray %mat4v4half %uint_4
+         %10 = OpTypeFunction %void %_arr_mat4v4half_uint_4
+         %17 = OpTypeFunction %void %mat4v4half
+         %21 = OpTypeFunction %void %v4half
+         %25 = OpTypeFunction %void %half
+         %29 = OpTypeFunction %mat4v4half %mat4x4_f16
+         %38 = OpTypeFunction %_arr_mat4v4half_uint_4 %_arr_mat4x4_f16_uint_4
+%_ptr_Function__arr_mat4v4half_uint_4 = OpTypePointer Function %_arr_mat4v4half_uint_4
+         %44 = OpConstantNull %_arr_mat4v4half_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %47 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_mat4x4_f16_uint_4 = OpTypePointer Function %_arr_mat4x4_f16_uint_4
+         %60 = OpConstantNull %_arr_mat4x4_f16_uint_4
+%_ptr_Function_mat4v4half = OpTypePointer Function %mat4v4half
+%_ptr_Function_mat4x4_f16 = OpTypePointer Function %mat4x4_f16
+     %uint_1 = OpConstant %uint 1
+         %73 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat4x4_f16_uint_4 = OpTypePointer Uniform %_arr_mat4x4_f16_uint_4
+%_ptr_Uniform_mat4x4_f16 = OpTypePointer Uniform %mat4x4_f16
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+          %a = OpFunction %void None %10
+        %a_1 = OpFunctionParameter %_arr_mat4v4half_uint_4
+         %16 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %b = OpFunction %void None %17
+          %m = OpFunctionParameter %mat4v4half
+         %20 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %c = OpFunction %void None %21
+          %v = OpFunctionParameter %v4half
+         %24 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %d = OpFunction %void None %25
+        %f_1 = OpFunctionParameter %half
+         %28 = OpLabel
+               OpReturn
+               OpFunctionEnd
+%conv_mat4x4_f16 = OpFunction %mat4v4half None %29
+        %val = OpFunctionParameter %mat4x4_f16
+         %32 = OpLabel
+         %33 = OpCompositeExtract %v4half %val 0
+         %34 = OpCompositeExtract %v4half %val 1
+         %35 = OpCompositeExtract %v4half %val 2
+         %36 = OpCompositeExtract %v4half %val 3
+         %37 = OpCompositeConstruct %mat4v4half %33 %34 %35 %36
+               OpReturnValue %37
+               OpFunctionEnd
+%conv_arr4_mat4x4_f16 = OpFunction %_arr_mat4v4half_uint_4 None %38
+      %val_0 = OpFunctionParameter %_arr_mat4x4_f16_uint_4
+         %41 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_mat4v4half_uint_4 Function %44
+          %i = OpVariable %_ptr_Function_uint Function %47
+%var_for_index = OpVariable %_ptr_Function__arr_mat4x4_f16_uint_4 Function %60
+               OpBranch %48
+         %48 = OpLabel
+               OpLoopMerge %49 %50 None
+               OpBranch %51
+         %51 = OpLabel
+         %53 = OpLoad %uint %i
+         %54 = OpULessThan %bool %53 %uint_4
+         %52 = OpLogicalNot %bool %54
+               OpSelectionMerge %56 None
+               OpBranchConditional %52 %57 %56
+         %57 = OpLabel
+               OpBranch %49
+         %56 = OpLabel
+               OpStore %var_for_index %val_0
+         %61 = OpLoad %uint %i
+         %63 = OpAccessChain %_ptr_Function_mat4v4half %arr %61
+         %65 = OpLoad %uint %i
+         %67 = OpAccessChain %_ptr_Function_mat4x4_f16 %var_for_index %65
+         %68 = OpLoad %mat4x4_f16 %67
+         %64 = OpFunctionCall %mat4v4half %conv_mat4x4_f16 %68
+               OpStore %63 %64
+               OpBranch %50
+         %50 = OpLabel
+         %69 = OpLoad %uint %i
+         %71 = OpIAdd %uint %69 %uint_1
+               OpStore %i %71
+               OpBranch %48
+         %49 = OpLabel
+         %72 = OpLoad %_arr_mat4v4half_uint_4 %arr
+               OpReturnValue %72
+               OpFunctionEnd
+          %f = OpFunction %void None %73
+         %75 = OpLabel
+         %80 = OpAccessChain %_ptr_Uniform__arr_mat4x4_f16_uint_4 %u %uint_0
+         %81 = OpLoad %_arr_mat4x4_f16_uint_4 %80
+         %77 = OpFunctionCall %_arr_mat4v4half_uint_4 %conv_arr4_mat4x4_f16 %81
+         %76 = OpFunctionCall %void %a %77
+         %85 = OpAccessChain %_ptr_Uniform_mat4x4_f16 %u %uint_0 %uint_1
+         %86 = OpLoad %mat4x4_f16 %85
+         %83 = OpFunctionCall %mat4v4half %conv_mat4x4_f16 %86
+         %82 = OpFunctionCall %void %b %83
+         %89 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0 %uint_1 %uint_0
+         %90 = OpLoad %v4half %89
+         %91 = OpVectorShuffle %v4half %90 %90 1 3 0 2
+         %87 = OpFunctionCall %void %c %91
+         %93 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0 %uint_1 %uint_0
+         %94 = OpLoad %v4half %93
+         %95 = OpVectorShuffle %v4half %94 %94 1 3 0 2
+         %96 = OpCompositeExtract %half %95 0
+         %92 = OpFunctionCall %void %d %96
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_fn.wgsl.expected.wgsl
new file mode 100644
index 0000000..830f697
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_fn.wgsl.expected.wgsl
@@ -0,0 +1,23 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat4x4<f16>, 4>;
+
+fn a(a : array<mat4x4<f16>, 4>) {
+}
+
+fn b(m : mat4x4<f16>) {
+}
+
+fn c(v : vec4<f16>) {
+}
+
+fn d(f : f16) {
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  a(u);
+  b(u[1]);
+  c(u[1][0].ywxz);
+  d(u[1][0].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_private.wgsl b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_private.wgsl
new file mode 100644
index 0000000..ea2580f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_private.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat4x4<f16>, 4>;
+var<private> p : array<mat4x4<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[2];
+    p[1][0] = u[0][1].ywxz;
+    p[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_private.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..d5fc3e3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_private.wgsl.expected.dxc.hlsl
@@ -0,0 +1,51 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[8];
+};
+static matrix<float16_t, 4, 4> p[4] = (matrix<float16_t, 4, 4>[4])0;
+
+matrix<float16_t, 4, 4> tint_symbol_1(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+}
+
+typedef matrix<float16_t, 4, 4> tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[8], uint offset) {
+  matrix<float16_t, 4, 4> arr[4] = (matrix<float16_t, 4, 4>[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 32u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 64u);
+  uint2 ubo_load_8 = u[0].zw;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_8_yw = vector<float16_t, 2>(f16tof32(ubo_load_8 >> 16));
+  p[1][0] = vector<float16_t, 4>(ubo_load_8_xz[0], ubo_load_8_yw[0], ubo_load_8_xz[1], ubo_load_8_yw[1]).ywxz;
+  p[1][0].x = float16_t(f16tof32(((u[0].z) & 0xFFFF)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_private.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..7983cff
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_private.wgsl.expected.fxc.hlsl
@@ -0,0 +1,56 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[8];
+};
+static matrix<float16_t, 4, 4> p[4] = (matrix<float16_t, 4, 4>[4])0;
+
+matrix<float16_t, 4, 4> tint_symbol_1(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+}
+
+typedef matrix<float16_t, 4, 4> tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[8], uint offset) {
+  matrix<float16_t, 4, 4> arr[4] = (matrix<float16_t, 4, 4>[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 32u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 64u);
+  uint2 ubo_load_8 = u[0].zw;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_8_yw = vector<float16_t, 2>(f16tof32(ubo_load_8 >> 16));
+  p[1][0] = vector<float16_t, 4>(ubo_load_8_xz[0], ubo_load_8_yw[0], ubo_load_8_xz[1], ubo_load_8_yw[1]).ywxz;
+  p[1][0].x = float16_t(f16tof32(((u[0].z) & 0xFFFF)));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x00000219133D8C70(4,15-23): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..67c856e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_private.wgsl.expected.glsl
@@ -0,0 +1,41 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct mat4x4_f16 {
+  f16vec4 col0;
+  f16vec4 col1;
+  f16vec4 col2;
+  f16vec4 col3;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  mat4x4_f16 inner[4];
+} u;
+
+f16mat4 p[4] = f16mat4[4](f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf));
+f16mat4 conv_mat4x4_f16(mat4x4_f16 val) {
+  return f16mat4(val.col0, val.col1, val.col2, val.col3);
+}
+
+f16mat4[4] conv_arr4_mat4x4_f16(mat4x4_f16 val[4]) {
+  f16mat4 arr[4] = f16mat4[4](f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat4x4_f16(val[i]);
+    }
+  }
+  return arr;
+}
+
+void f() {
+  p = conv_arr4_mat4x4_f16(u.inner);
+  p[1] = conv_mat4x4_f16(u.inner[2u]);
+  p[1][0] = u.inner[0u].col1.ywxz;
+  p[1][0].x = u.inner[0u].col1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..7cc2442
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_private.wgsl.expected.msl
@@ -0,0 +1,25 @@
+#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];
+};
+
+kernel void f(const constant tint_array<half4x4, 4>* tint_symbol_1 [[buffer(0)]]) {
+  thread tint_array<half4x4, 4> tint_symbol = {};
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[2];
+  tint_symbol[1][0] = half4((*(tint_symbol_1))[0][1]).ywxz;
+  tint_symbol[1][0][0] = (*(tint_symbol_1))[0][1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_private.wgsl.expected.spvasm
new file mode 100644
index 0000000..8a9baae
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_private.wgsl.expected.spvasm
@@ -0,0 +1,149 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 88
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %mat4x4_f16 "mat4x4_f16"
+               OpMemberName %mat4x4_f16 0 "col0"
+               OpMemberName %mat4x4_f16 1 "col1"
+               OpMemberName %mat4x4_f16 2 "col2"
+               OpMemberName %mat4x4_f16 3 "col3"
+               OpName %u "u"
+               OpName %p "p"
+               OpName %conv_mat4x4_f16 "conv_mat4x4_f16"
+               OpName %val "val"
+               OpName %conv_arr4_mat4x4_f16 "conv_arr4_mat4x4_f16"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %mat4x4_f16 0 Offset 0
+               OpMemberDecorate %mat4x4_f16 1 Offset 8
+               OpMemberDecorate %mat4x4_f16 2 Offset 16
+               OpMemberDecorate %mat4x4_f16 3 Offset 24
+               OpDecorate %_arr_mat4x4_f16_uint_4 ArrayStride 32
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %_arr_mat4v4half_uint_4 ArrayStride 32
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+ %mat4x4_f16 = OpTypeStruct %v4half %v4half %v4half %v4half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat4x4_f16_uint_4 = OpTypeArray %mat4x4_f16 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_mat4x4_f16_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat4v4half = OpTypeMatrix %v4half 4
+%_arr_mat4v4half_uint_4 = OpTypeArray %mat4v4half %uint_4
+%_ptr_Private__arr_mat4v4half_uint_4 = OpTypePointer Private %_arr_mat4v4half_uint_4
+         %14 = OpConstantNull %_arr_mat4v4half_uint_4
+          %p = OpVariable %_ptr_Private__arr_mat4v4half_uint_4 Private %14
+         %15 = OpTypeFunction %mat4v4half %mat4x4_f16
+         %24 = OpTypeFunction %_arr_mat4v4half_uint_4 %_arr_mat4x4_f16_uint_4
+%_ptr_Function__arr_mat4v4half_uint_4 = OpTypePointer Function %_arr_mat4v4half_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %32 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_mat4x4_f16_uint_4 = OpTypePointer Function %_arr_mat4x4_f16_uint_4
+         %45 = OpConstantNull %_arr_mat4x4_f16_uint_4
+%_ptr_Function_mat4v4half = OpTypePointer Function %mat4v4half
+%_ptr_Function_mat4x4_f16 = OpTypePointer Function %mat4x4_f16
+     %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %58 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat4x4_f16_uint_4 = OpTypePointer Uniform %_arr_mat4x4_f16_uint_4
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Private_mat4v4half = OpTypePointer Private %mat4v4half
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_mat4x4_f16 = OpTypePointer Uniform %mat4x4_f16
+         %76 = OpConstantNull %int
+%_ptr_Private_v4half = OpTypePointer Private %v4half
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+%_ptr_Private_half = OpTypePointer Private %half
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+%conv_mat4x4_f16 = OpFunction %mat4v4half None %15
+        %val = OpFunctionParameter %mat4x4_f16
+         %18 = OpLabel
+         %19 = OpCompositeExtract %v4half %val 0
+         %20 = OpCompositeExtract %v4half %val 1
+         %21 = OpCompositeExtract %v4half %val 2
+         %22 = OpCompositeExtract %v4half %val 3
+         %23 = OpCompositeConstruct %mat4v4half %19 %20 %21 %22
+               OpReturnValue %23
+               OpFunctionEnd
+%conv_arr4_mat4x4_f16 = OpFunction %_arr_mat4v4half_uint_4 None %24
+      %val_0 = OpFunctionParameter %_arr_mat4x4_f16_uint_4
+         %27 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_mat4v4half_uint_4 Function %14
+          %i = OpVariable %_ptr_Function_uint Function %32
+%var_for_index = OpVariable %_ptr_Function__arr_mat4x4_f16_uint_4 Function %45
+               OpBranch %33
+         %33 = OpLabel
+               OpLoopMerge %34 %35 None
+               OpBranch %36
+         %36 = OpLabel
+         %38 = OpLoad %uint %i
+         %39 = OpULessThan %bool %38 %uint_4
+         %37 = OpLogicalNot %bool %39
+               OpSelectionMerge %41 None
+               OpBranchConditional %37 %42 %41
+         %42 = OpLabel
+               OpBranch %34
+         %41 = OpLabel
+               OpStore %var_for_index %val_0
+         %46 = OpLoad %uint %i
+         %48 = OpAccessChain %_ptr_Function_mat4v4half %arr %46
+         %50 = OpLoad %uint %i
+         %52 = OpAccessChain %_ptr_Function_mat4x4_f16 %var_for_index %50
+         %53 = OpLoad %mat4x4_f16 %52
+         %49 = OpFunctionCall %mat4v4half %conv_mat4x4_f16 %53
+               OpStore %48 %49
+               OpBranch %35
+         %35 = OpLabel
+         %54 = OpLoad %uint %i
+         %56 = OpIAdd %uint %54 %uint_1
+               OpStore %i %56
+               OpBranch %33
+         %34 = OpLabel
+         %57 = OpLoad %_arr_mat4v4half_uint_4 %arr
+               OpReturnValue %57
+               OpFunctionEnd
+          %f = OpFunction %void None %58
+         %61 = OpLabel
+         %65 = OpAccessChain %_ptr_Uniform__arr_mat4x4_f16_uint_4 %u %uint_0
+         %66 = OpLoad %_arr_mat4x4_f16_uint_4 %65
+         %62 = OpFunctionCall %_arr_mat4v4half_uint_4 %conv_arr4_mat4x4_f16 %66
+               OpStore %p %62
+         %70 = OpAccessChain %_ptr_Private_mat4v4half %p %int_1
+         %74 = OpAccessChain %_ptr_Uniform_mat4x4_f16 %u %uint_0 %uint_2
+         %75 = OpLoad %mat4x4_f16 %74
+         %71 = OpFunctionCall %mat4v4half %conv_mat4x4_f16 %75
+               OpStore %70 %71
+         %78 = OpAccessChain %_ptr_Private_v4half %p %int_1 %76
+         %80 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0 %32 %uint_1
+         %81 = OpLoad %v4half %80
+         %82 = OpVectorShuffle %v4half %81 %81 1 3 0 2
+               OpStore %78 %82
+         %84 = OpAccessChain %_ptr_Private_half %p %int_1 %76 %uint_0
+         %86 = OpAccessChain %_ptr_Uniform_half %u %uint_0 %32 %uint_1 %32
+         %87 = OpLoad %half %86
+               OpStore %84 %87
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..635f7aa
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_private.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat4x4<f16>, 4>;
+
+var<private> p : array<mat4x4<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[2];
+  p[1][0] = u[0][1].ywxz;
+  p[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_storage.wgsl b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_storage.wgsl
new file mode 100644
index 0000000..6f266ff
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_storage.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat4x4<f16>, 4>;
+@group(0) @binding(1) var<storage, read_write> s : array<mat4x4<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[2];
+    s[1][0] = u[0][1].ywxz;
+    s[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_storage.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..8a3aa03
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_storage.wgsl.expected.dxc.hlsl
@@ -0,0 +1,67 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[8];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 4> value) {
+  buffer.Store<vector<float16_t, 4> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 8u), value[1u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 16u), value[2u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 24u), value[3u]);
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 4> value[4]) {
+  matrix<float16_t, 4, 4> array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 32u)), array[i]);
+    }
+  }
+}
+
+matrix<float16_t, 4, 4> tint_symbol_4(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+}
+
+typedef matrix<float16_t, 4, 4> tint_symbol_3_ret[4];
+tint_symbol_3_ret tint_symbol_3(uint4 buffer[8], uint offset) {
+  matrix<float16_t, 4, 4> arr[4] = (matrix<float16_t, 4, 4>[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_4(buffer, (offset + (i_1 * 32u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_3(u, 0u));
+  tint_symbol_1(s, 32u, tint_symbol_4(u, 64u));
+  uint2 ubo_load_8 = u[0].zw;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_8_yw = vector<float16_t, 2>(f16tof32(ubo_load_8 >> 16));
+  s.Store<vector<float16_t, 4> >(32u, vector<float16_t, 4>(ubo_load_8_xz[0], ubo_load_8_yw[0], ubo_load_8_xz[1], ubo_load_8_yw[1]).ywxz);
+  s.Store<float16_t>(32u, float16_t(f16tof32(((u[0].z) & 0xFFFF))));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_storage.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..85e99c8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_storage.wgsl.expected.fxc.hlsl
@@ -0,0 +1,73 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[8];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 4> value) {
+  buffer.Store<vector<float16_t, 4> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 8u), value[1u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 16u), value[2u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 24u), value[3u]);
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 4> value[4]) {
+  matrix<float16_t, 4, 4> array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 32u)), array[i]);
+    }
+  }
+}
+
+matrix<float16_t, 4, 4> tint_symbol_4(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+}
+
+typedef matrix<float16_t, 4, 4> tint_symbol_3_ret[4];
+tint_symbol_3_ret tint_symbol_3(uint4 buffer[8], uint offset) {
+  matrix<float16_t, 4, 4> arr[4] = (matrix<float16_t, 4, 4>[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_4(buffer, (offset + (i_1 * 32u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_3(u, 0u));
+  tint_symbol_1(s, 32u, tint_symbol_4(u, 64u));
+  uint2 ubo_load_8 = u[0].zw;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_8_yw = vector<float16_t, 2>(f16tof32(ubo_load_8 >> 16));
+  s.Store<vector<float16_t, 4> >(32u, vector<float16_t, 4>(ubo_load_8_xz[0], ubo_load_8_yw[0], ubo_load_8_xz[1], ubo_load_8_yw[1]).ywxz);
+  s.Store<float16_t>(32u, float16_t(f16tof32(((u[0].z) & 0xFFFF))));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000002420B3F4EF0(6,68-76): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000002420B3F4EF0(7,3-14): error X3018: invalid subscript 'Store'
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..a1c9b3d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_storage.wgsl.expected.glsl
@@ -0,0 +1,44 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct mat4x4_f16 {
+  f16vec4 col0;
+  f16vec4 col1;
+  f16vec4 col2;
+  f16vec4 col3;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  mat4x4_f16 inner[4];
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  f16mat4 inner[4];
+} s;
+
+f16mat4 conv_mat4x4_f16(mat4x4_f16 val) {
+  return f16mat4(val.col0, val.col1, val.col2, val.col3);
+}
+
+f16mat4[4] conv_arr4_mat4x4_f16(mat4x4_f16 val[4]) {
+  f16mat4 arr[4] = f16mat4[4](f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat4x4_f16(val[i]);
+    }
+  }
+  return arr;
+}
+
+void f() {
+  s.inner = conv_arr4_mat4x4_f16(u.inner);
+  s.inner[1] = conv_mat4x4_f16(u.inner[2u]);
+  s.inner[1][0] = u.inner[0u].col1.ywxz;
+  s.inner[1][0].x = u.inner[0u].col1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..a1a1e39
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_storage.wgsl.expected.msl
@@ -0,0 +1,24 @@
+#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];
+};
+
+kernel void f(device tint_array<half4x4, 4>* tint_symbol [[buffer(1)]], const constant tint_array<half4x4, 4>* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
+  (*(tint_symbol))[1][0] = half4((*(tint_symbol_1))[0][1]).ywxz;
+  (*(tint_symbol))[1][0][0] = (*(tint_symbol_1))[0][1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_storage.wgsl.expected.spvasm
new file mode 100644
index 0000000..ceb3651
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_storage.wgsl.expected.spvasm
@@ -0,0 +1,160 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 91
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %mat4x4_f16 "mat4x4_f16"
+               OpMemberName %mat4x4_f16 0 "col0"
+               OpMemberName %mat4x4_f16 1 "col1"
+               OpMemberName %mat4x4_f16 2 "col2"
+               OpMemberName %mat4x4_f16 3 "col3"
+               OpName %u "u"
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %s "s"
+               OpName %conv_mat4x4_f16 "conv_mat4x4_f16"
+               OpName %val "val"
+               OpName %conv_arr4_mat4x4_f16 "conv_arr4_mat4x4_f16"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %mat4x4_f16 0 Offset 0
+               OpMemberDecorate %mat4x4_f16 1 Offset 8
+               OpMemberDecorate %mat4x4_f16 2 Offset 16
+               OpMemberDecorate %mat4x4_f16 3 Offset 24
+               OpDecorate %_arr_mat4x4_f16_uint_4 ArrayStride 32
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 8
+               OpDecorate %_arr_mat4v4half_uint_4 ArrayStride 32
+               OpDecorate %s DescriptorSet 0
+               OpDecorate %s Binding 1
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+ %mat4x4_f16 = OpTypeStruct %v4half %v4half %v4half %v4half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat4x4_f16_uint_4 = OpTypeArray %mat4x4_f16 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_mat4x4_f16_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat4v4half = OpTypeMatrix %v4half 4
+%_arr_mat4v4half_uint_4 = OpTypeArray %mat4v4half %uint_4
+    %u_block = OpTypeStruct %_arr_mat4v4half_uint_4
+%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
+          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+         %15 = OpTypeFunction %mat4v4half %mat4x4_f16
+         %24 = OpTypeFunction %_arr_mat4v4half_uint_4 %_arr_mat4x4_f16_uint_4
+%_ptr_Function__arr_mat4v4half_uint_4 = OpTypePointer Function %_arr_mat4v4half_uint_4
+         %30 = OpConstantNull %_arr_mat4v4half_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %33 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_mat4x4_f16_uint_4 = OpTypePointer Function %_arr_mat4x4_f16_uint_4
+         %46 = OpConstantNull %_arr_mat4x4_f16_uint_4
+%_ptr_Function_mat4v4half = OpTypePointer Function %mat4v4half
+%_ptr_Function_mat4x4_f16 = OpTypePointer Function %mat4x4_f16
+     %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %59 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer__arr_mat4v4half_uint_4 = OpTypePointer StorageBuffer %_arr_mat4v4half_uint_4
+%_ptr_Uniform__arr_mat4x4_f16_uint_4 = OpTypePointer Uniform %_arr_mat4x4_f16_uint_4
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_mat4v4half = OpTypePointer StorageBuffer %mat4v4half
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_mat4x4_f16 = OpTypePointer Uniform %mat4x4_f16
+         %79 = OpConstantNull %int
+%_ptr_StorageBuffer_v4half = OpTypePointer StorageBuffer %v4half
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+%_ptr_StorageBuffer_half = OpTypePointer StorageBuffer %half
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+%conv_mat4x4_f16 = OpFunction %mat4v4half None %15
+        %val = OpFunctionParameter %mat4x4_f16
+         %18 = OpLabel
+         %19 = OpCompositeExtract %v4half %val 0
+         %20 = OpCompositeExtract %v4half %val 1
+         %21 = OpCompositeExtract %v4half %val 2
+         %22 = OpCompositeExtract %v4half %val 3
+         %23 = OpCompositeConstruct %mat4v4half %19 %20 %21 %22
+               OpReturnValue %23
+               OpFunctionEnd
+%conv_arr4_mat4x4_f16 = OpFunction %_arr_mat4v4half_uint_4 None %24
+      %val_0 = OpFunctionParameter %_arr_mat4x4_f16_uint_4
+         %27 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_mat4v4half_uint_4 Function %30
+          %i = OpVariable %_ptr_Function_uint Function %33
+%var_for_index = OpVariable %_ptr_Function__arr_mat4x4_f16_uint_4 Function %46
+               OpBranch %34
+         %34 = OpLabel
+               OpLoopMerge %35 %36 None
+               OpBranch %37
+         %37 = OpLabel
+         %39 = OpLoad %uint %i
+         %40 = OpULessThan %bool %39 %uint_4
+         %38 = OpLogicalNot %bool %40
+               OpSelectionMerge %42 None
+               OpBranchConditional %38 %43 %42
+         %43 = OpLabel
+               OpBranch %35
+         %42 = OpLabel
+               OpStore %var_for_index %val_0
+         %47 = OpLoad %uint %i
+         %49 = OpAccessChain %_ptr_Function_mat4v4half %arr %47
+         %51 = OpLoad %uint %i
+         %53 = OpAccessChain %_ptr_Function_mat4x4_f16 %var_for_index %51
+         %54 = OpLoad %mat4x4_f16 %53
+         %50 = OpFunctionCall %mat4v4half %conv_mat4x4_f16 %54
+               OpStore %49 %50
+               OpBranch %36
+         %36 = OpLabel
+         %55 = OpLoad %uint %i
+         %57 = OpIAdd %uint %55 %uint_1
+               OpStore %i %57
+               OpBranch %34
+         %35 = OpLabel
+         %58 = OpLoad %_arr_mat4v4half_uint_4 %arr
+               OpReturnValue %58
+               OpFunctionEnd
+          %f = OpFunction %void None %59
+         %62 = OpLabel
+         %65 = OpAccessChain %_ptr_StorageBuffer__arr_mat4v4half_uint_4 %s %uint_0
+         %68 = OpAccessChain %_ptr_Uniform__arr_mat4x4_f16_uint_4 %u %uint_0
+         %69 = OpLoad %_arr_mat4x4_f16_uint_4 %68
+         %66 = OpFunctionCall %_arr_mat4v4half_uint_4 %conv_arr4_mat4x4_f16 %69
+               OpStore %65 %66
+         %73 = OpAccessChain %_ptr_StorageBuffer_mat4v4half %s %uint_0 %int_1
+         %77 = OpAccessChain %_ptr_Uniform_mat4x4_f16 %u %uint_0 %uint_2
+         %78 = OpLoad %mat4x4_f16 %77
+         %74 = OpFunctionCall %mat4v4half %conv_mat4x4_f16 %78
+               OpStore %73 %74
+         %81 = OpAccessChain %_ptr_StorageBuffer_v4half %s %uint_0 %int_1 %79
+         %83 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0 %33 %uint_1
+         %84 = OpLoad %v4half %83
+         %85 = OpVectorShuffle %v4half %84 %84 1 3 0 2
+               OpStore %81 %85
+         %87 = OpAccessChain %_ptr_StorageBuffer_half %s %uint_0 %int_1 %79 %uint_0
+         %89 = OpAccessChain %_ptr_Uniform_half %u %uint_0 %33 %uint_1 %33
+         %90 = OpLoad %half %89
+               OpStore %87 %90
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..88e110e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat4x4<f16>, 4>;
+
+@group(0) @binding(1) var<storage, read_write> s : array<mat4x4<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[2];
+  s[1][0] = u[0][1].ywxz;
+  s[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_workgroup.wgsl
new file mode 100644
index 0000000..aff44e7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_workgroup.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat4x4<f16>, 4>;
+var<workgroup> w : array<mat4x4<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[2];
+    w[1][0] = u[0][1].ywxz;
+    w[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_workgroup.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..94db3c4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_workgroup.wgsl.expected.dxc.hlsl
@@ -0,0 +1,66 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[8];
+};
+groupshared matrix<float16_t, 4, 4> w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 4, 4> tint_symbol_3(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+}
+
+typedef matrix<float16_t, 4, 4> tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[8], uint offset) {
+  matrix<float16_t, 4, 4> arr[4] = (matrix<float16_t, 4, 4>[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 32u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      w[i] = matrix<float16_t, 4, 4>((float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx);
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 64u);
+  uint2 ubo_load_8 = u[0].zw;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_8_yw = vector<float16_t, 2>(f16tof32(ubo_load_8 >> 16));
+  w[1][0] = vector<float16_t, 4>(ubo_load_8_xz[0], ubo_load_8_yw[0], ubo_load_8_xz[1], ubo_load_8_yw[1]).ywxz;
+  w[1][0].x = float16_t(f16tof32(((u[0].z) & 0xFFFF)));
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_workgroup.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..ccb834a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_workgroup.wgsl.expected.fxc.hlsl
@@ -0,0 +1,71 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[8];
+};
+groupshared matrix<float16_t, 4, 4> w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 4, 4> tint_symbol_3(uint4 buffer[8], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+}
+
+typedef matrix<float16_t, 4, 4> tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[8], uint offset) {
+  matrix<float16_t, 4, 4> arr[4] = (matrix<float16_t, 4, 4>[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 32u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      w[i] = matrix<float16_t, 4, 4>((float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx);
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 64u);
+  uint2 ubo_load_8 = u[0].zw;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_8_yw = vector<float16_t, 2>(f16tof32(ubo_load_8 >> 16));
+  w[1][0] = vector<float16_t, 4>(ubo_load_8_xz[0], ubo_load_8_yw[0], ubo_load_8_xz[1], ubo_load_8_yw[1]).ywxz;
+  w[1][0].x = float16_t(f16tof32(((u[0].z) & 0xFFFF)));
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000002B4C90BEEA0(4,20-28): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..470c0fa
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,48 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct mat4x4_f16 {
+  f16vec4 col0;
+  f16vec4 col1;
+  f16vec4 col2;
+  f16vec4 col3;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  mat4x4_f16 inner[4];
+} u;
+
+shared f16mat4 w[4];
+f16mat4 conv_mat4x4_f16(mat4x4_f16 val) {
+  return f16mat4(val.col0, val.col1, val.col2, val.col3);
+}
+
+f16mat4[4] conv_arr4_mat4x4_f16(mat4x4_f16 val[4]) {
+  f16mat4 arr[4] = f16mat4[4](f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_mat4x4_f16(val[i]);
+    }
+  }
+  return arr;
+}
+
+void f(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      uint i = idx;
+      w[i] = f16mat4(f16vec4(0.0hf), f16vec4(0.0hf), f16vec4(0.0hf), f16vec4(0.0hf));
+    }
+  }
+  barrier();
+  w = conv_arr4_mat4x4_f16(u.inner);
+  w[1] = conv_mat4x4_f16(u.inner[2u]);
+  w[1][0] = u.inner[0u].col1.ywxz;
+  w[1][0].x = u.inner[0u].col1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..bd1f293
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,38 @@
+#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_symbol_5 {
+  tint_array<half4x4, 4> w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup tint_array<half4x4, 4>* const tint_symbol, const constant tint_array<half4x4, 4>* const tint_symbol_1) {
+  for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+    uint const i = idx;
+    (*(tint_symbol))[i] = half4x4(half4(0.0h), half4(0.0h), half4(0.0h), half4(0.0h));
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
+  (*(tint_symbol))[1][0] = half4((*(tint_symbol_1))[0][1]).ywxz;
+  (*(tint_symbol))[1][0][0] = (*(tint_symbol_1))[0][1][0];
+}
+
+kernel void f(const constant tint_array<half4x4, 4>* tint_symbol_4 [[buffer(0)]], threadgroup tint_symbol_5* tint_symbol_3 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup tint_array<half4x4, 4>* const tint_symbol_2 = &((*(tint_symbol_3)).w);
+  f_inner(local_invocation_index, tint_symbol_2, tint_symbol_4);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_workgroup.wgsl.expected.spvasm
new file mode 100644
index 0000000..a50827e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_workgroup.wgsl.expected.spvasm
@@ -0,0 +1,192 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 113
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %local_invocation_index_1 "local_invocation_index_1"
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %mat4x4_f16 "mat4x4_f16"
+               OpMemberName %mat4x4_f16 0 "col0"
+               OpMemberName %mat4x4_f16 1 "col1"
+               OpMemberName %mat4x4_f16 2 "col2"
+               OpMemberName %mat4x4_f16 3 "col3"
+               OpName %u "u"
+               OpName %w "w"
+               OpName %conv_mat4x4_f16 "conv_mat4x4_f16"
+               OpName %val "val"
+               OpName %conv_arr4_mat4x4_f16 "conv_arr4_mat4x4_f16"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %f_inner "f_inner"
+               OpName %local_invocation_index "local_invocation_index"
+               OpName %idx "idx"
+               OpName %f "f"
+               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %mat4x4_f16 0 Offset 0
+               OpMemberDecorate %mat4x4_f16 1 Offset 8
+               OpMemberDecorate %mat4x4_f16 2 Offset 16
+               OpMemberDecorate %mat4x4_f16 3 Offset 24
+               OpDecorate %_arr_mat4x4_f16_uint_4 ArrayStride 32
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %_arr_mat4v4half_uint_4 ArrayStride 32
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+ %mat4x4_f16 = OpTypeStruct %v4half %v4half %v4half %v4half
+     %uint_4 = OpConstant %uint 4
+%_arr_mat4x4_f16_uint_4 = OpTypeArray %mat4x4_f16 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_mat4x4_f16_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat4v4half = OpTypeMatrix %v4half 4
+%_arr_mat4v4half_uint_4 = OpTypeArray %mat4v4half %uint_4
+%_ptr_Workgroup__arr_mat4v4half_uint_4 = OpTypePointer Workgroup %_arr_mat4v4half_uint_4
+          %w = OpVariable %_ptr_Workgroup__arr_mat4v4half_uint_4 Workgroup
+         %16 = OpTypeFunction %mat4v4half %mat4x4_f16
+         %25 = OpTypeFunction %_arr_mat4v4half_uint_4 %_arr_mat4x4_f16_uint_4
+%_ptr_Function__arr_mat4v4half_uint_4 = OpTypePointer Function %_arr_mat4v4half_uint_4
+         %31 = OpConstantNull %_arr_mat4v4half_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %34 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_mat4x4_f16_uint_4 = OpTypePointer Function %_arr_mat4x4_f16_uint_4
+         %47 = OpConstantNull %_arr_mat4x4_f16_uint_4
+%_ptr_Function_mat4v4half = OpTypePointer Function %mat4v4half
+%_ptr_Function_mat4x4_f16 = OpTypePointer Function %mat4x4_f16
+     %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %60 = OpTypeFunction %void %uint
+%_ptr_Workgroup_mat4v4half = OpTypePointer Workgroup %mat4v4half
+         %78 = OpConstantNull %mat4v4half
+     %uint_2 = OpConstant %uint 2
+   %uint_264 = OpConstant %uint 264
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat4x4_f16_uint_4 = OpTypePointer Uniform %_arr_mat4x4_f16_uint_4
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_mat4x4_f16 = OpTypePointer Uniform %mat4x4_f16
+         %96 = OpConstantNull %int
+%_ptr_Workgroup_v4half = OpTypePointer Workgroup %v4half
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+%_ptr_Workgroup_half = OpTypePointer Workgroup %half
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+        %108 = OpTypeFunction %void
+%conv_mat4x4_f16 = OpFunction %mat4v4half None %16
+        %val = OpFunctionParameter %mat4x4_f16
+         %19 = OpLabel
+         %20 = OpCompositeExtract %v4half %val 0
+         %21 = OpCompositeExtract %v4half %val 1
+         %22 = OpCompositeExtract %v4half %val 2
+         %23 = OpCompositeExtract %v4half %val 3
+         %24 = OpCompositeConstruct %mat4v4half %20 %21 %22 %23
+               OpReturnValue %24
+               OpFunctionEnd
+%conv_arr4_mat4x4_f16 = OpFunction %_arr_mat4v4half_uint_4 None %25
+      %val_0 = OpFunctionParameter %_arr_mat4x4_f16_uint_4
+         %28 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_mat4v4half_uint_4 Function %31
+          %i = OpVariable %_ptr_Function_uint Function %34
+%var_for_index = OpVariable %_ptr_Function__arr_mat4x4_f16_uint_4 Function %47
+               OpBranch %35
+         %35 = OpLabel
+               OpLoopMerge %36 %37 None
+               OpBranch %38
+         %38 = OpLabel
+         %40 = OpLoad %uint %i
+         %41 = OpULessThan %bool %40 %uint_4
+         %39 = OpLogicalNot %bool %41
+               OpSelectionMerge %43 None
+               OpBranchConditional %39 %44 %43
+         %44 = OpLabel
+               OpBranch %36
+         %43 = OpLabel
+               OpStore %var_for_index %val_0
+         %48 = OpLoad %uint %i
+         %50 = OpAccessChain %_ptr_Function_mat4v4half %arr %48
+         %52 = OpLoad %uint %i
+         %54 = OpAccessChain %_ptr_Function_mat4x4_f16 %var_for_index %52
+         %55 = OpLoad %mat4x4_f16 %54
+         %51 = OpFunctionCall %mat4v4half %conv_mat4x4_f16 %55
+               OpStore %50 %51
+               OpBranch %37
+         %37 = OpLabel
+         %56 = OpLoad %uint %i
+         %58 = OpIAdd %uint %56 %uint_1
+               OpStore %i %58
+               OpBranch %35
+         %36 = OpLabel
+         %59 = OpLoad %_arr_mat4v4half_uint_4 %arr
+               OpReturnValue %59
+               OpFunctionEnd
+    %f_inner = OpFunction %void None %60
+%local_invocation_index = OpFunctionParameter %uint
+         %64 = OpLabel
+        %idx = OpVariable %_ptr_Function_uint Function %34
+               OpStore %idx %local_invocation_index
+               OpBranch %66
+         %66 = OpLabel
+               OpLoopMerge %67 %68 None
+               OpBranch %69
+         %69 = OpLabel
+         %71 = OpLoad %uint %idx
+         %72 = OpULessThan %bool %71 %uint_4
+         %70 = OpLogicalNot %bool %72
+               OpSelectionMerge %73 None
+               OpBranchConditional %70 %74 %73
+         %74 = OpLabel
+               OpBranch %67
+         %73 = OpLabel
+         %75 = OpLoad %uint %idx
+         %77 = OpAccessChain %_ptr_Workgroup_mat4v4half %w %75
+               OpStore %77 %78
+               OpBranch %68
+         %68 = OpLabel
+         %79 = OpLoad %uint %idx
+         %80 = OpIAdd %uint %79 %uint_1
+               OpStore %idx %80
+               OpBranch %66
+         %67 = OpLabel
+               OpControlBarrier %uint_2 %uint_2 %uint_264
+         %87 = OpAccessChain %_ptr_Uniform__arr_mat4x4_f16_uint_4 %u %uint_0
+         %88 = OpLoad %_arr_mat4x4_f16_uint_4 %87
+         %84 = OpFunctionCall %_arr_mat4v4half_uint_4 %conv_arr4_mat4x4_f16 %88
+               OpStore %w %84
+         %91 = OpAccessChain %_ptr_Workgroup_mat4v4half %w %int_1
+         %94 = OpAccessChain %_ptr_Uniform_mat4x4_f16 %u %uint_0 %uint_2
+         %95 = OpLoad %mat4x4_f16 %94
+         %92 = OpFunctionCall %mat4v4half %conv_mat4x4_f16 %95
+               OpStore %91 %92
+         %98 = OpAccessChain %_ptr_Workgroup_v4half %w %int_1 %96
+        %100 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0 %34 %uint_1
+        %101 = OpLoad %v4half %100
+        %102 = OpVectorShuffle %v4half %101 %101 1 3 0 2
+               OpStore %98 %102
+        %104 = OpAccessChain %_ptr_Workgroup_half %w %int_1 %96 %uint_0
+        %106 = OpAccessChain %_ptr_Uniform_half %u %uint_0 %34 %uint_1 %34
+        %107 = OpLoad %half %106
+               OpStore %104 %107
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %108
+        %110 = OpLabel
+        %112 = OpLoad %uint %local_invocation_index_1
+        %111 = OpFunctionCall %void %f_inner %112
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..98299cd
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f16/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : array<mat4x4<f16>, 4>;
+
+var<workgroup> w : array<mat4x4<f16>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[2];
+  w[1][0] = u[0][1].ywxz;
+  w[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/array/mat4x4_f32/dynamic_index_via_ptr.wgsl
new file mode 100644
index 0000000..cdc13d2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/dynamic_index_via_ptr.wgsl
@@ -0,0 +1,15 @@
+@group(0) @binding(0) var<uniform> a : array<mat4x4<f32>, 4>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a       = &a;
+  let p_a_i     = &((*p_a)[i()]);
+  let p_a_i_i   = &((*p_a_i)[i()]);
+
+  let l_a       : array<mat4x4<f32>, 4> = *p_a;
+  let l_a_i     : mat4x4<f32>           = *p_a_i;
+  let l_a_i_i   : vec4<f32>             = *p_a_i_i;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..cfb9ecf
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,39 @@
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[16];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float4x4 tint_symbol_1(uint4 buffer[16], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]), asfloat(buffer[scalar_offset_3 / 4]));
+}
+
+typedef float4x4 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[16], uint offset) {
+  float4x4 arr[4] = (float4x4[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_i_save = i();
+  const float4x4 l_a[4] = tint_symbol(a, 0u);
+  const float4x4 l_a_i = tint_symbol_1(a, (64u * uint(p_a_i_save)));
+  const uint scalar_offset_4 = (((64u * uint(p_a_i_save)) + (16u * uint(p_a_i_i_save)))) / 4;
+  const float4 l_a_i_i = asfloat(a[scalar_offset_4 / 4]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..cfb9ecf
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,39 @@
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[16];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float4x4 tint_symbol_1(uint4 buffer[16], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]), asfloat(buffer[scalar_offset_3 / 4]));
+}
+
+typedef float4x4 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[16], uint offset) {
+  float4x4 arr[4] = (float4x4[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_i_save = i();
+  const float4x4 l_a[4] = tint_symbol(a, 0u);
+  const float4x4 l_a_i = tint_symbol_1(a, (64u * uint(p_a_i_save)));
+  const uint scalar_offset_4 = (((64u * uint(p_a_i_save)) + (16u * uint(p_a_i_i_save)))) / 4;
+  const float4 l_a_i_i = asfloat(a[scalar_offset_4 / 4]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..da11781
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,27 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform a_block_ubo {
+  mat4 inner[4];
+} a;
+
+int counter = 0;
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+void f() {
+  int tint_symbol = i();
+  int p_a_i_save = tint_symbol;
+  int tint_symbol_1 = i();
+  int p_a_i_i_save = tint_symbol_1;
+  mat4 l_a[4] = a.inner;
+  mat4 l_a_i = a.inner[p_a_i_save];
+  vec4 l_a_i_i = a.inner[p_a_i_save][p_a_i_i_save];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..4aeaf64
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,33 @@
+#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];
+};
+
+int i() {
+  thread int tint_symbol_2 = 0;
+  tint_symbol_2 = as_type<int>((as_type<uint>(tint_symbol_2) + as_type<uint>(1)));
+  return tint_symbol_2;
+}
+
+kernel void f(const constant tint_array<float4x4, 4>* tint_symbol_3 [[buffer(0)]]) {
+  int const tint_symbol = i();
+  int const p_a_i_save = tint_symbol;
+  int const tint_symbol_1 = i();
+  int const p_a_i_i_save = tint_symbol_1;
+  tint_array<float4x4, 4> const l_a = *(tint_symbol_3);
+  float4x4 const l_a_i = (*(tint_symbol_3))[p_a_i_save];
+  float4 const l_a_i_i = (*(tint_symbol_3))[p_a_i_save][p_a_i_i_save];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..0cb33b1
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,64 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 37
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block "a_block"
+               OpMemberName %a_block 0 "inner"
+               OpName %a "a"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %f "f"
+               OpDecorate %a_block Block
+               OpMemberDecorate %a_block 0 Offset 0
+               OpMemberDecorate %a_block 0 ColMajor
+               OpMemberDecorate %a_block 0 MatrixStride 16
+               OpDecorate %_arr_mat4v4float_uint_4 ArrayStride 64
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat4v4float = OpTypeMatrix %v4float 4
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat4v4float_uint_4 = OpTypeArray %mat4v4float %uint_4
+    %a_block = OpTypeStruct %_arr_mat4v4float_uint_4
+%_ptr_Uniform_a_block = OpTypePointer Uniform %a_block
+          %a = OpVariable %_ptr_Uniform_a_block Uniform
+        %int = OpTypeInt 32 1
+         %11 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %11
+         %14 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+       %void = OpTypeVoid
+         %21 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat4v4float_uint_4 = OpTypePointer Uniform %_arr_mat4v4float_uint_4
+%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+          %i = OpFunction %int None %14
+         %16 = OpLabel
+         %17 = OpLoad %int %counter
+         %19 = OpIAdd %int %17 %int_1
+               OpStore %counter %19
+         %20 = OpLoad %int %counter
+               OpReturnValue %20
+               OpFunctionEnd
+          %f = OpFunction %void None %21
+         %24 = OpLabel
+         %25 = OpFunctionCall %int %i
+         %26 = OpFunctionCall %int %i
+         %29 = OpAccessChain %_ptr_Uniform__arr_mat4v4float_uint_4 %a %uint_0
+         %30 = OpLoad %_arr_mat4v4float_uint_4 %29
+         %32 = OpAccessChain %_ptr_Uniform_mat4v4float %a %uint_0 %25
+         %33 = OpLoad %mat4v4float %32
+         %35 = OpAccessChain %_ptr_Uniform_v4float %a %uint_0 %25 %26
+         %36 = OpLoad %v4float %35
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..3221228
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+@group(0) @binding(0) var<uniform> a : array<mat4x4<f32>, 4>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_i = &((*(p_a))[i()]);
+  let p_a_i_i = &((*(p_a_i))[i()]);
+  let l_a : array<mat4x4<f32>, 4> = *(p_a);
+  let l_a_i : mat4x4<f32> = *(p_a_i);
+  let l_a_i_i : vec4<f32> = *(p_a_i_i);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/array/mat4x4_f32/static_index_via_ptr.wgsl
new file mode 100644
index 0000000..120e0f8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/static_index_via_ptr.wgsl
@@ -0,0 +1,12 @@
+@group(0) @binding(0) var<uniform> a : array<mat4x4<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a       = &a;
+  let p_a_2     = &((*p_a)[2]);
+  let p_a_2_1   = &((*p_a_2)[1]);
+
+  let l_a       : array<mat4x4<f32>, 4> = *p_a;
+  let l_a_i     : mat4x4<f32>           = *p_a_2;
+  let l_a_i_i   : vec4<f32>             = *p_a_2_1;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x4_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..ac24f04
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,30 @@
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[16];
+};
+
+float4x4 tint_symbol_1(uint4 buffer[16], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]), asfloat(buffer[scalar_offset_3 / 4]));
+}
+
+typedef float4x4 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[16], uint offset) {
+  float4x4 arr[4] = (float4x4[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float4x4 l_a[4] = tint_symbol(a, 0u);
+  const float4x4 l_a_i = tint_symbol_1(a, 128u);
+  const float4 l_a_i_i = asfloat(a[9]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x4_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..ac24f04
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,30 @@
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[16];
+};
+
+float4x4 tint_symbol_1(uint4 buffer[16], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]), asfloat(buffer[scalar_offset_3 / 4]));
+}
+
+typedef float4x4 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[16], uint offset) {
+  float4x4 arr[4] = (float4x4[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float4x4 l_a[4] = tint_symbol(a, 0u);
+  const float4x4 l_a_i = tint_symbol_1(a, 128u);
+  const float4 l_a_i_i = asfloat(a[9]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x4_f32/static_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..7edadaf
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/static_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,17 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform a_block_ubo {
+  mat4 inner[4];
+} a;
+
+void f() {
+  mat4 l_a[4] = a.inner;
+  mat4 l_a_i = a.inner[2];
+  vec4 l_a_i_i = a.inner[2][1];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat4x4_f32/static_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..4686650
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/static_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,23 @@
+#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];
+};
+
+kernel void f(const constant tint_array<float4x4, 4>* tint_symbol [[buffer(0)]]) {
+  tint_array<float4x4, 4> const l_a = *(tint_symbol);
+  float4x4 const l_a_i = (*(tint_symbol))[2];
+  float4 const l_a_i_i = (*(tint_symbol))[2][1];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x4_f32/static_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..9cf1346
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/static_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,49 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 27
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block "a_block"
+               OpMemberName %a_block 0 "inner"
+               OpName %a "a"
+               OpName %f "f"
+               OpDecorate %a_block Block
+               OpMemberDecorate %a_block 0 Offset 0
+               OpMemberDecorate %a_block 0 ColMajor
+               OpMemberDecorate %a_block 0 MatrixStride 16
+               OpDecorate %_arr_mat4v4float_uint_4 ArrayStride 64
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat4v4float = OpTypeMatrix %v4float 4
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat4v4float_uint_4 = OpTypeArray %mat4v4float %uint_4
+    %a_block = OpTypeStruct %_arr_mat4v4float_uint_4
+%_ptr_Uniform_a_block = OpTypePointer Uniform %a_block
+          %a = OpVariable %_ptr_Uniform_a_block Uniform
+       %void = OpTypeVoid
+         %10 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat4v4float_uint_4 = OpTypePointer Uniform %_arr_mat4v4float_uint_4
+        %int = OpTypeInt 32 1
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+          %f = OpFunction %void None %10
+         %13 = OpLabel
+         %16 = OpAccessChain %_ptr_Uniform__arr_mat4v4float_uint_4 %a %uint_0
+         %17 = OpLoad %_arr_mat4v4float_uint_4 %16
+         %21 = OpAccessChain %_ptr_Uniform_mat4v4float %a %uint_0 %int_2
+         %22 = OpLoad %mat4v4float %21
+         %25 = OpAccessChain %_ptr_Uniform_v4float %a %uint_0 %int_2 %int_1
+         %26 = OpLoad %v4float %25
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat4x4_f32/static_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..750bb8f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/static_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> a : array<mat4x4<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_2 = &((*(p_a))[2]);
+  let p_a_2_1 = &((*(p_a_2))[1]);
+  let l_a : array<mat4x4<f32>, 4> = *(p_a);
+  let l_a_i : mat4x4<f32> = *(p_a_2);
+  let l_a_i_i : vec4<f32> = *(p_a_2_1);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_builtin.wgsl b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_builtin.wgsl
new file mode 100644
index 0000000..2f236c9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_builtin.wgsl
@@ -0,0 +1,8 @@
+@group(0) @binding(0) var<uniform> u : array<mat4x4<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    let t = transpose(u[2]);
+    let l = length(u[0][1].ywxz);
+    let a = abs(u[0][1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_builtin.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..bb637b6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_builtin.wgsl.expected.dxc.hlsl
@@ -0,0 +1,19 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[16];
+};
+
+float4x4 tint_symbol(uint4 buffer[16], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]), asfloat(buffer[scalar_offset_3 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float4x4 t = transpose(tint_symbol(u, 128u));
+  const float l = length(asfloat(u[1]).ywxz);
+  const float a = abs(asfloat(u[1]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_builtin.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..bb637b6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_builtin.wgsl.expected.fxc.hlsl
@@ -0,0 +1,19 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[16];
+};
+
+float4x4 tint_symbol(uint4 buffer[16], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]), asfloat(buffer[scalar_offset_3 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float4x4 t = transpose(tint_symbol(u, 128u));
+  const float l = length(asfloat(u[1]).ywxz);
+  const float a = abs(asfloat(u[1]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_builtin.wgsl.expected.glsl
new file mode 100644
index 0000000..8268770
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_builtin.wgsl.expected.glsl
@@ -0,0 +1,17 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat4 inner[4];
+} u;
+
+void f() {
+  mat4 t = transpose(u.inner[2]);
+  float l = length(u.inner[0][1].ywxz);
+  float a = abs(u.inner[0][1].ywxz.x);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_builtin.wgsl.expected.msl
new file mode 100644
index 0000000..b7a398b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_builtin.wgsl.expected.msl
@@ -0,0 +1,23 @@
+#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];
+};
+
+kernel void f(const constant tint_array<float4x4, 4>* tint_symbol [[buffer(0)]]) {
+  float4x4 const t = transpose((*(tint_symbol))[2]);
+  float const l = length(float4((*(tint_symbol))[0][1]).ywxz);
+  float const a = fabs(float4((*(tint_symbol))[0][1]).ywxz[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_builtin.wgsl.expected.spvasm
new file mode 100644
index 0000000..e923130
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_builtin.wgsl.expected.spvasm
@@ -0,0 +1,56 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 34
+; Schema: 0
+               OpCapability Shader
+         %22 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %_arr_mat4v4float_uint_4 ArrayStride 64
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat4v4float = OpTypeMatrix %v4float 4
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat4v4float_uint_4 = OpTypeArray %mat4v4float %uint_4
+    %u_block = OpTypeStruct %_arr_mat4v4float_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+         %10 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+        %int = OpTypeInt 32 1
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float
+         %23 = OpConstantNull %int
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+          %f = OpFunction %void None %10
+         %13 = OpLabel
+         %19 = OpAccessChain %_ptr_Uniform_mat4v4float %u %uint_0 %int_2
+         %20 = OpLoad %mat4v4float %19
+         %14 = OpTranspose %mat4v4float %20
+         %26 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %23 %int_1
+         %27 = OpLoad %v4float %26
+         %28 = OpVectorShuffle %v4float %27 %27 1 3 0 2
+         %21 = OpExtInst %float %22 Length %28
+         %30 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %23 %int_1
+         %31 = OpLoad %v4float %30
+         %32 = OpVectorShuffle %v4float %31 %31 1 3 0 2
+         %33 = OpCompositeExtract %float %32 0
+         %29 = OpExtInst %float %22 FAbs %33
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_builtin.wgsl.expected.wgsl
new file mode 100644
index 0000000..eec03cd
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_builtin.wgsl.expected.wgsl
@@ -0,0 +1,8 @@
+@group(0) @binding(0) var<uniform> u : array<mat4x4<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let t = transpose(u[2]);
+  let l = length(u[0][1].ywxz);
+  let a = abs(u[0][1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_fn.wgsl b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_fn.wgsl
new file mode 100644
index 0000000..2a62ac9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_fn.wgsl
@@ -0,0 +1,14 @@
+@group(0) @binding(0) var<uniform> u : array<mat4x4<f32>, 4>;
+
+fn a(a : array<mat4x4<f32>, 4>) {}
+fn b(m : mat4x4<f32>) {}
+fn c(v : vec4<f32>) {}
+fn d(f : f32) {}
+
+@compute @workgroup_size(1)
+fn f() {
+    a(u);
+    b(u[1]);
+    c(u[1][0].ywxz);
+    d(u[1][0].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_fn.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..c6389d9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_fn.wgsl.expected.dxc.hlsl
@@ -0,0 +1,43 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[16];
+};
+
+void a(float4x4 a_1[4]) {
+}
+
+void b(float4x4 m) {
+}
+
+void c(float4 v) {
+}
+
+void d(float f_1) {
+}
+
+float4x4 tint_symbol_1(uint4 buffer[16], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]), asfloat(buffer[scalar_offset_3 / 4]));
+}
+
+typedef float4x4 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[16], uint offset) {
+  float4x4 arr[4] = (float4x4[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 64u));
+  c(asfloat(u[4]).ywxz);
+  d(asfloat(u[4]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_fn.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..c6389d9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_fn.wgsl.expected.fxc.hlsl
@@ -0,0 +1,43 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[16];
+};
+
+void a(float4x4 a_1[4]) {
+}
+
+void b(float4x4 m) {
+}
+
+void c(float4 v) {
+}
+
+void d(float f_1) {
+}
+
+float4x4 tint_symbol_1(uint4 buffer[16], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]), asfloat(buffer[scalar_offset_3 / 4]));
+}
+
+typedef float4x4 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[16], uint offset) {
+  float4x4 arr[4] = (float4x4[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 64u));
+  c(asfloat(u[4]).ywxz);
+  d(asfloat(u[4]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_fn.wgsl.expected.glsl
new file mode 100644
index 0000000..20116f4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_fn.wgsl.expected.glsl
@@ -0,0 +1,30 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat4 inner[4];
+} u;
+
+void a(mat4 a_1[4]) {
+}
+
+void b(mat4 m) {
+}
+
+void c(vec4 v) {
+}
+
+void d(float f_1) {
+}
+
+void f() {
+  a(u.inner);
+  b(u.inner[1]);
+  c(u.inner[1][0].ywxz);
+  d(u.inner[1][0].ywxz.x);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_fn.wgsl.expected.msl
new file mode 100644
index 0000000..1d08324
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_fn.wgsl.expected.msl
@@ -0,0 +1,36 @@
+#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];
+};
+
+void a(tint_array<float4x4, 4> a_1) {
+}
+
+void b(float4x4 m) {
+}
+
+void c(float4 v) {
+}
+
+void d(float f_1) {
+}
+
+kernel void f(const constant tint_array<float4x4, 4>* tint_symbol [[buffer(0)]]) {
+  a(*(tint_symbol));
+  b((*(tint_symbol))[1]);
+  c(float4((*(tint_symbol))[1][0]).ywxz);
+  d(float4((*(tint_symbol))[1][0]).ywxz[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_fn.wgsl.expected.spvasm
new file mode 100644
index 0000000..776c363
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_fn.wgsl.expected.spvasm
@@ -0,0 +1,90 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 52
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %a "a"
+               OpName %a_1 "a_1"
+               OpName %b "b"
+               OpName %m "m"
+               OpName %c "c"
+               OpName %v "v"
+               OpName %d "d"
+               OpName %f_1 "f_1"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %_arr_mat4v4float_uint_4 ArrayStride 64
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat4v4float = OpTypeMatrix %v4float 4
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat4v4float_uint_4 = OpTypeArray %mat4v4float %uint_4
+    %u_block = OpTypeStruct %_arr_mat4v4float_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+         %10 = OpTypeFunction %void %_arr_mat4v4float_uint_4
+         %15 = OpTypeFunction %void %mat4v4float
+         %19 = OpTypeFunction %void %v4float
+         %23 = OpTypeFunction %void %float
+         %27 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat4v4float_uint_4 = OpTypePointer Uniform %_arr_mat4v4float_uint_4
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float
+         %42 = OpConstantNull %int
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+          %a = OpFunction %void None %10
+        %a_1 = OpFunctionParameter %_arr_mat4v4float_uint_4
+         %14 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %b = OpFunction %void None %15
+          %m = OpFunctionParameter %mat4v4float
+         %18 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %c = OpFunction %void None %19
+          %v = OpFunctionParameter %v4float
+         %22 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %d = OpFunction %void None %23
+        %f_1 = OpFunctionParameter %float
+         %26 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %27
+         %29 = OpLabel
+         %33 = OpAccessChain %_ptr_Uniform__arr_mat4v4float_uint_4 %u %uint_0
+         %34 = OpLoad %_arr_mat4v4float_uint_4 %33
+         %30 = OpFunctionCall %void %a %34
+         %39 = OpAccessChain %_ptr_Uniform_mat4v4float %u %uint_0 %int_1
+         %40 = OpLoad %mat4v4float %39
+         %35 = OpFunctionCall %void %b %40
+         %44 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %int_1 %42
+         %45 = OpLoad %v4float %44
+         %46 = OpVectorShuffle %v4float %45 %45 1 3 0 2
+         %41 = OpFunctionCall %void %c %46
+         %48 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %int_1 %42
+         %49 = OpLoad %v4float %48
+         %50 = OpVectorShuffle %v4float %49 %49 1 3 0 2
+         %51 = OpCompositeExtract %float %50 0
+         %47 = OpFunctionCall %void %d %51
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_fn.wgsl.expected.wgsl
new file mode 100644
index 0000000..d8a4bf3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_fn.wgsl.expected.wgsl
@@ -0,0 +1,21 @@
+@group(0) @binding(0) var<uniform> u : array<mat4x4<f32>, 4>;
+
+fn a(a : array<mat4x4<f32>, 4>) {
+}
+
+fn b(m : mat4x4<f32>) {
+}
+
+fn c(v : vec4<f32>) {
+}
+
+fn d(f : f32) {
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  a(u);
+  b(u[1]);
+  c(u[1][0].ywxz);
+  d(u[1][0].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_private.wgsl b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_private.wgsl
new file mode 100644
index 0000000..bc19927
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_private.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0) var<uniform> u : array<mat4x4<f32>, 4>;
+var<private> p : array<mat4x4<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[2];
+    p[1][0] = u[0][1].ywxz;
+    p[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_private.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..faaf6bb
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_private.wgsl.expected.dxc.hlsl
@@ -0,0 +1,32 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[16];
+};
+static float4x4 p[4] = (float4x4[4])0;
+
+float4x4 tint_symbol_1(uint4 buffer[16], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]), asfloat(buffer[scalar_offset_3 / 4]));
+}
+
+typedef float4x4 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[16], uint offset) {
+  float4x4 arr[4] = (float4x4[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 128u);
+  p[1][0] = asfloat(u[1]).ywxz;
+  p[1][0].x = asfloat(u[1].x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_private.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..faaf6bb
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_private.wgsl.expected.fxc.hlsl
@@ -0,0 +1,32 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[16];
+};
+static float4x4 p[4] = (float4x4[4])0;
+
+float4x4 tint_symbol_1(uint4 buffer[16], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]), asfloat(buffer[scalar_offset_3 / 4]));
+}
+
+typedef float4x4 tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[16], uint offset) {
+  float4x4 arr[4] = (float4x4[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 128u);
+  p[1][0] = asfloat(u[1]).ywxz;
+  p[1][0].x = asfloat(u[1].x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..6e23a7b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_private.wgsl.expected.glsl
@@ -0,0 +1,19 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat4 inner[4];
+} u;
+
+mat4 p[4] = mat4[4](mat4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), mat4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
+void f() {
+  p = u.inner;
+  p[1] = u.inner[2];
+  p[1][0] = u.inner[0][1].ywxz;
+  p[1][0].x = u.inner[0][1].x;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..9e7e72c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_private.wgsl.expected.msl
@@ -0,0 +1,25 @@
+#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];
+};
+
+kernel void f(const constant tint_array<float4x4, 4>* tint_symbol_1 [[buffer(0)]]) {
+  thread tint_array<float4x4, 4> tint_symbol = {};
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[2];
+  tint_symbol[1][0] = float4((*(tint_symbol_1))[0][1]).ywxz;
+  tint_symbol[1][0][0] = (*(tint_symbol_1))[0][1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_private.wgsl.expected.spvasm
new file mode 100644
index 0000000..0e3dad0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_private.wgsl.expected.spvasm
@@ -0,0 +1,68 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 41
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %p "p"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %_arr_mat4v4float_uint_4 ArrayStride 64
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat4v4float = OpTypeMatrix %v4float 4
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat4v4float_uint_4 = OpTypeArray %mat4v4float %uint_4
+    %u_block = OpTypeStruct %_arr_mat4v4float_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_Private__arr_mat4v4float_uint_4 = OpTypePointer Private %_arr_mat4v4float_uint_4
+         %12 = OpConstantNull %_arr_mat4v4float_uint_4
+          %p = OpVariable %_ptr_Private__arr_mat4v4float_uint_4 Private %12
+       %void = OpTypeVoid
+         %13 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat4v4float_uint_4 = OpTypePointer Uniform %_arr_mat4v4float_uint_4
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Private_mat4v4float = OpTypePointer Private %mat4v4float
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float
+         %29 = OpConstantNull %int
+%_ptr_Private_v4float = OpTypePointer Private %v4float
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+%_ptr_Private_float = OpTypePointer Private %float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+          %f = OpFunction %void None %13
+         %16 = OpLabel
+         %19 = OpAccessChain %_ptr_Uniform__arr_mat4v4float_uint_4 %u %uint_0
+         %20 = OpLoad %_arr_mat4v4float_uint_4 %19
+               OpStore %p %20
+         %24 = OpAccessChain %_ptr_Private_mat4v4float %p %int_1
+         %27 = OpAccessChain %_ptr_Uniform_mat4v4float %u %uint_0 %int_2
+         %28 = OpLoad %mat4v4float %27
+               OpStore %24 %28
+         %31 = OpAccessChain %_ptr_Private_v4float %p %int_1 %29
+         %33 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %29 %int_1
+         %34 = OpLoad %v4float %33
+         %35 = OpVectorShuffle %v4float %34 %34 1 3 0 2
+               OpStore %31 %35
+         %37 = OpAccessChain %_ptr_Private_float %p %int_1 %29 %uint_0
+         %39 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %29 %int_1 %uint_0
+         %40 = OpLoad %float %39
+               OpStore %37 %40
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..b309aad
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_private.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> u : array<mat4x4<f32>, 4>;
+
+var<private> p : array<mat4x4<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[2];
+  p[1][0] = u[0][1].ywxz;
+  p[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_storage.wgsl b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_storage.wgsl
new file mode 100644
index 0000000..20fd31a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_storage.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0) var<uniform> u : array<mat4x4<f32>, 4>;
+@group(0) @binding(1) var<storage, read_write> s : array<mat4x4<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[2];
+    s[1][0] = u[0][1].ywxz;
+    s[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_storage.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..9fd7977
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_storage.wgsl.expected.dxc.hlsl
@@ -0,0 +1,48 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[16];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, float4x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+  buffer.Store4((offset + 32u), asuint(value[2u]));
+  buffer.Store4((offset + 48u), asuint(value[3u]));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, float4x4 value[4]) {
+  float4x4 array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 64u)), array[i]);
+    }
+  }
+}
+
+float4x4 tint_symbol_4(uint4 buffer[16], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]), asfloat(buffer[scalar_offset_3 / 4]));
+}
+
+typedef float4x4 tint_symbol_3_ret[4];
+tint_symbol_3_ret tint_symbol_3(uint4 buffer[16], uint offset) {
+  float4x4 arr[4] = (float4x4[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_4(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_3(u, 0u));
+  tint_symbol_1(s, 64u, tint_symbol_4(u, 128u));
+  s.Store4(64u, asuint(asfloat(u[1]).ywxz));
+  s.Store(64u, asuint(asfloat(u[1].x)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_storage.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..9fd7977
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_storage.wgsl.expected.fxc.hlsl
@@ -0,0 +1,48 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[16];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, float4x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+  buffer.Store4((offset + 32u), asuint(value[2u]));
+  buffer.Store4((offset + 48u), asuint(value[3u]));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, float4x4 value[4]) {
+  float4x4 array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 64u)), array[i]);
+    }
+  }
+}
+
+float4x4 tint_symbol_4(uint4 buffer[16], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]), asfloat(buffer[scalar_offset_3 / 4]));
+}
+
+typedef float4x4 tint_symbol_3_ret[4];
+tint_symbol_3_ret tint_symbol_3(uint4 buffer[16], uint offset) {
+  float4x4 arr[4] = (float4x4[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_4(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_3(u, 0u));
+  tint_symbol_1(s, 64u, tint_symbol_4(u, 128u));
+  s.Store4(64u, asuint(asfloat(u[1]).ywxz));
+  s.Store(64u, asuint(asfloat(u[1].x)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..4cd2b78
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_storage.wgsl.expected.glsl
@@ -0,0 +1,22 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat4 inner[4];
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  mat4 inner[4];
+} s;
+
+void f() {
+  s.inner = u.inner;
+  s.inner[1] = u.inner[2];
+  s.inner[1][0] = u.inner[0][1].ywxz;
+  s.inner[1][0].x = u.inner[0][1].x;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..99338a6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_storage.wgsl.expected.msl
@@ -0,0 +1,24 @@
+#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];
+};
+
+kernel void f(device tint_array<float4x4, 4>* tint_symbol [[buffer(1)]], const constant tint_array<float4x4, 4>* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
+  (*(tint_symbol))[1][0] = float4((*(tint_symbol_1))[0][1]).ywxz;
+  (*(tint_symbol))[1][0][0] = (*(tint_symbol_1))[0][1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_storage.wgsl.expected.spvasm
new file mode 100644
index 0000000..8867684
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_storage.wgsl.expected.spvasm
@@ -0,0 +1,71 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 42
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %s "s"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %_arr_mat4v4float_uint_4 ArrayStride 64
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %s DescriptorSet 0
+               OpDecorate %s Binding 1
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat4v4float = OpTypeMatrix %v4float 4
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat4v4float_uint_4 = OpTypeArray %mat4v4float %uint_4
+    %u_block = OpTypeStruct %_arr_mat4v4float_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
+          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+       %void = OpTypeVoid
+         %12 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer__arr_mat4v4float_uint_4 = OpTypePointer StorageBuffer %_arr_mat4v4float_uint_4
+%_ptr_Uniform__arr_mat4v4float_uint_4 = OpTypePointer Uniform %_arr_mat4v4float_uint_4
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_mat4v4float = OpTypePointer StorageBuffer %mat4v4float
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float
+         %30 = OpConstantNull %int
+%_ptr_StorageBuffer_v4float = OpTypePointer StorageBuffer %v4float
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+          %f = OpFunction %void None %12
+         %15 = OpLabel
+         %18 = OpAccessChain %_ptr_StorageBuffer__arr_mat4v4float_uint_4 %s %uint_0
+         %20 = OpAccessChain %_ptr_Uniform__arr_mat4v4float_uint_4 %u %uint_0
+         %21 = OpLoad %_arr_mat4v4float_uint_4 %20
+               OpStore %18 %21
+         %25 = OpAccessChain %_ptr_StorageBuffer_mat4v4float %s %uint_0 %int_1
+         %28 = OpAccessChain %_ptr_Uniform_mat4v4float %u %uint_0 %int_2
+         %29 = OpLoad %mat4v4float %28
+               OpStore %25 %29
+         %32 = OpAccessChain %_ptr_StorageBuffer_v4float %s %uint_0 %int_1 %30
+         %34 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %30 %int_1
+         %35 = OpLoad %v4float %34
+         %36 = OpVectorShuffle %v4float %35 %35 1 3 0 2
+               OpStore %32 %36
+         %38 = OpAccessChain %_ptr_StorageBuffer_float %s %uint_0 %int_1 %30 %uint_0
+         %40 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %30 %int_1 %uint_0
+         %41 = OpLoad %float %40
+               OpStore %38 %41
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..3423e03
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> u : array<mat4x4<f32>, 4>;
+
+@group(0) @binding(1) var<storage, read_write> s : array<mat4x4<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[2];
+  s[1][0] = u[0][1].ywxz;
+  s[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_workgroup.wgsl
new file mode 100644
index 0000000..353d20c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_workgroup.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0) var<uniform> u : array<mat4x4<f32>, 4>;
+var<workgroup> w : array<mat4x4<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[2];
+    w[1][0] = u[0][1].ywxz;
+    w[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_workgroup.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..312730e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_workgroup.wgsl.expected.dxc.hlsl
@@ -0,0 +1,47 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[16];
+};
+groupshared float4x4 w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+float4x4 tint_symbol_3(uint4 buffer[16], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]), asfloat(buffer[scalar_offset_3 / 4]));
+}
+
+typedef float4x4 tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[16], uint offset) {
+  float4x4 arr[4] = (float4x4[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      w[i] = float4x4((0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx);
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 128u);
+  w[1][0] = asfloat(u[1]).ywxz;
+  w[1][0].x = asfloat(u[1].x);
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_workgroup.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..312730e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_workgroup.wgsl.expected.fxc.hlsl
@@ -0,0 +1,47 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[16];
+};
+groupshared float4x4 w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+float4x4 tint_symbol_3(uint4 buffer[16], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]), asfloat(buffer[scalar_offset_3 / 4]));
+}
+
+typedef float4x4 tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[16], uint offset) {
+  float4x4 arr[4] = (float4x4[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      w[i] = float4x4((0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx);
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 128u);
+  w[1][0] = asfloat(u[1]).ywxz;
+  w[1][0].x = asfloat(u[1].x);
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..3c9583f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,26 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat4 inner[4];
+} u;
+
+shared mat4 w[4];
+void f(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      uint i = idx;
+      w[i] = mat4(vec4(0.0f), vec4(0.0f), vec4(0.0f), vec4(0.0f));
+    }
+  }
+  barrier();
+  w = u.inner;
+  w[1] = u.inner[2];
+  w[1][0] = u.inner[0][1].ywxz;
+  w[1][0].x = u.inner[0][1].x;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..2e14882
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,38 @@
+#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_symbol_5 {
+  tint_array<float4x4, 4> w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup tint_array<float4x4, 4>* const tint_symbol, const constant tint_array<float4x4, 4>* const tint_symbol_1) {
+  for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+    uint const i = idx;
+    (*(tint_symbol))[i] = float4x4(float4(0.0f), float4(0.0f), float4(0.0f), float4(0.0f));
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
+  (*(tint_symbol))[1][0] = float4((*(tint_symbol_1))[0][1]).ywxz;
+  (*(tint_symbol))[1][0][0] = (*(tint_symbol_1))[0][1][0];
+}
+
+kernel void f(const constant tint_array<float4x4, 4>* tint_symbol_4 [[buffer(0)]], threadgroup tint_symbol_5* tint_symbol_3 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup tint_array<float4x4, 4>* const tint_symbol_2 = &((*(tint_symbol_3)).w);
+  f_inner(local_invocation_index, tint_symbol_2, tint_symbol_4);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_workgroup.wgsl.expected.spvasm
new file mode 100644
index 0000000..27d483d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_workgroup.wgsl.expected.spvasm
@@ -0,0 +1,115 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 70
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %local_invocation_index_1 "local_invocation_index_1"
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %w "w"
+               OpName %f_inner "f_inner"
+               OpName %local_invocation_index "local_invocation_index"
+               OpName %idx "idx"
+               OpName %f "f"
+               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %_arr_mat4v4float_uint_4 ArrayStride 64
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat4v4float = OpTypeMatrix %v4float 4
+     %uint_4 = OpConstant %uint 4
+%_arr_mat4v4float_uint_4 = OpTypeArray %mat4v4float %uint_4
+    %u_block = OpTypeStruct %_arr_mat4v4float_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_Workgroup__arr_mat4v4float_uint_4 = OpTypePointer Workgroup %_arr_mat4v4float_uint_4
+          %w = OpVariable %_ptr_Workgroup__arr_mat4v4float_uint_4 Workgroup
+       %void = OpTypeVoid
+         %14 = OpTypeFunction %void %uint
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %21 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Workgroup_mat4v4float = OpTypePointer Workgroup %mat4v4float
+         %35 = OpConstantNull %mat4v4float
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+   %uint_264 = OpConstant %uint 264
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_mat4v4float_uint_4 = OpTypePointer Uniform %_arr_mat4v4float_uint_4
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float
+         %53 = OpConstantNull %int
+%_ptr_Workgroup_v4float = OpTypePointer Workgroup %v4float
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+%_ptr_Workgroup_float = OpTypePointer Workgroup %float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+         %65 = OpTypeFunction %void
+    %f_inner = OpFunction %void None %14
+%local_invocation_index = OpFunctionParameter %uint
+         %18 = OpLabel
+        %idx = OpVariable %_ptr_Function_uint Function %21
+               OpStore %idx %local_invocation_index
+               OpBranch %22
+         %22 = OpLabel
+               OpLoopMerge %23 %24 None
+               OpBranch %25
+         %25 = OpLabel
+         %27 = OpLoad %uint %idx
+         %28 = OpULessThan %bool %27 %uint_4
+         %26 = OpLogicalNot %bool %28
+               OpSelectionMerge %30 None
+               OpBranchConditional %26 %31 %30
+         %31 = OpLabel
+               OpBranch %23
+         %30 = OpLabel
+         %32 = OpLoad %uint %idx
+         %34 = OpAccessChain %_ptr_Workgroup_mat4v4float %w %32
+               OpStore %34 %35
+               OpBranch %24
+         %24 = OpLabel
+         %36 = OpLoad %uint %idx
+         %38 = OpIAdd %uint %36 %uint_1
+               OpStore %idx %38
+               OpBranch %22
+         %23 = OpLabel
+               OpControlBarrier %uint_2 %uint_2 %uint_264
+         %44 = OpAccessChain %_ptr_Uniform__arr_mat4v4float_uint_4 %u %uint_0
+         %45 = OpLoad %_arr_mat4v4float_uint_4 %44
+               OpStore %w %45
+         %48 = OpAccessChain %_ptr_Workgroup_mat4v4float %w %int_1
+         %51 = OpAccessChain %_ptr_Uniform_mat4v4float %u %uint_0 %int_2
+         %52 = OpLoad %mat4v4float %51
+               OpStore %48 %52
+         %55 = OpAccessChain %_ptr_Workgroup_v4float %w %int_1 %53
+         %57 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %53 %int_1
+         %58 = OpLoad %v4float %57
+         %59 = OpVectorShuffle %v4float %58 %58 1 3 0 2
+               OpStore %55 %59
+         %61 = OpAccessChain %_ptr_Workgroup_float %w %int_1 %53 %uint_0
+         %63 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %53 %int_1 %uint_0
+         %64 = OpLoad %float %63
+               OpStore %61 %64
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %65
+         %67 = OpLabel
+         %69 = OpLoad %uint %local_invocation_index_1
+         %68 = OpFunctionCall %void %f_inner %69
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..bfd5a5d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/array/mat4x4_f32/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> u : array<mat4x4<f32>, 4>;
+
+var<workgroup> w : array<mat4x4<f32>, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[2];
+  w[1][0] = u[0][1].ywxz;
+  w[1][0].x = u[0][1].x;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x2/dynamic_index_via_ptr.wgsl
deleted file mode 100644
index fc1258e..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/dynamic_index_via_ptr.wgsl
+++ /dev/null
@@ -1,31 +0,0 @@
-struct Inner {
-  m : mat2x2<f32>,
-}
-
-struct Outer {
-  a : array<Inner, 4>,
-}
-
-@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
-
-var<private> counter = 0;
-fn i() -> i32 { counter++; return counter; }
-
-@compute @workgroup_size(1)
-fn f() {
-  let p_a           = &a;
-  let p_a_i         = &((*p_a)[i()]);
-  let p_a_i_a       = &((*p_a_i).a);
-  let p_a_i_a_i     = &((*p_a_i_a)[i()]);
-  let p_a_i_a_i_m   = &((*p_a_i_a_i).m);
-  let p_a_i_a_i_m_i = &((*p_a_i_a_i_m)[i()]);
-
-
-  let l_a             : array<Outer, 4> =  *p_a;
-  let l_a_i           : Outer           =  *p_a_i;
-  let l_a_i_a         : array<Inner, 4> =  *p_a_i_a;
-  let l_a_i_a_i       : Inner           =  *p_a_i_a_i;
-  let l_a_i_a_i_m     : mat2x2<f32>     =  *p_a_i_a_i_m;
-  let l_a_i_a_i_m_i   : vec2<f32>       =  *p_a_i_a_i_m_i;
-  let l_a_i_a_i_m_i_i : f32             = (*p_a_i_a_i_m_i)[i()];
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x2/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
deleted file mode 100644
index bf03768..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
+++ /dev/null
@@ -1,78 +0,0 @@
-struct Inner {
-  float2x2 m;
-};
-struct Outer {
-  Inner a[4];
-};
-
-cbuffer cbuffer_a : register(b0, space0) {
-  uint4 a[16];
-};
-static int counter = 0;
-
-int i() {
-  counter = (counter + 1);
-  return counter;
-}
-
-float2x2 tint_symbol_8(uint4 buffer[16], uint offset) {
-  const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset / 4];
-  const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
-  return float2x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)));
-}
-
-Inner tint_symbol_7(uint4 buffer[16], uint offset) {
-  const Inner tint_symbol_11 = {tint_symbol_8(buffer, (offset + 0u))};
-  return tint_symbol_11;
-}
-
-typedef Inner tint_symbol_6_ret[4];
-tint_symbol_6_ret tint_symbol_6(uint4 buffer[16], uint offset) {
-  Inner arr[4] = (Inner[4])0;
-  {
-    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
-      arr[i_1] = tint_symbol_7(buffer, (offset + (i_1 * 16u)));
-    }
-  }
-  return arr;
-}
-
-Outer tint_symbol_5(uint4 buffer[16], uint offset) {
-  const Outer tint_symbol_12 = {tint_symbol_6(buffer, (offset + 0u))};
-  return tint_symbol_12;
-}
-
-typedef Outer tint_symbol_4_ret[4];
-tint_symbol_4_ret tint_symbol_4(uint4 buffer[16], uint offset) {
-  Outer arr_1[4] = (Outer[4])0;
-  {
-    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
-      arr_1[i_2] = tint_symbol_5(buffer, (offset + (i_2 * 64u)));
-    }
-  }
-  return arr_1;
-}
-
-[numthreads(1, 1, 1)]
-void f() {
-  const int p_a_i_save = i();
-  const int p_a_i_a_i_save = i();
-  const int p_a_i_a_i_m_i_save = i();
-  const Outer l_a[4] = tint_symbol_4(a, 0u);
-  const Outer l_a_i = tint_symbol_5(a, (64u * uint(p_a_i_save)));
-  const Inner l_a_i_a[4] = tint_symbol_6(a, (64u * uint(p_a_i_save)));
-  const Inner l_a_i_a_i = tint_symbol_7(a, ((64u * uint(p_a_i_save)) + (16u * uint(p_a_i_a_i_save))));
-  const float2x2 l_a_i_a_i_m = tint_symbol_8(a, ((64u * uint(p_a_i_save)) + (16u * uint(p_a_i_a_i_save))));
-  const uint scalar_offset_2 = ((((64u * uint(p_a_i_save)) + (16u * uint(p_a_i_a_i_save))) + (8u * uint(p_a_i_a_i_m_i_save)))) / 4;
-  uint4 ubo_load_2 = a[scalar_offset_2 / 4];
-  const float2 l_a_i_a_i_m_i = asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy));
-  const int tint_symbol = p_a_i_save;
-  const int tint_symbol_1 = p_a_i_a_i_save;
-  const int tint_symbol_2 = p_a_i_a_i_m_i_save;
-  const int tint_symbol_3 = i();
-  const uint scalar_offset_3 = (((((64u * uint(tint_symbol)) + (16u * uint(tint_symbol_1))) + (8u * uint(tint_symbol_2))) + (4u * uint(tint_symbol_3)))) / 4;
-  const float l_a_i_a_i_m_i_i = asfloat(a[scalar_offset_3 / 4][scalar_offset_3 % 4]);
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x2/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
deleted file mode 100644
index bf03768..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
+++ /dev/null
@@ -1,78 +0,0 @@
-struct Inner {
-  float2x2 m;
-};
-struct Outer {
-  Inner a[4];
-};
-
-cbuffer cbuffer_a : register(b0, space0) {
-  uint4 a[16];
-};
-static int counter = 0;
-
-int i() {
-  counter = (counter + 1);
-  return counter;
-}
-
-float2x2 tint_symbol_8(uint4 buffer[16], uint offset) {
-  const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset / 4];
-  const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
-  return float2x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)));
-}
-
-Inner tint_symbol_7(uint4 buffer[16], uint offset) {
-  const Inner tint_symbol_11 = {tint_symbol_8(buffer, (offset + 0u))};
-  return tint_symbol_11;
-}
-
-typedef Inner tint_symbol_6_ret[4];
-tint_symbol_6_ret tint_symbol_6(uint4 buffer[16], uint offset) {
-  Inner arr[4] = (Inner[4])0;
-  {
-    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
-      arr[i_1] = tint_symbol_7(buffer, (offset + (i_1 * 16u)));
-    }
-  }
-  return arr;
-}
-
-Outer tint_symbol_5(uint4 buffer[16], uint offset) {
-  const Outer tint_symbol_12 = {tint_symbol_6(buffer, (offset + 0u))};
-  return tint_symbol_12;
-}
-
-typedef Outer tint_symbol_4_ret[4];
-tint_symbol_4_ret tint_symbol_4(uint4 buffer[16], uint offset) {
-  Outer arr_1[4] = (Outer[4])0;
-  {
-    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
-      arr_1[i_2] = tint_symbol_5(buffer, (offset + (i_2 * 64u)));
-    }
-  }
-  return arr_1;
-}
-
-[numthreads(1, 1, 1)]
-void f() {
-  const int p_a_i_save = i();
-  const int p_a_i_a_i_save = i();
-  const int p_a_i_a_i_m_i_save = i();
-  const Outer l_a[4] = tint_symbol_4(a, 0u);
-  const Outer l_a_i = tint_symbol_5(a, (64u * uint(p_a_i_save)));
-  const Inner l_a_i_a[4] = tint_symbol_6(a, (64u * uint(p_a_i_save)));
-  const Inner l_a_i_a_i = tint_symbol_7(a, ((64u * uint(p_a_i_save)) + (16u * uint(p_a_i_a_i_save))));
-  const float2x2 l_a_i_a_i_m = tint_symbol_8(a, ((64u * uint(p_a_i_save)) + (16u * uint(p_a_i_a_i_save))));
-  const uint scalar_offset_2 = ((((64u * uint(p_a_i_save)) + (16u * uint(p_a_i_a_i_save))) + (8u * uint(p_a_i_a_i_m_i_save)))) / 4;
-  uint4 ubo_load_2 = a[scalar_offset_2 / 4];
-  const float2 l_a_i_a_i_m_i = asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy));
-  const int tint_symbol = p_a_i_save;
-  const int tint_symbol_1 = p_a_i_a_i_save;
-  const int tint_symbol_2 = p_a_i_a_i_m_i_save;
-  const int tint_symbol_3 = i();
-  const uint scalar_offset_3 = (((((64u * uint(tint_symbol)) + (16u * uint(tint_symbol_1))) + (8u * uint(tint_symbol_2))) + (4u * uint(tint_symbol_3)))) / 4;
-  const float l_a_i_a_i_m_i_i = asfloat(a[scalar_offset_3 / 4][scalar_offset_3 % 4]);
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x2/dynamic_index_via_ptr.wgsl.expected.glsl
deleted file mode 100644
index 90e0cf3..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/dynamic_index_via_ptr.wgsl.expected.glsl
+++ /dev/null
@@ -1,122 +0,0 @@
-#version 310 es
-
-struct Inner {
-  mat2 m;
-};
-
-struct Inner_std140 {
-  vec2 m_0;
-  vec2 m_1;
-};
-
-struct Outer {
-  Inner a[4];
-};
-
-struct Outer_std140 {
-  Inner_std140 a[4];
-};
-
-layout(binding = 0, std140) uniform a_block_std140_ubo {
-  Outer_std140 inner[4];
-} a;
-
-int counter = 0;
-int i() {
-  counter = (counter + 1);
-  return counter;
-}
-
-Inner conv_Inner(Inner_std140 val) {
-  return Inner(mat2(val.m_0, val.m_1));
-}
-
-Inner[4] conv_arr4_Inner(Inner_std140 val[4]) {
-  Inner arr[4] = Inner[4](Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)));
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      arr[i] = conv_Inner(val[i]);
-    }
-  }
-  return arr;
-}
-
-Outer conv_Outer(Outer_std140 val) {
-  return Outer(conv_arr4_Inner(val.a));
-}
-
-Outer[4] conv_arr4_Outer(Outer_std140 val[4]) {
-  Outer arr[4] = Outer[4](Outer(Inner[4](Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)))), Outer(Inner[4](Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)))), Outer(Inner[4](Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)))), Outer(Inner[4](Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)))));
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      arr[i] = conv_Outer(val[i]);
-    }
-  }
-  return arr;
-}
-
-mat2 load_a_inner_p0_a_p1_m(uint p0, uint p1) {
-  uint s_save = p0;
-  uint s_save_1 = p1;
-  return mat2(a.inner[s_save].a[s_save_1].m_0, a.inner[s_save].a[s_save_1].m_1);
-}
-
-vec2 load_a_inner_p0_a_p1_m_p2(uint p0, uint p1, uint p2) {
-  switch(p2) {
-    case 0u: {
-      return a.inner[p0].a[p1].m_0;
-      break;
-    }
-    case 1u: {
-      return a.inner[p0].a[p1].m_1;
-      break;
-    }
-    default: {
-      return vec2(0.0f);
-      break;
-    }
-  }
-}
-
-float load_a_inner_p0_a_p1_m_p2_p3(uint p0, uint p1, uint p2, uint p3) {
-  switch(p2) {
-    case 0u: {
-      return a.inner[p0].a[p1].m_0[p3];
-      break;
-    }
-    case 1u: {
-      return a.inner[p0].a[p1].m_1[p3];
-      break;
-    }
-    default: {
-      return 0.0f;
-      break;
-    }
-  }
-}
-
-void f() {
-  Outer p_a[4] = conv_arr4_Outer(a.inner);
-  int tint_symbol = i();
-  Outer p_a_i = conv_Outer(a.inner[tint_symbol]);
-  Inner p_a_i_a[4] = conv_arr4_Inner(a.inner[tint_symbol].a);
-  int tint_symbol_1 = i();
-  Inner p_a_i_a_i = conv_Inner(a.inner[tint_symbol].a[tint_symbol_1]);
-  mat2 p_a_i_a_i_m = load_a_inner_p0_a_p1_m(uint(tint_symbol), uint(tint_symbol_1));
-  int tint_symbol_2 = i();
-  vec2 p_a_i_a_i_m_i = load_a_inner_p0_a_p1_m_p2(uint(tint_symbol), uint(tint_symbol_1), uint(tint_symbol_2));
-  Outer l_a[4] = conv_arr4_Outer(a.inner);
-  Outer l_a_i = conv_Outer(a.inner[tint_symbol]);
-  Inner l_a_i_a[4] = conv_arr4_Inner(a.inner[tint_symbol].a);
-  Inner l_a_i_a_i = conv_Inner(a.inner[tint_symbol].a[tint_symbol_1]);
-  mat2 l_a_i_a_i_m = load_a_inner_p0_a_p1_m(uint(tint_symbol), uint(tint_symbol_1));
-  vec2 l_a_i_a_i_m_i = load_a_inner_p0_a_p1_m_p2(uint(tint_symbol), uint(tint_symbol_1), uint(tint_symbol_2));
-  int tint_symbol_3 = i();
-  float l_a_i_a_i_m_i_i = load_a_inner_p0_a_p1_m_p2_p3(uint(tint_symbol), uint(tint_symbol_1), uint(tint_symbol_2), uint(tint_symbol_3));
-}
-
-layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
-void main() {
-  f();
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x2/dynamic_index_via_ptr.wgsl.expected.msl
deleted file mode 100644
index c1d8152..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/dynamic_index_via_ptr.wgsl.expected.msl
+++ /dev/null
@@ -1,48 +0,0 @@
-#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 Inner {
-  /* 0x0000 */ float2x2 m;
-};
-
-struct Outer {
-  /* 0x0000 */ tint_array<Inner, 4> a;
-};
-
-int i() {
-  thread int tint_symbol_4 = 0;
-  tint_symbol_4 = as_type<int>((as_type<uint>(tint_symbol_4) + as_type<uint>(1)));
-  return tint_symbol_4;
-}
-
-kernel void f(const constant tint_array<Outer, 4>* tint_symbol_5 [[buffer(0)]]) {
-  int const tint_symbol = i();
-  int const p_a_i_save = tint_symbol;
-  int const tint_symbol_1 = i();
-  int const p_a_i_a_i_save = tint_symbol_1;
-  int const tint_symbol_2 = i();
-  int const p_a_i_a_i_m_i_save = tint_symbol_2;
-  tint_array<Outer, 4> const l_a = *(tint_symbol_5);
-  Outer const l_a_i = (*(tint_symbol_5))[p_a_i_save];
-  tint_array<Inner, 4> const l_a_i_a = (*(tint_symbol_5))[p_a_i_save].a;
-  Inner const l_a_i_a_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save];
-  float2x2 const l_a_i_a_i_m = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m;
-  float2 const l_a_i_a_i_m_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save];
-  int const tint_symbol_3 = i();
-  float const l_a_i_a_i_m_i_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save][tint_symbol_3];
-  return;
-}
-
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x2/dynamic_index_via_ptr.wgsl.expected.spvasm
deleted file mode 100644
index 796a192..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/dynamic_index_via_ptr.wgsl.expected.spvasm
+++ /dev/null
@@ -1,306 +0,0 @@
-; SPIR-V
-; Version: 1.3
-; Generator: Google Tint Compiler; 0
-; Bound: 193
-; Schema: 0
-               OpCapability Shader
-               OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %f "f"
-               OpExecutionMode %f LocalSize 1 1 1
-               OpName %a_block_std140 "a_block_std140"
-               OpMemberName %a_block_std140 0 "inner"
-               OpName %Outer_std140 "Outer_std140"
-               OpMemberName %Outer_std140 0 "a"
-               OpName %Inner_std140 "Inner_std140"
-               OpMemberName %Inner_std140 0 "m_0"
-               OpMemberName %Inner_std140 1 "m_1"
-               OpName %a "a"
-               OpName %counter "counter"
-               OpName %i "i"
-               OpName %Inner "Inner"
-               OpMemberName %Inner 0 "m"
-               OpName %conv_Inner "conv_Inner"
-               OpName %val "val"
-               OpName %conv_arr4_Inner "conv_arr4_Inner"
-               OpName %val_0 "val"
-               OpName %arr "arr"
-               OpName %i_0 "i"
-               OpName %var_for_index_1 "var_for_index_1"
-               OpName %Outer "Outer"
-               OpMemberName %Outer 0 "a"
-               OpName %conv_Outer "conv_Outer"
-               OpName %val_1 "val"
-               OpName %conv_arr4_Outer "conv_arr4_Outer"
-               OpName %val_2 "val"
-               OpName %arr_0 "arr"
-               OpName %i_1 "i"
-               OpName %var_for_index "var_for_index"
-               OpName %load_a_inner_p0_a_p1_m "load_a_inner_p0_a_p1_m"
-               OpName %p0 "p0"
-               OpName %p1 "p1"
-               OpName %load_a_inner_p0_a_p1_m_p2 "load_a_inner_p0_a_p1_m_p2"
-               OpName %p0_0 "p0"
-               OpName %p1_0 "p1"
-               OpName %p2 "p2"
-               OpName %load_a_inner_p0_a_p1_m_p2_p3 "load_a_inner_p0_a_p1_m_p2_p3"
-               OpName %p0_1 "p0"
-               OpName %p1_1 "p1"
-               OpName %p2_0 "p2"
-               OpName %p3 "p3"
-               OpName %f "f"
-               OpDecorate %a_block_std140 Block
-               OpMemberDecorate %a_block_std140 0 Offset 0
-               OpMemberDecorate %Outer_std140 0 Offset 0
-               OpMemberDecorate %Inner_std140 0 Offset 0
-               OpMemberDecorate %Inner_std140 1 Offset 8
-               OpDecorate %_arr_Inner_std140_uint_4 ArrayStride 16
-               OpDecorate %_arr_Outer_std140_uint_4 ArrayStride 64
-               OpDecorate %a NonWritable
-               OpDecorate %a DescriptorSet 0
-               OpDecorate %a Binding 0
-               OpMemberDecorate %Inner 0 Offset 0
-               OpMemberDecorate %Inner 0 ColMajor
-               OpMemberDecorate %Inner 0 MatrixStride 8
-               OpDecorate %_arr_Inner_uint_4 ArrayStride 16
-               OpMemberDecorate %Outer 0 Offset 0
-               OpDecorate %_arr_Outer_uint_4 ArrayStride 64
-      %float = OpTypeFloat 32
-    %v2float = OpTypeVector %float 2
-%Inner_std140 = OpTypeStruct %v2float %v2float
-       %uint = OpTypeInt 32 0
-     %uint_4 = OpConstant %uint 4
-%_arr_Inner_std140_uint_4 = OpTypeArray %Inner_std140 %uint_4
-%Outer_std140 = OpTypeStruct %_arr_Inner_std140_uint_4
-%_arr_Outer_std140_uint_4 = OpTypeArray %Outer_std140 %uint_4
-%a_block_std140 = OpTypeStruct %_arr_Outer_std140_uint_4
-%_ptr_Uniform_a_block_std140 = OpTypePointer Uniform %a_block_std140
-          %a = OpVariable %_ptr_Uniform_a_block_std140 Uniform
-        %int = OpTypeInt 32 1
-         %13 = OpConstantNull %int
-%_ptr_Private_int = OpTypePointer Private %int
-    %counter = OpVariable %_ptr_Private_int Private %13
-         %16 = OpTypeFunction %int
-      %int_1 = OpConstant %int 1
-%mat2v2float = OpTypeMatrix %v2float 2
-      %Inner = OpTypeStruct %mat2v2float
-         %23 = OpTypeFunction %Inner %Inner_std140
-%_arr_Inner_uint_4 = OpTypeArray %Inner %uint_4
-         %33 = OpTypeFunction %_arr_Inner_uint_4 %_arr_Inner_std140_uint_4
-%_ptr_Function__arr_Inner_uint_4 = OpTypePointer Function %_arr_Inner_uint_4
-         %40 = OpConstantNull %_arr_Inner_uint_4
-%_ptr_Function_uint = OpTypePointer Function %uint
-         %43 = OpConstantNull %uint
-       %bool = OpTypeBool
-%_ptr_Function__arr_Inner_std140_uint_4 = OpTypePointer Function %_arr_Inner_std140_uint_4
-         %56 = OpConstantNull %_arr_Inner_std140_uint_4
-%_ptr_Function_Inner = OpTypePointer Function %Inner
-%_ptr_Function_Inner_std140 = OpTypePointer Function %Inner_std140
-     %uint_1 = OpConstant %uint 1
-      %Outer = OpTypeStruct %_arr_Inner_uint_4
-         %69 = OpTypeFunction %Outer %Outer_std140
-%_arr_Outer_uint_4 = OpTypeArray %Outer %uint_4
-         %77 = OpTypeFunction %_arr_Outer_uint_4 %_arr_Outer_std140_uint_4
-%_ptr_Function__arr_Outer_uint_4 = OpTypePointer Function %_arr_Outer_uint_4
-         %84 = OpConstantNull %_arr_Outer_uint_4
-%_ptr_Function__arr_Outer_std140_uint_4 = OpTypePointer Function %_arr_Outer_std140_uint_4
-         %97 = OpConstantNull %_arr_Outer_std140_uint_4
-%_ptr_Function_Outer = OpTypePointer Function %Outer
-%_ptr_Function_Outer_std140 = OpTypePointer Function %Outer_std140
-        %109 = OpTypeFunction %mat2v2float %uint %uint
-     %uint_0 = OpConstant %uint 0
-%_ptr_Uniform_Inner_std140 = OpTypePointer Uniform %Inner_std140
-%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
-        %126 = OpTypeFunction %v2float %uint %uint %uint
-        %140 = OpConstantNull %v2float
-        %141 = OpTypeFunction %float %uint %uint %uint %uint
-%_ptr_Uniform_float = OpTypePointer Uniform %float
-        %157 = OpConstantNull %float
-       %void = OpTypeVoid
-        %158 = OpTypeFunction %void
-%_ptr_Uniform__arr_Outer_std140_uint_4 = OpTypePointer Uniform %_arr_Outer_std140_uint_4
-%_ptr_Uniform_Outer_std140 = OpTypePointer Uniform %Outer_std140
-%_ptr_Uniform__arr_Inner_std140_uint_4 = OpTypePointer Uniform %_arr_Inner_std140_uint_4
-          %i = OpFunction %int None %16
-         %18 = OpLabel
-         %19 = OpLoad %int %counter
-         %21 = OpIAdd %int %19 %int_1
-               OpStore %counter %21
-         %22 = OpLoad %int %counter
-               OpReturnValue %22
-               OpFunctionEnd
- %conv_Inner = OpFunction %Inner None %23
-        %val = OpFunctionParameter %Inner_std140
-         %28 = OpLabel
-         %29 = OpCompositeExtract %v2float %val 0
-         %30 = OpCompositeExtract %v2float %val 1
-         %31 = OpCompositeConstruct %mat2v2float %29 %30
-         %32 = OpCompositeConstruct %Inner %31
-               OpReturnValue %32
-               OpFunctionEnd
-%conv_arr4_Inner = OpFunction %_arr_Inner_uint_4 None %33
-      %val_0 = OpFunctionParameter %_arr_Inner_std140_uint_4
-         %37 = OpLabel
-        %arr = OpVariable %_ptr_Function__arr_Inner_uint_4 Function %40
-        %i_0 = OpVariable %_ptr_Function_uint Function %43
-%var_for_index_1 = OpVariable %_ptr_Function__arr_Inner_std140_uint_4 Function %56
-               OpBranch %44
-         %44 = OpLabel
-               OpLoopMerge %45 %46 None
-               OpBranch %47
-         %47 = OpLabel
-         %49 = OpLoad %uint %i_0
-         %50 = OpULessThan %bool %49 %uint_4
-         %48 = OpLogicalNot %bool %50
-               OpSelectionMerge %52 None
-               OpBranchConditional %48 %53 %52
-         %53 = OpLabel
-               OpBranch %45
-         %52 = OpLabel
-               OpStore %var_for_index_1 %val_0
-         %57 = OpLoad %uint %i_0
-         %59 = OpAccessChain %_ptr_Function_Inner %arr %57
-         %61 = OpLoad %uint %i_0
-         %63 = OpAccessChain %_ptr_Function_Inner_std140 %var_for_index_1 %61
-         %64 = OpLoad %Inner_std140 %63
-         %60 = OpFunctionCall %Inner %conv_Inner %64
-               OpStore %59 %60
-               OpBranch %46
-         %46 = OpLabel
-         %65 = OpLoad %uint %i_0
-         %67 = OpIAdd %uint %65 %uint_1
-               OpStore %i_0 %67
-               OpBranch %44
-         %45 = OpLabel
-         %68 = OpLoad %_arr_Inner_uint_4 %arr
-               OpReturnValue %68
-               OpFunctionEnd
- %conv_Outer = OpFunction %Outer None %69
-      %val_1 = OpFunctionParameter %Outer_std140
-         %73 = OpLabel
-         %75 = OpCompositeExtract %_arr_Inner_std140_uint_4 %val_1 0
-         %74 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %75
-         %76 = OpCompositeConstruct %Outer %74
-               OpReturnValue %76
-               OpFunctionEnd
-%conv_arr4_Outer = OpFunction %_arr_Outer_uint_4 None %77
-      %val_2 = OpFunctionParameter %_arr_Outer_std140_uint_4
-         %81 = OpLabel
-      %arr_0 = OpVariable %_ptr_Function__arr_Outer_uint_4 Function %84
-        %i_1 = OpVariable %_ptr_Function_uint Function %43
-%var_for_index = OpVariable %_ptr_Function__arr_Outer_std140_uint_4 Function %97
-               OpBranch %86
-         %86 = OpLabel
-               OpLoopMerge %87 %88 None
-               OpBranch %89
-         %89 = OpLabel
-         %91 = OpLoad %uint %i_1
-         %92 = OpULessThan %bool %91 %uint_4
-         %90 = OpLogicalNot %bool %92
-               OpSelectionMerge %93 None
-               OpBranchConditional %90 %94 %93
-         %94 = OpLabel
-               OpBranch %87
-         %93 = OpLabel
-               OpStore %var_for_index %val_2
-         %98 = OpLoad %uint %i_1
-        %100 = OpAccessChain %_ptr_Function_Outer %arr_0 %98
-        %102 = OpLoad %uint %i_1
-        %104 = OpAccessChain %_ptr_Function_Outer_std140 %var_for_index %102
-        %105 = OpLoad %Outer_std140 %104
-        %101 = OpFunctionCall %Outer %conv_Outer %105
-               OpStore %100 %101
-               OpBranch %88
-         %88 = OpLabel
-        %106 = OpLoad %uint %i_1
-        %107 = OpIAdd %uint %106 %uint_1
-               OpStore %i_1 %107
-               OpBranch %86
-         %87 = OpLabel
-        %108 = OpLoad %_arr_Outer_uint_4 %arr_0
-               OpReturnValue %108
-               OpFunctionEnd
-%load_a_inner_p0_a_p1_m = OpFunction %mat2v2float None %109
-         %p0 = OpFunctionParameter %uint
-         %p1 = OpFunctionParameter %uint
-        %113 = OpLabel
-        %117 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %p0 %uint_0 %p1
-        %120 = OpAccessChain %_ptr_Uniform_v2float %117 %uint_0
-        %121 = OpLoad %v2float %120
-        %123 = OpAccessChain %_ptr_Uniform_v2float %117 %uint_1
-        %124 = OpLoad %v2float %123
-        %125 = OpCompositeConstruct %mat2v2float %121 %124
-               OpReturnValue %125
-               OpFunctionEnd
-%load_a_inner_p0_a_p1_m_p2 = OpFunction %v2float None %126
-       %p0_0 = OpFunctionParameter %uint
-       %p1_0 = OpFunctionParameter %uint
-         %p2 = OpFunctionParameter %uint
-        %131 = OpLabel
-               OpSelectionMerge %132 None
-               OpSwitch %p2 %133 0 %134 1 %135
-        %134 = OpLabel
-        %136 = OpAccessChain %_ptr_Uniform_v2float %a %uint_0 %p0_0 %uint_0 %p1_0 %uint_0
-        %137 = OpLoad %v2float %136
-               OpReturnValue %137
-        %135 = OpLabel
-        %138 = OpAccessChain %_ptr_Uniform_v2float %a %uint_0 %p0_0 %uint_0 %p1_0 %uint_1
-        %139 = OpLoad %v2float %138
-               OpReturnValue %139
-        %133 = OpLabel
-               OpReturnValue %140
-        %132 = OpLabel
-               OpReturnValue %140
-               OpFunctionEnd
-%load_a_inner_p0_a_p1_m_p2_p3 = OpFunction %float None %141
-       %p0_1 = OpFunctionParameter %uint
-       %p1_1 = OpFunctionParameter %uint
-       %p2_0 = OpFunctionParameter %uint
-         %p3 = OpFunctionParameter %uint
-        %147 = OpLabel
-               OpSelectionMerge %148 None
-               OpSwitch %p2_0 %149 0 %150 1 %151
-        %150 = OpLabel
-        %153 = OpAccessChain %_ptr_Uniform_float %a %uint_0 %p0_1 %uint_0 %p1_1 %uint_0 %p3
-        %154 = OpLoad %float %153
-               OpReturnValue %154
-        %151 = OpLabel
-        %155 = OpAccessChain %_ptr_Uniform_float %a %uint_0 %p0_1 %uint_0 %p1_1 %uint_1 %p3
-        %156 = OpLoad %float %155
-               OpReturnValue %156
-        %149 = OpLabel
-               OpReturnValue %157
-        %148 = OpLabel
-               OpReturnValue %157
-               OpFunctionEnd
-          %f = OpFunction %void None %158
-        %161 = OpLabel
-        %162 = OpFunctionCall %int %i
-        %163 = OpFunctionCall %int %i
-        %164 = OpFunctionCall %int %i
-        %167 = OpAccessChain %_ptr_Uniform__arr_Outer_std140_uint_4 %a %uint_0
-        %168 = OpLoad %_arr_Outer_std140_uint_4 %167
-        %165 = OpFunctionCall %_arr_Outer_uint_4 %conv_arr4_Outer %168
-        %171 = OpAccessChain %_ptr_Uniform_Outer_std140 %a %uint_0 %162
-        %172 = OpLoad %Outer_std140 %171
-        %169 = OpFunctionCall %Outer %conv_Outer %172
-        %175 = OpAccessChain %_ptr_Uniform__arr_Inner_std140_uint_4 %a %uint_0 %162 %uint_0
-        %176 = OpLoad %_arr_Inner_std140_uint_4 %175
-        %173 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %176
-        %178 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %162 %uint_0 %163
-        %179 = OpLoad %Inner_std140 %178
-        %177 = OpFunctionCall %Inner %conv_Inner %179
-        %181 = OpBitcast %uint %162
-        %182 = OpBitcast %uint %163
-        %180 = OpFunctionCall %mat2v2float %load_a_inner_p0_a_p1_m %181 %182
-        %184 = OpBitcast %uint %162
-        %185 = OpBitcast %uint %163
-        %186 = OpBitcast %uint %164
-        %183 = OpFunctionCall %v2float %load_a_inner_p0_a_p1_m_p2 %184 %185 %186
-        %187 = OpFunctionCall %int %i
-        %189 = OpBitcast %uint %162
-        %190 = OpBitcast %uint %163
-        %191 = OpBitcast %uint %164
-        %192 = OpBitcast %uint %187
-        %188 = OpFunctionCall %float %load_a_inner_p0_a_p1_m_p2_p3 %189 %190 %191 %192
-               OpReturn
-               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x2/dynamic_index_via_ptr.wgsl.expected.wgsl
deleted file mode 100644
index 97d5141..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/dynamic_index_via_ptr.wgsl.expected.wgsl
+++ /dev/null
@@ -1,33 +0,0 @@
-struct Inner {
-  m : mat2x2<f32>,
-}
-
-struct Outer {
-  a : array<Inner, 4>,
-}
-
-@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
-
-var<private> counter = 0;
-
-fn i() -> i32 {
-  counter++;
-  return counter;
-}
-
-@compute @workgroup_size(1)
-fn f() {
-  let p_a = &(a);
-  let p_a_i = &((*(p_a))[i()]);
-  let p_a_i_a = &((*(p_a_i)).a);
-  let p_a_i_a_i = &((*(p_a_i_a))[i()]);
-  let p_a_i_a_i_m = &((*(p_a_i_a_i)).m);
-  let p_a_i_a_i_m_i = &((*(p_a_i_a_i_m))[i()]);
-  let l_a : array<Outer, 4> = *(p_a);
-  let l_a_i : Outer = *(p_a_i);
-  let l_a_i_a : array<Inner, 4> = *(p_a_i_a);
-  let l_a_i_a_i : Inner = *(p_a_i_a_i);
-  let l_a_i_a_i_m : mat2x2<f32> = *(p_a_i_a_i_m);
-  let l_a_i_a_i_m_i : vec2<f32> = *(p_a_i_a_i_m_i);
-  let l_a_i_a_i_m_i_i : f32 = (*(p_a_i_a_i_m_i))[i()];
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x2/static_index_via_ptr.wgsl
deleted file mode 100644
index 0a790a9..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/static_index_via_ptr.wgsl
+++ /dev/null
@@ -1,28 +0,0 @@
-struct Inner {
-  m : mat2x2<f32>,
-}
-
-struct Outer {
-  a : array<Inner, 4>,
-}
-
-@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
-
-@compute @workgroup_size(1)
-fn f() {
-  let p_a = &a;
-  let p_a_3 = &((*p_a)[3]);
-  let p_a_3_a = &((*p_a_3).a);
-  let p_a_3_a_2 = &((*p_a_3_a)[2]);
-  let p_a_3_a_2_m = &((*p_a_3_a_2).m);
-  let p_a_3_a_2_m_1 = &((*p_a_3_a_2_m)[1]);
-
-
-  let l_a             : array<Outer, 4> = *p_a;
-  let l_a_3           : Outer           = *p_a_3;
-  let l_a_3_a         : array<Inner, 4> = *p_a_3_a;
-  let l_a_3_a_2       : Inner           = *p_a_3_a_2;
-  let l_a_3_a_2_m     : mat2x2<f32>     = *p_a_3_a_2_m;
-  let l_a_3_a_2_m_1   : vec2<f32>       = *p_a_3_a_2_m_1;
-  let l_a_3_a_2_m_1_0 : f32             = (*p_a_3_a_2_m_1)[0];
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x2/static_index_via_ptr.wgsl.expected.dxc.hlsl
deleted file mode 100644
index fcf8c2f..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/static_index_via_ptr.wgsl.expected.dxc.hlsl
+++ /dev/null
@@ -1,62 +0,0 @@
-struct Inner {
-  float2x2 m;
-};
-struct Outer {
-  Inner a[4];
-};
-
-cbuffer cbuffer_a : register(b0, space0) {
-  uint4 a[16];
-};
-
-float2x2 tint_symbol_4(uint4 buffer[16], uint offset) {
-  const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset / 4];
-  const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
-  return float2x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)));
-}
-
-Inner tint_symbol_3(uint4 buffer[16], uint offset) {
-  const Inner tint_symbol_7 = {tint_symbol_4(buffer, (offset + 0u))};
-  return tint_symbol_7;
-}
-
-typedef Inner tint_symbol_2_ret[4];
-tint_symbol_2_ret tint_symbol_2(uint4 buffer[16], uint offset) {
-  Inner arr[4] = (Inner[4])0;
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      arr[i] = tint_symbol_3(buffer, (offset + (i * 16u)));
-    }
-  }
-  return arr;
-}
-
-Outer tint_symbol_1(uint4 buffer[16], uint offset) {
-  const Outer tint_symbol_8 = {tint_symbol_2(buffer, (offset + 0u))};
-  return tint_symbol_8;
-}
-
-typedef Outer tint_symbol_ret[4];
-tint_symbol_ret tint_symbol(uint4 buffer[16], uint offset) {
-  Outer arr_1[4] = (Outer[4])0;
-  {
-    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
-      arr_1[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 64u)));
-    }
-  }
-  return arr_1;
-}
-
-[numthreads(1, 1, 1)]
-void f() {
-  const Outer l_a[4] = tint_symbol(a, 0u);
-  const Outer l_a_3 = tint_symbol_1(a, 192u);
-  const Inner l_a_3_a[4] = tint_symbol_2(a, 192u);
-  const Inner l_a_3_a_2 = tint_symbol_3(a, 224u);
-  const float2x2 l_a_3_a_2_m = tint_symbol_4(a, 224u);
-  const float2 l_a_3_a_2_m_1 = asfloat(a[14].zw);
-  const float l_a_3_a_2_m_1_0 = asfloat(a[14].z);
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x2/static_index_via_ptr.wgsl.expected.fxc.hlsl
deleted file mode 100644
index fcf8c2f..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/static_index_via_ptr.wgsl.expected.fxc.hlsl
+++ /dev/null
@@ -1,62 +0,0 @@
-struct Inner {
-  float2x2 m;
-};
-struct Outer {
-  Inner a[4];
-};
-
-cbuffer cbuffer_a : register(b0, space0) {
-  uint4 a[16];
-};
-
-float2x2 tint_symbol_4(uint4 buffer[16], uint offset) {
-  const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset / 4];
-  const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
-  return float2x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)));
-}
-
-Inner tint_symbol_3(uint4 buffer[16], uint offset) {
-  const Inner tint_symbol_7 = {tint_symbol_4(buffer, (offset + 0u))};
-  return tint_symbol_7;
-}
-
-typedef Inner tint_symbol_2_ret[4];
-tint_symbol_2_ret tint_symbol_2(uint4 buffer[16], uint offset) {
-  Inner arr[4] = (Inner[4])0;
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      arr[i] = tint_symbol_3(buffer, (offset + (i * 16u)));
-    }
-  }
-  return arr;
-}
-
-Outer tint_symbol_1(uint4 buffer[16], uint offset) {
-  const Outer tint_symbol_8 = {tint_symbol_2(buffer, (offset + 0u))};
-  return tint_symbol_8;
-}
-
-typedef Outer tint_symbol_ret[4];
-tint_symbol_ret tint_symbol(uint4 buffer[16], uint offset) {
-  Outer arr_1[4] = (Outer[4])0;
-  {
-    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
-      arr_1[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 64u)));
-    }
-  }
-  return arr_1;
-}
-
-[numthreads(1, 1, 1)]
-void f() {
-  const Outer l_a[4] = tint_symbol(a, 0u);
-  const Outer l_a_3 = tint_symbol_1(a, 192u);
-  const Inner l_a_3_a[4] = tint_symbol_2(a, 192u);
-  const Inner l_a_3_a_2 = tint_symbol_3(a, 224u);
-  const float2x2 l_a_3_a_2_m = tint_symbol_4(a, 224u);
-  const float2 l_a_3_a_2_m_1 = asfloat(a[14].zw);
-  const float l_a_3_a_2_m_1_0 = asfloat(a[14].z);
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x2/static_index_via_ptr.wgsl.expected.glsl
deleted file mode 100644
index 3564979..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/static_index_via_ptr.wgsl.expected.glsl
+++ /dev/null
@@ -1,76 +0,0 @@
-#version 310 es
-
-struct Inner {
-  mat2 m;
-};
-
-struct Inner_std140 {
-  vec2 m_0;
-  vec2 m_1;
-};
-
-struct Outer {
-  Inner a[4];
-};
-
-struct Outer_std140 {
-  Inner_std140 a[4];
-};
-
-layout(binding = 0, std140) uniform a_block_std140_ubo {
-  Outer_std140 inner[4];
-} a;
-
-Inner conv_Inner(Inner_std140 val) {
-  return Inner(mat2(val.m_0, val.m_1));
-}
-
-Inner[4] conv_arr4_Inner(Inner_std140 val[4]) {
-  Inner arr[4] = Inner[4](Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)));
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      arr[i] = conv_Inner(val[i]);
-    }
-  }
-  return arr;
-}
-
-Outer conv_Outer(Outer_std140 val) {
-  return Outer(conv_arr4_Inner(val.a));
-}
-
-Outer[4] conv_arr4_Outer(Outer_std140 val[4]) {
-  Outer arr[4] = Outer[4](Outer(Inner[4](Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)))), Outer(Inner[4](Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)))), Outer(Inner[4](Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)))), Outer(Inner[4](Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f)))));
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      arr[i] = conv_Outer(val[i]);
-    }
-  }
-  return arr;
-}
-
-mat2 load_a_inner_3_a_2_m() {
-  return mat2(a.inner[3u].a[2u].m_0, a.inner[3u].a[2u].m_1);
-}
-
-void f() {
-  Outer p_a[4] = conv_arr4_Outer(a.inner);
-  Outer p_a_3 = conv_Outer(a.inner[3u]);
-  Inner p_a_3_a[4] = conv_arr4_Inner(a.inner[3u].a);
-  Inner p_a_3_a_2 = conv_Inner(a.inner[3u].a[2u]);
-  mat2 p_a_3_a_2_m = load_a_inner_3_a_2_m();
-  vec2 p_a_3_a_2_m_1 = a.inner[3u].a[2u].m_1;
-  Outer l_a[4] = conv_arr4_Outer(a.inner);
-  Outer l_a_3 = conv_Outer(a.inner[3u]);
-  Inner l_a_3_a[4] = conv_arr4_Inner(a.inner[3u].a);
-  Inner l_a_3_a_2 = conv_Inner(a.inner[3u].a[2u]);
-  mat2 l_a_3_a_2_m = load_a_inner_3_a_2_m();
-  vec2 l_a_3_a_2_m_1 = a.inner[3u].a[2u].m_1;
-  float l_a_3_a_2_m_1_0 = a.inner[3u].a[2u].m_1[0u];
-}
-
-layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
-void main() {
-  f();
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x2/static_index_via_ptr.wgsl.expected.msl
deleted file mode 100644
index e0658ac..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/static_index_via_ptr.wgsl.expected.msl
+++ /dev/null
@@ -1,35 +0,0 @@
-#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 Inner {
-  /* 0x0000 */ float2x2 m;
-};
-
-struct Outer {
-  /* 0x0000 */ tint_array<Inner, 4> a;
-};
-
-kernel void f(const constant tint_array<Outer, 4>* tint_symbol [[buffer(0)]]) {
-  tint_array<Outer, 4> const l_a = *(tint_symbol);
-  Outer const l_a_3 = (*(tint_symbol))[3];
-  tint_array<Inner, 4> const l_a_3_a = (*(tint_symbol))[3].a;
-  Inner const l_a_3_a_2 = (*(tint_symbol))[3].a[2];
-  float2x2 const l_a_3_a_2_m = (*(tint_symbol))[3].a[2].m;
-  float2 const l_a_3_a_2_m_1 = (*(tint_symbol))[3].a[2].m[1];
-  float const l_a_3_a_2_m_1_0 = (*(tint_symbol))[3].a[2].m[1][0];
-  return;
-}
-
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x2/static_index_via_ptr.wgsl.expected.spvasm
deleted file mode 100644
index de1047e..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/static_index_via_ptr.wgsl.expected.spvasm
+++ /dev/null
@@ -1,223 +0,0 @@
-; SPIR-V
-; Version: 1.3
-; Generator: Google Tint Compiler; 0
-; Bound: 140
-; Schema: 0
-               OpCapability Shader
-               OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %f "f"
-               OpExecutionMode %f LocalSize 1 1 1
-               OpName %a_block_std140 "a_block_std140"
-               OpMemberName %a_block_std140 0 "inner"
-               OpName %Outer_std140 "Outer_std140"
-               OpMemberName %Outer_std140 0 "a"
-               OpName %Inner_std140 "Inner_std140"
-               OpMemberName %Inner_std140 0 "m_0"
-               OpMemberName %Inner_std140 1 "m_1"
-               OpName %a "a"
-               OpName %Inner "Inner"
-               OpMemberName %Inner 0 "m"
-               OpName %conv_Inner "conv_Inner"
-               OpName %val "val"
-               OpName %conv_arr4_Inner "conv_arr4_Inner"
-               OpName %val_0 "val"
-               OpName %arr "arr"
-               OpName %i "i"
-               OpName %var_for_index_1 "var_for_index_1"
-               OpName %Outer "Outer"
-               OpMemberName %Outer 0 "a"
-               OpName %conv_Outer "conv_Outer"
-               OpName %val_1 "val"
-               OpName %conv_arr4_Outer "conv_arr4_Outer"
-               OpName %val_2 "val"
-               OpName %arr_0 "arr"
-               OpName %i_0 "i"
-               OpName %var_for_index "var_for_index"
-               OpName %load_a_inner_3_a_2_m "load_a_inner_3_a_2_m"
-               OpName %f "f"
-               OpDecorate %a_block_std140 Block
-               OpMemberDecorate %a_block_std140 0 Offset 0
-               OpMemberDecorate %Outer_std140 0 Offset 0
-               OpMemberDecorate %Inner_std140 0 Offset 0
-               OpMemberDecorate %Inner_std140 1 Offset 8
-               OpDecorate %_arr_Inner_std140_uint_4 ArrayStride 16
-               OpDecorate %_arr_Outer_std140_uint_4 ArrayStride 64
-               OpDecorate %a NonWritable
-               OpDecorate %a DescriptorSet 0
-               OpDecorate %a Binding 0
-               OpMemberDecorate %Inner 0 Offset 0
-               OpMemberDecorate %Inner 0 ColMajor
-               OpMemberDecorate %Inner 0 MatrixStride 8
-               OpDecorate %_arr_Inner_uint_4 ArrayStride 16
-               OpMemberDecorate %Outer 0 Offset 0
-               OpDecorate %_arr_Outer_uint_4 ArrayStride 64
-      %float = OpTypeFloat 32
-    %v2float = OpTypeVector %float 2
-%Inner_std140 = OpTypeStruct %v2float %v2float
-       %uint = OpTypeInt 32 0
-     %uint_4 = OpConstant %uint 4
-%_arr_Inner_std140_uint_4 = OpTypeArray %Inner_std140 %uint_4
-%Outer_std140 = OpTypeStruct %_arr_Inner_std140_uint_4
-%_arr_Outer_std140_uint_4 = OpTypeArray %Outer_std140 %uint_4
-%a_block_std140 = OpTypeStruct %_arr_Outer_std140_uint_4
-%_ptr_Uniform_a_block_std140 = OpTypePointer Uniform %a_block_std140
-          %a = OpVariable %_ptr_Uniform_a_block_std140 Uniform
-%mat2v2float = OpTypeMatrix %v2float 2
-      %Inner = OpTypeStruct %mat2v2float
-         %12 = OpTypeFunction %Inner %Inner_std140
-%_arr_Inner_uint_4 = OpTypeArray %Inner %uint_4
-         %22 = OpTypeFunction %_arr_Inner_uint_4 %_arr_Inner_std140_uint_4
-%_ptr_Function__arr_Inner_uint_4 = OpTypePointer Function %_arr_Inner_uint_4
-         %29 = OpConstantNull %_arr_Inner_uint_4
-%_ptr_Function_uint = OpTypePointer Function %uint
-         %32 = OpConstantNull %uint
-       %bool = OpTypeBool
-%_ptr_Function__arr_Inner_std140_uint_4 = OpTypePointer Function %_arr_Inner_std140_uint_4
-         %45 = OpConstantNull %_arr_Inner_std140_uint_4
-%_ptr_Function_Inner = OpTypePointer Function %Inner
-%_ptr_Function_Inner_std140 = OpTypePointer Function %Inner_std140
-     %uint_1 = OpConstant %uint 1
-      %Outer = OpTypeStruct %_arr_Inner_uint_4
-         %58 = OpTypeFunction %Outer %Outer_std140
-%_arr_Outer_uint_4 = OpTypeArray %Outer %uint_4
-         %66 = OpTypeFunction %_arr_Outer_uint_4 %_arr_Outer_std140_uint_4
-%_ptr_Function__arr_Outer_uint_4 = OpTypePointer Function %_arr_Outer_uint_4
-         %73 = OpConstantNull %_arr_Outer_uint_4
-%_ptr_Function__arr_Outer_std140_uint_4 = OpTypePointer Function %_arr_Outer_std140_uint_4
-         %86 = OpConstantNull %_arr_Outer_std140_uint_4
-%_ptr_Function_Outer = OpTypePointer Function %Outer
-%_ptr_Function_Outer_std140 = OpTypePointer Function %Outer_std140
-         %98 = OpTypeFunction %mat2v2float
-     %uint_0 = OpConstant %uint 0
-     %uint_3 = OpConstant %uint 3
-     %uint_2 = OpConstant %uint 2
-%_ptr_Uniform_Inner_std140 = OpTypePointer Uniform %Inner_std140
-%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
-       %void = OpTypeVoid
-        %115 = OpTypeFunction %void
-%_ptr_Uniform__arr_Outer_std140_uint_4 = OpTypePointer Uniform %_arr_Outer_std140_uint_4
-%_ptr_Uniform_Outer_std140 = OpTypePointer Uniform %Outer_std140
-%_ptr_Uniform__arr_Inner_std140_uint_4 = OpTypePointer Uniform %_arr_Inner_std140_uint_4
-%_ptr_Uniform_float = OpTypePointer Uniform %float
- %conv_Inner = OpFunction %Inner None %12
-        %val = OpFunctionParameter %Inner_std140
-         %17 = OpLabel
-         %18 = OpCompositeExtract %v2float %val 0
-         %19 = OpCompositeExtract %v2float %val 1
-         %20 = OpCompositeConstruct %mat2v2float %18 %19
-         %21 = OpCompositeConstruct %Inner %20
-               OpReturnValue %21
-               OpFunctionEnd
-%conv_arr4_Inner = OpFunction %_arr_Inner_uint_4 None %22
-      %val_0 = OpFunctionParameter %_arr_Inner_std140_uint_4
-         %26 = OpLabel
-        %arr = OpVariable %_ptr_Function__arr_Inner_uint_4 Function %29
-          %i = OpVariable %_ptr_Function_uint Function %32
-%var_for_index_1 = OpVariable %_ptr_Function__arr_Inner_std140_uint_4 Function %45
-               OpBranch %33
-         %33 = OpLabel
-               OpLoopMerge %34 %35 None
-               OpBranch %36
-         %36 = OpLabel
-         %38 = OpLoad %uint %i
-         %39 = OpULessThan %bool %38 %uint_4
-         %37 = OpLogicalNot %bool %39
-               OpSelectionMerge %41 None
-               OpBranchConditional %37 %42 %41
-         %42 = OpLabel
-               OpBranch %34
-         %41 = OpLabel
-               OpStore %var_for_index_1 %val_0
-         %46 = OpLoad %uint %i
-         %48 = OpAccessChain %_ptr_Function_Inner %arr %46
-         %50 = OpLoad %uint %i
-         %52 = OpAccessChain %_ptr_Function_Inner_std140 %var_for_index_1 %50
-         %53 = OpLoad %Inner_std140 %52
-         %49 = OpFunctionCall %Inner %conv_Inner %53
-               OpStore %48 %49
-               OpBranch %35
-         %35 = OpLabel
-         %54 = OpLoad %uint %i
-         %56 = OpIAdd %uint %54 %uint_1
-               OpStore %i %56
-               OpBranch %33
-         %34 = OpLabel
-         %57 = OpLoad %_arr_Inner_uint_4 %arr
-               OpReturnValue %57
-               OpFunctionEnd
- %conv_Outer = OpFunction %Outer None %58
-      %val_1 = OpFunctionParameter %Outer_std140
-         %62 = OpLabel
-         %64 = OpCompositeExtract %_arr_Inner_std140_uint_4 %val_1 0
-         %63 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %64
-         %65 = OpCompositeConstruct %Outer %63
-               OpReturnValue %65
-               OpFunctionEnd
-%conv_arr4_Outer = OpFunction %_arr_Outer_uint_4 None %66
-      %val_2 = OpFunctionParameter %_arr_Outer_std140_uint_4
-         %70 = OpLabel
-      %arr_0 = OpVariable %_ptr_Function__arr_Outer_uint_4 Function %73
-        %i_0 = OpVariable %_ptr_Function_uint Function %32
-%var_for_index = OpVariable %_ptr_Function__arr_Outer_std140_uint_4 Function %86
-               OpBranch %75
-         %75 = OpLabel
-               OpLoopMerge %76 %77 None
-               OpBranch %78
-         %78 = OpLabel
-         %80 = OpLoad %uint %i_0
-         %81 = OpULessThan %bool %80 %uint_4
-         %79 = OpLogicalNot %bool %81
-               OpSelectionMerge %82 None
-               OpBranchConditional %79 %83 %82
-         %83 = OpLabel
-               OpBranch %76
-         %82 = OpLabel
-               OpStore %var_for_index %val_2
-         %87 = OpLoad %uint %i_0
-         %89 = OpAccessChain %_ptr_Function_Outer %arr_0 %87
-         %91 = OpLoad %uint %i_0
-         %93 = OpAccessChain %_ptr_Function_Outer_std140 %var_for_index %91
-         %94 = OpLoad %Outer_std140 %93
-         %90 = OpFunctionCall %Outer %conv_Outer %94
-               OpStore %89 %90
-               OpBranch %77
-         %77 = OpLabel
-         %95 = OpLoad %uint %i_0
-         %96 = OpIAdd %uint %95 %uint_1
-               OpStore %i_0 %96
-               OpBranch %75
-         %76 = OpLabel
-         %97 = OpLoad %_arr_Outer_uint_4 %arr_0
-               OpReturnValue %97
-               OpFunctionEnd
-%load_a_inner_3_a_2_m = OpFunction %mat2v2float None %98
-        %100 = OpLabel
-        %106 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %uint_3 %uint_0 %uint_2
-        %109 = OpAccessChain %_ptr_Uniform_v2float %106 %uint_0
-        %110 = OpLoad %v2float %109
-        %112 = OpAccessChain %_ptr_Uniform_v2float %106 %uint_1
-        %113 = OpLoad %v2float %112
-        %114 = OpCompositeConstruct %mat2v2float %110 %113
-               OpReturnValue %114
-               OpFunctionEnd
-          %f = OpFunction %void None %115
-        %118 = OpLabel
-        %121 = OpAccessChain %_ptr_Uniform__arr_Outer_std140_uint_4 %a %uint_0
-        %122 = OpLoad %_arr_Outer_std140_uint_4 %121
-        %119 = OpFunctionCall %_arr_Outer_uint_4 %conv_arr4_Outer %122
-        %125 = OpAccessChain %_ptr_Uniform_Outer_std140 %a %uint_0 %uint_3
-        %126 = OpLoad %Outer_std140 %125
-        %123 = OpFunctionCall %Outer %conv_Outer %126
-        %129 = OpAccessChain %_ptr_Uniform__arr_Inner_std140_uint_4 %a %uint_0 %uint_3 %uint_0
-        %130 = OpLoad %_arr_Inner_std140_uint_4 %129
-        %127 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %130
-        %132 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %uint_3 %uint_0 %uint_2
-        %133 = OpLoad %Inner_std140 %132
-        %131 = OpFunctionCall %Inner %conv_Inner %133
-        %134 = OpFunctionCall %mat2v2float %load_a_inner_3_a_2_m
-        %135 = OpAccessChain %_ptr_Uniform_v2float %a %uint_0 %uint_3 %uint_0 %uint_2 %uint_1
-        %136 = OpLoad %v2float %135
-        %138 = OpAccessChain %_ptr_Uniform_float %a %uint_0 %uint_3 %uint_0 %uint_2 %uint_1 %32
-        %139 = OpLoad %float %138
-               OpReturn
-               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x2/static_index_via_ptr.wgsl.expected.wgsl
deleted file mode 100644
index 2e24f26..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/static_index_via_ptr.wgsl.expected.wgsl
+++ /dev/null
@@ -1,26 +0,0 @@
-struct Inner {
-  m : mat2x2<f32>,
-}
-
-struct Outer {
-  a : array<Inner, 4>,
-}
-
-@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
-
-@compute @workgroup_size(1)
-fn f() {
-  let p_a = &(a);
-  let p_a_3 = &((*(p_a))[3]);
-  let p_a_3_a = &((*(p_a_3)).a);
-  let p_a_3_a_2 = &((*(p_a_3_a))[2]);
-  let p_a_3_a_2_m = &((*(p_a_3_a_2)).m);
-  let p_a_3_a_2_m_1 = &((*(p_a_3_a_2_m))[1]);
-  let l_a : array<Outer, 4> = *(p_a);
-  let l_a_3 : Outer = *(p_a_3);
-  let l_a_3_a : array<Inner, 4> = *(p_a_3_a);
-  let l_a_3_a_2 : Inner = *(p_a_3_a_2);
-  let l_a_3_a_2_m : mat2x2<f32> = *(p_a_3_a_2_m);
-  let l_a_3_a_2_m_1 : vec2<f32> = *(p_a_3_a_2_m_1);
-  let l_a_3_a_2_m_1_0 : f32 = (*(p_a_3_a_2_m_1))[0];
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/to_builtin.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x2/to_builtin.wgsl
deleted file mode 100644
index b712b62..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/to_builtin.wgsl
+++ /dev/null
@@ -1,14 +0,0 @@
-struct S {
-  before : i32,
-  m : mat2x2<f32>,
-  after : i32,
-}
-
-@group(0) @binding(0) var<uniform> u : array<S, 4>;
-
-@compute @workgroup_size(1)
-fn f() {
-    let t = transpose(u[2].m);
-    let l = length(u[0].m[1].yx);
-    let a = abs(u[0].m[1].yx.x);
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x2/to_builtin.wgsl.expected.dxc.hlsl
deleted file mode 100644
index a6bdd17..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/to_builtin.wgsl.expected.dxc.hlsl
+++ /dev/null
@@ -1,19 +0,0 @@
-cbuffer cbuffer_u : register(b0, space0) {
-  uint4 u[8];
-};
-
-float2x2 tint_symbol(uint4 buffer[8], uint offset) {
-  const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset / 4];
-  const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
-  return float2x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)));
-}
-
-[numthreads(1, 1, 1)]
-void f() {
-  const float2x2 t = transpose(tint_symbol(u, 72u));
-  const float l = length(asfloat(u[1].xy).yx);
-  const float a = abs(asfloat(u[1].xy).yx.x);
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x2/to_builtin.wgsl.expected.fxc.hlsl
deleted file mode 100644
index a6bdd17..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/to_builtin.wgsl.expected.fxc.hlsl
+++ /dev/null
@@ -1,19 +0,0 @@
-cbuffer cbuffer_u : register(b0, space0) {
-  uint4 u[8];
-};
-
-float2x2 tint_symbol(uint4 buffer[8], uint offset) {
-  const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset / 4];
-  const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
-  return float2x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)));
-}
-
-[numthreads(1, 1, 1)]
-void f() {
-  const float2x2 t = transpose(tint_symbol(u, 72u));
-  const float l = length(asfloat(u[1].xy).yx);
-  const float a = abs(asfloat(u[1].xy).yx.x);
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x2/to_builtin.wgsl.expected.glsl
deleted file mode 100644
index ee2a35b..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/to_builtin.wgsl.expected.glsl
+++ /dev/null
@@ -1,38 +0,0 @@
-#version 310 es
-
-struct S {
-  int before;
-  uint pad;
-  mat2 m;
-  int after;
-  uint pad_1;
-};
-
-struct S_std140 {
-  int before;
-  uint pad;
-  vec2 m_0;
-  vec2 m_1;
-  int after;
-  uint pad_1;
-};
-
-layout(binding = 0, std140) uniform u_block_std140_ubo {
-  S_std140 inner[4];
-} u;
-
-mat2 load_u_inner_2_m() {
-  return mat2(u.inner[2u].m_0, u.inner[2u].m_1);
-}
-
-void f() {
-  mat2 t = transpose(load_u_inner_2_m());
-  float l = length(u.inner[0u].m_1.yx);
-  float a = abs(u.inner[0u].m_1.yx[0u]);
-}
-
-layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
-void main() {
-  f();
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x2/to_builtin.wgsl.expected.msl
deleted file mode 100644
index 108d689..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/to_builtin.wgsl.expected.msl
+++ /dev/null
@@ -1,31 +0,0 @@
-#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 S {
-  /* 0x0000 */ int before;
-  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
-  /* 0x0008 */ float2x2 m;
-  /* 0x0018 */ int after;
-  /* 0x001c */ tint_array<int8_t, 4> tint_pad_1;
-};
-
-kernel void f(const constant tint_array<S, 4>* tint_symbol [[buffer(0)]]) {
-  float2x2 const t = transpose((*(tint_symbol))[2].m);
-  float const l = length(float2((*(tint_symbol))[0].m[1]).yx);
-  float const a = fabs(float2((*(tint_symbol))[0].m[1]).yx[0]);
-  return;
-}
-
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x2/to_builtin.wgsl.expected.spvasm
deleted file mode 100644
index e4863ac..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/to_builtin.wgsl.expected.spvasm
+++ /dev/null
@@ -1,75 +0,0 @@
-; SPIR-V
-; Version: 1.3
-; Generator: Google Tint Compiler; 0
-; Bound: 46
-; Schema: 0
-               OpCapability Shader
-         %36 = OpExtInstImport "GLSL.std.450"
-               OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %f "f"
-               OpExecutionMode %f LocalSize 1 1 1
-               OpName %u_block_std140 "u_block_std140"
-               OpMemberName %u_block_std140 0 "inner"
-               OpName %S_std140 "S_std140"
-               OpMemberName %S_std140 0 "before"
-               OpMemberName %S_std140 1 "m_0"
-               OpMemberName %S_std140 2 "m_1"
-               OpMemberName %S_std140 3 "after"
-               OpName %u "u"
-               OpName %load_u_inner_2_m "load_u_inner_2_m"
-               OpName %f "f"
-               OpDecorate %u_block_std140 Block
-               OpMemberDecorate %u_block_std140 0 Offset 0
-               OpMemberDecorate %S_std140 0 Offset 0
-               OpMemberDecorate %S_std140 1 Offset 8
-               OpMemberDecorate %S_std140 2 Offset 16
-               OpMemberDecorate %S_std140 3 Offset 24
-               OpDecorate %_arr_S_std140_uint_4 ArrayStride 32
-               OpDecorate %u NonWritable
-               OpDecorate %u DescriptorSet 0
-               OpDecorate %u Binding 0
-        %int = OpTypeInt 32 1
-      %float = OpTypeFloat 32
-    %v2float = OpTypeVector %float 2
-   %S_std140 = OpTypeStruct %int %v2float %v2float %int
-       %uint = OpTypeInt 32 0
-     %uint_4 = OpConstant %uint 4
-%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
-%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
-%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
-          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
-%mat2v2float = OpTypeMatrix %v2float 2
-         %11 = OpTypeFunction %mat2v2float
-     %uint_0 = OpConstant %uint 0
-     %uint_2 = OpConstant %uint 2
-%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
-     %uint_1 = OpConstant %uint 1
-%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
-       %void = OpTypeVoid
-         %29 = OpTypeFunction %void
-         %37 = OpConstantNull %uint
-%load_u_inner_2_m = OpFunction %mat2v2float None %11
-         %14 = OpLabel
-         %19 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
-         %23 = OpAccessChain %_ptr_Uniform_v2float %19 %uint_1
-         %24 = OpLoad %v2float %23
-         %26 = OpAccessChain %_ptr_Uniform_v2float %19 %uint_2
-         %27 = OpLoad %v2float %26
-         %28 = OpCompositeConstruct %mat2v2float %24 %27
-               OpReturnValue %28
-               OpFunctionEnd
-          %f = OpFunction %void None %29
-         %32 = OpLabel
-         %34 = OpFunctionCall %mat2v2float %load_u_inner_2_m
-         %33 = OpTranspose %mat2v2float %34
-         %38 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %37 %uint_2
-         %39 = OpLoad %v2float %38
-         %40 = OpVectorShuffle %v2float %39 %39 1 0
-         %35 = OpExtInst %float %36 Length %40
-         %42 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %37 %uint_2
-         %43 = OpLoad %v2float %42
-         %44 = OpVectorShuffle %v2float %43 %43 1 0
-         %45 = OpCompositeExtract %float %44 0
-         %41 = OpExtInst %float %36 FAbs %45
-               OpReturn
-               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x2/to_builtin.wgsl.expected.wgsl
deleted file mode 100644
index 2e27c88..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/to_builtin.wgsl.expected.wgsl
+++ /dev/null
@@ -1,14 +0,0 @@
-struct S {
-  before : i32,
-  m : mat2x2<f32>,
-  after : i32,
-}
-
-@group(0) @binding(0) var<uniform> u : array<S, 4>;
-
-@compute @workgroup_size(1)
-fn f() {
-  let t = transpose(u[2].m);
-  let l = length(u[0].m[1].yx);
-  let a = abs(u[0].m[1].yx.x);
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/to_fn.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x2/to_fn.wgsl
deleted file mode 100644
index 3ec4eda..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/to_fn.wgsl
+++ /dev/null
@@ -1,22 +0,0 @@
-struct S {
-  before : i32,
-  m : mat2x2<f32>,
-  after : i32,
-}
-
-@group(0) @binding(0) var<uniform> u : array<S, 4>;
-
-fn a(a : array<S, 4>) {}
-fn b(s : S) {}
-fn c(m : mat2x2<f32>) {}
-fn d(v : vec2<f32>) {}
-fn e(f : f32) {}
-
-@compute @workgroup_size(1)
-fn f() {
-    a(u);
-    b(u[2]);
-    c(u[2].m);
-    d(u[0].m[1].yx);
-    e(u[0].m[1].yx.x);
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x2/to_fn.wgsl.expected.dxc.hlsl
deleted file mode 100644
index 9170ce8..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/to_fn.wgsl.expected.dxc.hlsl
+++ /dev/null
@@ -1,60 +0,0 @@
-struct S {
-  int before;
-  float2x2 m;
-  int after;
-};
-
-cbuffer cbuffer_u : register(b0, space0) {
-  uint4 u[8];
-};
-
-void a(S a_1[4]) {
-}
-
-void b(S s) {
-}
-
-void c(float2x2 m) {
-}
-
-void d(float2 v) {
-}
-
-void e(float f_1) {
-}
-
-float2x2 tint_symbol_3(uint4 buffer[8], uint offset) {
-  const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset / 4];
-  const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
-  return float2x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)));
-}
-
-S tint_symbol_1(uint4 buffer[8], uint offset) {
-  const uint scalar_offset_2 = ((offset + 0u)) / 4;
-  const uint scalar_offset_3 = ((offset + 24u)) / 4;
-  const S tint_symbol_5 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
-  return tint_symbol_5;
-}
-
-typedef S tint_symbol_ret[4];
-tint_symbol_ret tint_symbol(uint4 buffer[8], uint offset) {
-  S arr[4] = (S[4])0;
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      arr[i] = tint_symbol_1(buffer, (offset + (i * 32u)));
-    }
-  }
-  return arr;
-}
-
-[numthreads(1, 1, 1)]
-void f() {
-  a(tint_symbol(u, 0u));
-  b(tint_symbol_1(u, 64u));
-  c(tint_symbol_3(u, 72u));
-  d(asfloat(u[1].xy).yx);
-  e(asfloat(u[1].xy).yx.x);
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x2/to_fn.wgsl.expected.fxc.hlsl
deleted file mode 100644
index 9170ce8..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/to_fn.wgsl.expected.fxc.hlsl
+++ /dev/null
@@ -1,60 +0,0 @@
-struct S {
-  int before;
-  float2x2 m;
-  int after;
-};
-
-cbuffer cbuffer_u : register(b0, space0) {
-  uint4 u[8];
-};
-
-void a(S a_1[4]) {
-}
-
-void b(S s) {
-}
-
-void c(float2x2 m) {
-}
-
-void d(float2 v) {
-}
-
-void e(float f_1) {
-}
-
-float2x2 tint_symbol_3(uint4 buffer[8], uint offset) {
-  const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset / 4];
-  const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
-  return float2x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)));
-}
-
-S tint_symbol_1(uint4 buffer[8], uint offset) {
-  const uint scalar_offset_2 = ((offset + 0u)) / 4;
-  const uint scalar_offset_3 = ((offset + 24u)) / 4;
-  const S tint_symbol_5 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
-  return tint_symbol_5;
-}
-
-typedef S tint_symbol_ret[4];
-tint_symbol_ret tint_symbol(uint4 buffer[8], uint offset) {
-  S arr[4] = (S[4])0;
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      arr[i] = tint_symbol_1(buffer, (offset + (i * 32u)));
-    }
-  }
-  return arr;
-}
-
-[numthreads(1, 1, 1)]
-void f() {
-  a(tint_symbol(u, 0u));
-  b(tint_symbol_1(u, 64u));
-  c(tint_symbol_3(u, 72u));
-  d(asfloat(u[1].xy).yx);
-  e(asfloat(u[1].xy).yx.x);
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x2/to_fn.wgsl.expected.glsl
deleted file mode 100644
index daaf731..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/to_fn.wgsl.expected.glsl
+++ /dev/null
@@ -1,69 +0,0 @@
-#version 310 es
-
-struct S {
-  int before;
-  uint pad;
-  mat2 m;
-  int after;
-  uint pad_1;
-};
-
-struct S_std140 {
-  int before;
-  uint pad;
-  vec2 m_0;
-  vec2 m_1;
-  int after;
-  uint pad_1;
-};
-
-layout(binding = 0, std140) uniform u_block_std140_ubo {
-  S_std140 inner[4];
-} u;
-
-void a(S a_1[4]) {
-}
-
-void b(S s) {
-}
-
-void c(mat2 m) {
-}
-
-void d(vec2 v) {
-}
-
-void e(float f_1) {
-}
-
-S conv_S(S_std140 val) {
-  return S(val.before, val.pad, mat2(val.m_0, val.m_1), val.after, val.pad_1);
-}
-
-S[4] conv_arr4_S(S_std140 val[4]) {
-  S arr[4] = S[4](S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0, 0u));
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      arr[i] = conv_S(val[i]);
-    }
-  }
-  return arr;
-}
-
-mat2 load_u_inner_2_m() {
-  return mat2(u.inner[2u].m_0, u.inner[2u].m_1);
-}
-
-void f() {
-  a(conv_arr4_S(u.inner));
-  b(conv_S(u.inner[2u]));
-  c(load_u_inner_2_m());
-  d(u.inner[0u].m_1.yx);
-  e(u.inner[0u].m_1.yx[0u]);
-}
-
-layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
-void main() {
-  f();
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x2/to_fn.wgsl.expected.msl
deleted file mode 100644
index eda83c5..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/to_fn.wgsl.expected.msl
+++ /dev/null
@@ -1,48 +0,0 @@
-#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 S {
-  /* 0x0000 */ int before;
-  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
-  /* 0x0008 */ float2x2 m;
-  /* 0x0018 */ int after;
-  /* 0x001c */ tint_array<int8_t, 4> tint_pad_1;
-};
-
-void a(tint_array<S, 4> a_1) {
-}
-
-void b(S s) {
-}
-
-void c(float2x2 m) {
-}
-
-void d(float2 v) {
-}
-
-void e(float f_1) {
-}
-
-kernel void f(const constant tint_array<S, 4>* tint_symbol [[buffer(0)]]) {
-  a(*(tint_symbol));
-  b((*(tint_symbol))[2]);
-  c((*(tint_symbol))[2].m);
-  d(float2((*(tint_symbol))[0].m[1]).yx);
-  e(float2((*(tint_symbol))[0].m[1]).yx[0]);
-  return;
-}
-
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x2/to_fn.wgsl.expected.spvasm
deleted file mode 100644
index facd977..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/to_fn.wgsl.expected.spvasm
+++ /dev/null
@@ -1,200 +0,0 @@
-; SPIR-V
-; Version: 1.3
-; Generator: Google Tint Compiler; 0
-; Bound: 119
-; Schema: 0
-               OpCapability Shader
-               OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %f "f"
-               OpExecutionMode %f LocalSize 1 1 1
-               OpName %u_block_std140 "u_block_std140"
-               OpMemberName %u_block_std140 0 "inner"
-               OpName %S_std140 "S_std140"
-               OpMemberName %S_std140 0 "before"
-               OpMemberName %S_std140 1 "m_0"
-               OpMemberName %S_std140 2 "m_1"
-               OpMemberName %S_std140 3 "after"
-               OpName %u "u"
-               OpName %S "S"
-               OpMemberName %S 0 "before"
-               OpMemberName %S 1 "m"
-               OpMemberName %S 2 "after"
-               OpName %a "a"
-               OpName %a_1 "a_1"
-               OpName %b "b"
-               OpName %s "s"
-               OpName %c "c"
-               OpName %m "m"
-               OpName %d "d"
-               OpName %v "v"
-               OpName %e "e"
-               OpName %f_1 "f_1"
-               OpName %conv_S "conv_S"
-               OpName %val "val"
-               OpName %conv_arr4_S "conv_arr4_S"
-               OpName %val_0 "val"
-               OpName %arr "arr"
-               OpName %i "i"
-               OpName %var_for_index "var_for_index"
-               OpName %load_u_inner_2_m "load_u_inner_2_m"
-               OpName %f "f"
-               OpDecorate %u_block_std140 Block
-               OpMemberDecorate %u_block_std140 0 Offset 0
-               OpMemberDecorate %S_std140 0 Offset 0
-               OpMemberDecorate %S_std140 1 Offset 8
-               OpMemberDecorate %S_std140 2 Offset 16
-               OpMemberDecorate %S_std140 3 Offset 24
-               OpDecorate %_arr_S_std140_uint_4 ArrayStride 32
-               OpDecorate %u NonWritable
-               OpDecorate %u DescriptorSet 0
-               OpDecorate %u Binding 0
-               OpMemberDecorate %S 0 Offset 0
-               OpMemberDecorate %S 1 Offset 8
-               OpMemberDecorate %S 1 ColMajor
-               OpMemberDecorate %S 1 MatrixStride 8
-               OpMemberDecorate %S 2 Offset 24
-               OpDecorate %_arr_S_uint_4 ArrayStride 32
-        %int = OpTypeInt 32 1
-      %float = OpTypeFloat 32
-    %v2float = OpTypeVector %float 2
-   %S_std140 = OpTypeStruct %int %v2float %v2float %int
-       %uint = OpTypeInt 32 0
-     %uint_4 = OpConstant %uint 4
-%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
-%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
-%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
-          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
-       %void = OpTypeVoid
-%mat2v2float = OpTypeMatrix %v2float 2
-          %S = OpTypeStruct %int %mat2v2float %int
-%_arr_S_uint_4 = OpTypeArray %S %uint_4
-         %11 = OpTypeFunction %void %_arr_S_uint_4
-         %19 = OpTypeFunction %void %S
-         %23 = OpTypeFunction %void %mat2v2float
-         %27 = OpTypeFunction %void %v2float
-         %31 = OpTypeFunction %void %float
-         %35 = OpTypeFunction %S %S_std140
-         %45 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
-%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
-         %51 = OpConstantNull %_arr_S_uint_4
-%_ptr_Function_uint = OpTypePointer Function %uint
-         %54 = OpConstantNull %uint
-       %bool = OpTypeBool
-%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
-         %67 = OpConstantNull %_arr_S_std140_uint_4
-%_ptr_Function_S = OpTypePointer Function %S
-%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
-     %uint_1 = OpConstant %uint 1
-         %80 = OpTypeFunction %mat2v2float
-     %uint_0 = OpConstant %uint 0
-     %uint_2 = OpConstant %uint 2
-%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
-%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
-         %96 = OpTypeFunction %void
-%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
-          %a = OpFunction %void None %11
-        %a_1 = OpFunctionParameter %_arr_S_uint_4
-         %18 = OpLabel
-               OpReturn
-               OpFunctionEnd
-          %b = OpFunction %void None %19
-          %s = OpFunctionParameter %S
-         %22 = OpLabel
-               OpReturn
-               OpFunctionEnd
-          %c = OpFunction %void None %23
-          %m = OpFunctionParameter %mat2v2float
-         %26 = OpLabel
-               OpReturn
-               OpFunctionEnd
-          %d = OpFunction %void None %27
-          %v = OpFunctionParameter %v2float
-         %30 = OpLabel
-               OpReturn
-               OpFunctionEnd
-          %e = OpFunction %void None %31
-        %f_1 = OpFunctionParameter %float
-         %34 = OpLabel
-               OpReturn
-               OpFunctionEnd
-     %conv_S = OpFunction %S None %35
-        %val = OpFunctionParameter %S_std140
-         %38 = OpLabel
-         %39 = OpCompositeExtract %int %val 0
-         %40 = OpCompositeExtract %v2float %val 1
-         %41 = OpCompositeExtract %v2float %val 2
-         %42 = OpCompositeConstruct %mat2v2float %40 %41
-         %43 = OpCompositeExtract %int %val 3
-         %44 = OpCompositeConstruct %S %39 %42 %43
-               OpReturnValue %44
-               OpFunctionEnd
-%conv_arr4_S = OpFunction %_arr_S_uint_4 None %45
-      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
-         %48 = OpLabel
-        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %51
-          %i = OpVariable %_ptr_Function_uint Function %54
-%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %67
-               OpBranch %55
-         %55 = OpLabel
-               OpLoopMerge %56 %57 None
-               OpBranch %58
-         %58 = OpLabel
-         %60 = OpLoad %uint %i
-         %61 = OpULessThan %bool %60 %uint_4
-         %59 = OpLogicalNot %bool %61
-               OpSelectionMerge %63 None
-               OpBranchConditional %59 %64 %63
-         %64 = OpLabel
-               OpBranch %56
-         %63 = OpLabel
-               OpStore %var_for_index %val_0
-         %68 = OpLoad %uint %i
-         %70 = OpAccessChain %_ptr_Function_S %arr %68
-         %72 = OpLoad %uint %i
-         %74 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %72
-         %75 = OpLoad %S_std140 %74
-         %71 = OpFunctionCall %S %conv_S %75
-               OpStore %70 %71
-               OpBranch %57
-         %57 = OpLabel
-         %76 = OpLoad %uint %i
-         %78 = OpIAdd %uint %76 %uint_1
-               OpStore %i %78
-               OpBranch %55
-         %56 = OpLabel
-         %79 = OpLoad %_arr_S_uint_4 %arr
-               OpReturnValue %79
-               OpFunctionEnd
-%load_u_inner_2_m = OpFunction %mat2v2float None %80
-         %82 = OpLabel
-         %87 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
-         %90 = OpAccessChain %_ptr_Uniform_v2float %87 %uint_1
-         %91 = OpLoad %v2float %90
-         %93 = OpAccessChain %_ptr_Uniform_v2float %87 %uint_2
-         %94 = OpLoad %v2float %93
-         %95 = OpCompositeConstruct %mat2v2float %91 %94
-               OpReturnValue %95
-               OpFunctionEnd
-          %f = OpFunction %void None %96
-         %98 = OpLabel
-        %102 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
-        %103 = OpLoad %_arr_S_std140_uint_4 %102
-        %100 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %103
-         %99 = OpFunctionCall %void %a %100
-        %106 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
-        %107 = OpLoad %S_std140 %106
-        %105 = OpFunctionCall %S %conv_S %107
-        %104 = OpFunctionCall %void %b %105
-        %109 = OpFunctionCall %mat2v2float %load_u_inner_2_m
-        %108 = OpFunctionCall %void %c %109
-        %111 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %54 %uint_2
-        %112 = OpLoad %v2float %111
-        %113 = OpVectorShuffle %v2float %112 %112 1 0
-        %110 = OpFunctionCall %void %d %113
-        %115 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %54 %uint_2
-        %116 = OpLoad %v2float %115
-        %117 = OpVectorShuffle %v2float %116 %116 1 0
-        %118 = OpCompositeExtract %float %117 0
-        %114 = OpFunctionCall %void %e %118
-               OpReturn
-               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x2/to_fn.wgsl.expected.wgsl
deleted file mode 100644
index f8ed037..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/to_fn.wgsl.expected.wgsl
+++ /dev/null
@@ -1,31 +0,0 @@
-struct S {
-  before : i32,
-  m : mat2x2<f32>,
-  after : i32,
-}
-
-@group(0) @binding(0) var<uniform> u : array<S, 4>;
-
-fn a(a : array<S, 4>) {
-}
-
-fn b(s : S) {
-}
-
-fn c(m : mat2x2<f32>) {
-}
-
-fn d(v : vec2<f32>) {
-}
-
-fn e(f : f32) {
-}
-
-@compute @workgroup_size(1)
-fn f() {
-  a(u);
-  b(u[2]);
-  c(u[2].m);
-  d(u[0].m[1].yx);
-  e(u[0].m[1].yx.x);
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/to_private.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x2/to_private.wgsl
deleted file mode 100644
index 4cf6d16..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/to_private.wgsl
+++ /dev/null
@@ -1,16 +0,0 @@
-struct S {
-  before : i32,
-  m : mat2x2<f32>,
-  after : i32,
-}
-
-@group(0) @binding(0) var<uniform> u : array<S, 4>;
-var<private> p : array<S, 4>;
-
-@compute @workgroup_size(1)
-fn f() {
-    p = u;
-    p[1] = u[2];
-    p[3].m = u[2].m;
-    p[1].m[0] = u[0].m[1].yx;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x2/to_private.wgsl.expected.dxc.hlsl
deleted file mode 100644
index 6aa0a11..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/to_private.wgsl.expected.dxc.hlsl
+++ /dev/null
@@ -1,45 +0,0 @@
-struct S {
-  int before;
-  float2x2 m;
-  int after;
-};
-
-cbuffer cbuffer_u : register(b0, space0) {
-  uint4 u[8];
-};
-static S p[4] = (S[4])0;
-
-float2x2 tint_symbol_3(uint4 buffer[8], uint offset) {
-  const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset / 4];
-  const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
-  return float2x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)));
-}
-
-S tint_symbol_1(uint4 buffer[8], uint offset) {
-  const uint scalar_offset_2 = ((offset + 0u)) / 4;
-  const uint scalar_offset_3 = ((offset + 24u)) / 4;
-  const S tint_symbol_5 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
-  return tint_symbol_5;
-}
-
-typedef S tint_symbol_ret[4];
-tint_symbol_ret tint_symbol(uint4 buffer[8], uint offset) {
-  S arr[4] = (S[4])0;
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      arr[i] = tint_symbol_1(buffer, (offset + (i * 32u)));
-    }
-  }
-  return arr;
-}
-
-[numthreads(1, 1, 1)]
-void f() {
-  p = tint_symbol(u, 0u);
-  p[1] = tint_symbol_1(u, 64u);
-  p[3].m = tint_symbol_3(u, 72u);
-  p[1].m[0] = asfloat(u[1].xy).yx;
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x2/to_private.wgsl.expected.fxc.hlsl
deleted file mode 100644
index 6aa0a11..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/to_private.wgsl.expected.fxc.hlsl
+++ /dev/null
@@ -1,45 +0,0 @@
-struct S {
-  int before;
-  float2x2 m;
-  int after;
-};
-
-cbuffer cbuffer_u : register(b0, space0) {
-  uint4 u[8];
-};
-static S p[4] = (S[4])0;
-
-float2x2 tint_symbol_3(uint4 buffer[8], uint offset) {
-  const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset / 4];
-  const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
-  return float2x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)));
-}
-
-S tint_symbol_1(uint4 buffer[8], uint offset) {
-  const uint scalar_offset_2 = ((offset + 0u)) / 4;
-  const uint scalar_offset_3 = ((offset + 24u)) / 4;
-  const S tint_symbol_5 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
-  return tint_symbol_5;
-}
-
-typedef S tint_symbol_ret[4];
-tint_symbol_ret tint_symbol(uint4 buffer[8], uint offset) {
-  S arr[4] = (S[4])0;
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      arr[i] = tint_symbol_1(buffer, (offset + (i * 32u)));
-    }
-  }
-  return arr;
-}
-
-[numthreads(1, 1, 1)]
-void f() {
-  p = tint_symbol(u, 0u);
-  p[1] = tint_symbol_1(u, 64u);
-  p[3].m = tint_symbol_3(u, 72u);
-  p[1].m[0] = asfloat(u[1].xy).yx;
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x2/to_private.wgsl.expected.glsl
deleted file mode 100644
index 9634531..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/to_private.wgsl.expected.glsl
+++ /dev/null
@@ -1,54 +0,0 @@
-#version 310 es
-
-struct S {
-  int before;
-  uint pad;
-  mat2 m;
-  int after;
-  uint pad_1;
-};
-
-struct S_std140 {
-  int before;
-  uint pad;
-  vec2 m_0;
-  vec2 m_1;
-  int after;
-  uint pad_1;
-};
-
-layout(binding = 0, std140) uniform u_block_std140_ubo {
-  S_std140 inner[4];
-} u;
-
-S p[4] = S[4](S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0, 0u));
-S conv_S(S_std140 val) {
-  return S(val.before, val.pad, mat2(val.m_0, val.m_1), val.after, val.pad_1);
-}
-
-S[4] conv_arr4_S(S_std140 val[4]) {
-  S arr[4] = S[4](S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0, 0u));
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      arr[i] = conv_S(val[i]);
-    }
-  }
-  return arr;
-}
-
-mat2 load_u_inner_2_m() {
-  return mat2(u.inner[2u].m_0, u.inner[2u].m_1);
-}
-
-void f() {
-  p = conv_arr4_S(u.inner);
-  p[1] = conv_S(u.inner[2u]);
-  p[3].m = load_u_inner_2_m();
-  p[1].m[0] = u.inner[0u].m_1.yx;
-}
-
-layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
-void main() {
-  f();
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x2/to_private.wgsl.expected.msl
deleted file mode 100644
index 87743fb..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/to_private.wgsl.expected.msl
+++ /dev/null
@@ -1,33 +0,0 @@
-#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 S {
-  /* 0x0000 */ int before;
-  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
-  /* 0x0008 */ float2x2 m;
-  /* 0x0018 */ int after;
-  /* 0x001c */ tint_array<int8_t, 4> tint_pad_1;
-};
-
-kernel void f(const constant tint_array<S, 4>* tint_symbol_1 [[buffer(0)]]) {
-  thread tint_array<S, 4> tint_symbol = {};
-  tint_symbol = *(tint_symbol_1);
-  tint_symbol[1] = (*(tint_symbol_1))[2];
-  tint_symbol[3].m = (*(tint_symbol_1))[2].m;
-  tint_symbol[1].m[0] = float2((*(tint_symbol_1))[0].m[1]).yx;
-  return;
-}
-
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x2/to_private.wgsl.expected.spvasm
deleted file mode 100644
index 57765b4..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/to_private.wgsl.expected.spvasm
+++ /dev/null
@@ -1,167 +0,0 @@
-; SPIR-V
-; Version: 1.3
-; Generator: Google Tint Compiler; 0
-; Bound: 101
-; Schema: 0
-               OpCapability Shader
-               OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %f "f"
-               OpExecutionMode %f LocalSize 1 1 1
-               OpName %u_block_std140 "u_block_std140"
-               OpMemberName %u_block_std140 0 "inner"
-               OpName %S_std140 "S_std140"
-               OpMemberName %S_std140 0 "before"
-               OpMemberName %S_std140 1 "m_0"
-               OpMemberName %S_std140 2 "m_1"
-               OpMemberName %S_std140 3 "after"
-               OpName %u "u"
-               OpName %S "S"
-               OpMemberName %S 0 "before"
-               OpMemberName %S 1 "m"
-               OpMemberName %S 2 "after"
-               OpName %p "p"
-               OpName %conv_S "conv_S"
-               OpName %val "val"
-               OpName %conv_arr4_S "conv_arr4_S"
-               OpName %val_0 "val"
-               OpName %arr "arr"
-               OpName %i "i"
-               OpName %var_for_index "var_for_index"
-               OpName %load_u_inner_2_m "load_u_inner_2_m"
-               OpName %f "f"
-               OpDecorate %u_block_std140 Block
-               OpMemberDecorate %u_block_std140 0 Offset 0
-               OpMemberDecorate %S_std140 0 Offset 0
-               OpMemberDecorate %S_std140 1 Offset 8
-               OpMemberDecorate %S_std140 2 Offset 16
-               OpMemberDecorate %S_std140 3 Offset 24
-               OpDecorate %_arr_S_std140_uint_4 ArrayStride 32
-               OpDecorate %u NonWritable
-               OpDecorate %u DescriptorSet 0
-               OpDecorate %u Binding 0
-               OpMemberDecorate %S 0 Offset 0
-               OpMemberDecorate %S 1 Offset 8
-               OpMemberDecorate %S 1 ColMajor
-               OpMemberDecorate %S 1 MatrixStride 8
-               OpMemberDecorate %S 2 Offset 24
-               OpDecorate %_arr_S_uint_4 ArrayStride 32
-        %int = OpTypeInt 32 1
-      %float = OpTypeFloat 32
-    %v2float = OpTypeVector %float 2
-   %S_std140 = OpTypeStruct %int %v2float %v2float %int
-       %uint = OpTypeInt 32 0
-     %uint_4 = OpConstant %uint 4
-%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
-%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
-%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
-          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
-%mat2v2float = OpTypeMatrix %v2float 2
-          %S = OpTypeStruct %int %mat2v2float %int
-%_arr_S_uint_4 = OpTypeArray %S %uint_4
-%_ptr_Private__arr_S_uint_4 = OpTypePointer Private %_arr_S_uint_4
-         %16 = OpConstantNull %_arr_S_uint_4
-          %p = OpVariable %_ptr_Private__arr_S_uint_4 Private %16
-         %17 = OpTypeFunction %S %S_std140
-         %27 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
-%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
-%_ptr_Function_uint = OpTypePointer Function %uint
-         %35 = OpConstantNull %uint
-       %bool = OpTypeBool
-%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
-         %48 = OpConstantNull %_arr_S_std140_uint_4
-%_ptr_Function_S = OpTypePointer Function %S
-%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
-     %uint_1 = OpConstant %uint 1
-         %61 = OpTypeFunction %mat2v2float
-     %uint_0 = OpConstant %uint 0
-     %uint_2 = OpConstant %uint 2
-%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
-%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
-       %void = OpTypeVoid
-         %77 = OpTypeFunction %void
-%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
-      %int_1 = OpConstant %int 1
-%_ptr_Private_S = OpTypePointer Private %S
-      %int_3 = OpConstant %int 3
-%_ptr_Private_mat2v2float = OpTypePointer Private %mat2v2float
-         %95 = OpConstantNull %int
-%_ptr_Private_v2float = OpTypePointer Private %v2float
-     %conv_S = OpFunction %S None %17
-        %val = OpFunctionParameter %S_std140
-         %20 = OpLabel
-         %21 = OpCompositeExtract %int %val 0
-         %22 = OpCompositeExtract %v2float %val 1
-         %23 = OpCompositeExtract %v2float %val 2
-         %24 = OpCompositeConstruct %mat2v2float %22 %23
-         %25 = OpCompositeExtract %int %val 3
-         %26 = OpCompositeConstruct %S %21 %24 %25
-               OpReturnValue %26
-               OpFunctionEnd
-%conv_arr4_S = OpFunction %_arr_S_uint_4 None %27
-      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
-         %30 = OpLabel
-        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %16
-          %i = OpVariable %_ptr_Function_uint Function %35
-%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %48
-               OpBranch %36
-         %36 = OpLabel
-               OpLoopMerge %37 %38 None
-               OpBranch %39
-         %39 = OpLabel
-         %41 = OpLoad %uint %i
-         %42 = OpULessThan %bool %41 %uint_4
-         %40 = OpLogicalNot %bool %42
-               OpSelectionMerge %44 None
-               OpBranchConditional %40 %45 %44
-         %45 = OpLabel
-               OpBranch %37
-         %44 = OpLabel
-               OpStore %var_for_index %val_0
-         %49 = OpLoad %uint %i
-         %51 = OpAccessChain %_ptr_Function_S %arr %49
-         %53 = OpLoad %uint %i
-         %55 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %53
-         %56 = OpLoad %S_std140 %55
-         %52 = OpFunctionCall %S %conv_S %56
-               OpStore %51 %52
-               OpBranch %38
-         %38 = OpLabel
-         %57 = OpLoad %uint %i
-         %59 = OpIAdd %uint %57 %uint_1
-               OpStore %i %59
-               OpBranch %36
-         %37 = OpLabel
-         %60 = OpLoad %_arr_S_uint_4 %arr
-               OpReturnValue %60
-               OpFunctionEnd
-%load_u_inner_2_m = OpFunction %mat2v2float None %61
-         %63 = OpLabel
-         %68 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
-         %71 = OpAccessChain %_ptr_Uniform_v2float %68 %uint_1
-         %72 = OpLoad %v2float %71
-         %74 = OpAccessChain %_ptr_Uniform_v2float %68 %uint_2
-         %75 = OpLoad %v2float %74
-         %76 = OpCompositeConstruct %mat2v2float %72 %75
-               OpReturnValue %76
-               OpFunctionEnd
-          %f = OpFunction %void None %77
-         %80 = OpLabel
-         %83 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
-         %84 = OpLoad %_arr_S_std140_uint_4 %83
-         %81 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %84
-               OpStore %p %81
-         %87 = OpAccessChain %_ptr_Private_S %p %int_1
-         %89 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
-         %90 = OpLoad %S_std140 %89
-         %88 = OpFunctionCall %S %conv_S %90
-               OpStore %87 %88
-         %93 = OpAccessChain %_ptr_Private_mat2v2float %p %int_3 %uint_1
-         %94 = OpFunctionCall %mat2v2float %load_u_inner_2_m
-               OpStore %93 %94
-         %97 = OpAccessChain %_ptr_Private_v2float %p %int_1 %uint_1 %95
-         %98 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %35 %uint_2
-         %99 = OpLoad %v2float %98
-        %100 = OpVectorShuffle %v2float %99 %99 1 0
-               OpStore %97 %100
-               OpReturn
-               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x2/to_private.wgsl.expected.wgsl
deleted file mode 100644
index 9d4358a..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/to_private.wgsl.expected.wgsl
+++ /dev/null
@@ -1,17 +0,0 @@
-struct S {
-  before : i32,
-  m : mat2x2<f32>,
-  after : i32,
-}
-
-@group(0) @binding(0) var<uniform> u : array<S, 4>;
-
-var<private> p : array<S, 4>;
-
-@compute @workgroup_size(1)
-fn f() {
-  p = u;
-  p[1] = u[2];
-  p[3].m = u[2].m;
-  p[1].m[0] = u[0].m[1].yx;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/to_storage.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x2/to_storage.wgsl
deleted file mode 100644
index 8d2687b..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/to_storage.wgsl
+++ /dev/null
@@ -1,16 +0,0 @@
-struct S {
-  before : i32,
-  m : mat2x2<f32>,
-  after : i32,
-}
-
-@group(0) @binding(0) var<uniform> u : array<S, 4>;
-@group(0) @binding(1) var<storage, read_write> s : array<S, 4>;
-
-@compute @workgroup_size(1)
-fn f() {
-    s = u;
-    s[1] = u[2];
-    s[3].m = u[2].m;
-    s[1].m[0] = u[0].m[1].yx;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x2/to_storage.wgsl.expected.dxc.hlsl
deleted file mode 100644
index c0ccad6..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/to_storage.wgsl.expected.dxc.hlsl
+++ /dev/null
@@ -1,65 +0,0 @@
-struct S {
-  int before;
-  float2x2 m;
-  int after;
-};
-
-cbuffer cbuffer_u : register(b0, space0) {
-  uint4 u[8];
-};
-RWByteAddressBuffer s : register(u1, space0);
-
-void tint_symbol_3(RWByteAddressBuffer buffer, uint offset, float2x2 value) {
-  buffer.Store2((offset + 0u), asuint(value[0u]));
-  buffer.Store2((offset + 8u), asuint(value[1u]));
-}
-
-void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, S value) {
-  buffer.Store((offset + 0u), asuint(value.before));
-  tint_symbol_3(buffer, (offset + 8u), value.m);
-  buffer.Store((offset + 24u), asuint(value.after));
-}
-
-void tint_symbol(RWByteAddressBuffer buffer, uint offset, S value[4]) {
-  S array[4] = value;
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      tint_symbol_1(buffer, (offset + (i * 32u)), array[i]);
-    }
-  }
-}
-
-float2x2 tint_symbol_8(uint4 buffer[8], uint offset) {
-  const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset / 4];
-  const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
-  return float2x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)));
-}
-
-S tint_symbol_6(uint4 buffer[8], uint offset) {
-  const uint scalar_offset_2 = ((offset + 0u)) / 4;
-  const uint scalar_offset_3 = ((offset + 24u)) / 4;
-  const S tint_symbol_10 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_8(buffer, (offset + 8u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
-  return tint_symbol_10;
-}
-
-typedef S tint_symbol_5_ret[4];
-tint_symbol_5_ret tint_symbol_5(uint4 buffer[8], uint offset) {
-  S arr[4] = (S[4])0;
-  {
-    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
-      arr[i_1] = tint_symbol_6(buffer, (offset + (i_1 * 32u)));
-    }
-  }
-  return arr;
-}
-
-[numthreads(1, 1, 1)]
-void f() {
-  tint_symbol(s, 0u, tint_symbol_5(u, 0u));
-  tint_symbol_1(s, 32u, tint_symbol_6(u, 64u));
-  tint_symbol_3(s, 104u, tint_symbol_8(u, 72u));
-  s.Store2(40u, asuint(asfloat(u[1].xy).yx));
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x2/to_storage.wgsl.expected.fxc.hlsl
deleted file mode 100644
index c0ccad6..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/to_storage.wgsl.expected.fxc.hlsl
+++ /dev/null
@@ -1,65 +0,0 @@
-struct S {
-  int before;
-  float2x2 m;
-  int after;
-};
-
-cbuffer cbuffer_u : register(b0, space0) {
-  uint4 u[8];
-};
-RWByteAddressBuffer s : register(u1, space0);
-
-void tint_symbol_3(RWByteAddressBuffer buffer, uint offset, float2x2 value) {
-  buffer.Store2((offset + 0u), asuint(value[0u]));
-  buffer.Store2((offset + 8u), asuint(value[1u]));
-}
-
-void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, S value) {
-  buffer.Store((offset + 0u), asuint(value.before));
-  tint_symbol_3(buffer, (offset + 8u), value.m);
-  buffer.Store((offset + 24u), asuint(value.after));
-}
-
-void tint_symbol(RWByteAddressBuffer buffer, uint offset, S value[4]) {
-  S array[4] = value;
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      tint_symbol_1(buffer, (offset + (i * 32u)), array[i]);
-    }
-  }
-}
-
-float2x2 tint_symbol_8(uint4 buffer[8], uint offset) {
-  const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset / 4];
-  const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
-  return float2x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)));
-}
-
-S tint_symbol_6(uint4 buffer[8], uint offset) {
-  const uint scalar_offset_2 = ((offset + 0u)) / 4;
-  const uint scalar_offset_3 = ((offset + 24u)) / 4;
-  const S tint_symbol_10 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_8(buffer, (offset + 8u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
-  return tint_symbol_10;
-}
-
-typedef S tint_symbol_5_ret[4];
-tint_symbol_5_ret tint_symbol_5(uint4 buffer[8], uint offset) {
-  S arr[4] = (S[4])0;
-  {
-    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
-      arr[i_1] = tint_symbol_6(buffer, (offset + (i_1 * 32u)));
-    }
-  }
-  return arr;
-}
-
-[numthreads(1, 1, 1)]
-void f() {
-  tint_symbol(s, 0u, tint_symbol_5(u, 0u));
-  tint_symbol_1(s, 32u, tint_symbol_6(u, 64u));
-  tint_symbol_3(s, 104u, tint_symbol_8(u, 72u));
-  s.Store2(40u, asuint(asfloat(u[1].xy).yx));
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x2/to_storage.wgsl.expected.glsl
deleted file mode 100644
index ec19f64..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/to_storage.wgsl.expected.glsl
+++ /dev/null
@@ -1,57 +0,0 @@
-#version 310 es
-
-struct S {
-  int before;
-  uint pad;
-  mat2 m;
-  int after;
-  uint pad_1;
-};
-
-struct S_std140 {
-  int before;
-  uint pad;
-  vec2 m_0;
-  vec2 m_1;
-  int after;
-  uint pad_1;
-};
-
-layout(binding = 0, std140) uniform u_block_std140_ubo {
-  S_std140 inner[4];
-} u;
-
-layout(binding = 1, std430) buffer u_block_ssbo {
-  S inner[4];
-} s;
-
-S conv_S(S_std140 val) {
-  return S(val.before, val.pad, mat2(val.m_0, val.m_1), val.after, val.pad_1);
-}
-
-S[4] conv_arr4_S(S_std140 val[4]) {
-  S arr[4] = S[4](S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0, 0u));
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      arr[i] = conv_S(val[i]);
-    }
-  }
-  return arr;
-}
-
-mat2 load_u_inner_2_m() {
-  return mat2(u.inner[2u].m_0, u.inner[2u].m_1);
-}
-
-void f() {
-  s.inner = conv_arr4_S(u.inner);
-  s.inner[1] = conv_S(u.inner[2u]);
-  s.inner[3].m = load_u_inner_2_m();
-  s.inner[1].m[0] = u.inner[0u].m_1.yx;
-}
-
-layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
-void main() {
-  f();
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x2/to_storage.wgsl.expected.msl
deleted file mode 100644
index b3b4048..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/to_storage.wgsl.expected.msl
+++ /dev/null
@@ -1,32 +0,0 @@
-#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 S {
-  /* 0x0000 */ int before;
-  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
-  /* 0x0008 */ float2x2 m;
-  /* 0x0018 */ int after;
-  /* 0x001c */ tint_array<int8_t, 4> tint_pad_1;
-};
-
-kernel void f(device tint_array<S, 4>* tint_symbol [[buffer(1)]], const constant tint_array<S, 4>* tint_symbol_1 [[buffer(0)]]) {
-  *(tint_symbol) = *(tint_symbol_1);
-  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
-  (*(tint_symbol))[3].m = (*(tint_symbol_1))[2].m;
-  (*(tint_symbol))[1].m[0] = float2((*(tint_symbol_1))[0].m[1]).yx;
-  return;
-}
-
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x2/to_storage.wgsl.expected.spvasm
deleted file mode 100644
index 6f393c7..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/to_storage.wgsl.expected.spvasm
+++ /dev/null
@@ -1,176 +0,0 @@
-; SPIR-V
-; Version: 1.3
-; Generator: Google Tint Compiler; 0
-; Bound: 104
-; Schema: 0
-               OpCapability Shader
-               OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %f "f"
-               OpExecutionMode %f LocalSize 1 1 1
-               OpName %u_block_std140 "u_block_std140"
-               OpMemberName %u_block_std140 0 "inner"
-               OpName %S_std140 "S_std140"
-               OpMemberName %S_std140 0 "before"
-               OpMemberName %S_std140 1 "m_0"
-               OpMemberName %S_std140 2 "m_1"
-               OpMemberName %S_std140 3 "after"
-               OpName %u "u"
-               OpName %u_block "u_block"
-               OpMemberName %u_block 0 "inner"
-               OpName %S "S"
-               OpMemberName %S 0 "before"
-               OpMemberName %S 1 "m"
-               OpMemberName %S 2 "after"
-               OpName %s "s"
-               OpName %conv_S "conv_S"
-               OpName %val "val"
-               OpName %conv_arr4_S "conv_arr4_S"
-               OpName %val_0 "val"
-               OpName %arr "arr"
-               OpName %i "i"
-               OpName %var_for_index "var_for_index"
-               OpName %load_u_inner_2_m "load_u_inner_2_m"
-               OpName %f "f"
-               OpDecorate %u_block_std140 Block
-               OpMemberDecorate %u_block_std140 0 Offset 0
-               OpMemberDecorate %S_std140 0 Offset 0
-               OpMemberDecorate %S_std140 1 Offset 8
-               OpMemberDecorate %S_std140 2 Offset 16
-               OpMemberDecorate %S_std140 3 Offset 24
-               OpDecorate %_arr_S_std140_uint_4 ArrayStride 32
-               OpDecorate %u NonWritable
-               OpDecorate %u DescriptorSet 0
-               OpDecorate %u Binding 0
-               OpDecorate %u_block Block
-               OpMemberDecorate %u_block 0 Offset 0
-               OpMemberDecorate %S 0 Offset 0
-               OpMemberDecorate %S 1 Offset 8
-               OpMemberDecorate %S 1 ColMajor
-               OpMemberDecorate %S 1 MatrixStride 8
-               OpMemberDecorate %S 2 Offset 24
-               OpDecorate %_arr_S_uint_4 ArrayStride 32
-               OpDecorate %s DescriptorSet 0
-               OpDecorate %s Binding 1
-        %int = OpTypeInt 32 1
-      %float = OpTypeFloat 32
-    %v2float = OpTypeVector %float 2
-   %S_std140 = OpTypeStruct %int %v2float %v2float %int
-       %uint = OpTypeInt 32 0
-     %uint_4 = OpConstant %uint 4
-%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
-%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
-%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
-          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
-%mat2v2float = OpTypeMatrix %v2float 2
-          %S = OpTypeStruct %int %mat2v2float %int
-%_arr_S_uint_4 = OpTypeArray %S %uint_4
-    %u_block = OpTypeStruct %_arr_S_uint_4
-%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
-          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
-         %17 = OpTypeFunction %S %S_std140
-         %27 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
-%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
-         %33 = OpConstantNull %_arr_S_uint_4
-%_ptr_Function_uint = OpTypePointer Function %uint
-         %36 = OpConstantNull %uint
-       %bool = OpTypeBool
-%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
-         %49 = OpConstantNull %_arr_S_std140_uint_4
-%_ptr_Function_S = OpTypePointer Function %S
-%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
-     %uint_1 = OpConstant %uint 1
-         %62 = OpTypeFunction %mat2v2float
-     %uint_0 = OpConstant %uint 0
-     %uint_2 = OpConstant %uint 2
-%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
-%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
-       %void = OpTypeVoid
-         %78 = OpTypeFunction %void
-%_ptr_StorageBuffer__arr_S_uint_4 = OpTypePointer StorageBuffer %_arr_S_uint_4
-%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
-      %int_1 = OpConstant %int 1
-%_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
-      %int_3 = OpConstant %int 3
-%_ptr_StorageBuffer_mat2v2float = OpTypePointer StorageBuffer %mat2v2float
-         %98 = OpConstantNull %int
-%_ptr_StorageBuffer_v2float = OpTypePointer StorageBuffer %v2float
-     %conv_S = OpFunction %S None %17
-        %val = OpFunctionParameter %S_std140
-         %20 = OpLabel
-         %21 = OpCompositeExtract %int %val 0
-         %22 = OpCompositeExtract %v2float %val 1
-         %23 = OpCompositeExtract %v2float %val 2
-         %24 = OpCompositeConstruct %mat2v2float %22 %23
-         %25 = OpCompositeExtract %int %val 3
-         %26 = OpCompositeConstruct %S %21 %24 %25
-               OpReturnValue %26
-               OpFunctionEnd
-%conv_arr4_S = OpFunction %_arr_S_uint_4 None %27
-      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
-         %30 = OpLabel
-        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %33
-          %i = OpVariable %_ptr_Function_uint Function %36
-%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %49
-               OpBranch %37
-         %37 = OpLabel
-               OpLoopMerge %38 %39 None
-               OpBranch %40
-         %40 = OpLabel
-         %42 = OpLoad %uint %i
-         %43 = OpULessThan %bool %42 %uint_4
-         %41 = OpLogicalNot %bool %43
-               OpSelectionMerge %45 None
-               OpBranchConditional %41 %46 %45
-         %46 = OpLabel
-               OpBranch %38
-         %45 = OpLabel
-               OpStore %var_for_index %val_0
-         %50 = OpLoad %uint %i
-         %52 = OpAccessChain %_ptr_Function_S %arr %50
-         %54 = OpLoad %uint %i
-         %56 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %54
-         %57 = OpLoad %S_std140 %56
-         %53 = OpFunctionCall %S %conv_S %57
-               OpStore %52 %53
-               OpBranch %39
-         %39 = OpLabel
-         %58 = OpLoad %uint %i
-         %60 = OpIAdd %uint %58 %uint_1
-               OpStore %i %60
-               OpBranch %37
-         %38 = OpLabel
-         %61 = OpLoad %_arr_S_uint_4 %arr
-               OpReturnValue %61
-               OpFunctionEnd
-%load_u_inner_2_m = OpFunction %mat2v2float None %62
-         %64 = OpLabel
-         %69 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
-         %72 = OpAccessChain %_ptr_Uniform_v2float %69 %uint_1
-         %73 = OpLoad %v2float %72
-         %75 = OpAccessChain %_ptr_Uniform_v2float %69 %uint_2
-         %76 = OpLoad %v2float %75
-         %77 = OpCompositeConstruct %mat2v2float %73 %76
-               OpReturnValue %77
-               OpFunctionEnd
-          %f = OpFunction %void None %78
-         %81 = OpLabel
-         %83 = OpAccessChain %_ptr_StorageBuffer__arr_S_uint_4 %s %uint_0
-         %86 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
-         %87 = OpLoad %_arr_S_std140_uint_4 %86
-         %84 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %87
-               OpStore %83 %84
-         %90 = OpAccessChain %_ptr_StorageBuffer_S %s %uint_0 %int_1
-         %92 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
-         %93 = OpLoad %S_std140 %92
-         %91 = OpFunctionCall %S %conv_S %93
-               OpStore %90 %91
-         %96 = OpAccessChain %_ptr_StorageBuffer_mat2v2float %s %uint_0 %int_3 %uint_1
-         %97 = OpFunctionCall %mat2v2float %load_u_inner_2_m
-               OpStore %96 %97
-        %100 = OpAccessChain %_ptr_StorageBuffer_v2float %s %uint_0 %int_1 %uint_1 %98
-        %101 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %36 %uint_2
-        %102 = OpLoad %v2float %101
-        %103 = OpVectorShuffle %v2float %102 %102 1 0
-               OpStore %100 %103
-               OpReturn
-               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x2/to_storage.wgsl.expected.wgsl
deleted file mode 100644
index e9ed5d0..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/to_storage.wgsl.expected.wgsl
+++ /dev/null
@@ -1,17 +0,0 @@
-struct S {
-  before : i32,
-  m : mat2x2<f32>,
-  after : i32,
-}
-
-@group(0) @binding(0) var<uniform> u : array<S, 4>;
-
-@group(0) @binding(1) var<storage, read_write> s : array<S, 4>;
-
-@compute @workgroup_size(1)
-fn f() {
-  s = u;
-  s[1] = u[2];
-  s[3].m = u[2].m;
-  s[1].m[0] = u[0].m[1].yx;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x2/to_workgroup.wgsl
deleted file mode 100644
index 714b643..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/to_workgroup.wgsl
+++ /dev/null
@@ -1,16 +0,0 @@
-struct S {
-  before : i32,
-  m : mat2x2<f32>,
-  after : i32,
-}
-
-@group(0) @binding(0) var<uniform> u : array<S, 4>;
-var<workgroup> w : array<S, 4>;
-
-@compute @workgroup_size(1)
-fn f() {
-    w = u;
-    w[1] = u[2];
-    w[3].m = u[2].m;
-    w[1].m[0] = u[0].m[1].yx;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x2/to_workgroup.wgsl.expected.dxc.hlsl
deleted file mode 100644
index 1310e9e..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/to_workgroup.wgsl.expected.dxc.hlsl
+++ /dev/null
@@ -1,61 +0,0 @@
-struct S {
-  int before;
-  float2x2 m;
-  int after;
-};
-
-cbuffer cbuffer_u : register(b0, space0) {
-  uint4 u[8];
-};
-groupshared S w[4];
-
-struct tint_symbol_1 {
-  uint local_invocation_index : SV_GroupIndex;
-};
-
-float2x2 tint_symbol_5(uint4 buffer[8], uint offset) {
-  const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset / 4];
-  const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
-  return float2x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)));
-}
-
-S tint_symbol_3(uint4 buffer[8], uint offset) {
-  const uint scalar_offset_2 = ((offset + 0u)) / 4;
-  const uint scalar_offset_3 = ((offset + 24u)) / 4;
-  const S tint_symbol_8 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_5(buffer, (offset + 8u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
-  return tint_symbol_8;
-}
-
-typedef S tint_symbol_2_ret[4];
-tint_symbol_2_ret tint_symbol_2(uint4 buffer[8], uint offset) {
-  S arr[4] = (S[4])0;
-  {
-    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
-      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 32u)));
-    }
-  }
-  return arr;
-}
-
-void f_inner(uint local_invocation_index) {
-  {
-    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
-      const uint i = idx;
-      const S tint_symbol_7 = (S)0;
-      w[i] = tint_symbol_7;
-    }
-  }
-  GroupMemoryBarrierWithGroupSync();
-  w = tint_symbol_2(u, 0u);
-  w[1] = tint_symbol_3(u, 64u);
-  w[3].m = tint_symbol_5(u, 72u);
-  w[1].m[0] = asfloat(u[1].xy).yx;
-}
-
-[numthreads(1, 1, 1)]
-void f(tint_symbol_1 tint_symbol) {
-  f_inner(tint_symbol.local_invocation_index);
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x2/to_workgroup.wgsl.expected.fxc.hlsl
deleted file mode 100644
index 1310e9e..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/to_workgroup.wgsl.expected.fxc.hlsl
+++ /dev/null
@@ -1,61 +0,0 @@
-struct S {
-  int before;
-  float2x2 m;
-  int after;
-};
-
-cbuffer cbuffer_u : register(b0, space0) {
-  uint4 u[8];
-};
-groupshared S w[4];
-
-struct tint_symbol_1 {
-  uint local_invocation_index : SV_GroupIndex;
-};
-
-float2x2 tint_symbol_5(uint4 buffer[8], uint offset) {
-  const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset / 4];
-  const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
-  return float2x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)));
-}
-
-S tint_symbol_3(uint4 buffer[8], uint offset) {
-  const uint scalar_offset_2 = ((offset + 0u)) / 4;
-  const uint scalar_offset_3 = ((offset + 24u)) / 4;
-  const S tint_symbol_8 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_5(buffer, (offset + 8u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
-  return tint_symbol_8;
-}
-
-typedef S tint_symbol_2_ret[4];
-tint_symbol_2_ret tint_symbol_2(uint4 buffer[8], uint offset) {
-  S arr[4] = (S[4])0;
-  {
-    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
-      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 32u)));
-    }
-  }
-  return arr;
-}
-
-void f_inner(uint local_invocation_index) {
-  {
-    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
-      const uint i = idx;
-      const S tint_symbol_7 = (S)0;
-      w[i] = tint_symbol_7;
-    }
-  }
-  GroupMemoryBarrierWithGroupSync();
-  w = tint_symbol_2(u, 0u);
-  w[1] = tint_symbol_3(u, 64u);
-  w[3].m = tint_symbol_5(u, 72u);
-  w[1].m[0] = asfloat(u[1].xy).yx;
-}
-
-[numthreads(1, 1, 1)]
-void f(tint_symbol_1 tint_symbol) {
-  f_inner(tint_symbol.local_invocation_index);
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x2/to_workgroup.wgsl.expected.glsl
deleted file mode 100644
index cdc0450..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/to_workgroup.wgsl.expected.glsl
+++ /dev/null
@@ -1,62 +0,0 @@
-#version 310 es
-
-struct S {
-  int before;
-  uint pad;
-  mat2 m;
-  int after;
-  uint pad_1;
-};
-
-struct S_std140 {
-  int before;
-  uint pad;
-  vec2 m_0;
-  vec2 m_1;
-  int after;
-  uint pad_1;
-};
-
-layout(binding = 0, std140) uniform u_block_std140_ubo {
-  S_std140 inner[4];
-} u;
-
-shared S w[4];
-S conv_S(S_std140 val) {
-  return S(val.before, val.pad, mat2(val.m_0, val.m_1), val.after, val.pad_1);
-}
-
-S[4] conv_arr4_S(S_std140 val[4]) {
-  S arr[4] = S[4](S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0, 0u));
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      arr[i] = conv_S(val[i]);
-    }
-  }
-  return arr;
-}
-
-mat2 load_u_inner_2_m() {
-  return mat2(u.inner[2u].m_0, u.inner[2u].m_1);
-}
-
-void f(uint local_invocation_index) {
-  {
-    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
-      uint i = idx;
-      S tint_symbol = S(0, 0u, mat2(vec2(0.0f), vec2(0.0f)), 0, 0u);
-      w[i] = tint_symbol;
-    }
-  }
-  barrier();
-  w = conv_arr4_S(u.inner);
-  w[1] = conv_S(u.inner[2u]);
-  w[3].m = load_u_inner_2_m();
-  w[1].m[0] = u.inner[0u].m_1.yx;
-}
-
-layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
-void main() {
-  f(gl_LocalInvocationIndex);
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x2/to_workgroup.wgsl.expected.msl
deleted file mode 100644
index 85861c7..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/to_workgroup.wgsl.expected.msl
+++ /dev/null
@@ -1,47 +0,0 @@
-#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 S {
-  /* 0x0000 */ int before;
-  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
-  /* 0x0008 */ float2x2 m;
-  /* 0x0018 */ int after;
-  /* 0x001c */ tint_array<int8_t, 4> tint_pad_1;
-};
-
-struct tint_symbol_6 {
-  tint_array<S, 4> w;
-};
-
-void f_inner(uint local_invocation_index, threadgroup tint_array<S, 4>* const tint_symbol_1, const constant tint_array<S, 4>* const tint_symbol_2) {
-  for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
-    uint const i = idx;
-    S const tint_symbol = S{};
-    (*(tint_symbol_1))[i] = tint_symbol;
-  }
-  threadgroup_barrier(mem_flags::mem_threadgroup);
-  *(tint_symbol_1) = *(tint_symbol_2);
-  (*(tint_symbol_1))[1] = (*(tint_symbol_2))[2];
-  (*(tint_symbol_1))[3].m = (*(tint_symbol_2))[2].m;
-  (*(tint_symbol_1))[1].m[0] = float2((*(tint_symbol_2))[0].m[1]).yx;
-}
-
-kernel void f(const constant tint_array<S, 4>* tint_symbol_5 [[buffer(0)]], threadgroup tint_symbol_6* tint_symbol_4 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
-  threadgroup tint_array<S, 4>* const tint_symbol_3 = &((*(tint_symbol_4)).w);
-  f_inner(local_invocation_index, tint_symbol_3, tint_symbol_5);
-  return;
-}
-
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x2/to_workgroup.wgsl.expected.spvasm
deleted file mode 100644
index a6922dc..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/to_workgroup.wgsl.expected.spvasm
+++ /dev/null
@@ -1,210 +0,0 @@
-; SPIR-V
-; Version: 1.3
-; Generator: Google Tint Compiler; 0
-; Bound: 126
-; Schema: 0
-               OpCapability Shader
-               OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
-               OpExecutionMode %f LocalSize 1 1 1
-               OpName %local_invocation_index_1 "local_invocation_index_1"
-               OpName %u_block_std140 "u_block_std140"
-               OpMemberName %u_block_std140 0 "inner"
-               OpName %S_std140 "S_std140"
-               OpMemberName %S_std140 0 "before"
-               OpMemberName %S_std140 1 "m_0"
-               OpMemberName %S_std140 2 "m_1"
-               OpMemberName %S_std140 3 "after"
-               OpName %u "u"
-               OpName %S "S"
-               OpMemberName %S 0 "before"
-               OpMemberName %S 1 "m"
-               OpMemberName %S 2 "after"
-               OpName %w "w"
-               OpName %conv_S "conv_S"
-               OpName %val "val"
-               OpName %conv_arr4_S "conv_arr4_S"
-               OpName %val_0 "val"
-               OpName %arr "arr"
-               OpName %i "i"
-               OpName %var_for_index "var_for_index"
-               OpName %load_u_inner_2_m "load_u_inner_2_m"
-               OpName %f_inner "f_inner"
-               OpName %local_invocation_index "local_invocation_index"
-               OpName %idx "idx"
-               OpName %f "f"
-               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
-               OpDecorate %u_block_std140 Block
-               OpMemberDecorate %u_block_std140 0 Offset 0
-               OpMemberDecorate %S_std140 0 Offset 0
-               OpMemberDecorate %S_std140 1 Offset 8
-               OpMemberDecorate %S_std140 2 Offset 16
-               OpMemberDecorate %S_std140 3 Offset 24
-               OpDecorate %_arr_S_std140_uint_4 ArrayStride 32
-               OpDecorate %u NonWritable
-               OpDecorate %u DescriptorSet 0
-               OpDecorate %u Binding 0
-               OpMemberDecorate %S 0 Offset 0
-               OpMemberDecorate %S 1 Offset 8
-               OpMemberDecorate %S 1 ColMajor
-               OpMemberDecorate %S 1 MatrixStride 8
-               OpMemberDecorate %S 2 Offset 24
-               OpDecorate %_arr_S_uint_4 ArrayStride 32
-       %uint = OpTypeInt 32 0
-%_ptr_Input_uint = OpTypePointer Input %uint
-%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
-        %int = OpTypeInt 32 1
-      %float = OpTypeFloat 32
-    %v2float = OpTypeVector %float 2
-   %S_std140 = OpTypeStruct %int %v2float %v2float %int
-     %uint_4 = OpConstant %uint 4
-%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
-%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
-%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
-          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
-%mat2v2float = OpTypeMatrix %v2float 2
-          %S = OpTypeStruct %int %mat2v2float %int
-%_arr_S_uint_4 = OpTypeArray %S %uint_4
-%_ptr_Workgroup__arr_S_uint_4 = OpTypePointer Workgroup %_arr_S_uint_4
-          %w = OpVariable %_ptr_Workgroup__arr_S_uint_4 Workgroup
-         %18 = OpTypeFunction %S %S_std140
-         %28 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
-%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
-         %34 = OpConstantNull %_arr_S_uint_4
-%_ptr_Function_uint = OpTypePointer Function %uint
-         %37 = OpConstantNull %uint
-       %bool = OpTypeBool
-%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
-         %50 = OpConstantNull %_arr_S_std140_uint_4
-%_ptr_Function_S = OpTypePointer Function %S
-%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
-     %uint_1 = OpConstant %uint 1
-         %63 = OpTypeFunction %mat2v2float
-     %uint_0 = OpConstant %uint 0
-     %uint_2 = OpConstant %uint 2
-%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
-%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
-       %void = OpTypeVoid
-         %79 = OpTypeFunction %void %uint
-%_ptr_Workgroup_S = OpTypePointer Workgroup %S
-         %97 = OpConstantNull %S
-   %uint_264 = OpConstant %uint 264
-%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
-      %int_1 = OpConstant %int 1
-      %int_3 = OpConstant %int 3
-%_ptr_Workgroup_mat2v2float = OpTypePointer Workgroup %mat2v2float
-        %115 = OpConstantNull %int
-%_ptr_Workgroup_v2float = OpTypePointer Workgroup %v2float
-        %121 = OpTypeFunction %void
-     %conv_S = OpFunction %S None %18
-        %val = OpFunctionParameter %S_std140
-         %21 = OpLabel
-         %22 = OpCompositeExtract %int %val 0
-         %23 = OpCompositeExtract %v2float %val 1
-         %24 = OpCompositeExtract %v2float %val 2
-         %25 = OpCompositeConstruct %mat2v2float %23 %24
-         %26 = OpCompositeExtract %int %val 3
-         %27 = OpCompositeConstruct %S %22 %25 %26
-               OpReturnValue %27
-               OpFunctionEnd
-%conv_arr4_S = OpFunction %_arr_S_uint_4 None %28
-      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
-         %31 = OpLabel
-        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %34
-          %i = OpVariable %_ptr_Function_uint Function %37
-%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %50
-               OpBranch %38
-         %38 = OpLabel
-               OpLoopMerge %39 %40 None
-               OpBranch %41
-         %41 = OpLabel
-         %43 = OpLoad %uint %i
-         %44 = OpULessThan %bool %43 %uint_4
-         %42 = OpLogicalNot %bool %44
-               OpSelectionMerge %46 None
-               OpBranchConditional %42 %47 %46
-         %47 = OpLabel
-               OpBranch %39
-         %46 = OpLabel
-               OpStore %var_for_index %val_0
-         %51 = OpLoad %uint %i
-         %53 = OpAccessChain %_ptr_Function_S %arr %51
-         %55 = OpLoad %uint %i
-         %57 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %55
-         %58 = OpLoad %S_std140 %57
-         %54 = OpFunctionCall %S %conv_S %58
-               OpStore %53 %54
-               OpBranch %40
-         %40 = OpLabel
-         %59 = OpLoad %uint %i
-         %61 = OpIAdd %uint %59 %uint_1
-               OpStore %i %61
-               OpBranch %38
-         %39 = OpLabel
-         %62 = OpLoad %_arr_S_uint_4 %arr
-               OpReturnValue %62
-               OpFunctionEnd
-%load_u_inner_2_m = OpFunction %mat2v2float None %63
-         %65 = OpLabel
-         %70 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
-         %73 = OpAccessChain %_ptr_Uniform_v2float %70 %uint_1
-         %74 = OpLoad %v2float %73
-         %76 = OpAccessChain %_ptr_Uniform_v2float %70 %uint_2
-         %77 = OpLoad %v2float %76
-         %78 = OpCompositeConstruct %mat2v2float %74 %77
-               OpReturnValue %78
-               OpFunctionEnd
-    %f_inner = OpFunction %void None %79
-%local_invocation_index = OpFunctionParameter %uint
-         %83 = OpLabel
-        %idx = OpVariable %_ptr_Function_uint Function %37
-               OpStore %idx %local_invocation_index
-               OpBranch %85
-         %85 = OpLabel
-               OpLoopMerge %86 %87 None
-               OpBranch %88
-         %88 = OpLabel
-         %90 = OpLoad %uint %idx
-         %91 = OpULessThan %bool %90 %uint_4
-         %89 = OpLogicalNot %bool %91
-               OpSelectionMerge %92 None
-               OpBranchConditional %89 %93 %92
-         %93 = OpLabel
-               OpBranch %86
-         %92 = OpLabel
-         %94 = OpLoad %uint %idx
-         %96 = OpAccessChain %_ptr_Workgroup_S %w %94
-               OpStore %96 %97
-               OpBranch %87
-         %87 = OpLabel
-         %98 = OpLoad %uint %idx
-         %99 = OpIAdd %uint %98 %uint_1
-               OpStore %idx %99
-               OpBranch %85
-         %86 = OpLabel
-               OpControlBarrier %uint_2 %uint_2 %uint_264
-        %104 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
-        %105 = OpLoad %_arr_S_std140_uint_4 %104
-        %102 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %105
-               OpStore %w %102
-        %107 = OpAccessChain %_ptr_Workgroup_S %w %int_1
-        %109 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
-        %110 = OpLoad %S_std140 %109
-        %108 = OpFunctionCall %S %conv_S %110
-               OpStore %107 %108
-        %113 = OpAccessChain %_ptr_Workgroup_mat2v2float %w %int_3 %uint_1
-        %114 = OpFunctionCall %mat2v2float %load_u_inner_2_m
-               OpStore %113 %114
-        %117 = OpAccessChain %_ptr_Workgroup_v2float %w %int_1 %uint_1 %115
-        %118 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %37 %uint_2
-        %119 = OpLoad %v2float %118
-        %120 = OpVectorShuffle %v2float %119 %119 1 0
-               OpStore %117 %120
-               OpReturn
-               OpFunctionEnd
-          %f = OpFunction %void None %121
-        %123 = OpLabel
-        %125 = OpLoad %uint %local_invocation_index_1
-        %124 = OpFunctionCall %void %f_inner %125
-               OpReturn
-               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x2/to_workgroup.wgsl.expected.wgsl
deleted file mode 100644
index 14ff361..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat2x2/to_workgroup.wgsl.expected.wgsl
+++ /dev/null
@@ -1,17 +0,0 @@
-struct S {
-  before : i32,
-  m : mat2x2<f32>,
-  after : i32,
-}
-
-@group(0) @binding(0) var<uniform> u : array<S, 4>;
-
-var<workgroup> w : array<S, 4>;
-
-@compute @workgroup_size(1)
-fn f() {
-  w = u;
-  w[1] = u[2];
-  w[3].m = u[2].m;
-  w[1].m[0] = u[0].m[1].yx;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/dynamic_index_via_ptr.wgsl
new file mode 100644
index 0000000..5a08d75
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/dynamic_index_via_ptr.wgsl
@@ -0,0 +1,34 @@
+enable f16;
+
+struct Inner {
+  @size(64)
+  m : mat2x2<f16>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a           = &a;
+  let p_a_i         = &((*p_a)[i()]);
+  let p_a_i_a       = &((*p_a_i).a);
+  let p_a_i_a_i     = &((*p_a_i_a)[i()]);
+  let p_a_i_a_i_m   = &((*p_a_i_a_i).m);
+  let p_a_i_a_i_m_i = &((*p_a_i_a_i_m)[i()]);
+
+
+  let l_a             : array<Outer, 4> =  *p_a;
+  let l_a_i           : Outer           =  *p_a_i;
+  let l_a_i_a         : array<Inner, 4> =  *p_a_i_a;
+  let l_a_i_a_i       : Inner           =  *p_a_i_a_i;
+  let l_a_i_a_i_m     : mat2x2<f16>     =  *p_a_i_a_i_m;
+  let l_a_i_a_i_m_i   : vec2<f16>       =  *p_a_i_a_i_m_i;
+  let l_a_i_a_i_m_i_i : f16             = (*p_a_i_a_i_m_i)[i()];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..6fdfa27
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,79 @@
+struct Inner {
+  matrix<float16_t, 2, 2> m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 2, 2> tint_symbol_8(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  return matrix<float16_t, 2, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))));
+}
+
+Inner tint_symbol_7(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_11 = {tint_symbol_8(buffer, (offset + 0u))};
+  return tint_symbol_11;
+}
+
+typedef Inner tint_symbol_6_ret[4];
+tint_symbol_6_ret tint_symbol_6(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_7(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_5(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_12 = {tint_symbol_6(buffer, (offset + 0u))};
+  return tint_symbol_12;
+}
+
+typedef Outer tint_symbol_4_ret[4];
+tint_symbol_4_ret tint_symbol_4(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
+      arr_1[i_2] = tint_symbol_5(buffer, (offset + (i_2 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_a_i_save = i();
+  const int p_a_i_a_i_m_i_save = i();
+  const Outer l_a[4] = tint_symbol_4(a, 0u);
+  const Outer l_a_i = tint_symbol_5(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a[4] = tint_symbol_6(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a_i = tint_symbol_7(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const matrix<float16_t, 2, 2> l_a_i_a_i_m = tint_symbol_8(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const uint scalar_offset_2 = ((((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))) + (4u * uint(p_a_i_a_i_m_i_save)))) / 4;
+  uint ubo_load_2 = a[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const vector<float16_t, 2> l_a_i_a_i_m_i = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16)));
+  const int tint_symbol = p_a_i_save;
+  const int tint_symbol_1 = p_a_i_a_i_save;
+  const int tint_symbol_2 = p_a_i_a_i_m_i_save;
+  const int tint_symbol_3 = i();
+  const uint scalar_offset_bytes = (((((256u * uint(tint_symbol)) + (64u * uint(tint_symbol_1))) + (4u * uint(tint_symbol_2))) + (2u * uint(tint_symbol_3))));
+  const uint scalar_offset_index = scalar_offset_bytes / 4;
+  const float16_t l_a_i_a_i_m_i_i = float16_t(f16tof32(((a[scalar_offset_index / 4][scalar_offset_index % 4] >> (scalar_offset_bytes % 4 == 0 ? 0 : 16)) & 0xFFFF)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..7ca22da
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,84 @@
+SKIP: FAILED
+
+struct Inner {
+  matrix<float16_t, 2, 2> m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 2, 2> tint_symbol_8(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  return matrix<float16_t, 2, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))));
+}
+
+Inner tint_symbol_7(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_11 = {tint_symbol_8(buffer, (offset + 0u))};
+  return tint_symbol_11;
+}
+
+typedef Inner tint_symbol_6_ret[4];
+tint_symbol_6_ret tint_symbol_6(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_7(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_5(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_12 = {tint_symbol_6(buffer, (offset + 0u))};
+  return tint_symbol_12;
+}
+
+typedef Outer tint_symbol_4_ret[4];
+tint_symbol_4_ret tint_symbol_4(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
+      arr_1[i_2] = tint_symbol_5(buffer, (offset + (i_2 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_a_i_save = i();
+  const int p_a_i_a_i_m_i_save = i();
+  const Outer l_a[4] = tint_symbol_4(a, 0u);
+  const Outer l_a_i = tint_symbol_5(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a[4] = tint_symbol_6(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a_i = tint_symbol_7(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const matrix<float16_t, 2, 2> l_a_i_a_i_m = tint_symbol_8(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const uint scalar_offset_2 = ((((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))) + (4u * uint(p_a_i_a_i_m_i_save)))) / 4;
+  uint ubo_load_2 = a[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const vector<float16_t, 2> l_a_i_a_i_m_i = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16)));
+  const int tint_symbol = p_a_i_save;
+  const int tint_symbol_1 = p_a_i_a_i_save;
+  const int tint_symbol_2 = p_a_i_a_i_m_i_save;
+  const int tint_symbol_3 = i();
+  const uint scalar_offset_bytes = (((((256u * uint(tint_symbol)) + (64u * uint(tint_symbol_1))) + (4u * uint(tint_symbol_2))) + (2u * uint(tint_symbol_3))));
+  const uint scalar_offset_index = scalar_offset_bytes / 4;
+  const float16_t l_a_i_a_i_m_i_i = float16_t(f16tof32(((a[scalar_offset_index / 4][scalar_offset_index % 4] >> (scalar_offset_bytes % 4 == 0 ? 0 : 16)) & 0xFFFF)));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x00000270DFBEAD70(2,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/dynamic_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..b75bad2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,151 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct Inner {
+  f16mat2 m;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+};
+
+struct Inner_std140 {
+  f16vec2 m_0;
+  f16vec2 m_1;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+};
+
+struct Outer {
+  Inner a[4];
+};
+
+struct Outer_std140 {
+  Inner_std140 a[4];
+};
+
+layout(binding = 0, std140) uniform a_block_std140_ubo {
+  Outer_std140 inner[4];
+} a;
+
+int counter = 0;
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+Inner conv_Inner(Inner_std140 val) {
+  return Inner(f16mat2(val.m_0, val.m_1), val.pad, val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.pad_11, val.pad_12, val.pad_13);
+}
+
+Inner[4] conv_arr4_Inner(Inner_std140 val[4]) {
+  Inner arr[4] = Inner[4](Inner(f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_Inner(val[i]);
+    }
+  }
+  return arr;
+}
+
+Outer conv_Outer(Outer_std140 val) {
+  return Outer(conv_arr4_Inner(val.a));
+}
+
+Outer[4] conv_arr4_Outer(Outer_std140 val[4]) {
+  Outer arr[4] = Outer[4](Outer(Inner[4](Inner(f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_Outer(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat2 load_a_inner_p0_a_p1_m(uint p0, uint p1) {
+  uint s_save = p0;
+  uint s_save_1 = p1;
+  return f16mat2(a.inner[s_save].a[s_save_1].m_0, a.inner[s_save].a[s_save_1].m_1);
+}
+
+f16vec2 load_a_inner_p0_a_p1_m_p2(uint p0, uint p1, uint p2) {
+  switch(p2) {
+    case 0u: {
+      return a.inner[p0].a[p1].m_0;
+      break;
+    }
+    case 1u: {
+      return a.inner[p0].a[p1].m_1;
+      break;
+    }
+    default: {
+      return f16vec2(0.0hf);
+      break;
+    }
+  }
+}
+
+float16_t load_a_inner_p0_a_p1_m_p2_p3(uint p0, uint p1, uint p2, uint p3) {
+  switch(p2) {
+    case 0u: {
+      return a.inner[p0].a[p1].m_0[p3];
+      break;
+    }
+    case 1u: {
+      return a.inner[p0].a[p1].m_1[p3];
+      break;
+    }
+    default: {
+      return 0.0hf;
+      break;
+    }
+  }
+}
+
+void f() {
+  Outer p_a[4] = conv_arr4_Outer(a.inner);
+  int tint_symbol = i();
+  Outer p_a_i = conv_Outer(a.inner[tint_symbol]);
+  Inner p_a_i_a[4] = conv_arr4_Inner(a.inner[tint_symbol].a);
+  int tint_symbol_1 = i();
+  Inner p_a_i_a_i = conv_Inner(a.inner[tint_symbol].a[tint_symbol_1]);
+  f16mat2 p_a_i_a_i_m = load_a_inner_p0_a_p1_m(uint(tint_symbol), uint(tint_symbol_1));
+  int tint_symbol_2 = i();
+  f16vec2 p_a_i_a_i_m_i = load_a_inner_p0_a_p1_m_p2(uint(tint_symbol), uint(tint_symbol_1), uint(tint_symbol_2));
+  Outer l_a[4] = conv_arr4_Outer(a.inner);
+  Outer l_a_i = conv_Outer(a.inner[tint_symbol]);
+  Inner l_a_i_a[4] = conv_arr4_Inner(a.inner[tint_symbol].a);
+  Inner l_a_i_a_i = conv_Inner(a.inner[tint_symbol].a[tint_symbol_1]);
+  f16mat2 l_a_i_a_i_m = load_a_inner_p0_a_p1_m(uint(tint_symbol), uint(tint_symbol_1));
+  f16vec2 l_a_i_a_i_m_i = load_a_inner_p0_a_p1_m_p2(uint(tint_symbol), uint(tint_symbol_1), uint(tint_symbol_2));
+  int tint_symbol_3 = i();
+  float16_t l_a_i_a_i_m_i_i = load_a_inner_p0_a_p1_m_p2_p3(uint(tint_symbol), uint(tint_symbol_1), uint(tint_symbol_2), uint(tint_symbol_3));
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/dynamic_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..3c067f3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/dynamic_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,49 @@
+#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 Inner {
+  /* 0x0000 */ half2x2 m;
+  /* 0x0008 */ tint_array<int8_t, 56> tint_pad;
+};
+
+struct Outer {
+  /* 0x0000 */ tint_array<Inner, 4> a;
+};
+
+int i() {
+  thread int tint_symbol_4 = 0;
+  tint_symbol_4 = as_type<int>((as_type<uint>(tint_symbol_4) + as_type<uint>(1)));
+  return tint_symbol_4;
+}
+
+kernel void f(const constant tint_array<Outer, 4>* tint_symbol_5 [[buffer(0)]]) {
+  int const tint_symbol = i();
+  int const p_a_i_save = tint_symbol;
+  int const tint_symbol_1 = i();
+  int const p_a_i_a_i_save = tint_symbol_1;
+  int const tint_symbol_2 = i();
+  int const p_a_i_a_i_m_i_save = tint_symbol_2;
+  tint_array<Outer, 4> const l_a = *(tint_symbol_5);
+  Outer const l_a_i = (*(tint_symbol_5))[p_a_i_save];
+  tint_array<Inner, 4> const l_a_i_a = (*(tint_symbol_5))[p_a_i_save].a;
+  Inner const l_a_i_a_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save];
+  half2x2 const l_a_i_a_i_m = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m;
+  half2 const l_a_i_a_i_m_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save];
+  int const tint_symbol_3 = i();
+  half const l_a_i_a_i_m_i_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save][tint_symbol_3];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..93f999c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,310 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 193
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block_std140 "a_block_std140"
+               OpMemberName %a_block_std140 0 "inner"
+               OpName %Outer_std140 "Outer_std140"
+               OpMemberName %Outer_std140 0 "a"
+               OpName %Inner_std140 "Inner_std140"
+               OpMemberName %Inner_std140 0 "m_0"
+               OpMemberName %Inner_std140 1 "m_1"
+               OpName %a "a"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %Inner "Inner"
+               OpMemberName %Inner 0 "m"
+               OpName %conv_Inner "conv_Inner"
+               OpName %val "val"
+               OpName %conv_arr4_Inner "conv_arr4_Inner"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i_0 "i"
+               OpName %var_for_index_1 "var_for_index_1"
+               OpName %Outer "Outer"
+               OpMemberName %Outer 0 "a"
+               OpName %conv_Outer "conv_Outer"
+               OpName %val_1 "val"
+               OpName %conv_arr4_Outer "conv_arr4_Outer"
+               OpName %val_2 "val"
+               OpName %arr_0 "arr"
+               OpName %i_1 "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_a_inner_p0_a_p1_m "load_a_inner_p0_a_p1_m"
+               OpName %p0 "p0"
+               OpName %p1 "p1"
+               OpName %load_a_inner_p0_a_p1_m_p2 "load_a_inner_p0_a_p1_m_p2"
+               OpName %p0_0 "p0"
+               OpName %p1_0 "p1"
+               OpName %p2 "p2"
+               OpName %load_a_inner_p0_a_p1_m_p2_p3 "load_a_inner_p0_a_p1_m_p2_p3"
+               OpName %p0_1 "p0"
+               OpName %p1_1 "p1"
+               OpName %p2_0 "p2"
+               OpName %p3 "p3"
+               OpName %f "f"
+               OpDecorate %a_block_std140 Block
+               OpMemberDecorate %a_block_std140 0 Offset 0
+               OpMemberDecorate %Outer_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 1 Offset 4
+               OpDecorate %_arr_Inner_std140_uint_4 ArrayStride 64
+               OpDecorate %_arr_Outer_std140_uint_4 ArrayStride 256
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+               OpMemberDecorate %Inner 0 Offset 0
+               OpMemberDecorate %Inner 0 ColMajor
+               OpMemberDecorate %Inner 0 MatrixStride 4
+               OpDecorate %_arr_Inner_uint_4 ArrayStride 64
+               OpMemberDecorate %Outer 0 Offset 0
+               OpDecorate %_arr_Outer_uint_4 ArrayStride 256
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+%Inner_std140 = OpTypeStruct %v2half %v2half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_Inner_std140_uint_4 = OpTypeArray %Inner_std140 %uint_4
+%Outer_std140 = OpTypeStruct %_arr_Inner_std140_uint_4
+%_arr_Outer_std140_uint_4 = OpTypeArray %Outer_std140 %uint_4
+%a_block_std140 = OpTypeStruct %_arr_Outer_std140_uint_4
+%_ptr_Uniform_a_block_std140 = OpTypePointer Uniform %a_block_std140
+          %a = OpVariable %_ptr_Uniform_a_block_std140 Uniform
+        %int = OpTypeInt 32 1
+         %13 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %13
+         %16 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+ %mat2v2half = OpTypeMatrix %v2half 2
+      %Inner = OpTypeStruct %mat2v2half
+         %23 = OpTypeFunction %Inner %Inner_std140
+%_arr_Inner_uint_4 = OpTypeArray %Inner %uint_4
+         %33 = OpTypeFunction %_arr_Inner_uint_4 %_arr_Inner_std140_uint_4
+%_ptr_Function__arr_Inner_uint_4 = OpTypePointer Function %_arr_Inner_uint_4
+         %40 = OpConstantNull %_arr_Inner_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %43 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_Inner_std140_uint_4 = OpTypePointer Function %_arr_Inner_std140_uint_4
+         %56 = OpConstantNull %_arr_Inner_std140_uint_4
+%_ptr_Function_Inner = OpTypePointer Function %Inner
+%_ptr_Function_Inner_std140 = OpTypePointer Function %Inner_std140
+     %uint_1 = OpConstant %uint 1
+      %Outer = OpTypeStruct %_arr_Inner_uint_4
+         %69 = OpTypeFunction %Outer %Outer_std140
+%_arr_Outer_uint_4 = OpTypeArray %Outer %uint_4
+         %77 = OpTypeFunction %_arr_Outer_uint_4 %_arr_Outer_std140_uint_4
+%_ptr_Function__arr_Outer_uint_4 = OpTypePointer Function %_arr_Outer_uint_4
+         %84 = OpConstantNull %_arr_Outer_uint_4
+%_ptr_Function__arr_Outer_std140_uint_4 = OpTypePointer Function %_arr_Outer_std140_uint_4
+         %97 = OpConstantNull %_arr_Outer_std140_uint_4
+%_ptr_Function_Outer = OpTypePointer Function %Outer
+%_ptr_Function_Outer_std140 = OpTypePointer Function %Outer_std140
+        %109 = OpTypeFunction %mat2v2half %uint %uint
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_Inner_std140 = OpTypePointer Uniform %Inner_std140
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+        %126 = OpTypeFunction %v2half %uint %uint %uint
+        %140 = OpConstantNull %v2half
+        %141 = OpTypeFunction %half %uint %uint %uint %uint
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+        %157 = OpConstantNull %half
+       %void = OpTypeVoid
+        %158 = OpTypeFunction %void
+%_ptr_Uniform__arr_Outer_std140_uint_4 = OpTypePointer Uniform %_arr_Outer_std140_uint_4
+%_ptr_Uniform_Outer_std140 = OpTypePointer Uniform %Outer_std140
+%_ptr_Uniform__arr_Inner_std140_uint_4 = OpTypePointer Uniform %_arr_Inner_std140_uint_4
+          %i = OpFunction %int None %16
+         %18 = OpLabel
+         %19 = OpLoad %int %counter
+         %21 = OpIAdd %int %19 %int_1
+               OpStore %counter %21
+         %22 = OpLoad %int %counter
+               OpReturnValue %22
+               OpFunctionEnd
+ %conv_Inner = OpFunction %Inner None %23
+        %val = OpFunctionParameter %Inner_std140
+         %28 = OpLabel
+         %29 = OpCompositeExtract %v2half %val 0
+         %30 = OpCompositeExtract %v2half %val 1
+         %31 = OpCompositeConstruct %mat2v2half %29 %30
+         %32 = OpCompositeConstruct %Inner %31
+               OpReturnValue %32
+               OpFunctionEnd
+%conv_arr4_Inner = OpFunction %_arr_Inner_uint_4 None %33
+      %val_0 = OpFunctionParameter %_arr_Inner_std140_uint_4
+         %37 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_Inner_uint_4 Function %40
+        %i_0 = OpVariable %_ptr_Function_uint Function %43
+%var_for_index_1 = OpVariable %_ptr_Function__arr_Inner_std140_uint_4 Function %56
+               OpBranch %44
+         %44 = OpLabel
+               OpLoopMerge %45 %46 None
+               OpBranch %47
+         %47 = OpLabel
+         %49 = OpLoad %uint %i_0
+         %50 = OpULessThan %bool %49 %uint_4
+         %48 = OpLogicalNot %bool %50
+               OpSelectionMerge %52 None
+               OpBranchConditional %48 %53 %52
+         %53 = OpLabel
+               OpBranch %45
+         %52 = OpLabel
+               OpStore %var_for_index_1 %val_0
+         %57 = OpLoad %uint %i_0
+         %59 = OpAccessChain %_ptr_Function_Inner %arr %57
+         %61 = OpLoad %uint %i_0
+         %63 = OpAccessChain %_ptr_Function_Inner_std140 %var_for_index_1 %61
+         %64 = OpLoad %Inner_std140 %63
+         %60 = OpFunctionCall %Inner %conv_Inner %64
+               OpStore %59 %60
+               OpBranch %46
+         %46 = OpLabel
+         %65 = OpLoad %uint %i_0
+         %67 = OpIAdd %uint %65 %uint_1
+               OpStore %i_0 %67
+               OpBranch %44
+         %45 = OpLabel
+         %68 = OpLoad %_arr_Inner_uint_4 %arr
+               OpReturnValue %68
+               OpFunctionEnd
+ %conv_Outer = OpFunction %Outer None %69
+      %val_1 = OpFunctionParameter %Outer_std140
+         %73 = OpLabel
+         %75 = OpCompositeExtract %_arr_Inner_std140_uint_4 %val_1 0
+         %74 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %75
+         %76 = OpCompositeConstruct %Outer %74
+               OpReturnValue %76
+               OpFunctionEnd
+%conv_arr4_Outer = OpFunction %_arr_Outer_uint_4 None %77
+      %val_2 = OpFunctionParameter %_arr_Outer_std140_uint_4
+         %81 = OpLabel
+      %arr_0 = OpVariable %_ptr_Function__arr_Outer_uint_4 Function %84
+        %i_1 = OpVariable %_ptr_Function_uint Function %43
+%var_for_index = OpVariable %_ptr_Function__arr_Outer_std140_uint_4 Function %97
+               OpBranch %86
+         %86 = OpLabel
+               OpLoopMerge %87 %88 None
+               OpBranch %89
+         %89 = OpLabel
+         %91 = OpLoad %uint %i_1
+         %92 = OpULessThan %bool %91 %uint_4
+         %90 = OpLogicalNot %bool %92
+               OpSelectionMerge %93 None
+               OpBranchConditional %90 %94 %93
+         %94 = OpLabel
+               OpBranch %87
+         %93 = OpLabel
+               OpStore %var_for_index %val_2
+         %98 = OpLoad %uint %i_1
+        %100 = OpAccessChain %_ptr_Function_Outer %arr_0 %98
+        %102 = OpLoad %uint %i_1
+        %104 = OpAccessChain %_ptr_Function_Outer_std140 %var_for_index %102
+        %105 = OpLoad %Outer_std140 %104
+        %101 = OpFunctionCall %Outer %conv_Outer %105
+               OpStore %100 %101
+               OpBranch %88
+         %88 = OpLabel
+        %106 = OpLoad %uint %i_1
+        %107 = OpIAdd %uint %106 %uint_1
+               OpStore %i_1 %107
+               OpBranch %86
+         %87 = OpLabel
+        %108 = OpLoad %_arr_Outer_uint_4 %arr_0
+               OpReturnValue %108
+               OpFunctionEnd
+%load_a_inner_p0_a_p1_m = OpFunction %mat2v2half None %109
+         %p0 = OpFunctionParameter %uint
+         %p1 = OpFunctionParameter %uint
+        %113 = OpLabel
+        %117 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %p0 %uint_0 %p1
+        %120 = OpAccessChain %_ptr_Uniform_v2half %117 %uint_0
+        %121 = OpLoad %v2half %120
+        %123 = OpAccessChain %_ptr_Uniform_v2half %117 %uint_1
+        %124 = OpLoad %v2half %123
+        %125 = OpCompositeConstruct %mat2v2half %121 %124
+               OpReturnValue %125
+               OpFunctionEnd
+%load_a_inner_p0_a_p1_m_p2 = OpFunction %v2half None %126
+       %p0_0 = OpFunctionParameter %uint
+       %p1_0 = OpFunctionParameter %uint
+         %p2 = OpFunctionParameter %uint
+        %131 = OpLabel
+               OpSelectionMerge %132 None
+               OpSwitch %p2 %133 0 %134 1 %135
+        %134 = OpLabel
+        %136 = OpAccessChain %_ptr_Uniform_v2half %a %uint_0 %p0_0 %uint_0 %p1_0 %uint_0
+        %137 = OpLoad %v2half %136
+               OpReturnValue %137
+        %135 = OpLabel
+        %138 = OpAccessChain %_ptr_Uniform_v2half %a %uint_0 %p0_0 %uint_0 %p1_0 %uint_1
+        %139 = OpLoad %v2half %138
+               OpReturnValue %139
+        %133 = OpLabel
+               OpReturnValue %140
+        %132 = OpLabel
+               OpReturnValue %140
+               OpFunctionEnd
+%load_a_inner_p0_a_p1_m_p2_p3 = OpFunction %half None %141
+       %p0_1 = OpFunctionParameter %uint
+       %p1_1 = OpFunctionParameter %uint
+       %p2_0 = OpFunctionParameter %uint
+         %p3 = OpFunctionParameter %uint
+        %147 = OpLabel
+               OpSelectionMerge %148 None
+               OpSwitch %p2_0 %149 0 %150 1 %151
+        %150 = OpLabel
+        %153 = OpAccessChain %_ptr_Uniform_half %a %uint_0 %p0_1 %uint_0 %p1_1 %uint_0 %p3
+        %154 = OpLoad %half %153
+               OpReturnValue %154
+        %151 = OpLabel
+        %155 = OpAccessChain %_ptr_Uniform_half %a %uint_0 %p0_1 %uint_0 %p1_1 %uint_1 %p3
+        %156 = OpLoad %half %155
+               OpReturnValue %156
+        %149 = OpLabel
+               OpReturnValue %157
+        %148 = OpLabel
+               OpReturnValue %157
+               OpFunctionEnd
+          %f = OpFunction %void None %158
+        %161 = OpLabel
+        %162 = OpFunctionCall %int %i
+        %163 = OpFunctionCall %int %i
+        %164 = OpFunctionCall %int %i
+        %167 = OpAccessChain %_ptr_Uniform__arr_Outer_std140_uint_4 %a %uint_0
+        %168 = OpLoad %_arr_Outer_std140_uint_4 %167
+        %165 = OpFunctionCall %_arr_Outer_uint_4 %conv_arr4_Outer %168
+        %171 = OpAccessChain %_ptr_Uniform_Outer_std140 %a %uint_0 %162
+        %172 = OpLoad %Outer_std140 %171
+        %169 = OpFunctionCall %Outer %conv_Outer %172
+        %175 = OpAccessChain %_ptr_Uniform__arr_Inner_std140_uint_4 %a %uint_0 %162 %uint_0
+        %176 = OpLoad %_arr_Inner_std140_uint_4 %175
+        %173 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %176
+        %178 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %162 %uint_0 %163
+        %179 = OpLoad %Inner_std140 %178
+        %177 = OpFunctionCall %Inner %conv_Inner %179
+        %181 = OpBitcast %uint %162
+        %182 = OpBitcast %uint %163
+        %180 = OpFunctionCall %mat2v2half %load_a_inner_p0_a_p1_m %181 %182
+        %184 = OpBitcast %uint %162
+        %185 = OpBitcast %uint %163
+        %186 = OpBitcast %uint %164
+        %183 = OpFunctionCall %v2half %load_a_inner_p0_a_p1_m_p2 %184 %185 %186
+        %187 = OpFunctionCall %int %i
+        %189 = OpBitcast %uint %162
+        %190 = OpBitcast %uint %163
+        %191 = OpBitcast %uint %164
+        %192 = OpBitcast %uint %187
+        %188 = OpFunctionCall %half %load_a_inner_p0_a_p1_m_p2_p3 %189 %190 %191 %192
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..59f69e1
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,36 @@
+enable f16;
+
+struct Inner {
+  @size(64)
+  m : mat2x2<f16>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_i = &((*(p_a))[i()]);
+  let p_a_i_a = &((*(p_a_i)).a);
+  let p_a_i_a_i = &((*(p_a_i_a))[i()]);
+  let p_a_i_a_i_m = &((*(p_a_i_a_i)).m);
+  let p_a_i_a_i_m_i = &((*(p_a_i_a_i_m))[i()]);
+  let l_a : array<Outer, 4> = *(p_a);
+  let l_a_i : Outer = *(p_a_i);
+  let l_a_i_a : array<Inner, 4> = *(p_a_i_a);
+  let l_a_i_a_i : Inner = *(p_a_i_a_i);
+  let l_a_i_a_i_m : mat2x2<f16> = *(p_a_i_a_i_m);
+  let l_a_i_a_i_m_i : vec2<f16> = *(p_a_i_a_i_m_i);
+  let l_a_i_a_i_m_i_i : f16 = (*(p_a_i_a_i_m_i))[i()];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/static_index_via_ptr.wgsl
new file mode 100644
index 0000000..3e2c36f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/static_index_via_ptr.wgsl
@@ -0,0 +1,31 @@
+enable f16;
+
+struct Inner {
+  @size(64)
+  m : mat2x2<f16>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &a;
+  let p_a_3 = &((*p_a)[3]);
+  let p_a_3_a = &((*p_a_3).a);
+  let p_a_3_a_2 = &((*p_a_3_a)[2]);
+  let p_a_3_a_2_m = &((*p_a_3_a_2).m);
+  let p_a_3_a_2_m_1 = &((*p_a_3_a_2_m)[1]);
+
+
+  let l_a             : array<Outer, 4> = *p_a;
+  let l_a_3           : Outer           = *p_a_3;
+  let l_a_3_a         : array<Inner, 4> = *p_a_3_a;
+  let l_a_3_a_2       : Inner           = *p_a_3_a_2;
+  let l_a_3_a_2_m     : mat2x2<f16>     = *p_a_3_a_2_m;
+  let l_a_3_a_2_m_1   : vec2<f16>       = *p_a_3_a_2_m_1;
+  let l_a_3_a_2_m_1_0 : f16             = (*p_a_3_a_2_m_1)[0];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..fa6940d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,63 @@
+struct Inner {
+  matrix<float16_t, 2, 2> m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+
+matrix<float16_t, 2, 2> tint_symbol_4(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  return matrix<float16_t, 2, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))));
+}
+
+Inner tint_symbol_3(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_7 = {tint_symbol_4(buffer, (offset + 0u))};
+  return tint_symbol_7;
+}
+
+typedef Inner tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_3(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_1(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_8 = {tint_symbol_2(buffer, (offset + 0u))};
+  return tint_symbol_8;
+}
+
+typedef Outer tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr_1[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const Outer l_a[4] = tint_symbol(a, 0u);
+  const Outer l_a_3 = tint_symbol_1(a, 768u);
+  const Inner l_a_3_a[4] = tint_symbol_2(a, 768u);
+  const Inner l_a_3_a_2 = tint_symbol_3(a, 896u);
+  const matrix<float16_t, 2, 2> l_a_3_a_2_m = tint_symbol_4(a, 896u);
+  uint ubo_load_2 = a[56].y;
+  const vector<float16_t, 2> l_a_3_a_2_m_1 = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16)));
+  const float16_t l_a_3_a_2_m_1_0 = float16_t(f16tof32(((a[56].y) & 0xFFFF)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..64dbf1e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,68 @@
+SKIP: FAILED
+
+struct Inner {
+  matrix<float16_t, 2, 2> m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+
+matrix<float16_t, 2, 2> tint_symbol_4(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  return matrix<float16_t, 2, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))));
+}
+
+Inner tint_symbol_3(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_7 = {tint_symbol_4(buffer, (offset + 0u))};
+  return tint_symbol_7;
+}
+
+typedef Inner tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_3(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_1(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_8 = {tint_symbol_2(buffer, (offset + 0u))};
+  return tint_symbol_8;
+}
+
+typedef Outer tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr_1[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const Outer l_a[4] = tint_symbol(a, 0u);
+  const Outer l_a_3 = tint_symbol_1(a, 768u);
+  const Inner l_a_3_a[4] = tint_symbol_2(a, 768u);
+  const Inner l_a_3_a_2 = tint_symbol_3(a, 896u);
+  const matrix<float16_t, 2, 2> l_a_3_a_2_m = tint_symbol_4(a, 896u);
+  uint ubo_load_2 = a[56].y;
+  const vector<float16_t, 2> l_a_3_a_2_m_1 = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16)));
+  const float16_t l_a_3_a_2_m_1_0 = float16_t(f16tof32(((a[56].y) & 0xFFFF)));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000025C8106DF60(2,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/static_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..c29755c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/static_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,105 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct Inner {
+  f16mat2 m;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+};
+
+struct Inner_std140 {
+  f16vec2 m_0;
+  f16vec2 m_1;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+};
+
+struct Outer {
+  Inner a[4];
+};
+
+struct Outer_std140 {
+  Inner_std140 a[4];
+};
+
+layout(binding = 0, std140) uniform a_block_std140_ubo {
+  Outer_std140 inner[4];
+} a;
+
+Inner conv_Inner(Inner_std140 val) {
+  return Inner(f16mat2(val.m_0, val.m_1), val.pad, val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.pad_11, val.pad_12, val.pad_13);
+}
+
+Inner[4] conv_arr4_Inner(Inner_std140 val[4]) {
+  Inner arr[4] = Inner[4](Inner(f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_Inner(val[i]);
+    }
+  }
+  return arr;
+}
+
+Outer conv_Outer(Outer_std140 val) {
+  return Outer(conv_arr4_Inner(val.a));
+}
+
+Outer[4] conv_arr4_Outer(Outer_std140 val[4]) {
+  Outer arr[4] = Outer[4](Outer(Inner[4](Inner(f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_Outer(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat2 load_a_inner_3_a_2_m() {
+  return f16mat2(a.inner[3u].a[2u].m_0, a.inner[3u].a[2u].m_1);
+}
+
+void f() {
+  Outer p_a[4] = conv_arr4_Outer(a.inner);
+  Outer p_a_3 = conv_Outer(a.inner[3u]);
+  Inner p_a_3_a[4] = conv_arr4_Inner(a.inner[3u].a);
+  Inner p_a_3_a_2 = conv_Inner(a.inner[3u].a[2u]);
+  f16mat2 p_a_3_a_2_m = load_a_inner_3_a_2_m();
+  f16vec2 p_a_3_a_2_m_1 = a.inner[3u].a[2u].m_1;
+  Outer l_a[4] = conv_arr4_Outer(a.inner);
+  Outer l_a_3 = conv_Outer(a.inner[3u]);
+  Inner l_a_3_a[4] = conv_arr4_Inner(a.inner[3u].a);
+  Inner l_a_3_a_2 = conv_Inner(a.inner[3u].a[2u]);
+  f16mat2 l_a_3_a_2_m = load_a_inner_3_a_2_m();
+  f16vec2 l_a_3_a_2_m_1 = a.inner[3u].a[2u].m_1;
+  float16_t l_a_3_a_2_m_1_0 = a.inner[3u].a[2u].m_1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/static_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..b44cfed
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/static_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,36 @@
+#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 Inner {
+  /* 0x0000 */ half2x2 m;
+  /* 0x0008 */ tint_array<int8_t, 56> tint_pad;
+};
+
+struct Outer {
+  /* 0x0000 */ tint_array<Inner, 4> a;
+};
+
+kernel void f(const constant tint_array<Outer, 4>* tint_symbol [[buffer(0)]]) {
+  tint_array<Outer, 4> const l_a = *(tint_symbol);
+  Outer const l_a_3 = (*(tint_symbol))[3];
+  tint_array<Inner, 4> const l_a_3_a = (*(tint_symbol))[3].a;
+  Inner const l_a_3_a_2 = (*(tint_symbol))[3].a[2];
+  half2x2 const l_a_3_a_2_m = (*(tint_symbol))[3].a[2].m;
+  half2 const l_a_3_a_2_m_1 = (*(tint_symbol))[3].a[2].m[1];
+  half const l_a_3_a_2_m_1_0 = (*(tint_symbol))[3].a[2].m[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/static_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..762929a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/static_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,227 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 140
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block_std140 "a_block_std140"
+               OpMemberName %a_block_std140 0 "inner"
+               OpName %Outer_std140 "Outer_std140"
+               OpMemberName %Outer_std140 0 "a"
+               OpName %Inner_std140 "Inner_std140"
+               OpMemberName %Inner_std140 0 "m_0"
+               OpMemberName %Inner_std140 1 "m_1"
+               OpName %a "a"
+               OpName %Inner "Inner"
+               OpMemberName %Inner 0 "m"
+               OpName %conv_Inner "conv_Inner"
+               OpName %val "val"
+               OpName %conv_arr4_Inner "conv_arr4_Inner"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index_1 "var_for_index_1"
+               OpName %Outer "Outer"
+               OpMemberName %Outer 0 "a"
+               OpName %conv_Outer "conv_Outer"
+               OpName %val_1 "val"
+               OpName %conv_arr4_Outer "conv_arr4_Outer"
+               OpName %val_2 "val"
+               OpName %arr_0 "arr"
+               OpName %i_0 "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_a_inner_3_a_2_m "load_a_inner_3_a_2_m"
+               OpName %f "f"
+               OpDecorate %a_block_std140 Block
+               OpMemberDecorate %a_block_std140 0 Offset 0
+               OpMemberDecorate %Outer_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 1 Offset 4
+               OpDecorate %_arr_Inner_std140_uint_4 ArrayStride 64
+               OpDecorate %_arr_Outer_std140_uint_4 ArrayStride 256
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+               OpMemberDecorate %Inner 0 Offset 0
+               OpMemberDecorate %Inner 0 ColMajor
+               OpMemberDecorate %Inner 0 MatrixStride 4
+               OpDecorate %_arr_Inner_uint_4 ArrayStride 64
+               OpMemberDecorate %Outer 0 Offset 0
+               OpDecorate %_arr_Outer_uint_4 ArrayStride 256
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+%Inner_std140 = OpTypeStruct %v2half %v2half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_Inner_std140_uint_4 = OpTypeArray %Inner_std140 %uint_4
+%Outer_std140 = OpTypeStruct %_arr_Inner_std140_uint_4
+%_arr_Outer_std140_uint_4 = OpTypeArray %Outer_std140 %uint_4
+%a_block_std140 = OpTypeStruct %_arr_Outer_std140_uint_4
+%_ptr_Uniform_a_block_std140 = OpTypePointer Uniform %a_block_std140
+          %a = OpVariable %_ptr_Uniform_a_block_std140 Uniform
+ %mat2v2half = OpTypeMatrix %v2half 2
+      %Inner = OpTypeStruct %mat2v2half
+         %12 = OpTypeFunction %Inner %Inner_std140
+%_arr_Inner_uint_4 = OpTypeArray %Inner %uint_4
+         %22 = OpTypeFunction %_arr_Inner_uint_4 %_arr_Inner_std140_uint_4
+%_ptr_Function__arr_Inner_uint_4 = OpTypePointer Function %_arr_Inner_uint_4
+         %29 = OpConstantNull %_arr_Inner_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %32 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_Inner_std140_uint_4 = OpTypePointer Function %_arr_Inner_std140_uint_4
+         %45 = OpConstantNull %_arr_Inner_std140_uint_4
+%_ptr_Function_Inner = OpTypePointer Function %Inner
+%_ptr_Function_Inner_std140 = OpTypePointer Function %Inner_std140
+     %uint_1 = OpConstant %uint 1
+      %Outer = OpTypeStruct %_arr_Inner_uint_4
+         %58 = OpTypeFunction %Outer %Outer_std140
+%_arr_Outer_uint_4 = OpTypeArray %Outer %uint_4
+         %66 = OpTypeFunction %_arr_Outer_uint_4 %_arr_Outer_std140_uint_4
+%_ptr_Function__arr_Outer_uint_4 = OpTypePointer Function %_arr_Outer_uint_4
+         %73 = OpConstantNull %_arr_Outer_uint_4
+%_ptr_Function__arr_Outer_std140_uint_4 = OpTypePointer Function %_arr_Outer_std140_uint_4
+         %86 = OpConstantNull %_arr_Outer_std140_uint_4
+%_ptr_Function_Outer = OpTypePointer Function %Outer
+%_ptr_Function_Outer_std140 = OpTypePointer Function %Outer_std140
+         %98 = OpTypeFunction %mat2v2half
+     %uint_0 = OpConstant %uint 0
+     %uint_3 = OpConstant %uint 3
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_Inner_std140 = OpTypePointer Uniform %Inner_std140
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+       %void = OpTypeVoid
+        %115 = OpTypeFunction %void
+%_ptr_Uniform__arr_Outer_std140_uint_4 = OpTypePointer Uniform %_arr_Outer_std140_uint_4
+%_ptr_Uniform_Outer_std140 = OpTypePointer Uniform %Outer_std140
+%_ptr_Uniform__arr_Inner_std140_uint_4 = OpTypePointer Uniform %_arr_Inner_std140_uint_4
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+ %conv_Inner = OpFunction %Inner None %12
+        %val = OpFunctionParameter %Inner_std140
+         %17 = OpLabel
+         %18 = OpCompositeExtract %v2half %val 0
+         %19 = OpCompositeExtract %v2half %val 1
+         %20 = OpCompositeConstruct %mat2v2half %18 %19
+         %21 = OpCompositeConstruct %Inner %20
+               OpReturnValue %21
+               OpFunctionEnd
+%conv_arr4_Inner = OpFunction %_arr_Inner_uint_4 None %22
+      %val_0 = OpFunctionParameter %_arr_Inner_std140_uint_4
+         %26 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_Inner_uint_4 Function %29
+          %i = OpVariable %_ptr_Function_uint Function %32
+%var_for_index_1 = OpVariable %_ptr_Function__arr_Inner_std140_uint_4 Function %45
+               OpBranch %33
+         %33 = OpLabel
+               OpLoopMerge %34 %35 None
+               OpBranch %36
+         %36 = OpLabel
+         %38 = OpLoad %uint %i
+         %39 = OpULessThan %bool %38 %uint_4
+         %37 = OpLogicalNot %bool %39
+               OpSelectionMerge %41 None
+               OpBranchConditional %37 %42 %41
+         %42 = OpLabel
+               OpBranch %34
+         %41 = OpLabel
+               OpStore %var_for_index_1 %val_0
+         %46 = OpLoad %uint %i
+         %48 = OpAccessChain %_ptr_Function_Inner %arr %46
+         %50 = OpLoad %uint %i
+         %52 = OpAccessChain %_ptr_Function_Inner_std140 %var_for_index_1 %50
+         %53 = OpLoad %Inner_std140 %52
+         %49 = OpFunctionCall %Inner %conv_Inner %53
+               OpStore %48 %49
+               OpBranch %35
+         %35 = OpLabel
+         %54 = OpLoad %uint %i
+         %56 = OpIAdd %uint %54 %uint_1
+               OpStore %i %56
+               OpBranch %33
+         %34 = OpLabel
+         %57 = OpLoad %_arr_Inner_uint_4 %arr
+               OpReturnValue %57
+               OpFunctionEnd
+ %conv_Outer = OpFunction %Outer None %58
+      %val_1 = OpFunctionParameter %Outer_std140
+         %62 = OpLabel
+         %64 = OpCompositeExtract %_arr_Inner_std140_uint_4 %val_1 0
+         %63 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %64
+         %65 = OpCompositeConstruct %Outer %63
+               OpReturnValue %65
+               OpFunctionEnd
+%conv_arr4_Outer = OpFunction %_arr_Outer_uint_4 None %66
+      %val_2 = OpFunctionParameter %_arr_Outer_std140_uint_4
+         %70 = OpLabel
+      %arr_0 = OpVariable %_ptr_Function__arr_Outer_uint_4 Function %73
+        %i_0 = OpVariable %_ptr_Function_uint Function %32
+%var_for_index = OpVariable %_ptr_Function__arr_Outer_std140_uint_4 Function %86
+               OpBranch %75
+         %75 = OpLabel
+               OpLoopMerge %76 %77 None
+               OpBranch %78
+         %78 = OpLabel
+         %80 = OpLoad %uint %i_0
+         %81 = OpULessThan %bool %80 %uint_4
+         %79 = OpLogicalNot %bool %81
+               OpSelectionMerge %82 None
+               OpBranchConditional %79 %83 %82
+         %83 = OpLabel
+               OpBranch %76
+         %82 = OpLabel
+               OpStore %var_for_index %val_2
+         %87 = OpLoad %uint %i_0
+         %89 = OpAccessChain %_ptr_Function_Outer %arr_0 %87
+         %91 = OpLoad %uint %i_0
+         %93 = OpAccessChain %_ptr_Function_Outer_std140 %var_for_index %91
+         %94 = OpLoad %Outer_std140 %93
+         %90 = OpFunctionCall %Outer %conv_Outer %94
+               OpStore %89 %90
+               OpBranch %77
+         %77 = OpLabel
+         %95 = OpLoad %uint %i_0
+         %96 = OpIAdd %uint %95 %uint_1
+               OpStore %i_0 %96
+               OpBranch %75
+         %76 = OpLabel
+         %97 = OpLoad %_arr_Outer_uint_4 %arr_0
+               OpReturnValue %97
+               OpFunctionEnd
+%load_a_inner_3_a_2_m = OpFunction %mat2v2half None %98
+        %100 = OpLabel
+        %106 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %uint_3 %uint_0 %uint_2
+        %109 = OpAccessChain %_ptr_Uniform_v2half %106 %uint_0
+        %110 = OpLoad %v2half %109
+        %112 = OpAccessChain %_ptr_Uniform_v2half %106 %uint_1
+        %113 = OpLoad %v2half %112
+        %114 = OpCompositeConstruct %mat2v2half %110 %113
+               OpReturnValue %114
+               OpFunctionEnd
+          %f = OpFunction %void None %115
+        %118 = OpLabel
+        %121 = OpAccessChain %_ptr_Uniform__arr_Outer_std140_uint_4 %a %uint_0
+        %122 = OpLoad %_arr_Outer_std140_uint_4 %121
+        %119 = OpFunctionCall %_arr_Outer_uint_4 %conv_arr4_Outer %122
+        %125 = OpAccessChain %_ptr_Uniform_Outer_std140 %a %uint_0 %uint_3
+        %126 = OpLoad %Outer_std140 %125
+        %123 = OpFunctionCall %Outer %conv_Outer %126
+        %129 = OpAccessChain %_ptr_Uniform__arr_Inner_std140_uint_4 %a %uint_0 %uint_3 %uint_0
+        %130 = OpLoad %_arr_Inner_std140_uint_4 %129
+        %127 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %130
+        %132 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %uint_3 %uint_0 %uint_2
+        %133 = OpLoad %Inner_std140 %132
+        %131 = OpFunctionCall %Inner %conv_Inner %133
+        %134 = OpFunctionCall %mat2v2half %load_a_inner_3_a_2_m
+        %135 = OpAccessChain %_ptr_Uniform_v2half %a %uint_0 %uint_3 %uint_0 %uint_2 %uint_1
+        %136 = OpLoad %v2half %135
+        %138 = OpAccessChain %_ptr_Uniform_half %a %uint_0 %uint_3 %uint_0 %uint_2 %uint_1 %32
+        %139 = OpLoad %half %138
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/static_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..d662d25
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/static_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,29 @@
+enable f16;
+
+struct Inner {
+  @size(64)
+  m : mat2x2<f16>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_3 = &((*(p_a))[3]);
+  let p_a_3_a = &((*(p_a_3)).a);
+  let p_a_3_a_2 = &((*(p_a_3_a))[2]);
+  let p_a_3_a_2_m = &((*(p_a_3_a_2)).m);
+  let p_a_3_a_2_m_1 = &((*(p_a_3_a_2_m))[1]);
+  let l_a : array<Outer, 4> = *(p_a);
+  let l_a_3 : Outer = *(p_a_3);
+  let l_a_3_a : array<Inner, 4> = *(p_a_3_a);
+  let l_a_3_a_2 : Inner = *(p_a_3_a_2);
+  let l_a_3_a_2_m : mat2x2<f16> = *(p_a_3_a_2_m);
+  let l_a_3_a_2_m_1 : vec2<f16> = *(p_a_3_a_2_m_1);
+  let l_a_3_a_2_m_1_0 : f16 = (*(p_a_3_a_2_m_1))[0];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_builtin.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_builtin.wgsl
new file mode 100644
index 0000000..5297789
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_builtin.wgsl
@@ -0,0 +1,17 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat2x2<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    let t = transpose(u[2].m);
+    let l = length(u[0].m[1].yx);
+    let a = abs(u[0].m[1].yx.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_builtin.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..bb82c5d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_builtin.wgsl.expected.dxc.hlsl
@@ -0,0 +1,21 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+matrix<float16_t, 2, 2> tint_symbol(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  return matrix<float16_t, 2, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 2, 2> t = transpose(tint_symbol(u, 260u));
+  uint ubo_load_2 = u[0].z;
+  const float16_t l = length(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))).yx);
+  uint ubo_load_3 = u[0].z;
+  const float16_t a = abs(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))).yx.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_builtin.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..f83ab60
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_builtin.wgsl.expected.fxc.hlsl
@@ -0,0 +1,26 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+matrix<float16_t, 2, 2> tint_symbol(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  return matrix<float16_t, 2, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 2, 2> t = transpose(tint_symbol(u, 260u));
+  uint ubo_load_2 = u[0].z;
+  const float16_t l = length(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))).yx);
+  uint ubo_load_3 = u[0].z;
+  const float16_t a = abs(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))).yx.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000002973821CED0(5,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_builtin.wgsl.expected.glsl
new file mode 100644
index 0000000..392c9d0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_builtin.wgsl.expected.glsl
@@ -0,0 +1,91 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct S {
+  int before;
+  f16mat2 m;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  int after;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+  uint pad_26;
+  uint pad_27;
+};
+
+struct S_std140 {
+  int before;
+  f16vec2 m_0;
+  f16vec2 m_1;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  int after;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+  uint pad_26;
+  uint pad_27;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+f16mat2 load_u_inner_2_m() {
+  return f16mat2(u.inner[2u].m_0, u.inner[2u].m_1);
+}
+
+void f() {
+  f16mat2 t = transpose(load_u_inner_2_m());
+  float16_t l = length(u.inner[0u].m_1.yx);
+  float16_t a = abs(u.inner[0u].m_1.yx[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_builtin.wgsl.expected.msl
new file mode 100644
index 0000000..f2a8adb
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_builtin.wgsl.expected.msl
@@ -0,0 +1,31 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ half2x2 m;
+  /* 0x000c */ tint_array<int8_t, 52> tint_pad;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_1;
+};
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol [[buffer(0)]]) {
+  half2x2 const t = transpose((*(tint_symbol))[2].m);
+  half const l = length(half2((*(tint_symbol))[0].m[1]).yx);
+  half const a = fabs(half2((*(tint_symbol))[0].m[1]).yx[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_builtin.wgsl.expected.spvasm
new file mode 100644
index 0000000..3bdf3d7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_builtin.wgsl.expected.spvasm
@@ -0,0 +1,79 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 46
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+         %36 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "after"
+               OpName %u "u"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 4
+               OpMemberDecorate %S_std140 2 Offset 8
+               OpMemberDecorate %S_std140 3 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+   %S_std140 = OpTypeStruct %int %v2half %v2half %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat2v2half = OpTypeMatrix %v2half 2
+         %11 = OpTypeFunction %mat2v2half
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+     %uint_1 = OpConstant %uint 1
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+       %void = OpTypeVoid
+         %29 = OpTypeFunction %void
+         %37 = OpConstantNull %uint
+%load_u_inner_2_m = OpFunction %mat2v2half None %11
+         %14 = OpLabel
+         %19 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %23 = OpAccessChain %_ptr_Uniform_v2half %19 %uint_1
+         %24 = OpLoad %v2half %23
+         %26 = OpAccessChain %_ptr_Uniform_v2half %19 %uint_2
+         %27 = OpLoad %v2half %26
+         %28 = OpCompositeConstruct %mat2v2half %24 %27
+               OpReturnValue %28
+               OpFunctionEnd
+          %f = OpFunction %void None %29
+         %32 = OpLabel
+         %34 = OpFunctionCall %mat2v2half %load_u_inner_2_m
+         %33 = OpTranspose %mat2v2half %34
+         %38 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0 %37 %uint_2
+         %39 = OpLoad %v2half %38
+         %40 = OpVectorShuffle %v2half %39 %39 1 0
+         %35 = OpExtInst %half %36 Length %40
+         %42 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0 %37 %uint_2
+         %43 = OpLoad %v2half %42
+         %44 = OpVectorShuffle %v2half %43 %43 1 0
+         %45 = OpCompositeExtract %half %44 0
+         %41 = OpExtInst %half %36 FAbs %45
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_builtin.wgsl.expected.wgsl
new file mode 100644
index 0000000..ade5de6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_builtin.wgsl.expected.wgsl
@@ -0,0 +1,17 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat2x2<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let t = transpose(u[2].m);
+  let l = length(u[0].m[1].yx);
+  let a = abs(u[0].m[1].yx.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_fn.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_fn.wgsl
new file mode 100644
index 0000000..1ddc722
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_fn.wgsl
@@ -0,0 +1,25 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat2x2<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+fn a(a : array<S, 4>) {}
+fn b(s : S) {}
+fn c(m : mat2x2<f16>) {}
+fn d(v : vec2<f16>) {}
+fn e(f : f16) {}
+
+@compute @workgroup_size(1)
+fn f() {
+    a(u);
+    b(u[2]);
+    c(u[2].m);
+    d(u[0].m[1].yx);
+    e(u[0].m[1].yx.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_fn.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..03670a0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_fn.wgsl.expected.dxc.hlsl
@@ -0,0 +1,62 @@
+struct S {
+  int before;
+  matrix<float16_t, 2, 2> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(matrix<float16_t, 2, 2> m) {
+}
+
+void d(vector<float16_t, 2> v) {
+}
+
+void e(float16_t f_1) {
+}
+
+matrix<float16_t, 2, 2> tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  return matrix<float16_t, 2, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_3(buffer, (offset + 4u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 256u));
+  c(tint_symbol_3(u, 260u));
+  uint ubo_load_2 = u[0].z;
+  d(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))).yx);
+  uint ubo_load_3 = u[0].z;
+  e(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))).yx.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_fn.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..ca733ad
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_fn.wgsl.expected.fxc.hlsl
@@ -0,0 +1,67 @@
+SKIP: FAILED
+
+struct S {
+  int before;
+  matrix<float16_t, 2, 2> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(matrix<float16_t, 2, 2> m) {
+}
+
+void d(vector<float16_t, 2> v) {
+}
+
+void e(float16_t f_1) {
+}
+
+matrix<float16_t, 2, 2> tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  return matrix<float16_t, 2, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_3(buffer, (offset + 4u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 256u));
+  c(tint_symbol_3(u, 260u));
+  uint ubo_load_2 = u[0].z;
+  d(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))).yx);
+  uint ubo_load_3 = u[0].z;
+  e(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))).yx.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000029EA87296E0(3,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_fn.wgsl.expected.glsl
new file mode 100644
index 0000000..5ddb289
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_fn.wgsl.expected.glsl
@@ -0,0 +1,122 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct S {
+  int before;
+  f16mat2 m;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  int after;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+  uint pad_26;
+  uint pad_27;
+};
+
+struct S_std140 {
+  int before;
+  f16vec2 m_0;
+  f16vec2 m_1;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  int after;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+  uint pad_26;
+  uint pad_27;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(f16mat2 m) {
+}
+
+void d(f16vec2 v) {
+}
+
+void e(float16_t f_1) {
+}
+
+S conv_S(S_std140 val) {
+  return S(val.before, f16mat2(val.m_0, val.m_1), val.pad, val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.pad_11, val.pad_12, val.after, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21, val.pad_22, val.pad_23, val.pad_24, val.pad_25, val.pad_26, val.pad_27);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat2 load_u_inner_2_m() {
+  return f16mat2(u.inner[2u].m_0, u.inner[2u].m_1);
+}
+
+void f() {
+  a(conv_arr4_S(u.inner));
+  b(conv_S(u.inner[2u]));
+  c(load_u_inner_2_m());
+  d(u.inner[0u].m_1.yx);
+  e(u.inner[0u].m_1.yx[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_fn.wgsl.expected.msl
new file mode 100644
index 0000000..377d72a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_fn.wgsl.expected.msl
@@ -0,0 +1,48 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ half2x2 m;
+  /* 0x000c */ tint_array<int8_t, 52> tint_pad;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_1;
+};
+
+void a(tint_array<S, 4> a_1) {
+}
+
+void b(S s) {
+}
+
+void c(half2x2 m) {
+}
+
+void d(half2 v) {
+}
+
+void e(half f_1) {
+}
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol [[buffer(0)]]) {
+  a(*(tint_symbol));
+  b((*(tint_symbol))[2]);
+  c((*(tint_symbol))[2].m);
+  d(half2((*(tint_symbol))[0].m[1]).yx);
+  e(half2((*(tint_symbol))[0].m[1]).yx[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_fn.wgsl.expected.spvasm
new file mode 100644
index 0000000..14ba4ae
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_fn.wgsl.expected.spvasm
@@ -0,0 +1,204 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 119
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "after"
+               OpName %u "u"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %a "a"
+               OpName %a_1 "a_1"
+               OpName %b "b"
+               OpName %s "s"
+               OpName %c "c"
+               OpName %m "m"
+               OpName %d "d"
+               OpName %v "v"
+               OpName %e "e"
+               OpName %f_1 "f_1"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 4
+               OpMemberDecorate %S_std140 2 Offset 8
+               OpMemberDecorate %S_std140 3 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 4
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 4
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+   %S_std140 = OpTypeStruct %int %v2half %v2half %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+       %void = OpTypeVoid
+ %mat2v2half = OpTypeMatrix %v2half 2
+          %S = OpTypeStruct %int %mat2v2half %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+         %11 = OpTypeFunction %void %_arr_S_uint_4
+         %19 = OpTypeFunction %void %S
+         %23 = OpTypeFunction %void %mat2v2half
+         %27 = OpTypeFunction %void %v2half
+         %31 = OpTypeFunction %void %half
+         %35 = OpTypeFunction %S %S_std140
+         %45 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+         %51 = OpConstantNull %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %54 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %67 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %80 = OpTypeFunction %mat2v2half
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+         %96 = OpTypeFunction %void
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+          %a = OpFunction %void None %11
+        %a_1 = OpFunctionParameter %_arr_S_uint_4
+         %18 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %b = OpFunction %void None %19
+          %s = OpFunctionParameter %S
+         %22 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %c = OpFunction %void None %23
+          %m = OpFunctionParameter %mat2v2half
+         %26 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %d = OpFunction %void None %27
+          %v = OpFunctionParameter %v2half
+         %30 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %e = OpFunction %void None %31
+        %f_1 = OpFunctionParameter %half
+         %34 = OpLabel
+               OpReturn
+               OpFunctionEnd
+     %conv_S = OpFunction %S None %35
+        %val = OpFunctionParameter %S_std140
+         %38 = OpLabel
+         %39 = OpCompositeExtract %int %val 0
+         %40 = OpCompositeExtract %v2half %val 1
+         %41 = OpCompositeExtract %v2half %val 2
+         %42 = OpCompositeConstruct %mat2v2half %40 %41
+         %43 = OpCompositeExtract %int %val 3
+         %44 = OpCompositeConstruct %S %39 %42 %43
+               OpReturnValue %44
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %45
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %48 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %51
+          %i = OpVariable %_ptr_Function_uint Function %54
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %67
+               OpBranch %55
+         %55 = OpLabel
+               OpLoopMerge %56 %57 None
+               OpBranch %58
+         %58 = OpLabel
+         %60 = OpLoad %uint %i
+         %61 = OpULessThan %bool %60 %uint_4
+         %59 = OpLogicalNot %bool %61
+               OpSelectionMerge %63 None
+               OpBranchConditional %59 %64 %63
+         %64 = OpLabel
+               OpBranch %56
+         %63 = OpLabel
+               OpStore %var_for_index %val_0
+         %68 = OpLoad %uint %i
+         %70 = OpAccessChain %_ptr_Function_S %arr %68
+         %72 = OpLoad %uint %i
+         %74 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %72
+         %75 = OpLoad %S_std140 %74
+         %71 = OpFunctionCall %S %conv_S %75
+               OpStore %70 %71
+               OpBranch %57
+         %57 = OpLabel
+         %76 = OpLoad %uint %i
+         %78 = OpIAdd %uint %76 %uint_1
+               OpStore %i %78
+               OpBranch %55
+         %56 = OpLabel
+         %79 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %79
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat2v2half None %80
+         %82 = OpLabel
+         %87 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %90 = OpAccessChain %_ptr_Uniform_v2half %87 %uint_1
+         %91 = OpLoad %v2half %90
+         %93 = OpAccessChain %_ptr_Uniform_v2half %87 %uint_2
+         %94 = OpLoad %v2half %93
+         %95 = OpCompositeConstruct %mat2v2half %91 %94
+               OpReturnValue %95
+               OpFunctionEnd
+          %f = OpFunction %void None %96
+         %98 = OpLabel
+        %102 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+        %103 = OpLoad %_arr_S_std140_uint_4 %102
+        %100 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %103
+         %99 = OpFunctionCall %void %a %100
+        %106 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+        %107 = OpLoad %S_std140 %106
+        %105 = OpFunctionCall %S %conv_S %107
+        %104 = OpFunctionCall %void %b %105
+        %109 = OpFunctionCall %mat2v2half %load_u_inner_2_m
+        %108 = OpFunctionCall %void %c %109
+        %111 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0 %54 %uint_2
+        %112 = OpLoad %v2half %111
+        %113 = OpVectorShuffle %v2half %112 %112 1 0
+        %110 = OpFunctionCall %void %d %113
+        %115 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0 %54 %uint_2
+        %116 = OpLoad %v2half %115
+        %117 = OpVectorShuffle %v2half %116 %116 1 0
+        %118 = OpCompositeExtract %half %117 0
+        %114 = OpFunctionCall %void %e %118
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_fn.wgsl.expected.wgsl
new file mode 100644
index 0000000..3e7d522
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_fn.wgsl.expected.wgsl
@@ -0,0 +1,34 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat2x2<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+fn a(a : array<S, 4>) {
+}
+
+fn b(s : S) {
+}
+
+fn c(m : mat2x2<f16>) {
+}
+
+fn d(v : vec2<f16>) {
+}
+
+fn e(f : f16) {
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  a(u);
+  b(u[2]);
+  c(u[2].m);
+  d(u[0].m[1].yx);
+  e(u[0].m[1].yx.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_private.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_private.wgsl
new file mode 100644
index 0000000..e25cc5b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_private.wgsl
@@ -0,0 +1,19 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat2x2<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+var<private> p : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[2];
+    p[3].m = u[2].m;
+    p[1].m[0] = u[0].m[1].yx;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_private.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..5ff5a75
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_private.wgsl.expected.dxc.hlsl
@@ -0,0 +1,46 @@
+struct S {
+  int before;
+  matrix<float16_t, 2, 2> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+static S p[4] = (S[4])0;
+
+matrix<float16_t, 2, 2> tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  return matrix<float16_t, 2, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_3(buffer, (offset + 4u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 256u);
+  p[3].m = tint_symbol_3(u, 260u);
+  uint ubo_load_2 = u[0].z;
+  p[1].m[0] = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))).yx;
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_private.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..e1bce07
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_private.wgsl.expected.fxc.hlsl
@@ -0,0 +1,51 @@
+SKIP: FAILED
+
+struct S {
+  int before;
+  matrix<float16_t, 2, 2> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+static S p[4] = (S[4])0;
+
+matrix<float16_t, 2, 2> tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  return matrix<float16_t, 2, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_3(buffer, (offset + 4u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 256u);
+  p[3].m = tint_symbol_3(u, 260u);
+  uint ubo_load_2 = u[0].z;
+  p[1].m[0] = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))).yx;
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x00000172713CA4A0(3,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..cecf067
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_private.wgsl.expected.glsl
@@ -0,0 +1,107 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct S {
+  int before;
+  f16mat2 m;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  int after;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+  uint pad_26;
+  uint pad_27;
+};
+
+struct S_std140 {
+  int before;
+  f16vec2 m_0;
+  f16vec2 m_1;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  int after;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+  uint pad_26;
+  uint pad_27;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+S p[4] = S[4](S(0, f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+S conv_S(S_std140 val) {
+  return S(val.before, f16mat2(val.m_0, val.m_1), val.pad, val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.pad_11, val.pad_12, val.after, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21, val.pad_22, val.pad_23, val.pad_24, val.pad_25, val.pad_26, val.pad_27);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat2 load_u_inner_2_m() {
+  return f16mat2(u.inner[2u].m_0, u.inner[2u].m_1);
+}
+
+void f() {
+  p = conv_arr4_S(u.inner);
+  p[1] = conv_S(u.inner[2u]);
+  p[3].m = load_u_inner_2_m();
+  p[1].m[0] = u.inner[0u].m_1.yx;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..a5d8527
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_private.wgsl.expected.msl
@@ -0,0 +1,33 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ half2x2 m;
+  /* 0x000c */ tint_array<int8_t, 52> tint_pad;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_1;
+};
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol_1 [[buffer(0)]]) {
+  thread tint_array<S, 4> tint_symbol = {};
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[2];
+  tint_symbol[3].m = (*(tint_symbol_1))[2].m;
+  tint_symbol[1].m[0] = half2((*(tint_symbol_1))[0].m[1]).yx;
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_private.wgsl.expected.spvasm
new file mode 100644
index 0000000..45b249e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_private.wgsl.expected.spvasm
@@ -0,0 +1,171 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 101
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "after"
+               OpName %u "u"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %p "p"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 4
+               OpMemberDecorate %S_std140 2 Offset 8
+               OpMemberDecorate %S_std140 3 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 4
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 4
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+   %S_std140 = OpTypeStruct %int %v2half %v2half %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat2v2half = OpTypeMatrix %v2half 2
+          %S = OpTypeStruct %int %mat2v2half %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+%_ptr_Private__arr_S_uint_4 = OpTypePointer Private %_arr_S_uint_4
+         %16 = OpConstantNull %_arr_S_uint_4
+          %p = OpVariable %_ptr_Private__arr_S_uint_4 Private %16
+         %17 = OpTypeFunction %S %S_std140
+         %27 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %35 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %48 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %61 = OpTypeFunction %mat2v2half
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+       %void = OpTypeVoid
+         %77 = OpTypeFunction %void
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+      %int_1 = OpConstant %int 1
+%_ptr_Private_S = OpTypePointer Private %S
+      %int_3 = OpConstant %int 3
+%_ptr_Private_mat2v2half = OpTypePointer Private %mat2v2half
+         %95 = OpConstantNull %int
+%_ptr_Private_v2half = OpTypePointer Private %v2half
+     %conv_S = OpFunction %S None %17
+        %val = OpFunctionParameter %S_std140
+         %20 = OpLabel
+         %21 = OpCompositeExtract %int %val 0
+         %22 = OpCompositeExtract %v2half %val 1
+         %23 = OpCompositeExtract %v2half %val 2
+         %24 = OpCompositeConstruct %mat2v2half %22 %23
+         %25 = OpCompositeExtract %int %val 3
+         %26 = OpCompositeConstruct %S %21 %24 %25
+               OpReturnValue %26
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %27
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %30 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %16
+          %i = OpVariable %_ptr_Function_uint Function %35
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %48
+               OpBranch %36
+         %36 = OpLabel
+               OpLoopMerge %37 %38 None
+               OpBranch %39
+         %39 = OpLabel
+         %41 = OpLoad %uint %i
+         %42 = OpULessThan %bool %41 %uint_4
+         %40 = OpLogicalNot %bool %42
+               OpSelectionMerge %44 None
+               OpBranchConditional %40 %45 %44
+         %45 = OpLabel
+               OpBranch %37
+         %44 = OpLabel
+               OpStore %var_for_index %val_0
+         %49 = OpLoad %uint %i
+         %51 = OpAccessChain %_ptr_Function_S %arr %49
+         %53 = OpLoad %uint %i
+         %55 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %53
+         %56 = OpLoad %S_std140 %55
+         %52 = OpFunctionCall %S %conv_S %56
+               OpStore %51 %52
+               OpBranch %38
+         %38 = OpLabel
+         %57 = OpLoad %uint %i
+         %59 = OpIAdd %uint %57 %uint_1
+               OpStore %i %59
+               OpBranch %36
+         %37 = OpLabel
+         %60 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %60
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat2v2half None %61
+         %63 = OpLabel
+         %68 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %71 = OpAccessChain %_ptr_Uniform_v2half %68 %uint_1
+         %72 = OpLoad %v2half %71
+         %74 = OpAccessChain %_ptr_Uniform_v2half %68 %uint_2
+         %75 = OpLoad %v2half %74
+         %76 = OpCompositeConstruct %mat2v2half %72 %75
+               OpReturnValue %76
+               OpFunctionEnd
+          %f = OpFunction %void None %77
+         %80 = OpLabel
+         %83 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+         %84 = OpLoad %_arr_S_std140_uint_4 %83
+         %81 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %84
+               OpStore %p %81
+         %87 = OpAccessChain %_ptr_Private_S %p %int_1
+         %89 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %90 = OpLoad %S_std140 %89
+         %88 = OpFunctionCall %S %conv_S %90
+               OpStore %87 %88
+         %93 = OpAccessChain %_ptr_Private_mat2v2half %p %int_3 %uint_1
+         %94 = OpFunctionCall %mat2v2half %load_u_inner_2_m
+               OpStore %93 %94
+         %97 = OpAccessChain %_ptr_Private_v2half %p %int_1 %uint_1 %95
+         %98 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0 %35 %uint_2
+         %99 = OpLoad %v2half %98
+        %100 = OpVectorShuffle %v2half %99 %99 1 0
+               OpStore %97 %100
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..ed6df05
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_private.wgsl.expected.wgsl
@@ -0,0 +1,20 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat2x2<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+var<private> p : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[2];
+  p[3].m = u[2].m;
+  p[1].m[0] = u[0].m[1].yx;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_storage.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_storage.wgsl
new file mode 100644
index 0000000..fc72568
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_storage.wgsl
@@ -0,0 +1,19 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat2x2<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+@group(0) @binding(1) var<storage, read_write> s : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[2];
+    s[3].m = u[2].m;
+    s[1].m[0] = u[0].m[1].yx;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_storage.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..e217232
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_storage.wgsl.expected.dxc.hlsl
@@ -0,0 +1,66 @@
+struct S {
+  int before;
+  matrix<float16_t, 2, 2> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_3(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 2, 2> value) {
+  buffer.Store<vector<float16_t, 2> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 4u), value[1u]);
+}
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, S value) {
+  buffer.Store((offset + 0u), asuint(value.before));
+  tint_symbol_3(buffer, (offset + 4u), value.m);
+  buffer.Store((offset + 64u), asuint(value.after));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, S value[4]) {
+  S array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 128u)), array[i]);
+    }
+  }
+}
+
+matrix<float16_t, 2, 2> tint_symbol_8(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  return matrix<float16_t, 2, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))));
+}
+
+S tint_symbol_6(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_10 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_8(buffer, (offset + 4u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_10;
+}
+
+typedef S tint_symbol_5_ret[4];
+tint_symbol_5_ret tint_symbol_5(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_6(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_5(u, 0u));
+  tint_symbol_1(s, 128u, tint_symbol_6(u, 256u));
+  tint_symbol_3(s, 388u, tint_symbol_8(u, 260u));
+  uint ubo_load_2 = u[0].z;
+  s.Store<vector<float16_t, 2> >(132u, vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))).yx);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_storage.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..fedbc87
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_storage.wgsl.expected.fxc.hlsl
@@ -0,0 +1,71 @@
+SKIP: FAILED
+
+struct S {
+  int before;
+  matrix<float16_t, 2, 2> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_3(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 2, 2> value) {
+  buffer.Store<vector<float16_t, 2> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 4u), value[1u]);
+}
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, S value) {
+  buffer.Store((offset + 0u), asuint(value.before));
+  tint_symbol_3(buffer, (offset + 4u), value.m);
+  buffer.Store((offset + 64u), asuint(value.after));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, S value[4]) {
+  S array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 128u)), array[i]);
+    }
+  }
+}
+
+matrix<float16_t, 2, 2> tint_symbol_8(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  return matrix<float16_t, 2, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))));
+}
+
+S tint_symbol_6(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_10 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_8(buffer, (offset + 4u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_10;
+}
+
+typedef S tint_symbol_5_ret[4];
+tint_symbol_5_ret tint_symbol_5(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_6(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_5(u, 0u));
+  tint_symbol_1(s, 128u, tint_symbol_6(u, 256u));
+  tint_symbol_3(s, 388u, tint_symbol_8(u, 260u));
+  uint ubo_load_2 = u[0].z;
+  s.Store<vector<float16_t, 2> >(132u, vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))).yx);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001A0472DA2E0(3,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..7980194
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_storage.wgsl.expected.glsl
@@ -0,0 +1,110 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct S {
+  int before;
+  f16mat2 m;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  int after;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+  uint pad_26;
+  uint pad_27;
+};
+
+struct S_std140 {
+  int before;
+  f16vec2 m_0;
+  f16vec2 m_1;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  int after;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+  uint pad_26;
+  uint pad_27;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  S inner[4];
+} s;
+
+S conv_S(S_std140 val) {
+  return S(val.before, f16mat2(val.m_0, val.m_1), val.pad, val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.pad_11, val.pad_12, val.after, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21, val.pad_22, val.pad_23, val.pad_24, val.pad_25, val.pad_26, val.pad_27);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat2 load_u_inner_2_m() {
+  return f16mat2(u.inner[2u].m_0, u.inner[2u].m_1);
+}
+
+void f() {
+  s.inner = conv_arr4_S(u.inner);
+  s.inner[1] = conv_S(u.inner[2u]);
+  s.inner[3].m = load_u_inner_2_m();
+  s.inner[1].m[0] = u.inner[0u].m_1.yx;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..9337ac0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_storage.wgsl.expected.msl
@@ -0,0 +1,32 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ half2x2 m;
+  /* 0x000c */ tint_array<int8_t, 52> tint_pad;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_1;
+};
+
+kernel void f(device tint_array<S, 4>* tint_symbol [[buffer(1)]], const constant tint_array<S, 4>* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
+  (*(tint_symbol))[3].m = (*(tint_symbol_1))[2].m;
+  (*(tint_symbol))[1].m[0] = half2((*(tint_symbol_1))[0].m[1]).yx;
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_storage.wgsl.expected.spvasm
new file mode 100644
index 0000000..b7cbc1b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_storage.wgsl.expected.spvasm
@@ -0,0 +1,180 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 104
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "after"
+               OpName %u "u"
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %s "s"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 4
+               OpMemberDecorate %S_std140 2 Offset 8
+               OpMemberDecorate %S_std140 3 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 4
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 4
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+               OpDecorate %s DescriptorSet 0
+               OpDecorate %s Binding 1
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+   %S_std140 = OpTypeStruct %int %v2half %v2half %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat2v2half = OpTypeMatrix %v2half 2
+          %S = OpTypeStruct %int %mat2v2half %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+    %u_block = OpTypeStruct %_arr_S_uint_4
+%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
+          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+         %17 = OpTypeFunction %S %S_std140
+         %27 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+         %33 = OpConstantNull %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %36 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %49 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %62 = OpTypeFunction %mat2v2half
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+       %void = OpTypeVoid
+         %78 = OpTypeFunction %void
+%_ptr_StorageBuffer__arr_S_uint_4 = OpTypePointer StorageBuffer %_arr_S_uint_4
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+      %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
+      %int_3 = OpConstant %int 3
+%_ptr_StorageBuffer_mat2v2half = OpTypePointer StorageBuffer %mat2v2half
+         %98 = OpConstantNull %int
+%_ptr_StorageBuffer_v2half = OpTypePointer StorageBuffer %v2half
+     %conv_S = OpFunction %S None %17
+        %val = OpFunctionParameter %S_std140
+         %20 = OpLabel
+         %21 = OpCompositeExtract %int %val 0
+         %22 = OpCompositeExtract %v2half %val 1
+         %23 = OpCompositeExtract %v2half %val 2
+         %24 = OpCompositeConstruct %mat2v2half %22 %23
+         %25 = OpCompositeExtract %int %val 3
+         %26 = OpCompositeConstruct %S %21 %24 %25
+               OpReturnValue %26
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %27
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %30 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %33
+          %i = OpVariable %_ptr_Function_uint Function %36
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %49
+               OpBranch %37
+         %37 = OpLabel
+               OpLoopMerge %38 %39 None
+               OpBranch %40
+         %40 = OpLabel
+         %42 = OpLoad %uint %i
+         %43 = OpULessThan %bool %42 %uint_4
+         %41 = OpLogicalNot %bool %43
+               OpSelectionMerge %45 None
+               OpBranchConditional %41 %46 %45
+         %46 = OpLabel
+               OpBranch %38
+         %45 = OpLabel
+               OpStore %var_for_index %val_0
+         %50 = OpLoad %uint %i
+         %52 = OpAccessChain %_ptr_Function_S %arr %50
+         %54 = OpLoad %uint %i
+         %56 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %54
+         %57 = OpLoad %S_std140 %56
+         %53 = OpFunctionCall %S %conv_S %57
+               OpStore %52 %53
+               OpBranch %39
+         %39 = OpLabel
+         %58 = OpLoad %uint %i
+         %60 = OpIAdd %uint %58 %uint_1
+               OpStore %i %60
+               OpBranch %37
+         %38 = OpLabel
+         %61 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %61
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat2v2half None %62
+         %64 = OpLabel
+         %69 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %72 = OpAccessChain %_ptr_Uniform_v2half %69 %uint_1
+         %73 = OpLoad %v2half %72
+         %75 = OpAccessChain %_ptr_Uniform_v2half %69 %uint_2
+         %76 = OpLoad %v2half %75
+         %77 = OpCompositeConstruct %mat2v2half %73 %76
+               OpReturnValue %77
+               OpFunctionEnd
+          %f = OpFunction %void None %78
+         %81 = OpLabel
+         %83 = OpAccessChain %_ptr_StorageBuffer__arr_S_uint_4 %s %uint_0
+         %86 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+         %87 = OpLoad %_arr_S_std140_uint_4 %86
+         %84 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %87
+               OpStore %83 %84
+         %90 = OpAccessChain %_ptr_StorageBuffer_S %s %uint_0 %int_1
+         %92 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %93 = OpLoad %S_std140 %92
+         %91 = OpFunctionCall %S %conv_S %93
+               OpStore %90 %91
+         %96 = OpAccessChain %_ptr_StorageBuffer_mat2v2half %s %uint_0 %int_3 %uint_1
+         %97 = OpFunctionCall %mat2v2half %load_u_inner_2_m
+               OpStore %96 %97
+        %100 = OpAccessChain %_ptr_StorageBuffer_v2half %s %uint_0 %int_1 %uint_1 %98
+        %101 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0 %36 %uint_2
+        %102 = OpLoad %v2half %101
+        %103 = OpVectorShuffle %v2half %102 %102 1 0
+               OpStore %100 %103
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..4f5e53f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,20 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat2x2<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@group(0) @binding(1) var<storage, read_write> s : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[2];
+  s[3].m = u[2].m;
+  s[1].m[0] = u[0].m[1].yx;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_workgroup.wgsl
new file mode 100644
index 0000000..e296fe2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_workgroup.wgsl
@@ -0,0 +1,19 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat2x2<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+var<workgroup> w : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[2];
+    w[3].m = u[2].m;
+    w[1].m[0] = u[0].m[1].yx;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_workgroup.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..15c8322
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_workgroup.wgsl.expected.dxc.hlsl
@@ -0,0 +1,62 @@
+struct S {
+  int before;
+  matrix<float16_t, 2, 2> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+groupshared S w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 2, 2> tint_symbol_5(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  return matrix<float16_t, 2, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))));
+}
+
+S tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_8 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_5(buffer, (offset + 4u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_8;
+}
+
+typedef S tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      const S tint_symbol_7 = (S)0;
+      w[i] = tint_symbol_7;
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 256u);
+  w[3].m = tint_symbol_5(u, 260u);
+  uint ubo_load_2 = u[0].z;
+  w[1].m[0] = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))).yx;
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_workgroup.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..50372ab
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_workgroup.wgsl.expected.fxc.hlsl
@@ -0,0 +1,67 @@
+SKIP: FAILED
+
+struct S {
+  int before;
+  matrix<float16_t, 2, 2> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+groupshared S w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 2, 2> tint_symbol_5(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  return matrix<float16_t, 2, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))));
+}
+
+S tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_8 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_5(buffer, (offset + 4u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_8;
+}
+
+typedef S tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      const S tint_symbol_7 = (S)0;
+      w[i] = tint_symbol_7;
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 256u);
+  w[3].m = tint_symbol_5(u, 260u);
+  uint ubo_load_2 = u[0].z;
+  w[1].m[0] = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))).yx;
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001CABCCF0160(3,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..0ea73a9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,115 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct S {
+  int before;
+  f16mat2 m;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  int after;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+  uint pad_26;
+  uint pad_27;
+};
+
+struct S_std140 {
+  int before;
+  f16vec2 m_0;
+  f16vec2 m_1;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  int after;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+  uint pad_26;
+  uint pad_27;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+shared S w[4];
+S conv_S(S_std140 val) {
+  return S(val.before, f16mat2(val.m_0, val.m_1), val.pad, val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.pad_11, val.pad_12, val.after, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21, val.pad_22, val.pad_23, val.pad_24, val.pad_25, val.pad_26, val.pad_27);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat2 load_u_inner_2_m() {
+  return f16mat2(u.inner[2u].m_0, u.inner[2u].m_1);
+}
+
+void f(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      uint i = idx;
+      S tint_symbol = S(0, f16mat2(f16vec2(0.0hf), f16vec2(0.0hf)), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u);
+      w[i] = tint_symbol;
+    }
+  }
+  barrier();
+  w = conv_arr4_S(u.inner);
+  w[1] = conv_S(u.inner[2u]);
+  w[3].m = load_u_inner_2_m();
+  w[1].m[0] = u.inner[0u].m_1.yx;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..6411d47
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,47 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ half2x2 m;
+  /* 0x000c */ tint_array<int8_t, 52> tint_pad;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_1;
+};
+
+struct tint_symbol_6 {
+  tint_array<S, 4> w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup tint_array<S, 4>* const tint_symbol_1, const constant tint_array<S, 4>* const tint_symbol_2) {
+  for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+    uint const i = idx;
+    S const tint_symbol = S{};
+    (*(tint_symbol_1))[i] = tint_symbol;
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol_1) = *(tint_symbol_2);
+  (*(tint_symbol_1))[1] = (*(tint_symbol_2))[2];
+  (*(tint_symbol_1))[3].m = (*(tint_symbol_2))[2].m;
+  (*(tint_symbol_1))[1].m[0] = half2((*(tint_symbol_2))[0].m[1]).yx;
+}
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol_5 [[buffer(0)]], threadgroup tint_symbol_6* tint_symbol_4 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup tint_array<S, 4>* const tint_symbol_3 = &((*(tint_symbol_4)).w);
+  f_inner(local_invocation_index, tint_symbol_3, tint_symbol_5);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_workgroup.wgsl.expected.spvasm
new file mode 100644
index 0000000..246193e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_workgroup.wgsl.expected.spvasm
@@ -0,0 +1,214 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 126
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %local_invocation_index_1 "local_invocation_index_1"
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "after"
+               OpName %u "u"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %w "w"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f_inner "f_inner"
+               OpName %local_invocation_index "local_invocation_index"
+               OpName %idx "idx"
+               OpName %f "f"
+               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 4
+               OpMemberDecorate %S_std140 2 Offset 8
+               OpMemberDecorate %S_std140 3 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 4
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 4
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+   %S_std140 = OpTypeStruct %int %v2half %v2half %int
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat2v2half = OpTypeMatrix %v2half 2
+          %S = OpTypeStruct %int %mat2v2half %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+%_ptr_Workgroup__arr_S_uint_4 = OpTypePointer Workgroup %_arr_S_uint_4
+          %w = OpVariable %_ptr_Workgroup__arr_S_uint_4 Workgroup
+         %18 = OpTypeFunction %S %S_std140
+         %28 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+         %34 = OpConstantNull %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %37 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %50 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %63 = OpTypeFunction %mat2v2half
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+       %void = OpTypeVoid
+         %79 = OpTypeFunction %void %uint
+%_ptr_Workgroup_S = OpTypePointer Workgroup %S
+         %97 = OpConstantNull %S
+   %uint_264 = OpConstant %uint 264
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+      %int_1 = OpConstant %int 1
+      %int_3 = OpConstant %int 3
+%_ptr_Workgroup_mat2v2half = OpTypePointer Workgroup %mat2v2half
+        %115 = OpConstantNull %int
+%_ptr_Workgroup_v2half = OpTypePointer Workgroup %v2half
+        %121 = OpTypeFunction %void
+     %conv_S = OpFunction %S None %18
+        %val = OpFunctionParameter %S_std140
+         %21 = OpLabel
+         %22 = OpCompositeExtract %int %val 0
+         %23 = OpCompositeExtract %v2half %val 1
+         %24 = OpCompositeExtract %v2half %val 2
+         %25 = OpCompositeConstruct %mat2v2half %23 %24
+         %26 = OpCompositeExtract %int %val 3
+         %27 = OpCompositeConstruct %S %22 %25 %26
+               OpReturnValue %27
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %28
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %31 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %34
+          %i = OpVariable %_ptr_Function_uint Function %37
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %50
+               OpBranch %38
+         %38 = OpLabel
+               OpLoopMerge %39 %40 None
+               OpBranch %41
+         %41 = OpLabel
+         %43 = OpLoad %uint %i
+         %44 = OpULessThan %bool %43 %uint_4
+         %42 = OpLogicalNot %bool %44
+               OpSelectionMerge %46 None
+               OpBranchConditional %42 %47 %46
+         %47 = OpLabel
+               OpBranch %39
+         %46 = OpLabel
+               OpStore %var_for_index %val_0
+         %51 = OpLoad %uint %i
+         %53 = OpAccessChain %_ptr_Function_S %arr %51
+         %55 = OpLoad %uint %i
+         %57 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %55
+         %58 = OpLoad %S_std140 %57
+         %54 = OpFunctionCall %S %conv_S %58
+               OpStore %53 %54
+               OpBranch %40
+         %40 = OpLabel
+         %59 = OpLoad %uint %i
+         %61 = OpIAdd %uint %59 %uint_1
+               OpStore %i %61
+               OpBranch %38
+         %39 = OpLabel
+         %62 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %62
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat2v2half None %63
+         %65 = OpLabel
+         %70 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %73 = OpAccessChain %_ptr_Uniform_v2half %70 %uint_1
+         %74 = OpLoad %v2half %73
+         %76 = OpAccessChain %_ptr_Uniform_v2half %70 %uint_2
+         %77 = OpLoad %v2half %76
+         %78 = OpCompositeConstruct %mat2v2half %74 %77
+               OpReturnValue %78
+               OpFunctionEnd
+    %f_inner = OpFunction %void None %79
+%local_invocation_index = OpFunctionParameter %uint
+         %83 = OpLabel
+        %idx = OpVariable %_ptr_Function_uint Function %37
+               OpStore %idx %local_invocation_index
+               OpBranch %85
+         %85 = OpLabel
+               OpLoopMerge %86 %87 None
+               OpBranch %88
+         %88 = OpLabel
+         %90 = OpLoad %uint %idx
+         %91 = OpULessThan %bool %90 %uint_4
+         %89 = OpLogicalNot %bool %91
+               OpSelectionMerge %92 None
+               OpBranchConditional %89 %93 %92
+         %93 = OpLabel
+               OpBranch %86
+         %92 = OpLabel
+         %94 = OpLoad %uint %idx
+         %96 = OpAccessChain %_ptr_Workgroup_S %w %94
+               OpStore %96 %97
+               OpBranch %87
+         %87 = OpLabel
+         %98 = OpLoad %uint %idx
+         %99 = OpIAdd %uint %98 %uint_1
+               OpStore %idx %99
+               OpBranch %85
+         %86 = OpLabel
+               OpControlBarrier %uint_2 %uint_2 %uint_264
+        %104 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+        %105 = OpLoad %_arr_S_std140_uint_4 %104
+        %102 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %105
+               OpStore %w %102
+        %107 = OpAccessChain %_ptr_Workgroup_S %w %int_1
+        %109 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+        %110 = OpLoad %S_std140 %109
+        %108 = OpFunctionCall %S %conv_S %110
+               OpStore %107 %108
+        %113 = OpAccessChain %_ptr_Workgroup_mat2v2half %w %int_3 %uint_1
+        %114 = OpFunctionCall %mat2v2half %load_u_inner_2_m
+               OpStore %113 %114
+        %117 = OpAccessChain %_ptr_Workgroup_v2half %w %int_1 %uint_1 %115
+        %118 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0 %37 %uint_2
+        %119 = OpLoad %v2half %118
+        %120 = OpVectorShuffle %v2half %119 %119 1 0
+               OpStore %117 %120
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %121
+        %123 = OpLabel
+        %125 = OpLoad %uint %local_invocation_index_1
+        %124 = OpFunctionCall %void %f_inner %125
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..572d1fc
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f16/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,20 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat2x2<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+var<workgroup> w : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[2];
+  w[3].m = u[2].m;
+  w[1].m[0] = u[0].m[1].yx;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/dynamic_index_via_ptr.wgsl
new file mode 100644
index 0000000..51aa7c6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/dynamic_index_via_ptr.wgsl
@@ -0,0 +1,32 @@
+struct Inner {
+  @size(64)
+  m : mat2x2<f32>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a           = &a;
+  let p_a_i         = &((*p_a)[i()]);
+  let p_a_i_a       = &((*p_a_i).a);
+  let p_a_i_a_i     = &((*p_a_i_a)[i()]);
+  let p_a_i_a_i_m   = &((*p_a_i_a_i).m);
+  let p_a_i_a_i_m_i = &((*p_a_i_a_i_m)[i()]);
+
+
+  let l_a             : array<Outer, 4> =  *p_a;
+  let l_a_i           : Outer           =  *p_a_i;
+  let l_a_i_a         : array<Inner, 4> =  *p_a_i_a;
+  let l_a_i_a_i       : Inner           =  *p_a_i_a_i;
+  let l_a_i_a_i_m     : mat2x2<f32>     =  *p_a_i_a_i_m;
+  let l_a_i_a_i_m_i   : vec2<f32>       =  *p_a_i_a_i_m_i;
+  let l_a_i_a_i_m_i_i : f32             = (*p_a_i_a_i_m_i)[i()];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..e08f4d5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,78 @@
+struct Inner {
+  float2x2 m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float2x2 tint_symbol_8(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  return float2x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)));
+}
+
+Inner tint_symbol_7(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_11 = {tint_symbol_8(buffer, (offset + 0u))};
+  return tint_symbol_11;
+}
+
+typedef Inner tint_symbol_6_ret[4];
+tint_symbol_6_ret tint_symbol_6(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_7(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_5(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_12 = {tint_symbol_6(buffer, (offset + 0u))};
+  return tint_symbol_12;
+}
+
+typedef Outer tint_symbol_4_ret[4];
+tint_symbol_4_ret tint_symbol_4(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
+      arr_1[i_2] = tint_symbol_5(buffer, (offset + (i_2 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_a_i_save = i();
+  const int p_a_i_a_i_m_i_save = i();
+  const Outer l_a[4] = tint_symbol_4(a, 0u);
+  const Outer l_a_i = tint_symbol_5(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a[4] = tint_symbol_6(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a_i = tint_symbol_7(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const float2x2 l_a_i_a_i_m = tint_symbol_8(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const uint scalar_offset_2 = ((((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))) + (8u * uint(p_a_i_a_i_m_i_save)))) / 4;
+  uint4 ubo_load_2 = a[scalar_offset_2 / 4];
+  const float2 l_a_i_a_i_m_i = asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy));
+  const int tint_symbol = p_a_i_save;
+  const int tint_symbol_1 = p_a_i_a_i_save;
+  const int tint_symbol_2 = p_a_i_a_i_m_i_save;
+  const int tint_symbol_3 = i();
+  const uint scalar_offset_3 = (((((256u * uint(tint_symbol)) + (64u * uint(tint_symbol_1))) + (8u * uint(tint_symbol_2))) + (4u * uint(tint_symbol_3)))) / 4;
+  const float l_a_i_a_i_m_i_i = asfloat(a[scalar_offset_3 / 4][scalar_offset_3 % 4]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..e08f4d5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,78 @@
+struct Inner {
+  float2x2 m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float2x2 tint_symbol_8(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  return float2x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)));
+}
+
+Inner tint_symbol_7(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_11 = {tint_symbol_8(buffer, (offset + 0u))};
+  return tint_symbol_11;
+}
+
+typedef Inner tint_symbol_6_ret[4];
+tint_symbol_6_ret tint_symbol_6(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_7(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_5(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_12 = {tint_symbol_6(buffer, (offset + 0u))};
+  return tint_symbol_12;
+}
+
+typedef Outer tint_symbol_4_ret[4];
+tint_symbol_4_ret tint_symbol_4(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
+      arr_1[i_2] = tint_symbol_5(buffer, (offset + (i_2 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_a_i_save = i();
+  const int p_a_i_a_i_m_i_save = i();
+  const Outer l_a[4] = tint_symbol_4(a, 0u);
+  const Outer l_a_i = tint_symbol_5(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a[4] = tint_symbol_6(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a_i = tint_symbol_7(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const float2x2 l_a_i_a_i_m = tint_symbol_8(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const uint scalar_offset_2 = ((((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))) + (8u * uint(p_a_i_a_i_m_i_save)))) / 4;
+  uint4 ubo_load_2 = a[scalar_offset_2 / 4];
+  const float2 l_a_i_a_i_m_i = asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy));
+  const int tint_symbol = p_a_i_save;
+  const int tint_symbol_1 = p_a_i_a_i_save;
+  const int tint_symbol_2 = p_a_i_a_i_m_i_save;
+  const int tint_symbol_3 = i();
+  const uint scalar_offset_3 = (((((256u * uint(tint_symbol)) + (64u * uint(tint_symbol_1))) + (8u * uint(tint_symbol_2))) + (4u * uint(tint_symbol_3)))) / 4;
+  const float l_a_i_a_i_m_i_i = asfloat(a[scalar_offset_3 / 4][scalar_offset_3 % 4]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/dynamic_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..92467b6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,146 @@
+#version 310 es
+
+struct Inner {
+  mat2 m;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+};
+
+struct Inner_std140 {
+  vec2 m_0;
+  vec2 m_1;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+};
+
+struct Outer {
+  Inner a[4];
+};
+
+struct Outer_std140 {
+  Inner_std140 a[4];
+};
+
+layout(binding = 0, std140) uniform a_block_std140_ubo {
+  Outer_std140 inner[4];
+} a;
+
+int counter = 0;
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+Inner conv_Inner(Inner_std140 val) {
+  return Inner(mat2(val.m_0, val.m_1), val.pad, val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.pad_11);
+}
+
+Inner[4] conv_arr4_Inner(Inner_std140 val[4]) {
+  Inner arr[4] = Inner[4](Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_Inner(val[i]);
+    }
+  }
+  return arr;
+}
+
+Outer conv_Outer(Outer_std140 val) {
+  return Outer(conv_arr4_Inner(val.a));
+}
+
+Outer[4] conv_arr4_Outer(Outer_std140 val[4]) {
+  Outer arr[4] = Outer[4](Outer(Inner[4](Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_Outer(val[i]);
+    }
+  }
+  return arr;
+}
+
+mat2 load_a_inner_p0_a_p1_m(uint p0, uint p1) {
+  uint s_save = p0;
+  uint s_save_1 = p1;
+  return mat2(a.inner[s_save].a[s_save_1].m_0, a.inner[s_save].a[s_save_1].m_1);
+}
+
+vec2 load_a_inner_p0_a_p1_m_p2(uint p0, uint p1, uint p2) {
+  switch(p2) {
+    case 0u: {
+      return a.inner[p0].a[p1].m_0;
+      break;
+    }
+    case 1u: {
+      return a.inner[p0].a[p1].m_1;
+      break;
+    }
+    default: {
+      return vec2(0.0f);
+      break;
+    }
+  }
+}
+
+float load_a_inner_p0_a_p1_m_p2_p3(uint p0, uint p1, uint p2, uint p3) {
+  switch(p2) {
+    case 0u: {
+      return a.inner[p0].a[p1].m_0[p3];
+      break;
+    }
+    case 1u: {
+      return a.inner[p0].a[p1].m_1[p3];
+      break;
+    }
+    default: {
+      return 0.0f;
+      break;
+    }
+  }
+}
+
+void f() {
+  Outer p_a[4] = conv_arr4_Outer(a.inner);
+  int tint_symbol = i();
+  Outer p_a_i = conv_Outer(a.inner[tint_symbol]);
+  Inner p_a_i_a[4] = conv_arr4_Inner(a.inner[tint_symbol].a);
+  int tint_symbol_1 = i();
+  Inner p_a_i_a_i = conv_Inner(a.inner[tint_symbol].a[tint_symbol_1]);
+  mat2 p_a_i_a_i_m = load_a_inner_p0_a_p1_m(uint(tint_symbol), uint(tint_symbol_1));
+  int tint_symbol_2 = i();
+  vec2 p_a_i_a_i_m_i = load_a_inner_p0_a_p1_m_p2(uint(tint_symbol), uint(tint_symbol_1), uint(tint_symbol_2));
+  Outer l_a[4] = conv_arr4_Outer(a.inner);
+  Outer l_a_i = conv_Outer(a.inner[tint_symbol]);
+  Inner l_a_i_a[4] = conv_arr4_Inner(a.inner[tint_symbol].a);
+  Inner l_a_i_a_i = conv_Inner(a.inner[tint_symbol].a[tint_symbol_1]);
+  mat2 l_a_i_a_i_m = load_a_inner_p0_a_p1_m(uint(tint_symbol), uint(tint_symbol_1));
+  vec2 l_a_i_a_i_m_i = load_a_inner_p0_a_p1_m_p2(uint(tint_symbol), uint(tint_symbol_1), uint(tint_symbol_2));
+  int tint_symbol_3 = i();
+  float l_a_i_a_i_m_i_i = load_a_inner_p0_a_p1_m_p2_p3(uint(tint_symbol), uint(tint_symbol_1), uint(tint_symbol_2), uint(tint_symbol_3));
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/dynamic_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..56ba8da
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/dynamic_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,49 @@
+#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 Inner {
+  /* 0x0000 */ float2x2 m;
+  /* 0x0010 */ tint_array<int8_t, 48> tint_pad;
+};
+
+struct Outer {
+  /* 0x0000 */ tint_array<Inner, 4> a;
+};
+
+int i() {
+  thread int tint_symbol_4 = 0;
+  tint_symbol_4 = as_type<int>((as_type<uint>(tint_symbol_4) + as_type<uint>(1)));
+  return tint_symbol_4;
+}
+
+kernel void f(const constant tint_array<Outer, 4>* tint_symbol_5 [[buffer(0)]]) {
+  int const tint_symbol = i();
+  int const p_a_i_save = tint_symbol;
+  int const tint_symbol_1 = i();
+  int const p_a_i_a_i_save = tint_symbol_1;
+  int const tint_symbol_2 = i();
+  int const p_a_i_a_i_m_i_save = tint_symbol_2;
+  tint_array<Outer, 4> const l_a = *(tint_symbol_5);
+  Outer const l_a_i = (*(tint_symbol_5))[p_a_i_save];
+  tint_array<Inner, 4> const l_a_i_a = (*(tint_symbol_5))[p_a_i_save].a;
+  Inner const l_a_i_a_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save];
+  float2x2 const l_a_i_a_i_m = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m;
+  float2 const l_a_i_a_i_m_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save];
+  int const tint_symbol_3 = i();
+  float const l_a_i_a_i_m_i_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save][tint_symbol_3];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..ca17b0c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,306 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 193
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block_std140 "a_block_std140"
+               OpMemberName %a_block_std140 0 "inner"
+               OpName %Outer_std140 "Outer_std140"
+               OpMemberName %Outer_std140 0 "a"
+               OpName %Inner_std140 "Inner_std140"
+               OpMemberName %Inner_std140 0 "m_0"
+               OpMemberName %Inner_std140 1 "m_1"
+               OpName %a "a"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %Inner "Inner"
+               OpMemberName %Inner 0 "m"
+               OpName %conv_Inner "conv_Inner"
+               OpName %val "val"
+               OpName %conv_arr4_Inner "conv_arr4_Inner"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i_0 "i"
+               OpName %var_for_index_1 "var_for_index_1"
+               OpName %Outer "Outer"
+               OpMemberName %Outer 0 "a"
+               OpName %conv_Outer "conv_Outer"
+               OpName %val_1 "val"
+               OpName %conv_arr4_Outer "conv_arr4_Outer"
+               OpName %val_2 "val"
+               OpName %arr_0 "arr"
+               OpName %i_1 "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_a_inner_p0_a_p1_m "load_a_inner_p0_a_p1_m"
+               OpName %p0 "p0"
+               OpName %p1 "p1"
+               OpName %load_a_inner_p0_a_p1_m_p2 "load_a_inner_p0_a_p1_m_p2"
+               OpName %p0_0 "p0"
+               OpName %p1_0 "p1"
+               OpName %p2 "p2"
+               OpName %load_a_inner_p0_a_p1_m_p2_p3 "load_a_inner_p0_a_p1_m_p2_p3"
+               OpName %p0_1 "p0"
+               OpName %p1_1 "p1"
+               OpName %p2_0 "p2"
+               OpName %p3 "p3"
+               OpName %f "f"
+               OpDecorate %a_block_std140 Block
+               OpMemberDecorate %a_block_std140 0 Offset 0
+               OpMemberDecorate %Outer_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 1 Offset 8
+               OpDecorate %_arr_Inner_std140_uint_4 ArrayStride 64
+               OpDecorate %_arr_Outer_std140_uint_4 ArrayStride 256
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+               OpMemberDecorate %Inner 0 Offset 0
+               OpMemberDecorate %Inner 0 ColMajor
+               OpMemberDecorate %Inner 0 MatrixStride 8
+               OpDecorate %_arr_Inner_uint_4 ArrayStride 64
+               OpMemberDecorate %Outer 0 Offset 0
+               OpDecorate %_arr_Outer_uint_4 ArrayStride 256
+      %float = OpTypeFloat 32
+    %v2float = OpTypeVector %float 2
+%Inner_std140 = OpTypeStruct %v2float %v2float
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_Inner_std140_uint_4 = OpTypeArray %Inner_std140 %uint_4
+%Outer_std140 = OpTypeStruct %_arr_Inner_std140_uint_4
+%_arr_Outer_std140_uint_4 = OpTypeArray %Outer_std140 %uint_4
+%a_block_std140 = OpTypeStruct %_arr_Outer_std140_uint_4
+%_ptr_Uniform_a_block_std140 = OpTypePointer Uniform %a_block_std140
+          %a = OpVariable %_ptr_Uniform_a_block_std140 Uniform
+        %int = OpTypeInt 32 1
+         %13 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %13
+         %16 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+%mat2v2float = OpTypeMatrix %v2float 2
+      %Inner = OpTypeStruct %mat2v2float
+         %23 = OpTypeFunction %Inner %Inner_std140
+%_arr_Inner_uint_4 = OpTypeArray %Inner %uint_4
+         %33 = OpTypeFunction %_arr_Inner_uint_4 %_arr_Inner_std140_uint_4
+%_ptr_Function__arr_Inner_uint_4 = OpTypePointer Function %_arr_Inner_uint_4
+         %40 = OpConstantNull %_arr_Inner_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %43 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_Inner_std140_uint_4 = OpTypePointer Function %_arr_Inner_std140_uint_4
+         %56 = OpConstantNull %_arr_Inner_std140_uint_4
+%_ptr_Function_Inner = OpTypePointer Function %Inner
+%_ptr_Function_Inner_std140 = OpTypePointer Function %Inner_std140
+     %uint_1 = OpConstant %uint 1
+      %Outer = OpTypeStruct %_arr_Inner_uint_4
+         %69 = OpTypeFunction %Outer %Outer_std140
+%_arr_Outer_uint_4 = OpTypeArray %Outer %uint_4
+         %77 = OpTypeFunction %_arr_Outer_uint_4 %_arr_Outer_std140_uint_4
+%_ptr_Function__arr_Outer_uint_4 = OpTypePointer Function %_arr_Outer_uint_4
+         %84 = OpConstantNull %_arr_Outer_uint_4
+%_ptr_Function__arr_Outer_std140_uint_4 = OpTypePointer Function %_arr_Outer_std140_uint_4
+         %97 = OpConstantNull %_arr_Outer_std140_uint_4
+%_ptr_Function_Outer = OpTypePointer Function %Outer
+%_ptr_Function_Outer_std140 = OpTypePointer Function %Outer_std140
+        %109 = OpTypeFunction %mat2v2float %uint %uint
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_Inner_std140 = OpTypePointer Uniform %Inner_std140
+%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
+        %126 = OpTypeFunction %v2float %uint %uint %uint
+        %140 = OpConstantNull %v2float
+        %141 = OpTypeFunction %float %uint %uint %uint %uint
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+        %157 = OpConstantNull %float
+       %void = OpTypeVoid
+        %158 = OpTypeFunction %void
+%_ptr_Uniform__arr_Outer_std140_uint_4 = OpTypePointer Uniform %_arr_Outer_std140_uint_4
+%_ptr_Uniform_Outer_std140 = OpTypePointer Uniform %Outer_std140
+%_ptr_Uniform__arr_Inner_std140_uint_4 = OpTypePointer Uniform %_arr_Inner_std140_uint_4
+          %i = OpFunction %int None %16
+         %18 = OpLabel
+         %19 = OpLoad %int %counter
+         %21 = OpIAdd %int %19 %int_1
+               OpStore %counter %21
+         %22 = OpLoad %int %counter
+               OpReturnValue %22
+               OpFunctionEnd
+ %conv_Inner = OpFunction %Inner None %23
+        %val = OpFunctionParameter %Inner_std140
+         %28 = OpLabel
+         %29 = OpCompositeExtract %v2float %val 0
+         %30 = OpCompositeExtract %v2float %val 1
+         %31 = OpCompositeConstruct %mat2v2float %29 %30
+         %32 = OpCompositeConstruct %Inner %31
+               OpReturnValue %32
+               OpFunctionEnd
+%conv_arr4_Inner = OpFunction %_arr_Inner_uint_4 None %33
+      %val_0 = OpFunctionParameter %_arr_Inner_std140_uint_4
+         %37 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_Inner_uint_4 Function %40
+        %i_0 = OpVariable %_ptr_Function_uint Function %43
+%var_for_index_1 = OpVariable %_ptr_Function__arr_Inner_std140_uint_4 Function %56
+               OpBranch %44
+         %44 = OpLabel
+               OpLoopMerge %45 %46 None
+               OpBranch %47
+         %47 = OpLabel
+         %49 = OpLoad %uint %i_0
+         %50 = OpULessThan %bool %49 %uint_4
+         %48 = OpLogicalNot %bool %50
+               OpSelectionMerge %52 None
+               OpBranchConditional %48 %53 %52
+         %53 = OpLabel
+               OpBranch %45
+         %52 = OpLabel
+               OpStore %var_for_index_1 %val_0
+         %57 = OpLoad %uint %i_0
+         %59 = OpAccessChain %_ptr_Function_Inner %arr %57
+         %61 = OpLoad %uint %i_0
+         %63 = OpAccessChain %_ptr_Function_Inner_std140 %var_for_index_1 %61
+         %64 = OpLoad %Inner_std140 %63
+         %60 = OpFunctionCall %Inner %conv_Inner %64
+               OpStore %59 %60
+               OpBranch %46
+         %46 = OpLabel
+         %65 = OpLoad %uint %i_0
+         %67 = OpIAdd %uint %65 %uint_1
+               OpStore %i_0 %67
+               OpBranch %44
+         %45 = OpLabel
+         %68 = OpLoad %_arr_Inner_uint_4 %arr
+               OpReturnValue %68
+               OpFunctionEnd
+ %conv_Outer = OpFunction %Outer None %69
+      %val_1 = OpFunctionParameter %Outer_std140
+         %73 = OpLabel
+         %75 = OpCompositeExtract %_arr_Inner_std140_uint_4 %val_1 0
+         %74 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %75
+         %76 = OpCompositeConstruct %Outer %74
+               OpReturnValue %76
+               OpFunctionEnd
+%conv_arr4_Outer = OpFunction %_arr_Outer_uint_4 None %77
+      %val_2 = OpFunctionParameter %_arr_Outer_std140_uint_4
+         %81 = OpLabel
+      %arr_0 = OpVariable %_ptr_Function__arr_Outer_uint_4 Function %84
+        %i_1 = OpVariable %_ptr_Function_uint Function %43
+%var_for_index = OpVariable %_ptr_Function__arr_Outer_std140_uint_4 Function %97
+               OpBranch %86
+         %86 = OpLabel
+               OpLoopMerge %87 %88 None
+               OpBranch %89
+         %89 = OpLabel
+         %91 = OpLoad %uint %i_1
+         %92 = OpULessThan %bool %91 %uint_4
+         %90 = OpLogicalNot %bool %92
+               OpSelectionMerge %93 None
+               OpBranchConditional %90 %94 %93
+         %94 = OpLabel
+               OpBranch %87
+         %93 = OpLabel
+               OpStore %var_for_index %val_2
+         %98 = OpLoad %uint %i_1
+        %100 = OpAccessChain %_ptr_Function_Outer %arr_0 %98
+        %102 = OpLoad %uint %i_1
+        %104 = OpAccessChain %_ptr_Function_Outer_std140 %var_for_index %102
+        %105 = OpLoad %Outer_std140 %104
+        %101 = OpFunctionCall %Outer %conv_Outer %105
+               OpStore %100 %101
+               OpBranch %88
+         %88 = OpLabel
+        %106 = OpLoad %uint %i_1
+        %107 = OpIAdd %uint %106 %uint_1
+               OpStore %i_1 %107
+               OpBranch %86
+         %87 = OpLabel
+        %108 = OpLoad %_arr_Outer_uint_4 %arr_0
+               OpReturnValue %108
+               OpFunctionEnd
+%load_a_inner_p0_a_p1_m = OpFunction %mat2v2float None %109
+         %p0 = OpFunctionParameter %uint
+         %p1 = OpFunctionParameter %uint
+        %113 = OpLabel
+        %117 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %p0 %uint_0 %p1
+        %120 = OpAccessChain %_ptr_Uniform_v2float %117 %uint_0
+        %121 = OpLoad %v2float %120
+        %123 = OpAccessChain %_ptr_Uniform_v2float %117 %uint_1
+        %124 = OpLoad %v2float %123
+        %125 = OpCompositeConstruct %mat2v2float %121 %124
+               OpReturnValue %125
+               OpFunctionEnd
+%load_a_inner_p0_a_p1_m_p2 = OpFunction %v2float None %126
+       %p0_0 = OpFunctionParameter %uint
+       %p1_0 = OpFunctionParameter %uint
+         %p2 = OpFunctionParameter %uint
+        %131 = OpLabel
+               OpSelectionMerge %132 None
+               OpSwitch %p2 %133 0 %134 1 %135
+        %134 = OpLabel
+        %136 = OpAccessChain %_ptr_Uniform_v2float %a %uint_0 %p0_0 %uint_0 %p1_0 %uint_0
+        %137 = OpLoad %v2float %136
+               OpReturnValue %137
+        %135 = OpLabel
+        %138 = OpAccessChain %_ptr_Uniform_v2float %a %uint_0 %p0_0 %uint_0 %p1_0 %uint_1
+        %139 = OpLoad %v2float %138
+               OpReturnValue %139
+        %133 = OpLabel
+               OpReturnValue %140
+        %132 = OpLabel
+               OpReturnValue %140
+               OpFunctionEnd
+%load_a_inner_p0_a_p1_m_p2_p3 = OpFunction %float None %141
+       %p0_1 = OpFunctionParameter %uint
+       %p1_1 = OpFunctionParameter %uint
+       %p2_0 = OpFunctionParameter %uint
+         %p3 = OpFunctionParameter %uint
+        %147 = OpLabel
+               OpSelectionMerge %148 None
+               OpSwitch %p2_0 %149 0 %150 1 %151
+        %150 = OpLabel
+        %153 = OpAccessChain %_ptr_Uniform_float %a %uint_0 %p0_1 %uint_0 %p1_1 %uint_0 %p3
+        %154 = OpLoad %float %153
+               OpReturnValue %154
+        %151 = OpLabel
+        %155 = OpAccessChain %_ptr_Uniform_float %a %uint_0 %p0_1 %uint_0 %p1_1 %uint_1 %p3
+        %156 = OpLoad %float %155
+               OpReturnValue %156
+        %149 = OpLabel
+               OpReturnValue %157
+        %148 = OpLabel
+               OpReturnValue %157
+               OpFunctionEnd
+          %f = OpFunction %void None %158
+        %161 = OpLabel
+        %162 = OpFunctionCall %int %i
+        %163 = OpFunctionCall %int %i
+        %164 = OpFunctionCall %int %i
+        %167 = OpAccessChain %_ptr_Uniform__arr_Outer_std140_uint_4 %a %uint_0
+        %168 = OpLoad %_arr_Outer_std140_uint_4 %167
+        %165 = OpFunctionCall %_arr_Outer_uint_4 %conv_arr4_Outer %168
+        %171 = OpAccessChain %_ptr_Uniform_Outer_std140 %a %uint_0 %162
+        %172 = OpLoad %Outer_std140 %171
+        %169 = OpFunctionCall %Outer %conv_Outer %172
+        %175 = OpAccessChain %_ptr_Uniform__arr_Inner_std140_uint_4 %a %uint_0 %162 %uint_0
+        %176 = OpLoad %_arr_Inner_std140_uint_4 %175
+        %173 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %176
+        %178 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %162 %uint_0 %163
+        %179 = OpLoad %Inner_std140 %178
+        %177 = OpFunctionCall %Inner %conv_Inner %179
+        %181 = OpBitcast %uint %162
+        %182 = OpBitcast %uint %163
+        %180 = OpFunctionCall %mat2v2float %load_a_inner_p0_a_p1_m %181 %182
+        %184 = OpBitcast %uint %162
+        %185 = OpBitcast %uint %163
+        %186 = OpBitcast %uint %164
+        %183 = OpFunctionCall %v2float %load_a_inner_p0_a_p1_m_p2 %184 %185 %186
+        %187 = OpFunctionCall %int %i
+        %189 = OpBitcast %uint %162
+        %190 = OpBitcast %uint %163
+        %191 = OpBitcast %uint %164
+        %192 = OpBitcast %uint %187
+        %188 = OpFunctionCall %float %load_a_inner_p0_a_p1_m_p2_p3 %189 %190 %191 %192
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..ac4c714
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,34 @@
+struct Inner {
+  @size(64)
+  m : mat2x2<f32>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_i = &((*(p_a))[i()]);
+  let p_a_i_a = &((*(p_a_i)).a);
+  let p_a_i_a_i = &((*(p_a_i_a))[i()]);
+  let p_a_i_a_i_m = &((*(p_a_i_a_i)).m);
+  let p_a_i_a_i_m_i = &((*(p_a_i_a_i_m))[i()]);
+  let l_a : array<Outer, 4> = *(p_a);
+  let l_a_i : Outer = *(p_a_i);
+  let l_a_i_a : array<Inner, 4> = *(p_a_i_a);
+  let l_a_i_a_i : Inner = *(p_a_i_a_i);
+  let l_a_i_a_i_m : mat2x2<f32> = *(p_a_i_a_i_m);
+  let l_a_i_a_i_m_i : vec2<f32> = *(p_a_i_a_i_m_i);
+  let l_a_i_a_i_m_i_i : f32 = (*(p_a_i_a_i_m_i))[i()];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/static_index_via_ptr.wgsl
new file mode 100644
index 0000000..98f52eb
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/static_index_via_ptr.wgsl
@@ -0,0 +1,29 @@
+struct Inner {
+  @size(64)
+  m : mat2x2<f32>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &a;
+  let p_a_3 = &((*p_a)[3]);
+  let p_a_3_a = &((*p_a_3).a);
+  let p_a_3_a_2 = &((*p_a_3_a)[2]);
+  let p_a_3_a_2_m = &((*p_a_3_a_2).m);
+  let p_a_3_a_2_m_1 = &((*p_a_3_a_2_m)[1]);
+
+
+  let l_a             : array<Outer, 4> = *p_a;
+  let l_a_3           : Outer           = *p_a_3;
+  let l_a_3_a         : array<Inner, 4> = *p_a_3_a;
+  let l_a_3_a_2       : Inner           = *p_a_3_a_2;
+  let l_a_3_a_2_m     : mat2x2<f32>     = *p_a_3_a_2_m;
+  let l_a_3_a_2_m_1   : vec2<f32>       = *p_a_3_a_2_m_1;
+  let l_a_3_a_2_m_1_0 : f32             = (*p_a_3_a_2_m_1)[0];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..e732e83
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,62 @@
+struct Inner {
+  float2x2 m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+
+float2x2 tint_symbol_4(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  return float2x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)));
+}
+
+Inner tint_symbol_3(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_7 = {tint_symbol_4(buffer, (offset + 0u))};
+  return tint_symbol_7;
+}
+
+typedef Inner tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_3(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_1(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_8 = {tint_symbol_2(buffer, (offset + 0u))};
+  return tint_symbol_8;
+}
+
+typedef Outer tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr_1[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const Outer l_a[4] = tint_symbol(a, 0u);
+  const Outer l_a_3 = tint_symbol_1(a, 768u);
+  const Inner l_a_3_a[4] = tint_symbol_2(a, 768u);
+  const Inner l_a_3_a_2 = tint_symbol_3(a, 896u);
+  const float2x2 l_a_3_a_2_m = tint_symbol_4(a, 896u);
+  const float2 l_a_3_a_2_m_1 = asfloat(a[56].zw);
+  const float l_a_3_a_2_m_1_0 = asfloat(a[56].z);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..e732e83
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,62 @@
+struct Inner {
+  float2x2 m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+
+float2x2 tint_symbol_4(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  return float2x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)));
+}
+
+Inner tint_symbol_3(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_7 = {tint_symbol_4(buffer, (offset + 0u))};
+  return tint_symbol_7;
+}
+
+typedef Inner tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_3(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_1(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_8 = {tint_symbol_2(buffer, (offset + 0u))};
+  return tint_symbol_8;
+}
+
+typedef Outer tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr_1[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const Outer l_a[4] = tint_symbol(a, 0u);
+  const Outer l_a_3 = tint_symbol_1(a, 768u);
+  const Inner l_a_3_a[4] = tint_symbol_2(a, 768u);
+  const Inner l_a_3_a_2 = tint_symbol_3(a, 896u);
+  const float2x2 l_a_3_a_2_m = tint_symbol_4(a, 896u);
+  const float2 l_a_3_a_2_m_1 = asfloat(a[56].zw);
+  const float l_a_3_a_2_m_1_0 = asfloat(a[56].z);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/static_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..41496f7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/static_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,100 @@
+#version 310 es
+
+struct Inner {
+  mat2 m;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+};
+
+struct Inner_std140 {
+  vec2 m_0;
+  vec2 m_1;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+};
+
+struct Outer {
+  Inner a[4];
+};
+
+struct Outer_std140 {
+  Inner_std140 a[4];
+};
+
+layout(binding = 0, std140) uniform a_block_std140_ubo {
+  Outer_std140 inner[4];
+} a;
+
+Inner conv_Inner(Inner_std140 val) {
+  return Inner(mat2(val.m_0, val.m_1), val.pad, val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.pad_11);
+}
+
+Inner[4] conv_arr4_Inner(Inner_std140 val[4]) {
+  Inner arr[4] = Inner[4](Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_Inner(val[i]);
+    }
+  }
+  return arr;
+}
+
+Outer conv_Outer(Outer_std140 val) {
+  return Outer(conv_arr4_Inner(val.a));
+}
+
+Outer[4] conv_arr4_Outer(Outer_std140 val[4]) {
+  Outer arr[4] = Outer[4](Outer(Inner[4](Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_Outer(val[i]);
+    }
+  }
+  return arr;
+}
+
+mat2 load_a_inner_3_a_2_m() {
+  return mat2(a.inner[3u].a[2u].m_0, a.inner[3u].a[2u].m_1);
+}
+
+void f() {
+  Outer p_a[4] = conv_arr4_Outer(a.inner);
+  Outer p_a_3 = conv_Outer(a.inner[3u]);
+  Inner p_a_3_a[4] = conv_arr4_Inner(a.inner[3u].a);
+  Inner p_a_3_a_2 = conv_Inner(a.inner[3u].a[2u]);
+  mat2 p_a_3_a_2_m = load_a_inner_3_a_2_m();
+  vec2 p_a_3_a_2_m_1 = a.inner[3u].a[2u].m_1;
+  Outer l_a[4] = conv_arr4_Outer(a.inner);
+  Outer l_a_3 = conv_Outer(a.inner[3u]);
+  Inner l_a_3_a[4] = conv_arr4_Inner(a.inner[3u].a);
+  Inner l_a_3_a_2 = conv_Inner(a.inner[3u].a[2u]);
+  mat2 l_a_3_a_2_m = load_a_inner_3_a_2_m();
+  vec2 l_a_3_a_2_m_1 = a.inner[3u].a[2u].m_1;
+  float l_a_3_a_2_m_1_0 = a.inner[3u].a[2u].m_1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/static_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..9b0f4f1
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/static_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,36 @@
+#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 Inner {
+  /* 0x0000 */ float2x2 m;
+  /* 0x0010 */ tint_array<int8_t, 48> tint_pad;
+};
+
+struct Outer {
+  /* 0x0000 */ tint_array<Inner, 4> a;
+};
+
+kernel void f(const constant tint_array<Outer, 4>* tint_symbol [[buffer(0)]]) {
+  tint_array<Outer, 4> const l_a = *(tint_symbol);
+  Outer const l_a_3 = (*(tint_symbol))[3];
+  tint_array<Inner, 4> const l_a_3_a = (*(tint_symbol))[3].a;
+  Inner const l_a_3_a_2 = (*(tint_symbol))[3].a[2];
+  float2x2 const l_a_3_a_2_m = (*(tint_symbol))[3].a[2].m;
+  float2 const l_a_3_a_2_m_1 = (*(tint_symbol))[3].a[2].m[1];
+  float const l_a_3_a_2_m_1_0 = (*(tint_symbol))[3].a[2].m[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/static_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..120d1f3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/static_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,223 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 140
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block_std140 "a_block_std140"
+               OpMemberName %a_block_std140 0 "inner"
+               OpName %Outer_std140 "Outer_std140"
+               OpMemberName %Outer_std140 0 "a"
+               OpName %Inner_std140 "Inner_std140"
+               OpMemberName %Inner_std140 0 "m_0"
+               OpMemberName %Inner_std140 1 "m_1"
+               OpName %a "a"
+               OpName %Inner "Inner"
+               OpMemberName %Inner 0 "m"
+               OpName %conv_Inner "conv_Inner"
+               OpName %val "val"
+               OpName %conv_arr4_Inner "conv_arr4_Inner"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index_1 "var_for_index_1"
+               OpName %Outer "Outer"
+               OpMemberName %Outer 0 "a"
+               OpName %conv_Outer "conv_Outer"
+               OpName %val_1 "val"
+               OpName %conv_arr4_Outer "conv_arr4_Outer"
+               OpName %val_2 "val"
+               OpName %arr_0 "arr"
+               OpName %i_0 "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_a_inner_3_a_2_m "load_a_inner_3_a_2_m"
+               OpName %f "f"
+               OpDecorate %a_block_std140 Block
+               OpMemberDecorate %a_block_std140 0 Offset 0
+               OpMemberDecorate %Outer_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 1 Offset 8
+               OpDecorate %_arr_Inner_std140_uint_4 ArrayStride 64
+               OpDecorate %_arr_Outer_std140_uint_4 ArrayStride 256
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+               OpMemberDecorate %Inner 0 Offset 0
+               OpMemberDecorate %Inner 0 ColMajor
+               OpMemberDecorate %Inner 0 MatrixStride 8
+               OpDecorate %_arr_Inner_uint_4 ArrayStride 64
+               OpMemberDecorate %Outer 0 Offset 0
+               OpDecorate %_arr_Outer_uint_4 ArrayStride 256
+      %float = OpTypeFloat 32
+    %v2float = OpTypeVector %float 2
+%Inner_std140 = OpTypeStruct %v2float %v2float
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_Inner_std140_uint_4 = OpTypeArray %Inner_std140 %uint_4
+%Outer_std140 = OpTypeStruct %_arr_Inner_std140_uint_4
+%_arr_Outer_std140_uint_4 = OpTypeArray %Outer_std140 %uint_4
+%a_block_std140 = OpTypeStruct %_arr_Outer_std140_uint_4
+%_ptr_Uniform_a_block_std140 = OpTypePointer Uniform %a_block_std140
+          %a = OpVariable %_ptr_Uniform_a_block_std140 Uniform
+%mat2v2float = OpTypeMatrix %v2float 2
+      %Inner = OpTypeStruct %mat2v2float
+         %12 = OpTypeFunction %Inner %Inner_std140
+%_arr_Inner_uint_4 = OpTypeArray %Inner %uint_4
+         %22 = OpTypeFunction %_arr_Inner_uint_4 %_arr_Inner_std140_uint_4
+%_ptr_Function__arr_Inner_uint_4 = OpTypePointer Function %_arr_Inner_uint_4
+         %29 = OpConstantNull %_arr_Inner_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %32 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_Inner_std140_uint_4 = OpTypePointer Function %_arr_Inner_std140_uint_4
+         %45 = OpConstantNull %_arr_Inner_std140_uint_4
+%_ptr_Function_Inner = OpTypePointer Function %Inner
+%_ptr_Function_Inner_std140 = OpTypePointer Function %Inner_std140
+     %uint_1 = OpConstant %uint 1
+      %Outer = OpTypeStruct %_arr_Inner_uint_4
+         %58 = OpTypeFunction %Outer %Outer_std140
+%_arr_Outer_uint_4 = OpTypeArray %Outer %uint_4
+         %66 = OpTypeFunction %_arr_Outer_uint_4 %_arr_Outer_std140_uint_4
+%_ptr_Function__arr_Outer_uint_4 = OpTypePointer Function %_arr_Outer_uint_4
+         %73 = OpConstantNull %_arr_Outer_uint_4
+%_ptr_Function__arr_Outer_std140_uint_4 = OpTypePointer Function %_arr_Outer_std140_uint_4
+         %86 = OpConstantNull %_arr_Outer_std140_uint_4
+%_ptr_Function_Outer = OpTypePointer Function %Outer
+%_ptr_Function_Outer_std140 = OpTypePointer Function %Outer_std140
+         %98 = OpTypeFunction %mat2v2float
+     %uint_0 = OpConstant %uint 0
+     %uint_3 = OpConstant %uint 3
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_Inner_std140 = OpTypePointer Uniform %Inner_std140
+%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
+       %void = OpTypeVoid
+        %115 = OpTypeFunction %void
+%_ptr_Uniform__arr_Outer_std140_uint_4 = OpTypePointer Uniform %_arr_Outer_std140_uint_4
+%_ptr_Uniform_Outer_std140 = OpTypePointer Uniform %Outer_std140
+%_ptr_Uniform__arr_Inner_std140_uint_4 = OpTypePointer Uniform %_arr_Inner_std140_uint_4
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+ %conv_Inner = OpFunction %Inner None %12
+        %val = OpFunctionParameter %Inner_std140
+         %17 = OpLabel
+         %18 = OpCompositeExtract %v2float %val 0
+         %19 = OpCompositeExtract %v2float %val 1
+         %20 = OpCompositeConstruct %mat2v2float %18 %19
+         %21 = OpCompositeConstruct %Inner %20
+               OpReturnValue %21
+               OpFunctionEnd
+%conv_arr4_Inner = OpFunction %_arr_Inner_uint_4 None %22
+      %val_0 = OpFunctionParameter %_arr_Inner_std140_uint_4
+         %26 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_Inner_uint_4 Function %29
+          %i = OpVariable %_ptr_Function_uint Function %32
+%var_for_index_1 = OpVariable %_ptr_Function__arr_Inner_std140_uint_4 Function %45
+               OpBranch %33
+         %33 = OpLabel
+               OpLoopMerge %34 %35 None
+               OpBranch %36
+         %36 = OpLabel
+         %38 = OpLoad %uint %i
+         %39 = OpULessThan %bool %38 %uint_4
+         %37 = OpLogicalNot %bool %39
+               OpSelectionMerge %41 None
+               OpBranchConditional %37 %42 %41
+         %42 = OpLabel
+               OpBranch %34
+         %41 = OpLabel
+               OpStore %var_for_index_1 %val_0
+         %46 = OpLoad %uint %i
+         %48 = OpAccessChain %_ptr_Function_Inner %arr %46
+         %50 = OpLoad %uint %i
+         %52 = OpAccessChain %_ptr_Function_Inner_std140 %var_for_index_1 %50
+         %53 = OpLoad %Inner_std140 %52
+         %49 = OpFunctionCall %Inner %conv_Inner %53
+               OpStore %48 %49
+               OpBranch %35
+         %35 = OpLabel
+         %54 = OpLoad %uint %i
+         %56 = OpIAdd %uint %54 %uint_1
+               OpStore %i %56
+               OpBranch %33
+         %34 = OpLabel
+         %57 = OpLoad %_arr_Inner_uint_4 %arr
+               OpReturnValue %57
+               OpFunctionEnd
+ %conv_Outer = OpFunction %Outer None %58
+      %val_1 = OpFunctionParameter %Outer_std140
+         %62 = OpLabel
+         %64 = OpCompositeExtract %_arr_Inner_std140_uint_4 %val_1 0
+         %63 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %64
+         %65 = OpCompositeConstruct %Outer %63
+               OpReturnValue %65
+               OpFunctionEnd
+%conv_arr4_Outer = OpFunction %_arr_Outer_uint_4 None %66
+      %val_2 = OpFunctionParameter %_arr_Outer_std140_uint_4
+         %70 = OpLabel
+      %arr_0 = OpVariable %_ptr_Function__arr_Outer_uint_4 Function %73
+        %i_0 = OpVariable %_ptr_Function_uint Function %32
+%var_for_index = OpVariable %_ptr_Function__arr_Outer_std140_uint_4 Function %86
+               OpBranch %75
+         %75 = OpLabel
+               OpLoopMerge %76 %77 None
+               OpBranch %78
+         %78 = OpLabel
+         %80 = OpLoad %uint %i_0
+         %81 = OpULessThan %bool %80 %uint_4
+         %79 = OpLogicalNot %bool %81
+               OpSelectionMerge %82 None
+               OpBranchConditional %79 %83 %82
+         %83 = OpLabel
+               OpBranch %76
+         %82 = OpLabel
+               OpStore %var_for_index %val_2
+         %87 = OpLoad %uint %i_0
+         %89 = OpAccessChain %_ptr_Function_Outer %arr_0 %87
+         %91 = OpLoad %uint %i_0
+         %93 = OpAccessChain %_ptr_Function_Outer_std140 %var_for_index %91
+         %94 = OpLoad %Outer_std140 %93
+         %90 = OpFunctionCall %Outer %conv_Outer %94
+               OpStore %89 %90
+               OpBranch %77
+         %77 = OpLabel
+         %95 = OpLoad %uint %i_0
+         %96 = OpIAdd %uint %95 %uint_1
+               OpStore %i_0 %96
+               OpBranch %75
+         %76 = OpLabel
+         %97 = OpLoad %_arr_Outer_uint_4 %arr_0
+               OpReturnValue %97
+               OpFunctionEnd
+%load_a_inner_3_a_2_m = OpFunction %mat2v2float None %98
+        %100 = OpLabel
+        %106 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %uint_3 %uint_0 %uint_2
+        %109 = OpAccessChain %_ptr_Uniform_v2float %106 %uint_0
+        %110 = OpLoad %v2float %109
+        %112 = OpAccessChain %_ptr_Uniform_v2float %106 %uint_1
+        %113 = OpLoad %v2float %112
+        %114 = OpCompositeConstruct %mat2v2float %110 %113
+               OpReturnValue %114
+               OpFunctionEnd
+          %f = OpFunction %void None %115
+        %118 = OpLabel
+        %121 = OpAccessChain %_ptr_Uniform__arr_Outer_std140_uint_4 %a %uint_0
+        %122 = OpLoad %_arr_Outer_std140_uint_4 %121
+        %119 = OpFunctionCall %_arr_Outer_uint_4 %conv_arr4_Outer %122
+        %125 = OpAccessChain %_ptr_Uniform_Outer_std140 %a %uint_0 %uint_3
+        %126 = OpLoad %Outer_std140 %125
+        %123 = OpFunctionCall %Outer %conv_Outer %126
+        %129 = OpAccessChain %_ptr_Uniform__arr_Inner_std140_uint_4 %a %uint_0 %uint_3 %uint_0
+        %130 = OpLoad %_arr_Inner_std140_uint_4 %129
+        %127 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %130
+        %132 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %uint_3 %uint_0 %uint_2
+        %133 = OpLoad %Inner_std140 %132
+        %131 = OpFunctionCall %Inner %conv_Inner %133
+        %134 = OpFunctionCall %mat2v2float %load_a_inner_3_a_2_m
+        %135 = OpAccessChain %_ptr_Uniform_v2float %a %uint_0 %uint_3 %uint_0 %uint_2 %uint_1
+        %136 = OpLoad %v2float %135
+        %138 = OpAccessChain %_ptr_Uniform_float %a %uint_0 %uint_3 %uint_0 %uint_2 %uint_1 %32
+        %139 = OpLoad %float %138
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/static_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..ca6c191
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/static_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,27 @@
+struct Inner {
+  @size(64)
+  m : mat2x2<f32>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_3 = &((*(p_a))[3]);
+  let p_a_3_a = &((*(p_a_3)).a);
+  let p_a_3_a_2 = &((*(p_a_3_a))[2]);
+  let p_a_3_a_2_m = &((*(p_a_3_a_2)).m);
+  let p_a_3_a_2_m_1 = &((*(p_a_3_a_2_m))[1]);
+  let l_a : array<Outer, 4> = *(p_a);
+  let l_a_3 : Outer = *(p_a_3);
+  let l_a_3_a : array<Inner, 4> = *(p_a_3_a);
+  let l_a_3_a_2 : Inner = *(p_a_3_a_2);
+  let l_a_3_a_2_m : mat2x2<f32> = *(p_a_3_a_2_m);
+  let l_a_3_a_2_m_1 : vec2<f32> = *(p_a_3_a_2_m_1);
+  let l_a_3_a_2_m_1_0 : f32 = (*(p_a_3_a_2_m_1))[0];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_builtin.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_builtin.wgsl
new file mode 100644
index 0000000..625dd07
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_builtin.wgsl
@@ -0,0 +1,15 @@
+struct S {
+  before : i32,
+  m : mat2x2<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    let t = transpose(u[2].m);
+    let l = length(u[0].m[1].yx);
+    let a = abs(u[0].m[1].yx.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_builtin.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..a6813b0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_builtin.wgsl.expected.dxc.hlsl
@@ -0,0 +1,19 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+float2x2 tint_symbol(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  return float2x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float2x2 t = transpose(tint_symbol(u, 264u));
+  const float l = length(asfloat(u[1].xy).yx);
+  const float a = abs(asfloat(u[1].xy).yx.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_builtin.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..a6813b0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_builtin.wgsl.expected.fxc.hlsl
@@ -0,0 +1,19 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+float2x2 tint_symbol(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  return float2x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float2x2 t = transpose(tint_symbol(u, 264u));
+  const float l = length(asfloat(u[1].xy).yx);
+  const float a = abs(asfloat(u[1].xy).yx.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_builtin.wgsl.expected.glsl
new file mode 100644
index 0000000..eeb3743
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_builtin.wgsl.expected.glsl
@@ -0,0 +1,86 @@
+#version 310 es
+
+struct S {
+  int before;
+  uint pad;
+  mat2 m;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  int after;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+};
+
+struct S_std140 {
+  int before;
+  uint pad;
+  vec2 m_0;
+  vec2 m_1;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  int after;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+mat2 load_u_inner_2_m() {
+  return mat2(u.inner[2u].m_0, u.inner[2u].m_1);
+}
+
+void f() {
+  mat2 t = transpose(load_u_inner_2_m());
+  float l = length(u.inner[0u].m_1.yx);
+  float a = abs(u.inner[0u].m_1.yx[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_builtin.wgsl.expected.msl
new file mode 100644
index 0000000..b2a40b3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_builtin.wgsl.expected.msl
@@ -0,0 +1,32 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0008 */ float2x2 m;
+  /* 0x0018 */ tint_array<int8_t, 40> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol [[buffer(0)]]) {
+  float2x2 const t = transpose((*(tint_symbol))[2].m);
+  float const l = length(float2((*(tint_symbol))[0].m[1]).yx);
+  float const a = fabs(float2((*(tint_symbol))[0].m[1]).yx[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_builtin.wgsl.expected.spvasm
new file mode 100644
index 0000000..44a6592
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_builtin.wgsl.expected.spvasm
@@ -0,0 +1,75 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 46
+; Schema: 0
+               OpCapability Shader
+         %36 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "after"
+               OpName %u "u"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 8
+               OpMemberDecorate %S_std140 2 Offset 16
+               OpMemberDecorate %S_std140 3 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v2float = OpTypeVector %float 2
+   %S_std140 = OpTypeStruct %int %v2float %v2float %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+%mat2v2float = OpTypeMatrix %v2float 2
+         %11 = OpTypeFunction %mat2v2float
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+     %uint_1 = OpConstant %uint 1
+%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
+       %void = OpTypeVoid
+         %29 = OpTypeFunction %void
+         %37 = OpConstantNull %uint
+%load_u_inner_2_m = OpFunction %mat2v2float None %11
+         %14 = OpLabel
+         %19 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %23 = OpAccessChain %_ptr_Uniform_v2float %19 %uint_1
+         %24 = OpLoad %v2float %23
+         %26 = OpAccessChain %_ptr_Uniform_v2float %19 %uint_2
+         %27 = OpLoad %v2float %26
+         %28 = OpCompositeConstruct %mat2v2float %24 %27
+               OpReturnValue %28
+               OpFunctionEnd
+          %f = OpFunction %void None %29
+         %32 = OpLabel
+         %34 = OpFunctionCall %mat2v2float %load_u_inner_2_m
+         %33 = OpTranspose %mat2v2float %34
+         %38 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %37 %uint_2
+         %39 = OpLoad %v2float %38
+         %40 = OpVectorShuffle %v2float %39 %39 1 0
+         %35 = OpExtInst %float %36 Length %40
+         %42 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %37 %uint_2
+         %43 = OpLoad %v2float %42
+         %44 = OpVectorShuffle %v2float %43 %43 1 0
+         %45 = OpCompositeExtract %float %44 0
+         %41 = OpExtInst %float %36 FAbs %45
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_builtin.wgsl.expected.wgsl
new file mode 100644
index 0000000..180955f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_builtin.wgsl.expected.wgsl
@@ -0,0 +1,15 @@
+struct S {
+  before : i32,
+  m : mat2x2<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let t = transpose(u[2].m);
+  let l = length(u[0].m[1].yx);
+  let a = abs(u[0].m[1].yx.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_fn.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_fn.wgsl
new file mode 100644
index 0000000..401e56d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_fn.wgsl
@@ -0,0 +1,23 @@
+struct S {
+  before : i32,
+  m : mat2x2<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+fn a(a : array<S, 4>) {}
+fn b(s : S) {}
+fn c(m : mat2x2<f32>) {}
+fn d(v : vec2<f32>) {}
+fn e(f : f32) {}
+
+@compute @workgroup_size(1)
+fn f() {
+    a(u);
+    b(u[2]);
+    c(u[2].m);
+    d(u[0].m[1].yx);
+    e(u[0].m[1].yx.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_fn.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..e8f7c79
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_fn.wgsl.expected.dxc.hlsl
@@ -0,0 +1,60 @@
+struct S {
+  int before;
+  float2x2 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(float2x2 m) {
+}
+
+void d(float2 v) {
+}
+
+void e(float f_1) {
+}
+
+float2x2 tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  return float2x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 256u));
+  c(tint_symbol_3(u, 264u));
+  d(asfloat(u[1].xy).yx);
+  e(asfloat(u[1].xy).yx.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_fn.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..e8f7c79
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_fn.wgsl.expected.fxc.hlsl
@@ -0,0 +1,60 @@
+struct S {
+  int before;
+  float2x2 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(float2x2 m) {
+}
+
+void d(float2 v) {
+}
+
+void e(float f_1) {
+}
+
+float2x2 tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  return float2x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 256u));
+  c(tint_symbol_3(u, 264u));
+  d(asfloat(u[1].xy).yx);
+  e(asfloat(u[1].xy).yx.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_fn.wgsl.expected.glsl
new file mode 100644
index 0000000..28796e7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_fn.wgsl.expected.glsl
@@ -0,0 +1,117 @@
+#version 310 es
+
+struct S {
+  int before;
+  uint pad;
+  mat2 m;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  int after;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+};
+
+struct S_std140 {
+  int before;
+  uint pad;
+  vec2 m_0;
+  vec2 m_1;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  int after;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(mat2 m) {
+}
+
+void d(vec2 v) {
+}
+
+void e(float f_1) {
+}
+
+S conv_S(S_std140 val) {
+  return S(val.before, val.pad, mat2(val.m_0, val.m_1), val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.after, val.pad_11, val.pad_12, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21, val.pad_22, val.pad_23, val.pad_24, val.pad_25);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+mat2 load_u_inner_2_m() {
+  return mat2(u.inner[2u].m_0, u.inner[2u].m_1);
+}
+
+void f() {
+  a(conv_arr4_S(u.inner));
+  b(conv_S(u.inner[2u]));
+  c(load_u_inner_2_m());
+  d(u.inner[0u].m_1.yx);
+  e(u.inner[0u].m_1.yx[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_fn.wgsl.expected.msl
new file mode 100644
index 0000000..caa1fb9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_fn.wgsl.expected.msl
@@ -0,0 +1,49 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0008 */ float2x2 m;
+  /* 0x0018 */ tint_array<int8_t, 40> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+void a(tint_array<S, 4> a_1) {
+}
+
+void b(S s) {
+}
+
+void c(float2x2 m) {
+}
+
+void d(float2 v) {
+}
+
+void e(float f_1) {
+}
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol [[buffer(0)]]) {
+  a(*(tint_symbol));
+  b((*(tint_symbol))[2]);
+  c((*(tint_symbol))[2].m);
+  d(float2((*(tint_symbol))[0].m[1]).yx);
+  e(float2((*(tint_symbol))[0].m[1]).yx[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_fn.wgsl.expected.spvasm
new file mode 100644
index 0000000..6f93912
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_fn.wgsl.expected.spvasm
@@ -0,0 +1,200 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 119
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "after"
+               OpName %u "u"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %a "a"
+               OpName %a_1 "a_1"
+               OpName %b "b"
+               OpName %s "s"
+               OpName %c "c"
+               OpName %m "m"
+               OpName %d "d"
+               OpName %v "v"
+               OpName %e "e"
+               OpName %f_1 "f_1"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 8
+               OpMemberDecorate %S_std140 2 Offset 16
+               OpMemberDecorate %S_std140 3 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 8
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 8
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v2float = OpTypeVector %float 2
+   %S_std140 = OpTypeStruct %int %v2float %v2float %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+       %void = OpTypeVoid
+%mat2v2float = OpTypeMatrix %v2float 2
+          %S = OpTypeStruct %int %mat2v2float %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+         %11 = OpTypeFunction %void %_arr_S_uint_4
+         %19 = OpTypeFunction %void %S
+         %23 = OpTypeFunction %void %mat2v2float
+         %27 = OpTypeFunction %void %v2float
+         %31 = OpTypeFunction %void %float
+         %35 = OpTypeFunction %S %S_std140
+         %45 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+         %51 = OpConstantNull %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %54 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %67 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %80 = OpTypeFunction %mat2v2float
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
+         %96 = OpTypeFunction %void
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+          %a = OpFunction %void None %11
+        %a_1 = OpFunctionParameter %_arr_S_uint_4
+         %18 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %b = OpFunction %void None %19
+          %s = OpFunctionParameter %S
+         %22 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %c = OpFunction %void None %23
+          %m = OpFunctionParameter %mat2v2float
+         %26 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %d = OpFunction %void None %27
+          %v = OpFunctionParameter %v2float
+         %30 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %e = OpFunction %void None %31
+        %f_1 = OpFunctionParameter %float
+         %34 = OpLabel
+               OpReturn
+               OpFunctionEnd
+     %conv_S = OpFunction %S None %35
+        %val = OpFunctionParameter %S_std140
+         %38 = OpLabel
+         %39 = OpCompositeExtract %int %val 0
+         %40 = OpCompositeExtract %v2float %val 1
+         %41 = OpCompositeExtract %v2float %val 2
+         %42 = OpCompositeConstruct %mat2v2float %40 %41
+         %43 = OpCompositeExtract %int %val 3
+         %44 = OpCompositeConstruct %S %39 %42 %43
+               OpReturnValue %44
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %45
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %48 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %51
+          %i = OpVariable %_ptr_Function_uint Function %54
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %67
+               OpBranch %55
+         %55 = OpLabel
+               OpLoopMerge %56 %57 None
+               OpBranch %58
+         %58 = OpLabel
+         %60 = OpLoad %uint %i
+         %61 = OpULessThan %bool %60 %uint_4
+         %59 = OpLogicalNot %bool %61
+               OpSelectionMerge %63 None
+               OpBranchConditional %59 %64 %63
+         %64 = OpLabel
+               OpBranch %56
+         %63 = OpLabel
+               OpStore %var_for_index %val_0
+         %68 = OpLoad %uint %i
+         %70 = OpAccessChain %_ptr_Function_S %arr %68
+         %72 = OpLoad %uint %i
+         %74 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %72
+         %75 = OpLoad %S_std140 %74
+         %71 = OpFunctionCall %S %conv_S %75
+               OpStore %70 %71
+               OpBranch %57
+         %57 = OpLabel
+         %76 = OpLoad %uint %i
+         %78 = OpIAdd %uint %76 %uint_1
+               OpStore %i %78
+               OpBranch %55
+         %56 = OpLabel
+         %79 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %79
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat2v2float None %80
+         %82 = OpLabel
+         %87 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %90 = OpAccessChain %_ptr_Uniform_v2float %87 %uint_1
+         %91 = OpLoad %v2float %90
+         %93 = OpAccessChain %_ptr_Uniform_v2float %87 %uint_2
+         %94 = OpLoad %v2float %93
+         %95 = OpCompositeConstruct %mat2v2float %91 %94
+               OpReturnValue %95
+               OpFunctionEnd
+          %f = OpFunction %void None %96
+         %98 = OpLabel
+        %102 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+        %103 = OpLoad %_arr_S_std140_uint_4 %102
+        %100 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %103
+         %99 = OpFunctionCall %void %a %100
+        %106 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+        %107 = OpLoad %S_std140 %106
+        %105 = OpFunctionCall %S %conv_S %107
+        %104 = OpFunctionCall %void %b %105
+        %109 = OpFunctionCall %mat2v2float %load_u_inner_2_m
+        %108 = OpFunctionCall %void %c %109
+        %111 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %54 %uint_2
+        %112 = OpLoad %v2float %111
+        %113 = OpVectorShuffle %v2float %112 %112 1 0
+        %110 = OpFunctionCall %void %d %113
+        %115 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %54 %uint_2
+        %116 = OpLoad %v2float %115
+        %117 = OpVectorShuffle %v2float %116 %116 1 0
+        %118 = OpCompositeExtract %float %117 0
+        %114 = OpFunctionCall %void %e %118
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_fn.wgsl.expected.wgsl
new file mode 100644
index 0000000..e1d57cd
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_fn.wgsl.expected.wgsl
@@ -0,0 +1,32 @@
+struct S {
+  before : i32,
+  m : mat2x2<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+fn a(a : array<S, 4>) {
+}
+
+fn b(s : S) {
+}
+
+fn c(m : mat2x2<f32>) {
+}
+
+fn d(v : vec2<f32>) {
+}
+
+fn e(f : f32) {
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  a(u);
+  b(u[2]);
+  c(u[2].m);
+  d(u[0].m[1].yx);
+  e(u[0].m[1].yx.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_private.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_private.wgsl
new file mode 100644
index 0000000..68839fa
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_private.wgsl
@@ -0,0 +1,17 @@
+struct S {
+  before : i32,
+  m : mat2x2<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+var<private> p : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[2];
+    p[3].m = u[2].m;
+    p[1].m[0] = u[0].m[1].yx;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_private.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..be509ec
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_private.wgsl.expected.dxc.hlsl
@@ -0,0 +1,45 @@
+struct S {
+  int before;
+  float2x2 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+static S p[4] = (S[4])0;
+
+float2x2 tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  return float2x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 256u);
+  p[3].m = tint_symbol_3(u, 264u);
+  p[1].m[0] = asfloat(u[1].xy).yx;
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_private.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..be509ec
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_private.wgsl.expected.fxc.hlsl
@@ -0,0 +1,45 @@
+struct S {
+  int before;
+  float2x2 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+static S p[4] = (S[4])0;
+
+float2x2 tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  return float2x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 256u);
+  p[3].m = tint_symbol_3(u, 264u);
+  p[1].m[0] = asfloat(u[1].xy).yx;
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..9859836
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_private.wgsl.expected.glsl
@@ -0,0 +1,102 @@
+#version 310 es
+
+struct S {
+  int before;
+  uint pad;
+  mat2 m;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  int after;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+};
+
+struct S_std140 {
+  int before;
+  uint pad;
+  vec2 m_0;
+  vec2 m_1;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  int after;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+S p[4] = S[4](S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+S conv_S(S_std140 val) {
+  return S(val.before, val.pad, mat2(val.m_0, val.m_1), val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.after, val.pad_11, val.pad_12, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21, val.pad_22, val.pad_23, val.pad_24, val.pad_25);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+mat2 load_u_inner_2_m() {
+  return mat2(u.inner[2u].m_0, u.inner[2u].m_1);
+}
+
+void f() {
+  p = conv_arr4_S(u.inner);
+  p[1] = conv_S(u.inner[2u]);
+  p[3].m = load_u_inner_2_m();
+  p[1].m[0] = u.inner[0u].m_1.yx;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..a1c599c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_private.wgsl.expected.msl
@@ -0,0 +1,34 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0008 */ float2x2 m;
+  /* 0x0018 */ tint_array<int8_t, 40> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol_1 [[buffer(0)]]) {
+  thread tint_array<S, 4> tint_symbol = {};
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[2];
+  tint_symbol[3].m = (*(tint_symbol_1))[2].m;
+  tint_symbol[1].m[0] = float2((*(tint_symbol_1))[0].m[1]).yx;
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_private.wgsl.expected.spvasm
new file mode 100644
index 0000000..067e7fd
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_private.wgsl.expected.spvasm
@@ -0,0 +1,167 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 101
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "after"
+               OpName %u "u"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %p "p"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 8
+               OpMemberDecorate %S_std140 2 Offset 16
+               OpMemberDecorate %S_std140 3 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 8
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 8
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v2float = OpTypeVector %float 2
+   %S_std140 = OpTypeStruct %int %v2float %v2float %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+%mat2v2float = OpTypeMatrix %v2float 2
+          %S = OpTypeStruct %int %mat2v2float %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+%_ptr_Private__arr_S_uint_4 = OpTypePointer Private %_arr_S_uint_4
+         %16 = OpConstantNull %_arr_S_uint_4
+          %p = OpVariable %_ptr_Private__arr_S_uint_4 Private %16
+         %17 = OpTypeFunction %S %S_std140
+         %27 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %35 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %48 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %61 = OpTypeFunction %mat2v2float
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
+       %void = OpTypeVoid
+         %77 = OpTypeFunction %void
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+      %int_1 = OpConstant %int 1
+%_ptr_Private_S = OpTypePointer Private %S
+      %int_3 = OpConstant %int 3
+%_ptr_Private_mat2v2float = OpTypePointer Private %mat2v2float
+         %95 = OpConstantNull %int
+%_ptr_Private_v2float = OpTypePointer Private %v2float
+     %conv_S = OpFunction %S None %17
+        %val = OpFunctionParameter %S_std140
+         %20 = OpLabel
+         %21 = OpCompositeExtract %int %val 0
+         %22 = OpCompositeExtract %v2float %val 1
+         %23 = OpCompositeExtract %v2float %val 2
+         %24 = OpCompositeConstruct %mat2v2float %22 %23
+         %25 = OpCompositeExtract %int %val 3
+         %26 = OpCompositeConstruct %S %21 %24 %25
+               OpReturnValue %26
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %27
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %30 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %16
+          %i = OpVariable %_ptr_Function_uint Function %35
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %48
+               OpBranch %36
+         %36 = OpLabel
+               OpLoopMerge %37 %38 None
+               OpBranch %39
+         %39 = OpLabel
+         %41 = OpLoad %uint %i
+         %42 = OpULessThan %bool %41 %uint_4
+         %40 = OpLogicalNot %bool %42
+               OpSelectionMerge %44 None
+               OpBranchConditional %40 %45 %44
+         %45 = OpLabel
+               OpBranch %37
+         %44 = OpLabel
+               OpStore %var_for_index %val_0
+         %49 = OpLoad %uint %i
+         %51 = OpAccessChain %_ptr_Function_S %arr %49
+         %53 = OpLoad %uint %i
+         %55 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %53
+         %56 = OpLoad %S_std140 %55
+         %52 = OpFunctionCall %S %conv_S %56
+               OpStore %51 %52
+               OpBranch %38
+         %38 = OpLabel
+         %57 = OpLoad %uint %i
+         %59 = OpIAdd %uint %57 %uint_1
+               OpStore %i %59
+               OpBranch %36
+         %37 = OpLabel
+         %60 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %60
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat2v2float None %61
+         %63 = OpLabel
+         %68 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %71 = OpAccessChain %_ptr_Uniform_v2float %68 %uint_1
+         %72 = OpLoad %v2float %71
+         %74 = OpAccessChain %_ptr_Uniform_v2float %68 %uint_2
+         %75 = OpLoad %v2float %74
+         %76 = OpCompositeConstruct %mat2v2float %72 %75
+               OpReturnValue %76
+               OpFunctionEnd
+          %f = OpFunction %void None %77
+         %80 = OpLabel
+         %83 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+         %84 = OpLoad %_arr_S_std140_uint_4 %83
+         %81 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %84
+               OpStore %p %81
+         %87 = OpAccessChain %_ptr_Private_S %p %int_1
+         %89 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %90 = OpLoad %S_std140 %89
+         %88 = OpFunctionCall %S %conv_S %90
+               OpStore %87 %88
+         %93 = OpAccessChain %_ptr_Private_mat2v2float %p %int_3 %uint_1
+         %94 = OpFunctionCall %mat2v2float %load_u_inner_2_m
+               OpStore %93 %94
+         %97 = OpAccessChain %_ptr_Private_v2float %p %int_1 %uint_1 %95
+         %98 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %35 %uint_2
+         %99 = OpLoad %v2float %98
+        %100 = OpVectorShuffle %v2float %99 %99 1 0
+               OpStore %97 %100
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..b7722ec
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_private.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+struct S {
+  before : i32,
+  m : mat2x2<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+var<private> p : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[2];
+  p[3].m = u[2].m;
+  p[1].m[0] = u[0].m[1].yx;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_storage.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_storage.wgsl
new file mode 100644
index 0000000..7226605
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_storage.wgsl
@@ -0,0 +1,17 @@
+struct S {
+  before : i32,
+  m : mat2x2<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+@group(0) @binding(1) var<storage, read_write> s : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[2];
+    s[3].m = u[2].m;
+    s[1].m[0] = u[0].m[1].yx;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_storage.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..bfcca34
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_storage.wgsl.expected.dxc.hlsl
@@ -0,0 +1,65 @@
+struct S {
+  int before;
+  float2x2 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_3(RWByteAddressBuffer buffer, uint offset, float2x2 value) {
+  buffer.Store2((offset + 0u), asuint(value[0u]));
+  buffer.Store2((offset + 8u), asuint(value[1u]));
+}
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, S value) {
+  buffer.Store((offset + 0u), asuint(value.before));
+  tint_symbol_3(buffer, (offset + 8u), value.m);
+  buffer.Store((offset + 64u), asuint(value.after));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, S value[4]) {
+  S array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 128u)), array[i]);
+    }
+  }
+}
+
+float2x2 tint_symbol_8(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  return float2x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)));
+}
+
+S tint_symbol_6(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_10 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_8(buffer, (offset + 8u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_10;
+}
+
+typedef S tint_symbol_5_ret[4];
+tint_symbol_5_ret tint_symbol_5(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_6(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_5(u, 0u));
+  tint_symbol_1(s, 128u, tint_symbol_6(u, 256u));
+  tint_symbol_3(s, 392u, tint_symbol_8(u, 264u));
+  s.Store2(136u, asuint(asfloat(u[1].xy).yx));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_storage.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..bfcca34
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_storage.wgsl.expected.fxc.hlsl
@@ -0,0 +1,65 @@
+struct S {
+  int before;
+  float2x2 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_3(RWByteAddressBuffer buffer, uint offset, float2x2 value) {
+  buffer.Store2((offset + 0u), asuint(value[0u]));
+  buffer.Store2((offset + 8u), asuint(value[1u]));
+}
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, S value) {
+  buffer.Store((offset + 0u), asuint(value.before));
+  tint_symbol_3(buffer, (offset + 8u), value.m);
+  buffer.Store((offset + 64u), asuint(value.after));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, S value[4]) {
+  S array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 128u)), array[i]);
+    }
+  }
+}
+
+float2x2 tint_symbol_8(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  return float2x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)));
+}
+
+S tint_symbol_6(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_10 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_8(buffer, (offset + 8u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_10;
+}
+
+typedef S tint_symbol_5_ret[4];
+tint_symbol_5_ret tint_symbol_5(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_6(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_5(u, 0u));
+  tint_symbol_1(s, 128u, tint_symbol_6(u, 256u));
+  tint_symbol_3(s, 392u, tint_symbol_8(u, 264u));
+  s.Store2(136u, asuint(asfloat(u[1].xy).yx));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..4056465
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_storage.wgsl.expected.glsl
@@ -0,0 +1,105 @@
+#version 310 es
+
+struct S {
+  int before;
+  uint pad;
+  mat2 m;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  int after;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+};
+
+struct S_std140 {
+  int before;
+  uint pad;
+  vec2 m_0;
+  vec2 m_1;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  int after;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  S inner[4];
+} s;
+
+S conv_S(S_std140 val) {
+  return S(val.before, val.pad, mat2(val.m_0, val.m_1), val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.after, val.pad_11, val.pad_12, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21, val.pad_22, val.pad_23, val.pad_24, val.pad_25);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+mat2 load_u_inner_2_m() {
+  return mat2(u.inner[2u].m_0, u.inner[2u].m_1);
+}
+
+void f() {
+  s.inner = conv_arr4_S(u.inner);
+  s.inner[1] = conv_S(u.inner[2u]);
+  s.inner[3].m = load_u_inner_2_m();
+  s.inner[1].m[0] = u.inner[0u].m_1.yx;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..c949492
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_storage.wgsl.expected.msl
@@ -0,0 +1,33 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0008 */ float2x2 m;
+  /* 0x0018 */ tint_array<int8_t, 40> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+kernel void f(device tint_array<S, 4>* tint_symbol [[buffer(1)]], const constant tint_array<S, 4>* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
+  (*(tint_symbol))[3].m = (*(tint_symbol_1))[2].m;
+  (*(tint_symbol))[1].m[0] = float2((*(tint_symbol_1))[0].m[1]).yx;
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_storage.wgsl.expected.spvasm
new file mode 100644
index 0000000..be8fa7d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_storage.wgsl.expected.spvasm
@@ -0,0 +1,176 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 104
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "after"
+               OpName %u "u"
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %s "s"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 8
+               OpMemberDecorate %S_std140 2 Offset 16
+               OpMemberDecorate %S_std140 3 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 8
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 8
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+               OpDecorate %s DescriptorSet 0
+               OpDecorate %s Binding 1
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v2float = OpTypeVector %float 2
+   %S_std140 = OpTypeStruct %int %v2float %v2float %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+%mat2v2float = OpTypeMatrix %v2float 2
+          %S = OpTypeStruct %int %mat2v2float %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+    %u_block = OpTypeStruct %_arr_S_uint_4
+%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
+          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+         %17 = OpTypeFunction %S %S_std140
+         %27 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+         %33 = OpConstantNull %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %36 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %49 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %62 = OpTypeFunction %mat2v2float
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
+       %void = OpTypeVoid
+         %78 = OpTypeFunction %void
+%_ptr_StorageBuffer__arr_S_uint_4 = OpTypePointer StorageBuffer %_arr_S_uint_4
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+      %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
+      %int_3 = OpConstant %int 3
+%_ptr_StorageBuffer_mat2v2float = OpTypePointer StorageBuffer %mat2v2float
+         %98 = OpConstantNull %int
+%_ptr_StorageBuffer_v2float = OpTypePointer StorageBuffer %v2float
+     %conv_S = OpFunction %S None %17
+        %val = OpFunctionParameter %S_std140
+         %20 = OpLabel
+         %21 = OpCompositeExtract %int %val 0
+         %22 = OpCompositeExtract %v2float %val 1
+         %23 = OpCompositeExtract %v2float %val 2
+         %24 = OpCompositeConstruct %mat2v2float %22 %23
+         %25 = OpCompositeExtract %int %val 3
+         %26 = OpCompositeConstruct %S %21 %24 %25
+               OpReturnValue %26
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %27
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %30 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %33
+          %i = OpVariable %_ptr_Function_uint Function %36
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %49
+               OpBranch %37
+         %37 = OpLabel
+               OpLoopMerge %38 %39 None
+               OpBranch %40
+         %40 = OpLabel
+         %42 = OpLoad %uint %i
+         %43 = OpULessThan %bool %42 %uint_4
+         %41 = OpLogicalNot %bool %43
+               OpSelectionMerge %45 None
+               OpBranchConditional %41 %46 %45
+         %46 = OpLabel
+               OpBranch %38
+         %45 = OpLabel
+               OpStore %var_for_index %val_0
+         %50 = OpLoad %uint %i
+         %52 = OpAccessChain %_ptr_Function_S %arr %50
+         %54 = OpLoad %uint %i
+         %56 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %54
+         %57 = OpLoad %S_std140 %56
+         %53 = OpFunctionCall %S %conv_S %57
+               OpStore %52 %53
+               OpBranch %39
+         %39 = OpLabel
+         %58 = OpLoad %uint %i
+         %60 = OpIAdd %uint %58 %uint_1
+               OpStore %i %60
+               OpBranch %37
+         %38 = OpLabel
+         %61 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %61
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat2v2float None %62
+         %64 = OpLabel
+         %69 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %72 = OpAccessChain %_ptr_Uniform_v2float %69 %uint_1
+         %73 = OpLoad %v2float %72
+         %75 = OpAccessChain %_ptr_Uniform_v2float %69 %uint_2
+         %76 = OpLoad %v2float %75
+         %77 = OpCompositeConstruct %mat2v2float %73 %76
+               OpReturnValue %77
+               OpFunctionEnd
+          %f = OpFunction %void None %78
+         %81 = OpLabel
+         %83 = OpAccessChain %_ptr_StorageBuffer__arr_S_uint_4 %s %uint_0
+         %86 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+         %87 = OpLoad %_arr_S_std140_uint_4 %86
+         %84 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %87
+               OpStore %83 %84
+         %90 = OpAccessChain %_ptr_StorageBuffer_S %s %uint_0 %int_1
+         %92 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %93 = OpLoad %S_std140 %92
+         %91 = OpFunctionCall %S %conv_S %93
+               OpStore %90 %91
+         %96 = OpAccessChain %_ptr_StorageBuffer_mat2v2float %s %uint_0 %int_3 %uint_1
+         %97 = OpFunctionCall %mat2v2float %load_u_inner_2_m
+               OpStore %96 %97
+        %100 = OpAccessChain %_ptr_StorageBuffer_v2float %s %uint_0 %int_1 %uint_1 %98
+        %101 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %36 %uint_2
+        %102 = OpLoad %v2float %101
+        %103 = OpVectorShuffle %v2float %102 %102 1 0
+               OpStore %100 %103
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..0205aaf
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+struct S {
+  before : i32,
+  m : mat2x2<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@group(0) @binding(1) var<storage, read_write> s : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[2];
+  s[3].m = u[2].m;
+  s[1].m[0] = u[0].m[1].yx;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_workgroup.wgsl
new file mode 100644
index 0000000..af9a3b3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_workgroup.wgsl
@@ -0,0 +1,17 @@
+struct S {
+  before : i32,
+  m : mat2x2<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+var<workgroup> w : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[2];
+    w[3].m = u[2].m;
+    w[1].m[0] = u[0].m[1].yx;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_workgroup.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..c0c70b3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_workgroup.wgsl.expected.dxc.hlsl
@@ -0,0 +1,61 @@
+struct S {
+  int before;
+  float2x2 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+groupshared S w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+float2x2 tint_symbol_5(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  return float2x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)));
+}
+
+S tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_8 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_5(buffer, (offset + 8u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_8;
+}
+
+typedef S tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      const S tint_symbol_7 = (S)0;
+      w[i] = tint_symbol_7;
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 256u);
+  w[3].m = tint_symbol_5(u, 264u);
+  w[1].m[0] = asfloat(u[1].xy).yx;
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_workgroup.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..c0c70b3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_workgroup.wgsl.expected.fxc.hlsl
@@ -0,0 +1,61 @@
+struct S {
+  int before;
+  float2x2 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+groupshared S w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+float2x2 tint_symbol_5(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  return float2x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)));
+}
+
+S tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_8 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_5(buffer, (offset + 8u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_8;
+}
+
+typedef S tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      const S tint_symbol_7 = (S)0;
+      w[i] = tint_symbol_7;
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 256u);
+  w[3].m = tint_symbol_5(u, 264u);
+  w[1].m[0] = asfloat(u[1].xy).yx;
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..727abb5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,110 @@
+#version 310 es
+
+struct S {
+  int before;
+  uint pad;
+  mat2 m;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  int after;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+};
+
+struct S_std140 {
+  int before;
+  uint pad;
+  vec2 m_0;
+  vec2 m_1;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  int after;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+shared S w[4];
+S conv_S(S_std140 val) {
+  return S(val.before, val.pad, mat2(val.m_0, val.m_1), val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.after, val.pad_11, val.pad_12, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21, val.pad_22, val.pad_23, val.pad_24, val.pad_25);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, mat2(0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+mat2 load_u_inner_2_m() {
+  return mat2(u.inner[2u].m_0, u.inner[2u].m_1);
+}
+
+void f(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      uint i = idx;
+      S tint_symbol = S(0, 0u, mat2(vec2(0.0f), vec2(0.0f)), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u);
+      w[i] = tint_symbol;
+    }
+  }
+  barrier();
+  w = conv_arr4_S(u.inner);
+  w[1] = conv_S(u.inner[2u]);
+  w[3].m = load_u_inner_2_m();
+  w[1].m[0] = u.inner[0u].m_1.yx;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..667db2d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,48 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0008 */ float2x2 m;
+  /* 0x0018 */ tint_array<int8_t, 40> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+struct tint_symbol_6 {
+  tint_array<S, 4> w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup tint_array<S, 4>* const tint_symbol_1, const constant tint_array<S, 4>* const tint_symbol_2) {
+  for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+    uint const i = idx;
+    S const tint_symbol = S{};
+    (*(tint_symbol_1))[i] = tint_symbol;
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol_1) = *(tint_symbol_2);
+  (*(tint_symbol_1))[1] = (*(tint_symbol_2))[2];
+  (*(tint_symbol_1))[3].m = (*(tint_symbol_2))[2].m;
+  (*(tint_symbol_1))[1].m[0] = float2((*(tint_symbol_2))[0].m[1]).yx;
+}
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol_5 [[buffer(0)]], threadgroup tint_symbol_6* tint_symbol_4 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup tint_array<S, 4>* const tint_symbol_3 = &((*(tint_symbol_4)).w);
+  f_inner(local_invocation_index, tint_symbol_3, tint_symbol_5);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_workgroup.wgsl.expected.spvasm
new file mode 100644
index 0000000..68218cc
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_workgroup.wgsl.expected.spvasm
@@ -0,0 +1,210 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 126
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %local_invocation_index_1 "local_invocation_index_1"
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "after"
+               OpName %u "u"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %w "w"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f_inner "f_inner"
+               OpName %local_invocation_index "local_invocation_index"
+               OpName %idx "idx"
+               OpName %f "f"
+               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 8
+               OpMemberDecorate %S_std140 2 Offset 16
+               OpMemberDecorate %S_std140 3 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 8
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 8
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v2float = OpTypeVector %float 2
+   %S_std140 = OpTypeStruct %int %v2float %v2float %int
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+%mat2v2float = OpTypeMatrix %v2float 2
+          %S = OpTypeStruct %int %mat2v2float %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+%_ptr_Workgroup__arr_S_uint_4 = OpTypePointer Workgroup %_arr_S_uint_4
+          %w = OpVariable %_ptr_Workgroup__arr_S_uint_4 Workgroup
+         %18 = OpTypeFunction %S %S_std140
+         %28 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+         %34 = OpConstantNull %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %37 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %50 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %63 = OpTypeFunction %mat2v2float
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
+       %void = OpTypeVoid
+         %79 = OpTypeFunction %void %uint
+%_ptr_Workgroup_S = OpTypePointer Workgroup %S
+         %97 = OpConstantNull %S
+   %uint_264 = OpConstant %uint 264
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+      %int_1 = OpConstant %int 1
+      %int_3 = OpConstant %int 3
+%_ptr_Workgroup_mat2v2float = OpTypePointer Workgroup %mat2v2float
+        %115 = OpConstantNull %int
+%_ptr_Workgroup_v2float = OpTypePointer Workgroup %v2float
+        %121 = OpTypeFunction %void
+     %conv_S = OpFunction %S None %18
+        %val = OpFunctionParameter %S_std140
+         %21 = OpLabel
+         %22 = OpCompositeExtract %int %val 0
+         %23 = OpCompositeExtract %v2float %val 1
+         %24 = OpCompositeExtract %v2float %val 2
+         %25 = OpCompositeConstruct %mat2v2float %23 %24
+         %26 = OpCompositeExtract %int %val 3
+         %27 = OpCompositeConstruct %S %22 %25 %26
+               OpReturnValue %27
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %28
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %31 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %34
+          %i = OpVariable %_ptr_Function_uint Function %37
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %50
+               OpBranch %38
+         %38 = OpLabel
+               OpLoopMerge %39 %40 None
+               OpBranch %41
+         %41 = OpLabel
+         %43 = OpLoad %uint %i
+         %44 = OpULessThan %bool %43 %uint_4
+         %42 = OpLogicalNot %bool %44
+               OpSelectionMerge %46 None
+               OpBranchConditional %42 %47 %46
+         %47 = OpLabel
+               OpBranch %39
+         %46 = OpLabel
+               OpStore %var_for_index %val_0
+         %51 = OpLoad %uint %i
+         %53 = OpAccessChain %_ptr_Function_S %arr %51
+         %55 = OpLoad %uint %i
+         %57 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %55
+         %58 = OpLoad %S_std140 %57
+         %54 = OpFunctionCall %S %conv_S %58
+               OpStore %53 %54
+               OpBranch %40
+         %40 = OpLabel
+         %59 = OpLoad %uint %i
+         %61 = OpIAdd %uint %59 %uint_1
+               OpStore %i %61
+               OpBranch %38
+         %39 = OpLabel
+         %62 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %62
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat2v2float None %63
+         %65 = OpLabel
+         %70 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %73 = OpAccessChain %_ptr_Uniform_v2float %70 %uint_1
+         %74 = OpLoad %v2float %73
+         %76 = OpAccessChain %_ptr_Uniform_v2float %70 %uint_2
+         %77 = OpLoad %v2float %76
+         %78 = OpCompositeConstruct %mat2v2float %74 %77
+               OpReturnValue %78
+               OpFunctionEnd
+    %f_inner = OpFunction %void None %79
+%local_invocation_index = OpFunctionParameter %uint
+         %83 = OpLabel
+        %idx = OpVariable %_ptr_Function_uint Function %37
+               OpStore %idx %local_invocation_index
+               OpBranch %85
+         %85 = OpLabel
+               OpLoopMerge %86 %87 None
+               OpBranch %88
+         %88 = OpLabel
+         %90 = OpLoad %uint %idx
+         %91 = OpULessThan %bool %90 %uint_4
+         %89 = OpLogicalNot %bool %91
+               OpSelectionMerge %92 None
+               OpBranchConditional %89 %93 %92
+         %93 = OpLabel
+               OpBranch %86
+         %92 = OpLabel
+         %94 = OpLoad %uint %idx
+         %96 = OpAccessChain %_ptr_Workgroup_S %w %94
+               OpStore %96 %97
+               OpBranch %87
+         %87 = OpLabel
+         %98 = OpLoad %uint %idx
+         %99 = OpIAdd %uint %98 %uint_1
+               OpStore %idx %99
+               OpBranch %85
+         %86 = OpLabel
+               OpControlBarrier %uint_2 %uint_2 %uint_264
+        %104 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+        %105 = OpLoad %_arr_S_std140_uint_4 %104
+        %102 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %105
+               OpStore %w %102
+        %107 = OpAccessChain %_ptr_Workgroup_S %w %int_1
+        %109 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+        %110 = OpLoad %S_std140 %109
+        %108 = OpFunctionCall %S %conv_S %110
+               OpStore %107 %108
+        %113 = OpAccessChain %_ptr_Workgroup_mat2v2float %w %int_3 %uint_1
+        %114 = OpFunctionCall %mat2v2float %load_u_inner_2_m
+               OpStore %113 %114
+        %117 = OpAccessChain %_ptr_Workgroup_v2float %w %int_1 %uint_1 %115
+        %118 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %37 %uint_2
+        %119 = OpLoad %v2float %118
+        %120 = OpVectorShuffle %v2float %119 %119 1 0
+               OpStore %117 %120
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %121
+        %123 = OpLabel
+        %125 = OpLoad %uint %local_invocation_index_1
+        %124 = OpFunctionCall %void %f_inner %125
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..645ac59
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x2_f32/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+struct S {
+  before : i32,
+  m : mat2x2<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+var<workgroup> w : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[2];
+  w[3].m = u[2].m;
+  w[1].m[0] = u[0].m[1].yx;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/dynamic_index_via_ptr.wgsl
new file mode 100644
index 0000000..b2eab8f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/dynamic_index_via_ptr.wgsl
@@ -0,0 +1,34 @@
+enable f16;
+
+struct Inner {
+  @size(64)
+  m : mat2x3<f16>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a           = &a;
+  let p_a_i         = &((*p_a)[i()]);
+  let p_a_i_a       = &((*p_a_i).a);
+  let p_a_i_a_i     = &((*p_a_i_a)[i()]);
+  let p_a_i_a_i_m   = &((*p_a_i_a_i).m);
+  let p_a_i_a_i_m_i = &((*p_a_i_a_i_m)[i()]);
+
+
+  let l_a             : array<Outer, 4> =  *p_a;
+  let l_a_i           : Outer           =  *p_a_i;
+  let l_a_i_a         : array<Inner, 4> =  *p_a_i_a;
+  let l_a_i_a_i       : Inner           =  *p_a_i_a_i;
+  let l_a_i_a_i_m     : mat2x3<f16>     =  *p_a_i_a_i_m;
+  let l_a_i_a_i_m_i   : vec3<f16>       =  *p_a_i_a_i_m_i;
+  let l_a_i_a_i_m_i_i : f16             = (*p_a_i_a_i_m_i)[i()];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..63633dc
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,88 @@
+struct Inner {
+  matrix<float16_t, 2, 3> m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 2, 3> tint_symbol_8(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
+}
+
+Inner tint_symbol_7(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_11 = {tint_symbol_8(buffer, (offset + 0u))};
+  return tint_symbol_11;
+}
+
+typedef Inner tint_symbol_6_ret[4];
+tint_symbol_6_ret tint_symbol_6(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_7(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_5(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_12 = {tint_symbol_6(buffer, (offset + 0u))};
+  return tint_symbol_12;
+}
+
+typedef Outer tint_symbol_4_ret[4];
+tint_symbol_4_ret tint_symbol_4(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
+      arr_1[i_2] = tint_symbol_5(buffer, (offset + (i_2 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_a_i_save = i();
+  const int p_a_i_a_i_m_i_save = i();
+  const Outer l_a[4] = tint_symbol_4(a, 0u);
+  const Outer l_a_i = tint_symbol_5(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a[4] = tint_symbol_6(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a_i = tint_symbol_7(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const matrix<float16_t, 2, 3> l_a_i_a_i_m = tint_symbol_8(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const uint scalar_offset_2 = ((((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))) + (8u * uint(p_a_i_a_i_m_i_save)))) / 4;
+  uint4 ubo_load_5 = a[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const vector<float16_t, 3> l_a_i_a_i_m_i = vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]);
+  const int tint_symbol = p_a_i_save;
+  const int tint_symbol_1 = p_a_i_a_i_save;
+  const int tint_symbol_2 = p_a_i_a_i_m_i_save;
+  const int tint_symbol_3 = i();
+  const uint scalar_offset_bytes = (((((256u * uint(tint_symbol)) + (64u * uint(tint_symbol_1))) + (8u * uint(tint_symbol_2))) + (2u * uint(tint_symbol_3))));
+  const uint scalar_offset_index = scalar_offset_bytes / 4;
+  const float16_t l_a_i_a_i_m_i_i = float16_t(f16tof32(((a[scalar_offset_index / 4][scalar_offset_index % 4] >> (scalar_offset_bytes % 4 == 0 ? 0 : 16)) & 0xFFFF)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..1b18347
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,93 @@
+SKIP: FAILED
+
+struct Inner {
+  matrix<float16_t, 2, 3> m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 2, 3> tint_symbol_8(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
+}
+
+Inner tint_symbol_7(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_11 = {tint_symbol_8(buffer, (offset + 0u))};
+  return tint_symbol_11;
+}
+
+typedef Inner tint_symbol_6_ret[4];
+tint_symbol_6_ret tint_symbol_6(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_7(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_5(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_12 = {tint_symbol_6(buffer, (offset + 0u))};
+  return tint_symbol_12;
+}
+
+typedef Outer tint_symbol_4_ret[4];
+tint_symbol_4_ret tint_symbol_4(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
+      arr_1[i_2] = tint_symbol_5(buffer, (offset + (i_2 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_a_i_save = i();
+  const int p_a_i_a_i_m_i_save = i();
+  const Outer l_a[4] = tint_symbol_4(a, 0u);
+  const Outer l_a_i = tint_symbol_5(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a[4] = tint_symbol_6(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a_i = tint_symbol_7(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const matrix<float16_t, 2, 3> l_a_i_a_i_m = tint_symbol_8(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const uint scalar_offset_2 = ((((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))) + (8u * uint(p_a_i_a_i_m_i_save)))) / 4;
+  uint4 ubo_load_5 = a[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const vector<float16_t, 3> l_a_i_a_i_m_i = vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]);
+  const int tint_symbol = p_a_i_save;
+  const int tint_symbol_1 = p_a_i_a_i_save;
+  const int tint_symbol_2 = p_a_i_a_i_m_i_save;
+  const int tint_symbol_3 = i();
+  const uint scalar_offset_bytes = (((((256u * uint(tint_symbol)) + (64u * uint(tint_symbol_1))) + (8u * uint(tint_symbol_2))) + (2u * uint(tint_symbol_3))));
+  const uint scalar_offset_index = scalar_offset_bytes / 4;
+  const float16_t l_a_i_a_i_m_i_i = float16_t(f16tof32(((a[scalar_offset_index / 4][scalar_offset_index % 4] >> (scalar_offset_bytes % 4 == 0 ? 0 : 16)) & 0xFFFF)));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000021B8B701620(2,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..dbc6cf5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,147 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct Inner {
+  f16mat2x3 m;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+};
+
+struct Inner_std140 {
+  f16vec3 m_0;
+  f16vec3 m_1;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+};
+
+struct Outer {
+  Inner a[4];
+};
+
+struct Outer_std140 {
+  Inner_std140 a[4];
+};
+
+layout(binding = 0, std140) uniform a_block_std140_ubo {
+  Outer_std140 inner[4];
+} a;
+
+int counter = 0;
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+Inner conv_Inner(Inner_std140 val) {
+  return Inner(f16mat2x3(val.m_0, val.m_1), val.pad, val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.pad_11);
+}
+
+Inner[4] conv_arr4_Inner(Inner_std140 val[4]) {
+  Inner arr[4] = Inner[4](Inner(f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_Inner(val[i]);
+    }
+  }
+  return arr;
+}
+
+Outer conv_Outer(Outer_std140 val) {
+  return Outer(conv_arr4_Inner(val.a));
+}
+
+Outer[4] conv_arr4_Outer(Outer_std140 val[4]) {
+  Outer arr[4] = Outer[4](Outer(Inner[4](Inner(f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_Outer(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat2x3 load_a_inner_p0_a_p1_m(uint p0, uint p1) {
+  uint s_save = p0;
+  uint s_save_1 = p1;
+  return f16mat2x3(a.inner[s_save].a[s_save_1].m_0, a.inner[s_save].a[s_save_1].m_1);
+}
+
+f16vec3 load_a_inner_p0_a_p1_m_p2(uint p0, uint p1, uint p2) {
+  switch(p2) {
+    case 0u: {
+      return a.inner[p0].a[p1].m_0;
+      break;
+    }
+    case 1u: {
+      return a.inner[p0].a[p1].m_1;
+      break;
+    }
+    default: {
+      return f16vec3(0.0hf);
+      break;
+    }
+  }
+}
+
+float16_t load_a_inner_p0_a_p1_m_p2_p3(uint p0, uint p1, uint p2, uint p3) {
+  switch(p2) {
+    case 0u: {
+      return a.inner[p0].a[p1].m_0[p3];
+      break;
+    }
+    case 1u: {
+      return a.inner[p0].a[p1].m_1[p3];
+      break;
+    }
+    default: {
+      return 0.0hf;
+      break;
+    }
+  }
+}
+
+void f() {
+  Outer p_a[4] = conv_arr4_Outer(a.inner);
+  int tint_symbol = i();
+  Outer p_a_i = conv_Outer(a.inner[tint_symbol]);
+  Inner p_a_i_a[4] = conv_arr4_Inner(a.inner[tint_symbol].a);
+  int tint_symbol_1 = i();
+  Inner p_a_i_a_i = conv_Inner(a.inner[tint_symbol].a[tint_symbol_1]);
+  f16mat2x3 p_a_i_a_i_m = load_a_inner_p0_a_p1_m(uint(tint_symbol), uint(tint_symbol_1));
+  int tint_symbol_2 = i();
+  f16vec3 p_a_i_a_i_m_i = load_a_inner_p0_a_p1_m_p2(uint(tint_symbol), uint(tint_symbol_1), uint(tint_symbol_2));
+  Outer l_a[4] = conv_arr4_Outer(a.inner);
+  Outer l_a_i = conv_Outer(a.inner[tint_symbol]);
+  Inner l_a_i_a[4] = conv_arr4_Inner(a.inner[tint_symbol].a);
+  Inner l_a_i_a_i = conv_Inner(a.inner[tint_symbol].a[tint_symbol_1]);
+  f16mat2x3 l_a_i_a_i_m = load_a_inner_p0_a_p1_m(uint(tint_symbol), uint(tint_symbol_1));
+  f16vec3 l_a_i_a_i_m_i = load_a_inner_p0_a_p1_m_p2(uint(tint_symbol), uint(tint_symbol_1), uint(tint_symbol_2));
+  int tint_symbol_3 = i();
+  float16_t l_a_i_a_i_m_i_i = load_a_inner_p0_a_p1_m_p2_p3(uint(tint_symbol), uint(tint_symbol_1), uint(tint_symbol_2), uint(tint_symbol_3));
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..322c363
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,49 @@
+#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 Inner {
+  /* 0x0000 */ half2x3 m;
+  /* 0x0010 */ tint_array<int8_t, 48> tint_pad;
+};
+
+struct Outer {
+  /* 0x0000 */ tint_array<Inner, 4> a;
+};
+
+int i() {
+  thread int tint_symbol_4 = 0;
+  tint_symbol_4 = as_type<int>((as_type<uint>(tint_symbol_4) + as_type<uint>(1)));
+  return tint_symbol_4;
+}
+
+kernel void f(const constant tint_array<Outer, 4>* tint_symbol_5 [[buffer(0)]]) {
+  int const tint_symbol = i();
+  int const p_a_i_save = tint_symbol;
+  int const tint_symbol_1 = i();
+  int const p_a_i_a_i_save = tint_symbol_1;
+  int const tint_symbol_2 = i();
+  int const p_a_i_a_i_m_i_save = tint_symbol_2;
+  tint_array<Outer, 4> const l_a = *(tint_symbol_5);
+  Outer const l_a_i = (*(tint_symbol_5))[p_a_i_save];
+  tint_array<Inner, 4> const l_a_i_a = (*(tint_symbol_5))[p_a_i_save].a;
+  Inner const l_a_i_a_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save];
+  half2x3 const l_a_i_a_i_m = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m;
+  half3 const l_a_i_a_i_m_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save];
+  int const tint_symbol_3 = i();
+  half const l_a_i_a_i_m_i_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save][tint_symbol_3];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..7710af2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,310 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 193
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block_std140 "a_block_std140"
+               OpMemberName %a_block_std140 0 "inner"
+               OpName %Outer_std140 "Outer_std140"
+               OpMemberName %Outer_std140 0 "a"
+               OpName %Inner_std140 "Inner_std140"
+               OpMemberName %Inner_std140 0 "m_0"
+               OpMemberName %Inner_std140 1 "m_1"
+               OpName %a "a"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %Inner "Inner"
+               OpMemberName %Inner 0 "m"
+               OpName %conv_Inner "conv_Inner"
+               OpName %val "val"
+               OpName %conv_arr4_Inner "conv_arr4_Inner"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i_0 "i"
+               OpName %var_for_index_1 "var_for_index_1"
+               OpName %Outer "Outer"
+               OpMemberName %Outer 0 "a"
+               OpName %conv_Outer "conv_Outer"
+               OpName %val_1 "val"
+               OpName %conv_arr4_Outer "conv_arr4_Outer"
+               OpName %val_2 "val"
+               OpName %arr_0 "arr"
+               OpName %i_1 "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_a_inner_p0_a_p1_m "load_a_inner_p0_a_p1_m"
+               OpName %p0 "p0"
+               OpName %p1 "p1"
+               OpName %load_a_inner_p0_a_p1_m_p2 "load_a_inner_p0_a_p1_m_p2"
+               OpName %p0_0 "p0"
+               OpName %p1_0 "p1"
+               OpName %p2 "p2"
+               OpName %load_a_inner_p0_a_p1_m_p2_p3 "load_a_inner_p0_a_p1_m_p2_p3"
+               OpName %p0_1 "p0"
+               OpName %p1_1 "p1"
+               OpName %p2_0 "p2"
+               OpName %p3 "p3"
+               OpName %f "f"
+               OpDecorate %a_block_std140 Block
+               OpMemberDecorate %a_block_std140 0 Offset 0
+               OpMemberDecorate %Outer_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 1 Offset 8
+               OpDecorate %_arr_Inner_std140_uint_4 ArrayStride 64
+               OpDecorate %_arr_Outer_std140_uint_4 ArrayStride 256
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+               OpMemberDecorate %Inner 0 Offset 0
+               OpMemberDecorate %Inner 0 ColMajor
+               OpMemberDecorate %Inner 0 MatrixStride 8
+               OpDecorate %_arr_Inner_uint_4 ArrayStride 64
+               OpMemberDecorate %Outer 0 Offset 0
+               OpDecorate %_arr_Outer_uint_4 ArrayStride 256
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+%Inner_std140 = OpTypeStruct %v3half %v3half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_Inner_std140_uint_4 = OpTypeArray %Inner_std140 %uint_4
+%Outer_std140 = OpTypeStruct %_arr_Inner_std140_uint_4
+%_arr_Outer_std140_uint_4 = OpTypeArray %Outer_std140 %uint_4
+%a_block_std140 = OpTypeStruct %_arr_Outer_std140_uint_4
+%_ptr_Uniform_a_block_std140 = OpTypePointer Uniform %a_block_std140
+          %a = OpVariable %_ptr_Uniform_a_block_std140 Uniform
+        %int = OpTypeInt 32 1
+         %13 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %13
+         %16 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+ %mat2v3half = OpTypeMatrix %v3half 2
+      %Inner = OpTypeStruct %mat2v3half
+         %23 = OpTypeFunction %Inner %Inner_std140
+%_arr_Inner_uint_4 = OpTypeArray %Inner %uint_4
+         %33 = OpTypeFunction %_arr_Inner_uint_4 %_arr_Inner_std140_uint_4
+%_ptr_Function__arr_Inner_uint_4 = OpTypePointer Function %_arr_Inner_uint_4
+         %40 = OpConstantNull %_arr_Inner_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %43 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_Inner_std140_uint_4 = OpTypePointer Function %_arr_Inner_std140_uint_4
+         %56 = OpConstantNull %_arr_Inner_std140_uint_4
+%_ptr_Function_Inner = OpTypePointer Function %Inner
+%_ptr_Function_Inner_std140 = OpTypePointer Function %Inner_std140
+     %uint_1 = OpConstant %uint 1
+      %Outer = OpTypeStruct %_arr_Inner_uint_4
+         %69 = OpTypeFunction %Outer %Outer_std140
+%_arr_Outer_uint_4 = OpTypeArray %Outer %uint_4
+         %77 = OpTypeFunction %_arr_Outer_uint_4 %_arr_Outer_std140_uint_4
+%_ptr_Function__arr_Outer_uint_4 = OpTypePointer Function %_arr_Outer_uint_4
+         %84 = OpConstantNull %_arr_Outer_uint_4
+%_ptr_Function__arr_Outer_std140_uint_4 = OpTypePointer Function %_arr_Outer_std140_uint_4
+         %97 = OpConstantNull %_arr_Outer_std140_uint_4
+%_ptr_Function_Outer = OpTypePointer Function %Outer
+%_ptr_Function_Outer_std140 = OpTypePointer Function %Outer_std140
+        %109 = OpTypeFunction %mat2v3half %uint %uint
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_Inner_std140 = OpTypePointer Uniform %Inner_std140
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+        %126 = OpTypeFunction %v3half %uint %uint %uint
+        %140 = OpConstantNull %v3half
+        %141 = OpTypeFunction %half %uint %uint %uint %uint
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+        %157 = OpConstantNull %half
+       %void = OpTypeVoid
+        %158 = OpTypeFunction %void
+%_ptr_Uniform__arr_Outer_std140_uint_4 = OpTypePointer Uniform %_arr_Outer_std140_uint_4
+%_ptr_Uniform_Outer_std140 = OpTypePointer Uniform %Outer_std140
+%_ptr_Uniform__arr_Inner_std140_uint_4 = OpTypePointer Uniform %_arr_Inner_std140_uint_4
+          %i = OpFunction %int None %16
+         %18 = OpLabel
+         %19 = OpLoad %int %counter
+         %21 = OpIAdd %int %19 %int_1
+               OpStore %counter %21
+         %22 = OpLoad %int %counter
+               OpReturnValue %22
+               OpFunctionEnd
+ %conv_Inner = OpFunction %Inner None %23
+        %val = OpFunctionParameter %Inner_std140
+         %28 = OpLabel
+         %29 = OpCompositeExtract %v3half %val 0
+         %30 = OpCompositeExtract %v3half %val 1
+         %31 = OpCompositeConstruct %mat2v3half %29 %30
+         %32 = OpCompositeConstruct %Inner %31
+               OpReturnValue %32
+               OpFunctionEnd
+%conv_arr4_Inner = OpFunction %_arr_Inner_uint_4 None %33
+      %val_0 = OpFunctionParameter %_arr_Inner_std140_uint_4
+         %37 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_Inner_uint_4 Function %40
+        %i_0 = OpVariable %_ptr_Function_uint Function %43
+%var_for_index_1 = OpVariable %_ptr_Function__arr_Inner_std140_uint_4 Function %56
+               OpBranch %44
+         %44 = OpLabel
+               OpLoopMerge %45 %46 None
+               OpBranch %47
+         %47 = OpLabel
+         %49 = OpLoad %uint %i_0
+         %50 = OpULessThan %bool %49 %uint_4
+         %48 = OpLogicalNot %bool %50
+               OpSelectionMerge %52 None
+               OpBranchConditional %48 %53 %52
+         %53 = OpLabel
+               OpBranch %45
+         %52 = OpLabel
+               OpStore %var_for_index_1 %val_0
+         %57 = OpLoad %uint %i_0
+         %59 = OpAccessChain %_ptr_Function_Inner %arr %57
+         %61 = OpLoad %uint %i_0
+         %63 = OpAccessChain %_ptr_Function_Inner_std140 %var_for_index_1 %61
+         %64 = OpLoad %Inner_std140 %63
+         %60 = OpFunctionCall %Inner %conv_Inner %64
+               OpStore %59 %60
+               OpBranch %46
+         %46 = OpLabel
+         %65 = OpLoad %uint %i_0
+         %67 = OpIAdd %uint %65 %uint_1
+               OpStore %i_0 %67
+               OpBranch %44
+         %45 = OpLabel
+         %68 = OpLoad %_arr_Inner_uint_4 %arr
+               OpReturnValue %68
+               OpFunctionEnd
+ %conv_Outer = OpFunction %Outer None %69
+      %val_1 = OpFunctionParameter %Outer_std140
+         %73 = OpLabel
+         %75 = OpCompositeExtract %_arr_Inner_std140_uint_4 %val_1 0
+         %74 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %75
+         %76 = OpCompositeConstruct %Outer %74
+               OpReturnValue %76
+               OpFunctionEnd
+%conv_arr4_Outer = OpFunction %_arr_Outer_uint_4 None %77
+      %val_2 = OpFunctionParameter %_arr_Outer_std140_uint_4
+         %81 = OpLabel
+      %arr_0 = OpVariable %_ptr_Function__arr_Outer_uint_4 Function %84
+        %i_1 = OpVariable %_ptr_Function_uint Function %43
+%var_for_index = OpVariable %_ptr_Function__arr_Outer_std140_uint_4 Function %97
+               OpBranch %86
+         %86 = OpLabel
+               OpLoopMerge %87 %88 None
+               OpBranch %89
+         %89 = OpLabel
+         %91 = OpLoad %uint %i_1
+         %92 = OpULessThan %bool %91 %uint_4
+         %90 = OpLogicalNot %bool %92
+               OpSelectionMerge %93 None
+               OpBranchConditional %90 %94 %93
+         %94 = OpLabel
+               OpBranch %87
+         %93 = OpLabel
+               OpStore %var_for_index %val_2
+         %98 = OpLoad %uint %i_1
+        %100 = OpAccessChain %_ptr_Function_Outer %arr_0 %98
+        %102 = OpLoad %uint %i_1
+        %104 = OpAccessChain %_ptr_Function_Outer_std140 %var_for_index %102
+        %105 = OpLoad %Outer_std140 %104
+        %101 = OpFunctionCall %Outer %conv_Outer %105
+               OpStore %100 %101
+               OpBranch %88
+         %88 = OpLabel
+        %106 = OpLoad %uint %i_1
+        %107 = OpIAdd %uint %106 %uint_1
+               OpStore %i_1 %107
+               OpBranch %86
+         %87 = OpLabel
+        %108 = OpLoad %_arr_Outer_uint_4 %arr_0
+               OpReturnValue %108
+               OpFunctionEnd
+%load_a_inner_p0_a_p1_m = OpFunction %mat2v3half None %109
+         %p0 = OpFunctionParameter %uint
+         %p1 = OpFunctionParameter %uint
+        %113 = OpLabel
+        %117 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %p0 %uint_0 %p1
+        %120 = OpAccessChain %_ptr_Uniform_v3half %117 %uint_0
+        %121 = OpLoad %v3half %120
+        %123 = OpAccessChain %_ptr_Uniform_v3half %117 %uint_1
+        %124 = OpLoad %v3half %123
+        %125 = OpCompositeConstruct %mat2v3half %121 %124
+               OpReturnValue %125
+               OpFunctionEnd
+%load_a_inner_p0_a_p1_m_p2 = OpFunction %v3half None %126
+       %p0_0 = OpFunctionParameter %uint
+       %p1_0 = OpFunctionParameter %uint
+         %p2 = OpFunctionParameter %uint
+        %131 = OpLabel
+               OpSelectionMerge %132 None
+               OpSwitch %p2 %133 0 %134 1 %135
+        %134 = OpLabel
+        %136 = OpAccessChain %_ptr_Uniform_v3half %a %uint_0 %p0_0 %uint_0 %p1_0 %uint_0
+        %137 = OpLoad %v3half %136
+               OpReturnValue %137
+        %135 = OpLabel
+        %138 = OpAccessChain %_ptr_Uniform_v3half %a %uint_0 %p0_0 %uint_0 %p1_0 %uint_1
+        %139 = OpLoad %v3half %138
+               OpReturnValue %139
+        %133 = OpLabel
+               OpReturnValue %140
+        %132 = OpLabel
+               OpReturnValue %140
+               OpFunctionEnd
+%load_a_inner_p0_a_p1_m_p2_p3 = OpFunction %half None %141
+       %p0_1 = OpFunctionParameter %uint
+       %p1_1 = OpFunctionParameter %uint
+       %p2_0 = OpFunctionParameter %uint
+         %p3 = OpFunctionParameter %uint
+        %147 = OpLabel
+               OpSelectionMerge %148 None
+               OpSwitch %p2_0 %149 0 %150 1 %151
+        %150 = OpLabel
+        %153 = OpAccessChain %_ptr_Uniform_half %a %uint_0 %p0_1 %uint_0 %p1_1 %uint_0 %p3
+        %154 = OpLoad %half %153
+               OpReturnValue %154
+        %151 = OpLabel
+        %155 = OpAccessChain %_ptr_Uniform_half %a %uint_0 %p0_1 %uint_0 %p1_1 %uint_1 %p3
+        %156 = OpLoad %half %155
+               OpReturnValue %156
+        %149 = OpLabel
+               OpReturnValue %157
+        %148 = OpLabel
+               OpReturnValue %157
+               OpFunctionEnd
+          %f = OpFunction %void None %158
+        %161 = OpLabel
+        %162 = OpFunctionCall %int %i
+        %163 = OpFunctionCall %int %i
+        %164 = OpFunctionCall %int %i
+        %167 = OpAccessChain %_ptr_Uniform__arr_Outer_std140_uint_4 %a %uint_0
+        %168 = OpLoad %_arr_Outer_std140_uint_4 %167
+        %165 = OpFunctionCall %_arr_Outer_uint_4 %conv_arr4_Outer %168
+        %171 = OpAccessChain %_ptr_Uniform_Outer_std140 %a %uint_0 %162
+        %172 = OpLoad %Outer_std140 %171
+        %169 = OpFunctionCall %Outer %conv_Outer %172
+        %175 = OpAccessChain %_ptr_Uniform__arr_Inner_std140_uint_4 %a %uint_0 %162 %uint_0
+        %176 = OpLoad %_arr_Inner_std140_uint_4 %175
+        %173 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %176
+        %178 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %162 %uint_0 %163
+        %179 = OpLoad %Inner_std140 %178
+        %177 = OpFunctionCall %Inner %conv_Inner %179
+        %181 = OpBitcast %uint %162
+        %182 = OpBitcast %uint %163
+        %180 = OpFunctionCall %mat2v3half %load_a_inner_p0_a_p1_m %181 %182
+        %184 = OpBitcast %uint %162
+        %185 = OpBitcast %uint %163
+        %186 = OpBitcast %uint %164
+        %183 = OpFunctionCall %v3half %load_a_inner_p0_a_p1_m_p2 %184 %185 %186
+        %187 = OpFunctionCall %int %i
+        %189 = OpBitcast %uint %162
+        %190 = OpBitcast %uint %163
+        %191 = OpBitcast %uint %164
+        %192 = OpBitcast %uint %187
+        %188 = OpFunctionCall %half %load_a_inner_p0_a_p1_m_p2_p3 %189 %190 %191 %192
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..67b4731
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,36 @@
+enable f16;
+
+struct Inner {
+  @size(64)
+  m : mat2x3<f16>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_i = &((*(p_a))[i()]);
+  let p_a_i_a = &((*(p_a_i)).a);
+  let p_a_i_a_i = &((*(p_a_i_a))[i()]);
+  let p_a_i_a_i_m = &((*(p_a_i_a_i)).m);
+  let p_a_i_a_i_m_i = &((*(p_a_i_a_i_m))[i()]);
+  let l_a : array<Outer, 4> = *(p_a);
+  let l_a_i : Outer = *(p_a_i);
+  let l_a_i_a : array<Inner, 4> = *(p_a_i_a);
+  let l_a_i_a_i : Inner = *(p_a_i_a_i);
+  let l_a_i_a_i_m : mat2x3<f16> = *(p_a_i_a_i_m);
+  let l_a_i_a_i_m_i : vec3<f16> = *(p_a_i_a_i_m_i);
+  let l_a_i_a_i_m_i_i : f16 = (*(p_a_i_a_i_m_i))[i()];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/static_index_via_ptr.wgsl
new file mode 100644
index 0000000..8f21106
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/static_index_via_ptr.wgsl
@@ -0,0 +1,31 @@
+enable f16;
+
+struct Inner {
+  @size(64)
+  m : mat2x3<f16>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &a;
+  let p_a_3 = &((*p_a)[3]);
+  let p_a_3_a = &((*p_a_3).a);
+  let p_a_3_a_2 = &((*p_a_3_a)[2]);
+  let p_a_3_a_2_m = &((*p_a_3_a_2).m);
+  let p_a_3_a_2_m_1 = &((*p_a_3_a_2_m)[1]);
+
+
+  let l_a             : array<Outer, 4> = *p_a;
+  let l_a_3           : Outer           = *p_a_3;
+  let l_a_3_a         : array<Inner, 4> = *p_a_3_a;
+  let l_a_3_a_2       : Inner           = *p_a_3_a_2;
+  let l_a_3_a_2_m     : mat2x3<f16>     = *p_a_3_a_2_m;
+  let l_a_3_a_2_m_1   : vec3<f16>       = *p_a_3_a_2_m_1;
+  let l_a_3_a_2_m_1_0 : f16             = (*p_a_3_a_2_m_1)[0];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..eca3eed
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,71 @@
+struct Inner {
+  matrix<float16_t, 2, 3> m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+
+matrix<float16_t, 2, 3> tint_symbol_4(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
+}
+
+Inner tint_symbol_3(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_7 = {tint_symbol_4(buffer, (offset + 0u))};
+  return tint_symbol_7;
+}
+
+typedef Inner tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_3(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_1(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_8 = {tint_symbol_2(buffer, (offset + 0u))};
+  return tint_symbol_8;
+}
+
+typedef Outer tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr_1[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const Outer l_a[4] = tint_symbol(a, 0u);
+  const Outer l_a_3 = tint_symbol_1(a, 768u);
+  const Inner l_a_3_a[4] = tint_symbol_2(a, 768u);
+  const Inner l_a_3_a_2 = tint_symbol_3(a, 896u);
+  const matrix<float16_t, 2, 3> l_a_3_a_2_m = tint_symbol_4(a, 896u);
+  uint2 ubo_load_4 = a[56].zw;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const vector<float16_t, 3> l_a_3_a_2_m_1 = vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]);
+  const float16_t l_a_3_a_2_m_1_0 = float16_t(f16tof32(((a[56].z) & 0xFFFF)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..b6de301
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,76 @@
+SKIP: FAILED
+
+struct Inner {
+  matrix<float16_t, 2, 3> m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+
+matrix<float16_t, 2, 3> tint_symbol_4(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
+}
+
+Inner tint_symbol_3(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_7 = {tint_symbol_4(buffer, (offset + 0u))};
+  return tint_symbol_7;
+}
+
+typedef Inner tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_3(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_1(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_8 = {tint_symbol_2(buffer, (offset + 0u))};
+  return tint_symbol_8;
+}
+
+typedef Outer tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr_1[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const Outer l_a[4] = tint_symbol(a, 0u);
+  const Outer l_a_3 = tint_symbol_1(a, 768u);
+  const Inner l_a_3_a[4] = tint_symbol_2(a, 768u);
+  const Inner l_a_3_a_2 = tint_symbol_3(a, 896u);
+  const matrix<float16_t, 2, 3> l_a_3_a_2_m = tint_symbol_4(a, 896u);
+  uint2 ubo_load_4 = a[56].zw;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const vector<float16_t, 3> l_a_3_a_2_m_1 = vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]);
+  const float16_t l_a_3_a_2_m_1_0 = float16_t(f16tof32(((a[56].z) & 0xFFFF)));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000016A3B044D10(2,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/static_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..1a1a8cc
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/static_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,101 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct Inner {
+  f16mat2x3 m;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+};
+
+struct Inner_std140 {
+  f16vec3 m_0;
+  f16vec3 m_1;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+};
+
+struct Outer {
+  Inner a[4];
+};
+
+struct Outer_std140 {
+  Inner_std140 a[4];
+};
+
+layout(binding = 0, std140) uniform a_block_std140_ubo {
+  Outer_std140 inner[4];
+} a;
+
+Inner conv_Inner(Inner_std140 val) {
+  return Inner(f16mat2x3(val.m_0, val.m_1), val.pad, val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.pad_11);
+}
+
+Inner[4] conv_arr4_Inner(Inner_std140 val[4]) {
+  Inner arr[4] = Inner[4](Inner(f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_Inner(val[i]);
+    }
+  }
+  return arr;
+}
+
+Outer conv_Outer(Outer_std140 val) {
+  return Outer(conv_arr4_Inner(val.a));
+}
+
+Outer[4] conv_arr4_Outer(Outer_std140 val[4]) {
+  Outer arr[4] = Outer[4](Outer(Inner[4](Inner(f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_Outer(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat2x3 load_a_inner_3_a_2_m() {
+  return f16mat2x3(a.inner[3u].a[2u].m_0, a.inner[3u].a[2u].m_1);
+}
+
+void f() {
+  Outer p_a[4] = conv_arr4_Outer(a.inner);
+  Outer p_a_3 = conv_Outer(a.inner[3u]);
+  Inner p_a_3_a[4] = conv_arr4_Inner(a.inner[3u].a);
+  Inner p_a_3_a_2 = conv_Inner(a.inner[3u].a[2u]);
+  f16mat2x3 p_a_3_a_2_m = load_a_inner_3_a_2_m();
+  f16vec3 p_a_3_a_2_m_1 = a.inner[3u].a[2u].m_1;
+  Outer l_a[4] = conv_arr4_Outer(a.inner);
+  Outer l_a_3 = conv_Outer(a.inner[3u]);
+  Inner l_a_3_a[4] = conv_arr4_Inner(a.inner[3u].a);
+  Inner l_a_3_a_2 = conv_Inner(a.inner[3u].a[2u]);
+  f16mat2x3 l_a_3_a_2_m = load_a_inner_3_a_2_m();
+  f16vec3 l_a_3_a_2_m_1 = a.inner[3u].a[2u].m_1;
+  float16_t l_a_3_a_2_m_1_0 = a.inner[3u].a[2u].m_1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/static_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..646eacf
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/static_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,36 @@
+#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 Inner {
+  /* 0x0000 */ half2x3 m;
+  /* 0x0010 */ tint_array<int8_t, 48> tint_pad;
+};
+
+struct Outer {
+  /* 0x0000 */ tint_array<Inner, 4> a;
+};
+
+kernel void f(const constant tint_array<Outer, 4>* tint_symbol [[buffer(0)]]) {
+  tint_array<Outer, 4> const l_a = *(tint_symbol);
+  Outer const l_a_3 = (*(tint_symbol))[3];
+  tint_array<Inner, 4> const l_a_3_a = (*(tint_symbol))[3].a;
+  Inner const l_a_3_a_2 = (*(tint_symbol))[3].a[2];
+  half2x3 const l_a_3_a_2_m = (*(tint_symbol))[3].a[2].m;
+  half3 const l_a_3_a_2_m_1 = (*(tint_symbol))[3].a[2].m[1];
+  half const l_a_3_a_2_m_1_0 = (*(tint_symbol))[3].a[2].m[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/static_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..8522fa4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/static_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,227 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 140
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block_std140 "a_block_std140"
+               OpMemberName %a_block_std140 0 "inner"
+               OpName %Outer_std140 "Outer_std140"
+               OpMemberName %Outer_std140 0 "a"
+               OpName %Inner_std140 "Inner_std140"
+               OpMemberName %Inner_std140 0 "m_0"
+               OpMemberName %Inner_std140 1 "m_1"
+               OpName %a "a"
+               OpName %Inner "Inner"
+               OpMemberName %Inner 0 "m"
+               OpName %conv_Inner "conv_Inner"
+               OpName %val "val"
+               OpName %conv_arr4_Inner "conv_arr4_Inner"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index_1 "var_for_index_1"
+               OpName %Outer "Outer"
+               OpMemberName %Outer 0 "a"
+               OpName %conv_Outer "conv_Outer"
+               OpName %val_1 "val"
+               OpName %conv_arr4_Outer "conv_arr4_Outer"
+               OpName %val_2 "val"
+               OpName %arr_0 "arr"
+               OpName %i_0 "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_a_inner_3_a_2_m "load_a_inner_3_a_2_m"
+               OpName %f "f"
+               OpDecorate %a_block_std140 Block
+               OpMemberDecorate %a_block_std140 0 Offset 0
+               OpMemberDecorate %Outer_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 1 Offset 8
+               OpDecorate %_arr_Inner_std140_uint_4 ArrayStride 64
+               OpDecorate %_arr_Outer_std140_uint_4 ArrayStride 256
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+               OpMemberDecorate %Inner 0 Offset 0
+               OpMemberDecorate %Inner 0 ColMajor
+               OpMemberDecorate %Inner 0 MatrixStride 8
+               OpDecorate %_arr_Inner_uint_4 ArrayStride 64
+               OpMemberDecorate %Outer 0 Offset 0
+               OpDecorate %_arr_Outer_uint_4 ArrayStride 256
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+%Inner_std140 = OpTypeStruct %v3half %v3half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_Inner_std140_uint_4 = OpTypeArray %Inner_std140 %uint_4
+%Outer_std140 = OpTypeStruct %_arr_Inner_std140_uint_4
+%_arr_Outer_std140_uint_4 = OpTypeArray %Outer_std140 %uint_4
+%a_block_std140 = OpTypeStruct %_arr_Outer_std140_uint_4
+%_ptr_Uniform_a_block_std140 = OpTypePointer Uniform %a_block_std140
+          %a = OpVariable %_ptr_Uniform_a_block_std140 Uniform
+ %mat2v3half = OpTypeMatrix %v3half 2
+      %Inner = OpTypeStruct %mat2v3half
+         %12 = OpTypeFunction %Inner %Inner_std140
+%_arr_Inner_uint_4 = OpTypeArray %Inner %uint_4
+         %22 = OpTypeFunction %_arr_Inner_uint_4 %_arr_Inner_std140_uint_4
+%_ptr_Function__arr_Inner_uint_4 = OpTypePointer Function %_arr_Inner_uint_4
+         %29 = OpConstantNull %_arr_Inner_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %32 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_Inner_std140_uint_4 = OpTypePointer Function %_arr_Inner_std140_uint_4
+         %45 = OpConstantNull %_arr_Inner_std140_uint_4
+%_ptr_Function_Inner = OpTypePointer Function %Inner
+%_ptr_Function_Inner_std140 = OpTypePointer Function %Inner_std140
+     %uint_1 = OpConstant %uint 1
+      %Outer = OpTypeStruct %_arr_Inner_uint_4
+         %58 = OpTypeFunction %Outer %Outer_std140
+%_arr_Outer_uint_4 = OpTypeArray %Outer %uint_4
+         %66 = OpTypeFunction %_arr_Outer_uint_4 %_arr_Outer_std140_uint_4
+%_ptr_Function__arr_Outer_uint_4 = OpTypePointer Function %_arr_Outer_uint_4
+         %73 = OpConstantNull %_arr_Outer_uint_4
+%_ptr_Function__arr_Outer_std140_uint_4 = OpTypePointer Function %_arr_Outer_std140_uint_4
+         %86 = OpConstantNull %_arr_Outer_std140_uint_4
+%_ptr_Function_Outer = OpTypePointer Function %Outer
+%_ptr_Function_Outer_std140 = OpTypePointer Function %Outer_std140
+         %98 = OpTypeFunction %mat2v3half
+     %uint_0 = OpConstant %uint 0
+     %uint_3 = OpConstant %uint 3
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_Inner_std140 = OpTypePointer Uniform %Inner_std140
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+       %void = OpTypeVoid
+        %115 = OpTypeFunction %void
+%_ptr_Uniform__arr_Outer_std140_uint_4 = OpTypePointer Uniform %_arr_Outer_std140_uint_4
+%_ptr_Uniform_Outer_std140 = OpTypePointer Uniform %Outer_std140
+%_ptr_Uniform__arr_Inner_std140_uint_4 = OpTypePointer Uniform %_arr_Inner_std140_uint_4
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+ %conv_Inner = OpFunction %Inner None %12
+        %val = OpFunctionParameter %Inner_std140
+         %17 = OpLabel
+         %18 = OpCompositeExtract %v3half %val 0
+         %19 = OpCompositeExtract %v3half %val 1
+         %20 = OpCompositeConstruct %mat2v3half %18 %19
+         %21 = OpCompositeConstruct %Inner %20
+               OpReturnValue %21
+               OpFunctionEnd
+%conv_arr4_Inner = OpFunction %_arr_Inner_uint_4 None %22
+      %val_0 = OpFunctionParameter %_arr_Inner_std140_uint_4
+         %26 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_Inner_uint_4 Function %29
+          %i = OpVariable %_ptr_Function_uint Function %32
+%var_for_index_1 = OpVariable %_ptr_Function__arr_Inner_std140_uint_4 Function %45
+               OpBranch %33
+         %33 = OpLabel
+               OpLoopMerge %34 %35 None
+               OpBranch %36
+         %36 = OpLabel
+         %38 = OpLoad %uint %i
+         %39 = OpULessThan %bool %38 %uint_4
+         %37 = OpLogicalNot %bool %39
+               OpSelectionMerge %41 None
+               OpBranchConditional %37 %42 %41
+         %42 = OpLabel
+               OpBranch %34
+         %41 = OpLabel
+               OpStore %var_for_index_1 %val_0
+         %46 = OpLoad %uint %i
+         %48 = OpAccessChain %_ptr_Function_Inner %arr %46
+         %50 = OpLoad %uint %i
+         %52 = OpAccessChain %_ptr_Function_Inner_std140 %var_for_index_1 %50
+         %53 = OpLoad %Inner_std140 %52
+         %49 = OpFunctionCall %Inner %conv_Inner %53
+               OpStore %48 %49
+               OpBranch %35
+         %35 = OpLabel
+         %54 = OpLoad %uint %i
+         %56 = OpIAdd %uint %54 %uint_1
+               OpStore %i %56
+               OpBranch %33
+         %34 = OpLabel
+         %57 = OpLoad %_arr_Inner_uint_4 %arr
+               OpReturnValue %57
+               OpFunctionEnd
+ %conv_Outer = OpFunction %Outer None %58
+      %val_1 = OpFunctionParameter %Outer_std140
+         %62 = OpLabel
+         %64 = OpCompositeExtract %_arr_Inner_std140_uint_4 %val_1 0
+         %63 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %64
+         %65 = OpCompositeConstruct %Outer %63
+               OpReturnValue %65
+               OpFunctionEnd
+%conv_arr4_Outer = OpFunction %_arr_Outer_uint_4 None %66
+      %val_2 = OpFunctionParameter %_arr_Outer_std140_uint_4
+         %70 = OpLabel
+      %arr_0 = OpVariable %_ptr_Function__arr_Outer_uint_4 Function %73
+        %i_0 = OpVariable %_ptr_Function_uint Function %32
+%var_for_index = OpVariable %_ptr_Function__arr_Outer_std140_uint_4 Function %86
+               OpBranch %75
+         %75 = OpLabel
+               OpLoopMerge %76 %77 None
+               OpBranch %78
+         %78 = OpLabel
+         %80 = OpLoad %uint %i_0
+         %81 = OpULessThan %bool %80 %uint_4
+         %79 = OpLogicalNot %bool %81
+               OpSelectionMerge %82 None
+               OpBranchConditional %79 %83 %82
+         %83 = OpLabel
+               OpBranch %76
+         %82 = OpLabel
+               OpStore %var_for_index %val_2
+         %87 = OpLoad %uint %i_0
+         %89 = OpAccessChain %_ptr_Function_Outer %arr_0 %87
+         %91 = OpLoad %uint %i_0
+         %93 = OpAccessChain %_ptr_Function_Outer_std140 %var_for_index %91
+         %94 = OpLoad %Outer_std140 %93
+         %90 = OpFunctionCall %Outer %conv_Outer %94
+               OpStore %89 %90
+               OpBranch %77
+         %77 = OpLabel
+         %95 = OpLoad %uint %i_0
+         %96 = OpIAdd %uint %95 %uint_1
+               OpStore %i_0 %96
+               OpBranch %75
+         %76 = OpLabel
+         %97 = OpLoad %_arr_Outer_uint_4 %arr_0
+               OpReturnValue %97
+               OpFunctionEnd
+%load_a_inner_3_a_2_m = OpFunction %mat2v3half None %98
+        %100 = OpLabel
+        %106 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %uint_3 %uint_0 %uint_2
+        %109 = OpAccessChain %_ptr_Uniform_v3half %106 %uint_0
+        %110 = OpLoad %v3half %109
+        %112 = OpAccessChain %_ptr_Uniform_v3half %106 %uint_1
+        %113 = OpLoad %v3half %112
+        %114 = OpCompositeConstruct %mat2v3half %110 %113
+               OpReturnValue %114
+               OpFunctionEnd
+          %f = OpFunction %void None %115
+        %118 = OpLabel
+        %121 = OpAccessChain %_ptr_Uniform__arr_Outer_std140_uint_4 %a %uint_0
+        %122 = OpLoad %_arr_Outer_std140_uint_4 %121
+        %119 = OpFunctionCall %_arr_Outer_uint_4 %conv_arr4_Outer %122
+        %125 = OpAccessChain %_ptr_Uniform_Outer_std140 %a %uint_0 %uint_3
+        %126 = OpLoad %Outer_std140 %125
+        %123 = OpFunctionCall %Outer %conv_Outer %126
+        %129 = OpAccessChain %_ptr_Uniform__arr_Inner_std140_uint_4 %a %uint_0 %uint_3 %uint_0
+        %130 = OpLoad %_arr_Inner_std140_uint_4 %129
+        %127 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %130
+        %132 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %uint_3 %uint_0 %uint_2
+        %133 = OpLoad %Inner_std140 %132
+        %131 = OpFunctionCall %Inner %conv_Inner %133
+        %134 = OpFunctionCall %mat2v3half %load_a_inner_3_a_2_m
+        %135 = OpAccessChain %_ptr_Uniform_v3half %a %uint_0 %uint_3 %uint_0 %uint_2 %uint_1
+        %136 = OpLoad %v3half %135
+        %138 = OpAccessChain %_ptr_Uniform_half %a %uint_0 %uint_3 %uint_0 %uint_2 %uint_1 %32
+        %139 = OpLoad %half %138
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/static_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..bceee7d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/static_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,29 @@
+enable f16;
+
+struct Inner {
+  @size(64)
+  m : mat2x3<f16>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_3 = &((*(p_a))[3]);
+  let p_a_3_a = &((*(p_a_3)).a);
+  let p_a_3_a_2 = &((*(p_a_3_a))[2]);
+  let p_a_3_a_2_m = &((*(p_a_3_a_2)).m);
+  let p_a_3_a_2_m_1 = &((*(p_a_3_a_2_m))[1]);
+  let l_a : array<Outer, 4> = *(p_a);
+  let l_a_3 : Outer = *(p_a_3);
+  let l_a_3_a : array<Inner, 4> = *(p_a_3_a);
+  let l_a_3_a_2 : Inner = *(p_a_3_a_2);
+  let l_a_3_a_2_m : mat2x3<f16> = *(p_a_3_a_2_m);
+  let l_a_3_a_2_m_1 : vec3<f16> = *(p_a_3_a_2_m_1);
+  let l_a_3_a_2_m_1_0 : f16 = (*(p_a_3_a_2_m_1))[0];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_builtin.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_builtin.wgsl
new file mode 100644
index 0000000..765f539
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_builtin.wgsl
@@ -0,0 +1,17 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat2x3<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    let t = transpose(u[2].m);
+    let l = length(u[0].m[1].zxy);
+    let a = abs(u[0].m[1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_builtin.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..fbcd74f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_builtin.wgsl.expected.dxc.hlsl
@@ -0,0 +1,31 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+matrix<float16_t, 2, 3> tint_symbol(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 3, 2> t = transpose(tint_symbol(u, 264u));
+  uint2 ubo_load_4 = u[1].xy;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const float16_t l = length(vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]).zxy);
+  uint2 ubo_load_5 = u[1].xy;
+  vector<float16_t, 2> ubo_load_5_xz = vector<float16_t, 2>(f16tof32(ubo_load_5 & 0xFFFF));
+  float16_t ubo_load_5_y = f16tof32(ubo_load_5[0] >> 16);
+  const float16_t a = abs(vector<float16_t, 3>(ubo_load_5_xz[0], ubo_load_5_y, ubo_load_5_xz[1]).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_builtin.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..d695652
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_builtin.wgsl.expected.fxc.hlsl
@@ -0,0 +1,36 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+matrix<float16_t, 2, 3> tint_symbol(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 3, 2> t = transpose(tint_symbol(u, 264u));
+  uint2 ubo_load_4 = u[1].xy;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const float16_t l = length(vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]).zxy);
+  uint2 ubo_load_5 = u[1].xy;
+  vector<float16_t, 2> ubo_load_5_xz = vector<float16_t, 2>(f16tof32(ubo_load_5 & 0xFFFF));
+  float16_t ubo_load_5_y = f16tof32(ubo_load_5[0] >> 16);
+  const float16_t a = abs(vector<float16_t, 3>(ubo_load_5_xz[0], ubo_load_5_y, ubo_load_5_xz[1]).zxy.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000002BEEDB9DED0(5,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_builtin.wgsl.expected.glsl
new file mode 100644
index 0000000..55d79ff
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_builtin.wgsl.expected.glsl
@@ -0,0 +1,87 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct S {
+  int before;
+  uint pad;
+  f16mat2x3 m;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  int after;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+};
+
+struct S_std140 {
+  int before;
+  uint pad;
+  f16vec3 m_0;
+  f16vec3 m_1;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  int after;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+f16mat2x3 load_u_inner_2_m() {
+  return f16mat2x3(u.inner[2u].m_0, u.inner[2u].m_1);
+}
+
+void f() {
+  f16mat3x2 t = transpose(load_u_inner_2_m());
+  float16_t l = length(u.inner[0u].m_1.zxy);
+  float16_t a = abs(u.inner[0u].m_1.zxy[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_builtin.wgsl.expected.msl
new file mode 100644
index 0000000..7f897eb
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_builtin.wgsl.expected.msl
@@ -0,0 +1,32 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0008 */ half2x3 m;
+  /* 0x0018 */ tint_array<int8_t, 40> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol [[buffer(0)]]) {
+  half3x2 const t = transpose((*(tint_symbol))[2].m);
+  half const l = length(half3((*(tint_symbol))[0].m[1]).zxy);
+  half const a = fabs(half3((*(tint_symbol))[0].m[1]).zxy[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_builtin.wgsl.expected.spvasm
new file mode 100644
index 0000000..f0c24f2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_builtin.wgsl.expected.spvasm
@@ -0,0 +1,81 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 48
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+         %38 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "after"
+               OpName %u "u"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 8
+               OpMemberDecorate %S_std140 2 Offset 16
+               OpMemberDecorate %S_std140 3 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+   %S_std140 = OpTypeStruct %int %v3half %v3half %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat2v3half = OpTypeMatrix %v3half 2
+         %11 = OpTypeFunction %mat2v3half
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+     %uint_1 = OpConstant %uint 1
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+       %void = OpTypeVoid
+         %29 = OpTypeFunction %void
+     %v2half = OpTypeVector %half 2
+ %mat3v2half = OpTypeMatrix %v2half 3
+         %39 = OpConstantNull %uint
+%load_u_inner_2_m = OpFunction %mat2v3half None %11
+         %14 = OpLabel
+         %19 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %23 = OpAccessChain %_ptr_Uniform_v3half %19 %uint_1
+         %24 = OpLoad %v3half %23
+         %26 = OpAccessChain %_ptr_Uniform_v3half %19 %uint_2
+         %27 = OpLoad %v3half %26
+         %28 = OpCompositeConstruct %mat2v3half %24 %27
+               OpReturnValue %28
+               OpFunctionEnd
+          %f = OpFunction %void None %29
+         %32 = OpLabel
+         %36 = OpFunctionCall %mat2v3half %load_u_inner_2_m
+         %33 = OpTranspose %mat3v2half %36
+         %40 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0 %39 %uint_2
+         %41 = OpLoad %v3half %40
+         %42 = OpVectorShuffle %v3half %41 %41 2 0 1
+         %37 = OpExtInst %half %38 Length %42
+         %44 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0 %39 %uint_2
+         %45 = OpLoad %v3half %44
+         %46 = OpVectorShuffle %v3half %45 %45 2 0 1
+         %47 = OpCompositeExtract %half %46 0
+         %43 = OpExtInst %half %38 FAbs %47
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_builtin.wgsl.expected.wgsl
new file mode 100644
index 0000000..37f0157
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_builtin.wgsl.expected.wgsl
@@ -0,0 +1,17 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat2x3<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let t = transpose(u[2].m);
+  let l = length(u[0].m[1].zxy);
+  let a = abs(u[0].m[1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_fn.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_fn.wgsl
new file mode 100644
index 0000000..c601f63
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_fn.wgsl
@@ -0,0 +1,25 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat2x3<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+fn a(a : array<S, 4>) {}
+fn b(s : S) {}
+fn c(m : mat2x3<f16>) {}
+fn d(v : vec3<f16>) {}
+fn e(f : f16) {}
+
+@compute @workgroup_size(1)
+fn f() {
+    a(u);
+    b(u[2]);
+    c(u[2].m);
+    d(u[0].m[1].zxy);
+    e(u[0].m[1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_fn.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..0e799ce
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_fn.wgsl.expected.dxc.hlsl
@@ -0,0 +1,72 @@
+struct S {
+  int before;
+  matrix<float16_t, 2, 3> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(matrix<float16_t, 2, 3> m) {
+}
+
+void d(vector<float16_t, 3> v) {
+}
+
+void e(float16_t f_1) {
+}
+
+matrix<float16_t, 2, 3> tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 256u));
+  c(tint_symbol_3(u, 264u));
+  uint2 ubo_load_4 = u[1].xy;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  d(vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]).zxy);
+  uint2 ubo_load_5 = u[1].xy;
+  vector<float16_t, 2> ubo_load_5_xz = vector<float16_t, 2>(f16tof32(ubo_load_5 & 0xFFFF));
+  float16_t ubo_load_5_y = f16tof32(ubo_load_5[0] >> 16);
+  e(vector<float16_t, 3>(ubo_load_5_xz[0], ubo_load_5_y, ubo_load_5_xz[1]).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_fn.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..aeb6e6f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_fn.wgsl.expected.fxc.hlsl
@@ -0,0 +1,77 @@
+SKIP: FAILED
+
+struct S {
+  int before;
+  matrix<float16_t, 2, 3> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(matrix<float16_t, 2, 3> m) {
+}
+
+void d(vector<float16_t, 3> v) {
+}
+
+void e(float16_t f_1) {
+}
+
+matrix<float16_t, 2, 3> tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 256u));
+  c(tint_symbol_3(u, 264u));
+  uint2 ubo_load_4 = u[1].xy;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  d(vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]).zxy);
+  uint2 ubo_load_5 = u[1].xy;
+  vector<float16_t, 2> ubo_load_5_xz = vector<float16_t, 2>(f16tof32(ubo_load_5 & 0xFFFF));
+  float16_t ubo_load_5_y = f16tof32(ubo_load_5[0] >> 16);
+  e(vector<float16_t, 3>(ubo_load_5_xz[0], ubo_load_5_y, ubo_load_5_xz[1]).zxy.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000002273DEDC980(3,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_fn.wgsl.expected.glsl
new file mode 100644
index 0000000..c0fdc72
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_fn.wgsl.expected.glsl
@@ -0,0 +1,118 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct S {
+  int before;
+  uint pad;
+  f16mat2x3 m;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  int after;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+};
+
+struct S_std140 {
+  int before;
+  uint pad;
+  f16vec3 m_0;
+  f16vec3 m_1;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  int after;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(f16mat2x3 m) {
+}
+
+void d(f16vec3 v) {
+}
+
+void e(float16_t f_1) {
+}
+
+S conv_S(S_std140 val) {
+  return S(val.before, val.pad, f16mat2x3(val.m_0, val.m_1), val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.after, val.pad_11, val.pad_12, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21, val.pad_22, val.pad_23, val.pad_24, val.pad_25);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, 0u, f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat2x3 load_u_inner_2_m() {
+  return f16mat2x3(u.inner[2u].m_0, u.inner[2u].m_1);
+}
+
+void f() {
+  a(conv_arr4_S(u.inner));
+  b(conv_S(u.inner[2u]));
+  c(load_u_inner_2_m());
+  d(u.inner[0u].m_1.zxy);
+  e(u.inner[0u].m_1.zxy[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_fn.wgsl.expected.msl
new file mode 100644
index 0000000..9031d44
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_fn.wgsl.expected.msl
@@ -0,0 +1,49 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0008 */ half2x3 m;
+  /* 0x0018 */ tint_array<int8_t, 40> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+void a(tint_array<S, 4> a_1) {
+}
+
+void b(S s) {
+}
+
+void c(half2x3 m) {
+}
+
+void d(half3 v) {
+}
+
+void e(half f_1) {
+}
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol [[buffer(0)]]) {
+  a(*(tint_symbol));
+  b((*(tint_symbol))[2]);
+  c((*(tint_symbol))[2].m);
+  d(half3((*(tint_symbol))[0].m[1]).zxy);
+  e(half3((*(tint_symbol))[0].m[1]).zxy[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_fn.wgsl.expected.spvasm
new file mode 100644
index 0000000..9f29608
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_fn.wgsl.expected.spvasm
@@ -0,0 +1,204 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 119
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "after"
+               OpName %u "u"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %a "a"
+               OpName %a_1 "a_1"
+               OpName %b "b"
+               OpName %s "s"
+               OpName %c "c"
+               OpName %m "m"
+               OpName %d "d"
+               OpName %v "v"
+               OpName %e "e"
+               OpName %f_1 "f_1"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 8
+               OpMemberDecorate %S_std140 2 Offset 16
+               OpMemberDecorate %S_std140 3 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 8
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 8
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+   %S_std140 = OpTypeStruct %int %v3half %v3half %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+       %void = OpTypeVoid
+ %mat2v3half = OpTypeMatrix %v3half 2
+          %S = OpTypeStruct %int %mat2v3half %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+         %11 = OpTypeFunction %void %_arr_S_uint_4
+         %19 = OpTypeFunction %void %S
+         %23 = OpTypeFunction %void %mat2v3half
+         %27 = OpTypeFunction %void %v3half
+         %31 = OpTypeFunction %void %half
+         %35 = OpTypeFunction %S %S_std140
+         %45 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+         %51 = OpConstantNull %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %54 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %67 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %80 = OpTypeFunction %mat2v3half
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+         %96 = OpTypeFunction %void
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+          %a = OpFunction %void None %11
+        %a_1 = OpFunctionParameter %_arr_S_uint_4
+         %18 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %b = OpFunction %void None %19
+          %s = OpFunctionParameter %S
+         %22 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %c = OpFunction %void None %23
+          %m = OpFunctionParameter %mat2v3half
+         %26 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %d = OpFunction %void None %27
+          %v = OpFunctionParameter %v3half
+         %30 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %e = OpFunction %void None %31
+        %f_1 = OpFunctionParameter %half
+         %34 = OpLabel
+               OpReturn
+               OpFunctionEnd
+     %conv_S = OpFunction %S None %35
+        %val = OpFunctionParameter %S_std140
+         %38 = OpLabel
+         %39 = OpCompositeExtract %int %val 0
+         %40 = OpCompositeExtract %v3half %val 1
+         %41 = OpCompositeExtract %v3half %val 2
+         %42 = OpCompositeConstruct %mat2v3half %40 %41
+         %43 = OpCompositeExtract %int %val 3
+         %44 = OpCompositeConstruct %S %39 %42 %43
+               OpReturnValue %44
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %45
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %48 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %51
+          %i = OpVariable %_ptr_Function_uint Function %54
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %67
+               OpBranch %55
+         %55 = OpLabel
+               OpLoopMerge %56 %57 None
+               OpBranch %58
+         %58 = OpLabel
+         %60 = OpLoad %uint %i
+         %61 = OpULessThan %bool %60 %uint_4
+         %59 = OpLogicalNot %bool %61
+               OpSelectionMerge %63 None
+               OpBranchConditional %59 %64 %63
+         %64 = OpLabel
+               OpBranch %56
+         %63 = OpLabel
+               OpStore %var_for_index %val_0
+         %68 = OpLoad %uint %i
+         %70 = OpAccessChain %_ptr_Function_S %arr %68
+         %72 = OpLoad %uint %i
+         %74 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %72
+         %75 = OpLoad %S_std140 %74
+         %71 = OpFunctionCall %S %conv_S %75
+               OpStore %70 %71
+               OpBranch %57
+         %57 = OpLabel
+         %76 = OpLoad %uint %i
+         %78 = OpIAdd %uint %76 %uint_1
+               OpStore %i %78
+               OpBranch %55
+         %56 = OpLabel
+         %79 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %79
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat2v3half None %80
+         %82 = OpLabel
+         %87 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %90 = OpAccessChain %_ptr_Uniform_v3half %87 %uint_1
+         %91 = OpLoad %v3half %90
+         %93 = OpAccessChain %_ptr_Uniform_v3half %87 %uint_2
+         %94 = OpLoad %v3half %93
+         %95 = OpCompositeConstruct %mat2v3half %91 %94
+               OpReturnValue %95
+               OpFunctionEnd
+          %f = OpFunction %void None %96
+         %98 = OpLabel
+        %102 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+        %103 = OpLoad %_arr_S_std140_uint_4 %102
+        %100 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %103
+         %99 = OpFunctionCall %void %a %100
+        %106 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+        %107 = OpLoad %S_std140 %106
+        %105 = OpFunctionCall %S %conv_S %107
+        %104 = OpFunctionCall %void %b %105
+        %109 = OpFunctionCall %mat2v3half %load_u_inner_2_m
+        %108 = OpFunctionCall %void %c %109
+        %111 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0 %54 %uint_2
+        %112 = OpLoad %v3half %111
+        %113 = OpVectorShuffle %v3half %112 %112 2 0 1
+        %110 = OpFunctionCall %void %d %113
+        %115 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0 %54 %uint_2
+        %116 = OpLoad %v3half %115
+        %117 = OpVectorShuffle %v3half %116 %116 2 0 1
+        %118 = OpCompositeExtract %half %117 0
+        %114 = OpFunctionCall %void %e %118
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_fn.wgsl.expected.wgsl
new file mode 100644
index 0000000..cca1442
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_fn.wgsl.expected.wgsl
@@ -0,0 +1,34 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat2x3<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+fn a(a : array<S, 4>) {
+}
+
+fn b(s : S) {
+}
+
+fn c(m : mat2x3<f16>) {
+}
+
+fn d(v : vec3<f16>) {
+}
+
+fn e(f : f16) {
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  a(u);
+  b(u[2]);
+  c(u[2].m);
+  d(u[0].m[1].zxy);
+  e(u[0].m[1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_private.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_private.wgsl
new file mode 100644
index 0000000..9c99b5b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_private.wgsl
@@ -0,0 +1,19 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat2x3<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+var<private> p : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[2];
+    p[3].m = u[2].m;
+    p[1].m[0] = u[0].m[1].zxy;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_private.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..918efe0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_private.wgsl.expected.dxc.hlsl
@@ -0,0 +1,54 @@
+struct S {
+  int before;
+  matrix<float16_t, 2, 3> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+static S p[4] = (S[4])0;
+
+matrix<float16_t, 2, 3> tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 256u);
+  p[3].m = tint_symbol_3(u, 264u);
+  uint2 ubo_load_4 = u[1].xy;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  p[1].m[0] = vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]).zxy;
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_private.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..b82501d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_private.wgsl.expected.fxc.hlsl
@@ -0,0 +1,59 @@
+SKIP: FAILED
+
+struct S {
+  int before;
+  matrix<float16_t, 2, 3> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+static S p[4] = (S[4])0;
+
+matrix<float16_t, 2, 3> tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 256u);
+  p[3].m = tint_symbol_3(u, 264u);
+  uint2 ubo_load_4 = u[1].xy;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  p[1].m[0] = vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]).zxy;
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x00000296576AF9E0(3,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..38b15d7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_private.wgsl.expected.glsl
@@ -0,0 +1,103 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct S {
+  int before;
+  uint pad;
+  f16mat2x3 m;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  int after;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+};
+
+struct S_std140 {
+  int before;
+  uint pad;
+  f16vec3 m_0;
+  f16vec3 m_1;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  int after;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+S p[4] = S[4](S(0, 0u, f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+S conv_S(S_std140 val) {
+  return S(val.before, val.pad, f16mat2x3(val.m_0, val.m_1), val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.after, val.pad_11, val.pad_12, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21, val.pad_22, val.pad_23, val.pad_24, val.pad_25);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, 0u, f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat2x3 load_u_inner_2_m() {
+  return f16mat2x3(u.inner[2u].m_0, u.inner[2u].m_1);
+}
+
+void f() {
+  p = conv_arr4_S(u.inner);
+  p[1] = conv_S(u.inner[2u]);
+  p[3].m = load_u_inner_2_m();
+  p[1].m[0] = u.inner[0u].m_1.zxy;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..53a16ab
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_private.wgsl.expected.msl
@@ -0,0 +1,34 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0008 */ half2x3 m;
+  /* 0x0018 */ tint_array<int8_t, 40> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol_1 [[buffer(0)]]) {
+  thread tint_array<S, 4> tint_symbol = {};
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[2];
+  tint_symbol[3].m = (*(tint_symbol_1))[2].m;
+  tint_symbol[1].m[0] = half3((*(tint_symbol_1))[0].m[1]).zxy;
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_private.wgsl.expected.spvasm
new file mode 100644
index 0000000..e047cd5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_private.wgsl.expected.spvasm
@@ -0,0 +1,171 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 101
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "after"
+               OpName %u "u"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %p "p"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 8
+               OpMemberDecorate %S_std140 2 Offset 16
+               OpMemberDecorate %S_std140 3 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 8
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 8
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+   %S_std140 = OpTypeStruct %int %v3half %v3half %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat2v3half = OpTypeMatrix %v3half 2
+          %S = OpTypeStruct %int %mat2v3half %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+%_ptr_Private__arr_S_uint_4 = OpTypePointer Private %_arr_S_uint_4
+         %16 = OpConstantNull %_arr_S_uint_4
+          %p = OpVariable %_ptr_Private__arr_S_uint_4 Private %16
+         %17 = OpTypeFunction %S %S_std140
+         %27 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %35 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %48 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %61 = OpTypeFunction %mat2v3half
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+       %void = OpTypeVoid
+         %77 = OpTypeFunction %void
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+      %int_1 = OpConstant %int 1
+%_ptr_Private_S = OpTypePointer Private %S
+      %int_3 = OpConstant %int 3
+%_ptr_Private_mat2v3half = OpTypePointer Private %mat2v3half
+         %95 = OpConstantNull %int
+%_ptr_Private_v3half = OpTypePointer Private %v3half
+     %conv_S = OpFunction %S None %17
+        %val = OpFunctionParameter %S_std140
+         %20 = OpLabel
+         %21 = OpCompositeExtract %int %val 0
+         %22 = OpCompositeExtract %v3half %val 1
+         %23 = OpCompositeExtract %v3half %val 2
+         %24 = OpCompositeConstruct %mat2v3half %22 %23
+         %25 = OpCompositeExtract %int %val 3
+         %26 = OpCompositeConstruct %S %21 %24 %25
+               OpReturnValue %26
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %27
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %30 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %16
+          %i = OpVariable %_ptr_Function_uint Function %35
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %48
+               OpBranch %36
+         %36 = OpLabel
+               OpLoopMerge %37 %38 None
+               OpBranch %39
+         %39 = OpLabel
+         %41 = OpLoad %uint %i
+         %42 = OpULessThan %bool %41 %uint_4
+         %40 = OpLogicalNot %bool %42
+               OpSelectionMerge %44 None
+               OpBranchConditional %40 %45 %44
+         %45 = OpLabel
+               OpBranch %37
+         %44 = OpLabel
+               OpStore %var_for_index %val_0
+         %49 = OpLoad %uint %i
+         %51 = OpAccessChain %_ptr_Function_S %arr %49
+         %53 = OpLoad %uint %i
+         %55 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %53
+         %56 = OpLoad %S_std140 %55
+         %52 = OpFunctionCall %S %conv_S %56
+               OpStore %51 %52
+               OpBranch %38
+         %38 = OpLabel
+         %57 = OpLoad %uint %i
+         %59 = OpIAdd %uint %57 %uint_1
+               OpStore %i %59
+               OpBranch %36
+         %37 = OpLabel
+         %60 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %60
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat2v3half None %61
+         %63 = OpLabel
+         %68 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %71 = OpAccessChain %_ptr_Uniform_v3half %68 %uint_1
+         %72 = OpLoad %v3half %71
+         %74 = OpAccessChain %_ptr_Uniform_v3half %68 %uint_2
+         %75 = OpLoad %v3half %74
+         %76 = OpCompositeConstruct %mat2v3half %72 %75
+               OpReturnValue %76
+               OpFunctionEnd
+          %f = OpFunction %void None %77
+         %80 = OpLabel
+         %83 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+         %84 = OpLoad %_arr_S_std140_uint_4 %83
+         %81 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %84
+               OpStore %p %81
+         %87 = OpAccessChain %_ptr_Private_S %p %int_1
+         %89 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %90 = OpLoad %S_std140 %89
+         %88 = OpFunctionCall %S %conv_S %90
+               OpStore %87 %88
+         %93 = OpAccessChain %_ptr_Private_mat2v3half %p %int_3 %uint_1
+         %94 = OpFunctionCall %mat2v3half %load_u_inner_2_m
+               OpStore %93 %94
+         %97 = OpAccessChain %_ptr_Private_v3half %p %int_1 %uint_1 %95
+         %98 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0 %35 %uint_2
+         %99 = OpLoad %v3half %98
+        %100 = OpVectorShuffle %v3half %99 %99 2 0 1
+               OpStore %97 %100
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..015af90
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_private.wgsl.expected.wgsl
@@ -0,0 +1,20 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat2x3<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+var<private> p : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[2];
+  p[3].m = u[2].m;
+  p[1].m[0] = u[0].m[1].zxy;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_storage.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_storage.wgsl
new file mode 100644
index 0000000..40bb077
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_storage.wgsl
@@ -0,0 +1,19 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat2x3<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+@group(0) @binding(1) var<storage, read_write> s : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[2];
+    s[3].m = u[2].m;
+    s[1].m[0] = u[0].m[1].zxy;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_storage.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..ba15d73
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_storage.wgsl.expected.dxc.hlsl
@@ -0,0 +1,74 @@
+struct S {
+  int before;
+  matrix<float16_t, 2, 3> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_3(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 2, 3> value) {
+  buffer.Store<vector<float16_t, 3> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 8u), value[1u]);
+}
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, S value) {
+  buffer.Store((offset + 0u), asuint(value.before));
+  tint_symbol_3(buffer, (offset + 8u), value.m);
+  buffer.Store((offset + 64u), asuint(value.after));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, S value[4]) {
+  S array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 128u)), array[i]);
+    }
+  }
+}
+
+matrix<float16_t, 2, 3> tint_symbol_8(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
+}
+
+S tint_symbol_6(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_10 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_8(buffer, (offset + 8u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_10;
+}
+
+typedef S tint_symbol_5_ret[4];
+tint_symbol_5_ret tint_symbol_5(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_6(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_5(u, 0u));
+  tint_symbol_1(s, 128u, tint_symbol_6(u, 256u));
+  tint_symbol_3(s, 392u, tint_symbol_8(u, 264u));
+  uint2 ubo_load_4 = u[1].xy;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  s.Store<vector<float16_t, 3> >(136u, vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]).zxy);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_storage.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..ecf95e4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_storage.wgsl.expected.fxc.hlsl
@@ -0,0 +1,79 @@
+SKIP: FAILED
+
+struct S {
+  int before;
+  matrix<float16_t, 2, 3> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_3(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 2, 3> value) {
+  buffer.Store<vector<float16_t, 3> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 8u), value[1u]);
+}
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, S value) {
+  buffer.Store((offset + 0u), asuint(value.before));
+  tint_symbol_3(buffer, (offset + 8u), value.m);
+  buffer.Store((offset + 64u), asuint(value.after));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, S value[4]) {
+  S array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 128u)), array[i]);
+    }
+  }
+}
+
+matrix<float16_t, 2, 3> tint_symbol_8(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
+}
+
+S tint_symbol_6(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_10 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_8(buffer, (offset + 8u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_10;
+}
+
+typedef S tint_symbol_5_ret[4];
+tint_symbol_5_ret tint_symbol_5(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_6(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_5(u, 0u));
+  tint_symbol_1(s, 128u, tint_symbol_6(u, 256u));
+  tint_symbol_3(s, 392u, tint_symbol_8(u, 264u));
+  uint2 ubo_load_4 = u[1].xy;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  s.Store<vector<float16_t, 3> >(136u, vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]).zxy);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001EAD8916A10(3,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..4129467
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_storage.wgsl.expected.glsl
@@ -0,0 +1,106 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct S {
+  int before;
+  uint pad;
+  f16mat2x3 m;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  int after;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+};
+
+struct S_std140 {
+  int before;
+  uint pad;
+  f16vec3 m_0;
+  f16vec3 m_1;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  int after;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  S inner[4];
+} s;
+
+S conv_S(S_std140 val) {
+  return S(val.before, val.pad, f16mat2x3(val.m_0, val.m_1), val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.after, val.pad_11, val.pad_12, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21, val.pad_22, val.pad_23, val.pad_24, val.pad_25);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, 0u, f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat2x3 load_u_inner_2_m() {
+  return f16mat2x3(u.inner[2u].m_0, u.inner[2u].m_1);
+}
+
+void f() {
+  s.inner = conv_arr4_S(u.inner);
+  s.inner[1] = conv_S(u.inner[2u]);
+  s.inner[3].m = load_u_inner_2_m();
+  s.inner[1].m[0] = u.inner[0u].m_1.zxy;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..58393ab
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_storage.wgsl.expected.msl
@@ -0,0 +1,33 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0008 */ half2x3 m;
+  /* 0x0018 */ tint_array<int8_t, 40> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+kernel void f(device tint_array<S, 4>* tint_symbol [[buffer(1)]], const constant tint_array<S, 4>* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
+  (*(tint_symbol))[3].m = (*(tint_symbol_1))[2].m;
+  (*(tint_symbol))[1].m[0] = half3((*(tint_symbol_1))[0].m[1]).zxy;
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_storage.wgsl.expected.spvasm
new file mode 100644
index 0000000..68c548d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_storage.wgsl.expected.spvasm
@@ -0,0 +1,180 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 104
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "after"
+               OpName %u "u"
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %s "s"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 8
+               OpMemberDecorate %S_std140 2 Offset 16
+               OpMemberDecorate %S_std140 3 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 8
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 8
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+               OpDecorate %s DescriptorSet 0
+               OpDecorate %s Binding 1
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+   %S_std140 = OpTypeStruct %int %v3half %v3half %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat2v3half = OpTypeMatrix %v3half 2
+          %S = OpTypeStruct %int %mat2v3half %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+    %u_block = OpTypeStruct %_arr_S_uint_4
+%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
+          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+         %17 = OpTypeFunction %S %S_std140
+         %27 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+         %33 = OpConstantNull %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %36 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %49 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %62 = OpTypeFunction %mat2v3half
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+       %void = OpTypeVoid
+         %78 = OpTypeFunction %void
+%_ptr_StorageBuffer__arr_S_uint_4 = OpTypePointer StorageBuffer %_arr_S_uint_4
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+      %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
+      %int_3 = OpConstant %int 3
+%_ptr_StorageBuffer_mat2v3half = OpTypePointer StorageBuffer %mat2v3half
+         %98 = OpConstantNull %int
+%_ptr_StorageBuffer_v3half = OpTypePointer StorageBuffer %v3half
+     %conv_S = OpFunction %S None %17
+        %val = OpFunctionParameter %S_std140
+         %20 = OpLabel
+         %21 = OpCompositeExtract %int %val 0
+         %22 = OpCompositeExtract %v3half %val 1
+         %23 = OpCompositeExtract %v3half %val 2
+         %24 = OpCompositeConstruct %mat2v3half %22 %23
+         %25 = OpCompositeExtract %int %val 3
+         %26 = OpCompositeConstruct %S %21 %24 %25
+               OpReturnValue %26
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %27
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %30 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %33
+          %i = OpVariable %_ptr_Function_uint Function %36
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %49
+               OpBranch %37
+         %37 = OpLabel
+               OpLoopMerge %38 %39 None
+               OpBranch %40
+         %40 = OpLabel
+         %42 = OpLoad %uint %i
+         %43 = OpULessThan %bool %42 %uint_4
+         %41 = OpLogicalNot %bool %43
+               OpSelectionMerge %45 None
+               OpBranchConditional %41 %46 %45
+         %46 = OpLabel
+               OpBranch %38
+         %45 = OpLabel
+               OpStore %var_for_index %val_0
+         %50 = OpLoad %uint %i
+         %52 = OpAccessChain %_ptr_Function_S %arr %50
+         %54 = OpLoad %uint %i
+         %56 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %54
+         %57 = OpLoad %S_std140 %56
+         %53 = OpFunctionCall %S %conv_S %57
+               OpStore %52 %53
+               OpBranch %39
+         %39 = OpLabel
+         %58 = OpLoad %uint %i
+         %60 = OpIAdd %uint %58 %uint_1
+               OpStore %i %60
+               OpBranch %37
+         %38 = OpLabel
+         %61 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %61
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat2v3half None %62
+         %64 = OpLabel
+         %69 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %72 = OpAccessChain %_ptr_Uniform_v3half %69 %uint_1
+         %73 = OpLoad %v3half %72
+         %75 = OpAccessChain %_ptr_Uniform_v3half %69 %uint_2
+         %76 = OpLoad %v3half %75
+         %77 = OpCompositeConstruct %mat2v3half %73 %76
+               OpReturnValue %77
+               OpFunctionEnd
+          %f = OpFunction %void None %78
+         %81 = OpLabel
+         %83 = OpAccessChain %_ptr_StorageBuffer__arr_S_uint_4 %s %uint_0
+         %86 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+         %87 = OpLoad %_arr_S_std140_uint_4 %86
+         %84 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %87
+               OpStore %83 %84
+         %90 = OpAccessChain %_ptr_StorageBuffer_S %s %uint_0 %int_1
+         %92 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %93 = OpLoad %S_std140 %92
+         %91 = OpFunctionCall %S %conv_S %93
+               OpStore %90 %91
+         %96 = OpAccessChain %_ptr_StorageBuffer_mat2v3half %s %uint_0 %int_3 %uint_1
+         %97 = OpFunctionCall %mat2v3half %load_u_inner_2_m
+               OpStore %96 %97
+        %100 = OpAccessChain %_ptr_StorageBuffer_v3half %s %uint_0 %int_1 %uint_1 %98
+        %101 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0 %36 %uint_2
+        %102 = OpLoad %v3half %101
+        %103 = OpVectorShuffle %v3half %102 %102 2 0 1
+               OpStore %100 %103
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..2cf8a20
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,20 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat2x3<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@group(0) @binding(1) var<storage, read_write> s : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[2];
+  s[3].m = u[2].m;
+  s[1].m[0] = u[0].m[1].zxy;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_workgroup.wgsl
new file mode 100644
index 0000000..3292542
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_workgroup.wgsl
@@ -0,0 +1,19 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat2x3<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+var<workgroup> w : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[2];
+    w[3].m = u[2].m;
+    w[1].m[0] = u[0].m[1].zxy;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_workgroup.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..3ddda98
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_workgroup.wgsl.expected.dxc.hlsl
@@ -0,0 +1,70 @@
+struct S {
+  int before;
+  matrix<float16_t, 2, 3> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+groupshared S w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 2, 3> tint_symbol_5(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
+}
+
+S tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_8 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_5(buffer, (offset + 8u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_8;
+}
+
+typedef S tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      const S tint_symbol_7 = (S)0;
+      w[i] = tint_symbol_7;
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 256u);
+  w[3].m = tint_symbol_5(u, 264u);
+  uint2 ubo_load_4 = u[1].xy;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  w[1].m[0] = vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]).zxy;
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_workgroup.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..20fbb45
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_workgroup.wgsl.expected.fxc.hlsl
@@ -0,0 +1,75 @@
+SKIP: FAILED
+
+struct S {
+  int before;
+  matrix<float16_t, 2, 3> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+groupshared S w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 2, 3> tint_symbol_5(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
+}
+
+S tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_8 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_5(buffer, (offset + 8u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_8;
+}
+
+typedef S tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      const S tint_symbol_7 = (S)0;
+      w[i] = tint_symbol_7;
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 256u);
+  w[3].m = tint_symbol_5(u, 264u);
+  uint2 ubo_load_4 = u[1].xy;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  w[1].m[0] = vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]).zxy;
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001CE6EDD85C0(3,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..d3addb0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,111 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct S {
+  int before;
+  uint pad;
+  f16mat2x3 m;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  int after;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+};
+
+struct S_std140 {
+  int before;
+  uint pad;
+  f16vec3 m_0;
+  f16vec3 m_1;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  int after;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+shared S w[4];
+S conv_S(S_std140 val) {
+  return S(val.before, val.pad, f16mat2x3(val.m_0, val.m_1), val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.after, val.pad_11, val.pad_12, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21, val.pad_22, val.pad_23, val.pad_24, val.pad_25);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, 0u, f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat2x3 load_u_inner_2_m() {
+  return f16mat2x3(u.inner[2u].m_0, u.inner[2u].m_1);
+}
+
+void f(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      uint i = idx;
+      S tint_symbol = S(0, 0u, f16mat2x3(f16vec3(0.0hf), f16vec3(0.0hf)), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u);
+      w[i] = tint_symbol;
+    }
+  }
+  barrier();
+  w = conv_arr4_S(u.inner);
+  w[1] = conv_S(u.inner[2u]);
+  w[3].m = load_u_inner_2_m();
+  w[1].m[0] = u.inner[0u].m_1.zxy;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..816c6c6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,48 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0008 */ half2x3 m;
+  /* 0x0018 */ tint_array<int8_t, 40> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+struct tint_symbol_6 {
+  tint_array<S, 4> w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup tint_array<S, 4>* const tint_symbol_1, const constant tint_array<S, 4>* const tint_symbol_2) {
+  for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+    uint const i = idx;
+    S const tint_symbol = S{};
+    (*(tint_symbol_1))[i] = tint_symbol;
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol_1) = *(tint_symbol_2);
+  (*(tint_symbol_1))[1] = (*(tint_symbol_2))[2];
+  (*(tint_symbol_1))[3].m = (*(tint_symbol_2))[2].m;
+  (*(tint_symbol_1))[1].m[0] = half3((*(tint_symbol_2))[0].m[1]).zxy;
+}
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol_5 [[buffer(0)]], threadgroup tint_symbol_6* tint_symbol_4 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup tint_array<S, 4>* const tint_symbol_3 = &((*(tint_symbol_4)).w);
+  f_inner(local_invocation_index, tint_symbol_3, tint_symbol_5);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_workgroup.wgsl.expected.spvasm
new file mode 100644
index 0000000..261be93
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_workgroup.wgsl.expected.spvasm
@@ -0,0 +1,214 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 126
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %local_invocation_index_1 "local_invocation_index_1"
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "after"
+               OpName %u "u"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %w "w"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f_inner "f_inner"
+               OpName %local_invocation_index "local_invocation_index"
+               OpName %idx "idx"
+               OpName %f "f"
+               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 8
+               OpMemberDecorate %S_std140 2 Offset 16
+               OpMemberDecorate %S_std140 3 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 8
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 8
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+   %S_std140 = OpTypeStruct %int %v3half %v3half %int
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat2v3half = OpTypeMatrix %v3half 2
+          %S = OpTypeStruct %int %mat2v3half %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+%_ptr_Workgroup__arr_S_uint_4 = OpTypePointer Workgroup %_arr_S_uint_4
+          %w = OpVariable %_ptr_Workgroup__arr_S_uint_4 Workgroup
+         %18 = OpTypeFunction %S %S_std140
+         %28 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+         %34 = OpConstantNull %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %37 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %50 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %63 = OpTypeFunction %mat2v3half
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+       %void = OpTypeVoid
+         %79 = OpTypeFunction %void %uint
+%_ptr_Workgroup_S = OpTypePointer Workgroup %S
+         %97 = OpConstantNull %S
+   %uint_264 = OpConstant %uint 264
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+      %int_1 = OpConstant %int 1
+      %int_3 = OpConstant %int 3
+%_ptr_Workgroup_mat2v3half = OpTypePointer Workgroup %mat2v3half
+        %115 = OpConstantNull %int
+%_ptr_Workgroup_v3half = OpTypePointer Workgroup %v3half
+        %121 = OpTypeFunction %void
+     %conv_S = OpFunction %S None %18
+        %val = OpFunctionParameter %S_std140
+         %21 = OpLabel
+         %22 = OpCompositeExtract %int %val 0
+         %23 = OpCompositeExtract %v3half %val 1
+         %24 = OpCompositeExtract %v3half %val 2
+         %25 = OpCompositeConstruct %mat2v3half %23 %24
+         %26 = OpCompositeExtract %int %val 3
+         %27 = OpCompositeConstruct %S %22 %25 %26
+               OpReturnValue %27
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %28
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %31 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %34
+          %i = OpVariable %_ptr_Function_uint Function %37
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %50
+               OpBranch %38
+         %38 = OpLabel
+               OpLoopMerge %39 %40 None
+               OpBranch %41
+         %41 = OpLabel
+         %43 = OpLoad %uint %i
+         %44 = OpULessThan %bool %43 %uint_4
+         %42 = OpLogicalNot %bool %44
+               OpSelectionMerge %46 None
+               OpBranchConditional %42 %47 %46
+         %47 = OpLabel
+               OpBranch %39
+         %46 = OpLabel
+               OpStore %var_for_index %val_0
+         %51 = OpLoad %uint %i
+         %53 = OpAccessChain %_ptr_Function_S %arr %51
+         %55 = OpLoad %uint %i
+         %57 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %55
+         %58 = OpLoad %S_std140 %57
+         %54 = OpFunctionCall %S %conv_S %58
+               OpStore %53 %54
+               OpBranch %40
+         %40 = OpLabel
+         %59 = OpLoad %uint %i
+         %61 = OpIAdd %uint %59 %uint_1
+               OpStore %i %61
+               OpBranch %38
+         %39 = OpLabel
+         %62 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %62
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat2v3half None %63
+         %65 = OpLabel
+         %70 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %73 = OpAccessChain %_ptr_Uniform_v3half %70 %uint_1
+         %74 = OpLoad %v3half %73
+         %76 = OpAccessChain %_ptr_Uniform_v3half %70 %uint_2
+         %77 = OpLoad %v3half %76
+         %78 = OpCompositeConstruct %mat2v3half %74 %77
+               OpReturnValue %78
+               OpFunctionEnd
+    %f_inner = OpFunction %void None %79
+%local_invocation_index = OpFunctionParameter %uint
+         %83 = OpLabel
+        %idx = OpVariable %_ptr_Function_uint Function %37
+               OpStore %idx %local_invocation_index
+               OpBranch %85
+         %85 = OpLabel
+               OpLoopMerge %86 %87 None
+               OpBranch %88
+         %88 = OpLabel
+         %90 = OpLoad %uint %idx
+         %91 = OpULessThan %bool %90 %uint_4
+         %89 = OpLogicalNot %bool %91
+               OpSelectionMerge %92 None
+               OpBranchConditional %89 %93 %92
+         %93 = OpLabel
+               OpBranch %86
+         %92 = OpLabel
+         %94 = OpLoad %uint %idx
+         %96 = OpAccessChain %_ptr_Workgroup_S %w %94
+               OpStore %96 %97
+               OpBranch %87
+         %87 = OpLabel
+         %98 = OpLoad %uint %idx
+         %99 = OpIAdd %uint %98 %uint_1
+               OpStore %idx %99
+               OpBranch %85
+         %86 = OpLabel
+               OpControlBarrier %uint_2 %uint_2 %uint_264
+        %104 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+        %105 = OpLoad %_arr_S_std140_uint_4 %104
+        %102 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %105
+               OpStore %w %102
+        %107 = OpAccessChain %_ptr_Workgroup_S %w %int_1
+        %109 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+        %110 = OpLoad %S_std140 %109
+        %108 = OpFunctionCall %S %conv_S %110
+               OpStore %107 %108
+        %113 = OpAccessChain %_ptr_Workgroup_mat2v3half %w %int_3 %uint_1
+        %114 = OpFunctionCall %mat2v3half %load_u_inner_2_m
+               OpStore %113 %114
+        %117 = OpAccessChain %_ptr_Workgroup_v3half %w %int_1 %uint_1 %115
+        %118 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0 %37 %uint_2
+        %119 = OpLoad %v3half %118
+        %120 = OpVectorShuffle %v3half %119 %119 2 0 1
+               OpStore %117 %120
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %121
+        %123 = OpLabel
+        %125 = OpLoad %uint %local_invocation_index_1
+        %124 = OpFunctionCall %void %f_inner %125
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..dfe935a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f16/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,20 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat2x3<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+var<workgroup> w : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[2];
+  w[3].m = u[2].m;
+  w[1].m[0] = u[0].m[1].zxy;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/dynamic_index_via_ptr.wgsl
new file mode 100644
index 0000000..133588b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/dynamic_index_via_ptr.wgsl
@@ -0,0 +1,32 @@
+struct Inner {
+  @size(64)
+  m : mat2x3<f32>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a           = &a;
+  let p_a_i         = &((*p_a)[i()]);
+  let p_a_i_a       = &((*p_a_i).a);
+  let p_a_i_a_i     = &((*p_a_i_a)[i()]);
+  let p_a_i_a_i_m   = &((*p_a_i_a_i).m);
+  let p_a_i_a_i_m_i = &((*p_a_i_a_i_m)[i()]);
+
+
+  let l_a             : array<Outer, 4> =  *p_a;
+  let l_a_i           : Outer           =  *p_a_i;
+  let l_a_i_a         : array<Inner, 4> =  *p_a_i_a;
+  let l_a_i_a_i       : Inner           =  *p_a_i_a_i;
+  let l_a_i_a_i_m     : mat2x3<f32>     =  *p_a_i_a_i_m;
+  let l_a_i_a_i_m_i   : vec3<f32>       =  *p_a_i_a_i_m_i;
+  let l_a_i_a_i_m_i_i : f32             = (*p_a_i_a_i_m_i)[i()];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..553de51
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,75 @@
+struct Inner {
+  float2x3 m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float2x3 tint_symbol_8(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+}
+
+Inner tint_symbol_7(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_11 = {tint_symbol_8(buffer, (offset + 0u))};
+  return tint_symbol_11;
+}
+
+typedef Inner tint_symbol_6_ret[4];
+tint_symbol_6_ret tint_symbol_6(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_7(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_5(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_12 = {tint_symbol_6(buffer, (offset + 0u))};
+  return tint_symbol_12;
+}
+
+typedef Outer tint_symbol_4_ret[4];
+tint_symbol_4_ret tint_symbol_4(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
+      arr_1[i_2] = tint_symbol_5(buffer, (offset + (i_2 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_a_i_save = i();
+  const int p_a_i_a_i_m_i_save = i();
+  const Outer l_a[4] = tint_symbol_4(a, 0u);
+  const Outer l_a_i = tint_symbol_5(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a[4] = tint_symbol_6(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a_i = tint_symbol_7(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const float2x3 l_a_i_a_i_m = tint_symbol_8(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const uint scalar_offset_2 = ((((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))) + (16u * uint(p_a_i_a_i_m_i_save)))) / 4;
+  const float3 l_a_i_a_i_m_i = asfloat(a[scalar_offset_2 / 4].xyz);
+  const int tint_symbol = p_a_i_save;
+  const int tint_symbol_1 = p_a_i_a_i_save;
+  const int tint_symbol_2 = p_a_i_a_i_m_i_save;
+  const int tint_symbol_3 = i();
+  const uint scalar_offset_3 = (((((256u * uint(tint_symbol)) + (64u * uint(tint_symbol_1))) + (16u * uint(tint_symbol_2))) + (4u * uint(tint_symbol_3)))) / 4;
+  const float l_a_i_a_i_m_i_i = asfloat(a[scalar_offset_3 / 4][scalar_offset_3 % 4]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..553de51
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,75 @@
+struct Inner {
+  float2x3 m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float2x3 tint_symbol_8(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+}
+
+Inner tint_symbol_7(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_11 = {tint_symbol_8(buffer, (offset + 0u))};
+  return tint_symbol_11;
+}
+
+typedef Inner tint_symbol_6_ret[4];
+tint_symbol_6_ret tint_symbol_6(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_7(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_5(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_12 = {tint_symbol_6(buffer, (offset + 0u))};
+  return tint_symbol_12;
+}
+
+typedef Outer tint_symbol_4_ret[4];
+tint_symbol_4_ret tint_symbol_4(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
+      arr_1[i_2] = tint_symbol_5(buffer, (offset + (i_2 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_a_i_save = i();
+  const int p_a_i_a_i_m_i_save = i();
+  const Outer l_a[4] = tint_symbol_4(a, 0u);
+  const Outer l_a_i = tint_symbol_5(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a[4] = tint_symbol_6(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a_i = tint_symbol_7(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const float2x3 l_a_i_a_i_m = tint_symbol_8(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const uint scalar_offset_2 = ((((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))) + (16u * uint(p_a_i_a_i_m_i_save)))) / 4;
+  const float3 l_a_i_a_i_m_i = asfloat(a[scalar_offset_2 / 4].xyz);
+  const int tint_symbol = p_a_i_save;
+  const int tint_symbol_1 = p_a_i_a_i_save;
+  const int tint_symbol_2 = p_a_i_a_i_m_i_save;
+  const int tint_symbol_3 = i();
+  const uint scalar_offset_3 = (((((256u * uint(tint_symbol)) + (64u * uint(tint_symbol_1))) + (16u * uint(tint_symbol_2))) + (4u * uint(tint_symbol_3)))) / 4;
+  const float l_a_i_a_i_m_i_i = asfloat(a[scalar_offset_3 / 4][scalar_offset_3 % 4]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..6fa3df3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,50 @@
+#version 310 es
+
+struct Inner {
+  mat2x3 m;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+};
+
+struct Outer {
+  Inner a[4];
+};
+
+layout(binding = 0, std140) uniform a_block_ubo {
+  Outer inner[4];
+} a;
+
+int counter = 0;
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+void f() {
+  int tint_symbol = i();
+  int p_a_i_save = tint_symbol;
+  int tint_symbol_1 = i();
+  int p_a_i_a_i_save = tint_symbol_1;
+  int tint_symbol_2 = i();
+  int p_a_i_a_i_m_i_save = tint_symbol_2;
+  Outer l_a[4] = a.inner;
+  Outer l_a_i = a.inner[p_a_i_save];
+  Inner l_a_i_a[4] = a.inner[p_a_i_save].a;
+  Inner l_a_i_a_i = a.inner[p_a_i_save].a[p_a_i_a_i_save];
+  mat2x3 l_a_i_a_i_m = a.inner[p_a_i_save].a[p_a_i_a_i_save].m;
+  vec3 l_a_i_a_i_m_i = a.inner[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save];
+  int tint_symbol_3 = i();
+  float l_a_i_a_i_m_i_i = a.inner[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save][tint_symbol_3];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..d4767f8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,49 @@
+#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 Inner {
+  /* 0x0000 */ float2x3 m;
+  /* 0x0020 */ tint_array<int8_t, 32> tint_pad;
+};
+
+struct Outer {
+  /* 0x0000 */ tint_array<Inner, 4> a;
+};
+
+int i() {
+  thread int tint_symbol_4 = 0;
+  tint_symbol_4 = as_type<int>((as_type<uint>(tint_symbol_4) + as_type<uint>(1)));
+  return tint_symbol_4;
+}
+
+kernel void f(const constant tint_array<Outer, 4>* tint_symbol_5 [[buffer(0)]]) {
+  int const tint_symbol = i();
+  int const p_a_i_save = tint_symbol;
+  int const tint_symbol_1 = i();
+  int const p_a_i_a_i_save = tint_symbol_1;
+  int const tint_symbol_2 = i();
+  int const p_a_i_a_i_m_i_save = tint_symbol_2;
+  tint_array<Outer, 4> const l_a = *(tint_symbol_5);
+  Outer const l_a_i = (*(tint_symbol_5))[p_a_i_save];
+  tint_array<Inner, 4> const l_a_i_a = (*(tint_symbol_5))[p_a_i_save].a;
+  Inner const l_a_i_a_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save];
+  float2x3 const l_a_i_a_i_m = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m;
+  float3 const l_a_i_a_i_m_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save];
+  int const tint_symbol_3 = i();
+  float const l_a_i_a_i_m_i_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save][tint_symbol_3];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..355a8dd
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,88 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 54
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block "a_block"
+               OpMemberName %a_block 0 "inner"
+               OpName %Outer "Outer"
+               OpMemberName %Outer 0 "a"
+               OpName %Inner "Inner"
+               OpMemberName %Inner 0 "m"
+               OpName %a "a"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %f "f"
+               OpDecorate %a_block Block
+               OpMemberDecorate %a_block 0 Offset 0
+               OpMemberDecorate %Outer 0 Offset 0
+               OpMemberDecorate %Inner 0 Offset 0
+               OpMemberDecorate %Inner 0 ColMajor
+               OpMemberDecorate %Inner 0 MatrixStride 16
+               OpDecorate %_arr_Inner_uint_4 ArrayStride 64
+               OpDecorate %_arr_Outer_uint_4 ArrayStride 256
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat2v3float = OpTypeMatrix %v3float 2
+      %Inner = OpTypeStruct %mat2v3float
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_Inner_uint_4 = OpTypeArray %Inner %uint_4
+      %Outer = OpTypeStruct %_arr_Inner_uint_4
+%_arr_Outer_uint_4 = OpTypeArray %Outer %uint_4
+    %a_block = OpTypeStruct %_arr_Outer_uint_4
+%_ptr_Uniform_a_block = OpTypePointer Uniform %a_block
+          %a = OpVariable %_ptr_Uniform_a_block Uniform
+        %int = OpTypeInt 32 1
+         %14 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %14
+         %17 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+       %void = OpTypeVoid
+         %24 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_Outer_uint_4 = OpTypePointer Uniform %_arr_Outer_uint_4
+%_ptr_Uniform_Outer = OpTypePointer Uniform %Outer
+%_ptr_Uniform__arr_Inner_uint_4 = OpTypePointer Uniform %_arr_Inner_uint_4
+%_ptr_Uniform_Inner = OpTypePointer Uniform %Inner
+%_ptr_Uniform_mat2v3float = OpTypePointer Uniform %mat2v3float
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+          %i = OpFunction %int None %17
+         %19 = OpLabel
+         %20 = OpLoad %int %counter
+         %22 = OpIAdd %int %20 %int_1
+               OpStore %counter %22
+         %23 = OpLoad %int %counter
+               OpReturnValue %23
+               OpFunctionEnd
+          %f = OpFunction %void None %24
+         %27 = OpLabel
+         %28 = OpFunctionCall %int %i
+         %29 = OpFunctionCall %int %i
+         %30 = OpFunctionCall %int %i
+         %33 = OpAccessChain %_ptr_Uniform__arr_Outer_uint_4 %a %uint_0
+         %34 = OpLoad %_arr_Outer_uint_4 %33
+         %36 = OpAccessChain %_ptr_Uniform_Outer %a %uint_0 %28
+         %37 = OpLoad %Outer %36
+         %39 = OpAccessChain %_ptr_Uniform__arr_Inner_uint_4 %a %uint_0 %28 %uint_0
+         %40 = OpLoad %_arr_Inner_uint_4 %39
+         %42 = OpAccessChain %_ptr_Uniform_Inner %a %uint_0 %28 %uint_0 %29
+         %43 = OpLoad %Inner %42
+         %45 = OpAccessChain %_ptr_Uniform_mat2v3float %a %uint_0 %28 %uint_0 %29 %uint_0
+         %46 = OpLoad %mat2v3float %45
+         %48 = OpAccessChain %_ptr_Uniform_v3float %a %uint_0 %28 %uint_0 %29 %uint_0 %30
+         %49 = OpLoad %v3float %48
+         %50 = OpFunctionCall %int %i
+         %52 = OpAccessChain %_ptr_Uniform_float %a %uint_0 %28 %uint_0 %29 %uint_0 %30 %50
+         %53 = OpLoad %float %52
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..38d96d7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,34 @@
+struct Inner {
+  @size(64)
+  m : mat2x3<f32>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_i = &((*(p_a))[i()]);
+  let p_a_i_a = &((*(p_a_i)).a);
+  let p_a_i_a_i = &((*(p_a_i_a))[i()]);
+  let p_a_i_a_i_m = &((*(p_a_i_a_i)).m);
+  let p_a_i_a_i_m_i = &((*(p_a_i_a_i_m))[i()]);
+  let l_a : array<Outer, 4> = *(p_a);
+  let l_a_i : Outer = *(p_a_i);
+  let l_a_i_a : array<Inner, 4> = *(p_a_i_a);
+  let l_a_i_a_i : Inner = *(p_a_i_a_i);
+  let l_a_i_a_i_m : mat2x3<f32> = *(p_a_i_a_i_m);
+  let l_a_i_a_i_m_i : vec3<f32> = *(p_a_i_a_i_m_i);
+  let l_a_i_a_i_m_i_i : f32 = (*(p_a_i_a_i_m_i))[i()];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/static_index_via_ptr.wgsl
new file mode 100644
index 0000000..6222c44
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/static_index_via_ptr.wgsl
@@ -0,0 +1,29 @@
+struct Inner {
+  @size(64)
+  m : mat2x3<f32>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &a;
+  let p_a_3 = &((*p_a)[3]);
+  let p_a_3_a = &((*p_a_3).a);
+  let p_a_3_a_2 = &((*p_a_3_a)[2]);
+  let p_a_3_a_2_m = &((*p_a_3_a_2).m);
+  let p_a_3_a_2_m_1 = &((*p_a_3_a_2_m)[1]);
+
+
+  let l_a             : array<Outer, 4> = *p_a;
+  let l_a_3           : Outer           = *p_a_3;
+  let l_a_3_a         : array<Inner, 4> = *p_a_3_a;
+  let l_a_3_a_2       : Inner           = *p_a_3_a_2;
+  let l_a_3_a_2_m     : mat2x3<f32>     = *p_a_3_a_2_m;
+  let l_a_3_a_2_m_1   : vec3<f32>       = *p_a_3_a_2_m_1;
+  let l_a_3_a_2_m_1_0 : f32             = (*p_a_3_a_2_m_1)[0];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..2273b9f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,60 @@
+struct Inner {
+  float2x3 m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+
+float2x3 tint_symbol_4(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+}
+
+Inner tint_symbol_3(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_7 = {tint_symbol_4(buffer, (offset + 0u))};
+  return tint_symbol_7;
+}
+
+typedef Inner tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_3(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_1(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_8 = {tint_symbol_2(buffer, (offset + 0u))};
+  return tint_symbol_8;
+}
+
+typedef Outer tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr_1[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const Outer l_a[4] = tint_symbol(a, 0u);
+  const Outer l_a_3 = tint_symbol_1(a, 768u);
+  const Inner l_a_3_a[4] = tint_symbol_2(a, 768u);
+  const Inner l_a_3_a_2 = tint_symbol_3(a, 896u);
+  const float2x3 l_a_3_a_2_m = tint_symbol_4(a, 896u);
+  const float3 l_a_3_a_2_m_1 = asfloat(a[57].xyz);
+  const float l_a_3_a_2_m_1_0 = asfloat(a[57].x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..2273b9f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,60 @@
+struct Inner {
+  float2x3 m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+
+float2x3 tint_symbol_4(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+}
+
+Inner tint_symbol_3(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_7 = {tint_symbol_4(buffer, (offset + 0u))};
+  return tint_symbol_7;
+}
+
+typedef Inner tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_3(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_1(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_8 = {tint_symbol_2(buffer, (offset + 0u))};
+  return tint_symbol_8;
+}
+
+typedef Outer tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr_1[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const Outer l_a[4] = tint_symbol(a, 0u);
+  const Outer l_a_3 = tint_symbol_1(a, 768u);
+  const Inner l_a_3_a[4] = tint_symbol_2(a, 768u);
+  const Inner l_a_3_a_2 = tint_symbol_3(a, 896u);
+  const float2x3 l_a_3_a_2_m = tint_symbol_4(a, 896u);
+  const float3 l_a_3_a_2_m_1 = asfloat(a[57].xyz);
+  const float l_a_3_a_2_m_1_0 = asfloat(a[57].x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/static_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..68a7980
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/static_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,37 @@
+#version 310 es
+
+struct Inner {
+  mat2x3 m;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+};
+
+struct Outer {
+  Inner a[4];
+};
+
+layout(binding = 0, std140) uniform a_block_ubo {
+  Outer inner[4];
+} a;
+
+void f() {
+  Outer l_a[4] = a.inner;
+  Outer l_a_3 = a.inner[3];
+  Inner l_a_3_a[4] = a.inner[3].a;
+  Inner l_a_3_a_2 = a.inner[3].a[2];
+  mat2x3 l_a_3_a_2_m = a.inner[3].a[2].m;
+  vec3 l_a_3_a_2_m_1 = a.inner[3].a[2].m[1];
+  float l_a_3_a_2_m_1_0 = a.inner[3].a[2].m[1][0];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/static_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..b36ca6e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/static_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,36 @@
+#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 Inner {
+  /* 0x0000 */ float2x3 m;
+  /* 0x0020 */ tint_array<int8_t, 32> tint_pad;
+};
+
+struct Outer {
+  /* 0x0000 */ tint_array<Inner, 4> a;
+};
+
+kernel void f(const constant tint_array<Outer, 4>* tint_symbol [[buffer(0)]]) {
+  tint_array<Outer, 4> const l_a = *(tint_symbol);
+  Outer const l_a_3 = (*(tint_symbol))[3];
+  tint_array<Inner, 4> const l_a_3_a = (*(tint_symbol))[3].a;
+  Inner const l_a_3_a_2 = (*(tint_symbol))[3].a[2];
+  float2x3 const l_a_3_a_2_m = (*(tint_symbol))[3].a[2].m;
+  float3 const l_a_3_a_2_m_1 = (*(tint_symbol))[3].a[2].m[1];
+  float const l_a_3_a_2_m_1_0 = (*(tint_symbol))[3].a[2].m[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/static_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..a330e0d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/static_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,73 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 44
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block "a_block"
+               OpMemberName %a_block 0 "inner"
+               OpName %Outer "Outer"
+               OpMemberName %Outer 0 "a"
+               OpName %Inner "Inner"
+               OpMemberName %Inner 0 "m"
+               OpName %a "a"
+               OpName %f "f"
+               OpDecorate %a_block Block
+               OpMemberDecorate %a_block 0 Offset 0
+               OpMemberDecorate %Outer 0 Offset 0
+               OpMemberDecorate %Inner 0 Offset 0
+               OpMemberDecorate %Inner 0 ColMajor
+               OpMemberDecorate %Inner 0 MatrixStride 16
+               OpDecorate %_arr_Inner_uint_4 ArrayStride 64
+               OpDecorate %_arr_Outer_uint_4 ArrayStride 256
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat2v3float = OpTypeMatrix %v3float 2
+      %Inner = OpTypeStruct %mat2v3float
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_Inner_uint_4 = OpTypeArray %Inner %uint_4
+      %Outer = OpTypeStruct %_arr_Inner_uint_4
+%_arr_Outer_uint_4 = OpTypeArray %Outer %uint_4
+    %a_block = OpTypeStruct %_arr_Outer_uint_4
+%_ptr_Uniform_a_block = OpTypePointer Uniform %a_block
+          %a = OpVariable %_ptr_Uniform_a_block Uniform
+       %void = OpTypeVoid
+         %13 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_Outer_uint_4 = OpTypePointer Uniform %_arr_Outer_uint_4
+        %int = OpTypeInt 32 1
+      %int_3 = OpConstant %int 3
+%_ptr_Uniform_Outer = OpTypePointer Uniform %Outer
+%_ptr_Uniform__arr_Inner_uint_4 = OpTypePointer Uniform %_arr_Inner_uint_4
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_Inner = OpTypePointer Uniform %Inner
+%_ptr_Uniform_mat2v3float = OpTypePointer Uniform %mat2v3float
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+         %40 = OpConstantNull %int
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+          %f = OpFunction %void None %13
+         %16 = OpLabel
+         %19 = OpAccessChain %_ptr_Uniform__arr_Outer_uint_4 %a %uint_0
+         %20 = OpLoad %_arr_Outer_uint_4 %19
+         %24 = OpAccessChain %_ptr_Uniform_Outer %a %uint_0 %int_3
+         %25 = OpLoad %Outer %24
+         %27 = OpAccessChain %_ptr_Uniform__arr_Inner_uint_4 %a %uint_0 %int_3 %uint_0
+         %28 = OpLoad %_arr_Inner_uint_4 %27
+         %31 = OpAccessChain %_ptr_Uniform_Inner %a %uint_0 %int_3 %uint_0 %int_2
+         %32 = OpLoad %Inner %31
+         %34 = OpAccessChain %_ptr_Uniform_mat2v3float %a %uint_0 %int_3 %uint_0 %int_2 %uint_0
+         %35 = OpLoad %mat2v3float %34
+         %38 = OpAccessChain %_ptr_Uniform_v3float %a %uint_0 %int_3 %uint_0 %int_2 %uint_0 %int_1
+         %39 = OpLoad %v3float %38
+         %42 = OpAccessChain %_ptr_Uniform_float %a %uint_0 %int_3 %uint_0 %int_2 %uint_0 %int_1 %40
+         %43 = OpLoad %float %42
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/static_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..df426aa
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/static_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,27 @@
+struct Inner {
+  @size(64)
+  m : mat2x3<f32>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_3 = &((*(p_a))[3]);
+  let p_a_3_a = &((*(p_a_3)).a);
+  let p_a_3_a_2 = &((*(p_a_3_a))[2]);
+  let p_a_3_a_2_m = &((*(p_a_3_a_2)).m);
+  let p_a_3_a_2_m_1 = &((*(p_a_3_a_2_m))[1]);
+  let l_a : array<Outer, 4> = *(p_a);
+  let l_a_3 : Outer = *(p_a_3);
+  let l_a_3_a : array<Inner, 4> = *(p_a_3_a);
+  let l_a_3_a_2 : Inner = *(p_a_3_a_2);
+  let l_a_3_a_2_m : mat2x3<f32> = *(p_a_3_a_2_m);
+  let l_a_3_a_2_m_1 : vec3<f32> = *(p_a_3_a_2_m_1);
+  let l_a_3_a_2_m_1_0 : f32 = (*(p_a_3_a_2_m_1))[0];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_builtin.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_builtin.wgsl
new file mode 100644
index 0000000..75fee9d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_builtin.wgsl
@@ -0,0 +1,15 @@
+struct S {
+  before : i32,
+  m : mat2x3<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    let t = transpose(u[2].m);
+    let l = length(u[0].m[1].zxy);
+    let a = abs(u[0].m[1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_builtin.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..158973f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_builtin.wgsl.expected.dxc.hlsl
@@ -0,0 +1,17 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+float2x3 tint_symbol(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float3x2 t = transpose(tint_symbol(u, 272u));
+  const float l = length(asfloat(u[2].xyz).zxy);
+  const float a = abs(asfloat(u[2].xyz).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_builtin.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..158973f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_builtin.wgsl.expected.fxc.hlsl
@@ -0,0 +1,17 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+float2x3 tint_symbol(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float3x2 t = transpose(tint_symbol(u, 272u));
+  const float l = length(asfloat(u[2].xyz).zxy);
+  const float a = abs(asfloat(u[2].xyz).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_builtin.wgsl.expected.glsl
new file mode 100644
index 0000000..60746c6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_builtin.wgsl.expected.glsl
@@ -0,0 +1,45 @@
+#version 310 es
+
+struct S {
+  int before;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  mat2x3 m;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  int after;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+};
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  S inner[4];
+} u;
+
+void f() {
+  mat3x2 t = transpose(u.inner[2].m);
+  float l = length(u.inner[0].m[1].zxy);
+  float a = abs(u.inner[0].m[1].zxy.x);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_builtin.wgsl.expected.msl
new file mode 100644
index 0000000..febc7d5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_builtin.wgsl.expected.msl
@@ -0,0 +1,32 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 12> tint_pad;
+  /* 0x0010 */ float2x3 m;
+  /* 0x0030 */ tint_array<int8_t, 16> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol [[buffer(0)]]) {
+  float3x2 const t = transpose((*(tint_symbol))[2].m);
+  float const l = length(float3((*(tint_symbol))[0].m[1]).zxy);
+  float const a = fabs(float3((*(tint_symbol))[0].m[1]).zxy[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_builtin.wgsl.expected.spvasm
new file mode 100644
index 0000000..329aa40
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_builtin.wgsl.expected.spvasm
@@ -0,0 +1,67 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 38
+; Schema: 0
+               OpCapability Shader
+         %26 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %u "u"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 16
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 16
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat2v3float = OpTypeMatrix %v3float 2
+          %S = OpTypeStruct %int %mat2v3float %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+    %u_block = OpTypeStruct %_arr_S_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+         %12 = OpTypeFunction %void
+    %v2float = OpTypeVector %float 2
+%mat3v2float = OpTypeMatrix %v2float 3
+     %uint_0 = OpConstant %uint 0
+      %int_2 = OpConstant %int 2
+     %uint_1 = OpConstant %uint 1
+%_ptr_Uniform_mat2v3float = OpTypePointer Uniform %mat2v3float
+         %27 = OpConstantNull %int
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+          %f = OpFunction %void None %12
+         %15 = OpLabel
+         %23 = OpAccessChain %_ptr_Uniform_mat2v3float %u %uint_0 %int_2 %uint_1
+         %24 = OpLoad %mat2v3float %23
+         %16 = OpTranspose %mat3v2float %24
+         %30 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %27 %uint_1 %int_1
+         %31 = OpLoad %v3float %30
+         %32 = OpVectorShuffle %v3float %31 %31 2 0 1
+         %25 = OpExtInst %float %26 Length %32
+         %34 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %27 %uint_1 %int_1
+         %35 = OpLoad %v3float %34
+         %36 = OpVectorShuffle %v3float %35 %35 2 0 1
+         %37 = OpCompositeExtract %float %36 0
+         %33 = OpExtInst %float %26 FAbs %37
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_builtin.wgsl.expected.wgsl
new file mode 100644
index 0000000..32a5a51
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_builtin.wgsl.expected.wgsl
@@ -0,0 +1,15 @@
+struct S {
+  before : i32,
+  m : mat2x3<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let t = transpose(u[2].m);
+  let l = length(u[0].m[1].zxy);
+  let a = abs(u[0].m[1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_fn.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_fn.wgsl
new file mode 100644
index 0000000..d8af58b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_fn.wgsl
@@ -0,0 +1,23 @@
+struct S {
+  before : i32,
+  m : mat2x3<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+fn a(a : array<S, 4>) {}
+fn b(s : S) {}
+fn c(m : mat2x3<f32>) {}
+fn d(v : vec3<f32>) {}
+fn e(f : f32) {}
+
+@compute @workgroup_size(1)
+fn f() {
+    a(u);
+    b(u[2]);
+    c(u[2].m);
+    d(u[0].m[1].zxy);
+    e(u[0].m[1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_fn.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..c48f877
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_fn.wgsl.expected.dxc.hlsl
@@ -0,0 +1,58 @@
+struct S {
+  int before;
+  float2x3 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(float2x3 m) {
+}
+
+void d(float3 v) {
+}
+
+void e(float f_1) {
+}
+
+float2x3 tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_3(buffer, (offset + 16u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 256u));
+  c(tint_symbol_3(u, 272u));
+  d(asfloat(u[2].xyz).zxy);
+  e(asfloat(u[2].xyz).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_fn.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..c48f877
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_fn.wgsl.expected.fxc.hlsl
@@ -0,0 +1,58 @@
+struct S {
+  int before;
+  float2x3 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(float2x3 m) {
+}
+
+void d(float3 v) {
+}
+
+void e(float f_1) {
+}
+
+float2x3 tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_3(buffer, (offset + 16u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 256u));
+  c(tint_symbol_3(u, 272u));
+  d(asfloat(u[2].xyz).zxy);
+  e(asfloat(u[2].xyz).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_fn.wgsl.expected.glsl
new file mode 100644
index 0000000..5fb9e19
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_fn.wgsl.expected.glsl
@@ -0,0 +1,62 @@
+#version 310 es
+
+struct S {
+  int before;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  mat2x3 m;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  int after;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+};
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  S inner[4];
+} u;
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(mat2x3 m) {
+}
+
+void d(vec3 v) {
+}
+
+void e(float f_1) {
+}
+
+void f() {
+  a(u.inner);
+  b(u.inner[2]);
+  c(u.inner[2].m);
+  d(u.inner[0].m[1].zxy);
+  e(u.inner[0].m[1].zxy.x);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_fn.wgsl.expected.msl
new file mode 100644
index 0000000..5835b92
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_fn.wgsl.expected.msl
@@ -0,0 +1,49 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 12> tint_pad;
+  /* 0x0010 */ float2x3 m;
+  /* 0x0030 */ tint_array<int8_t, 16> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+void a(tint_array<S, 4> a_1) {
+}
+
+void b(S s) {
+}
+
+void c(float2x3 m) {
+}
+
+void d(float3 v) {
+}
+
+void e(float f_1) {
+}
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol [[buffer(0)]]) {
+  a(*(tint_symbol));
+  b((*(tint_symbol))[2]);
+  c((*(tint_symbol))[2].m);
+  d(float3((*(tint_symbol))[0].m[1]).zxy);
+  e(float3((*(tint_symbol))[0].m[1]).zxy[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_fn.wgsl.expected.spvasm
new file mode 100644
index 0000000..7bcf25c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_fn.wgsl.expected.spvasm
@@ -0,0 +1,112 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 63
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %u "u"
+               OpName %a "a"
+               OpName %a_1 "a_1"
+               OpName %b "b"
+               OpName %s "s"
+               OpName %c "c"
+               OpName %m "m"
+               OpName %d "d"
+               OpName %v "v"
+               OpName %e "e"
+               OpName %f_1 "f_1"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 16
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 16
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat2v3float = OpTypeMatrix %v3float 2
+          %S = OpTypeStruct %int %mat2v3float %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+    %u_block = OpTypeStruct %_arr_S_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+         %12 = OpTypeFunction %void %_arr_S_uint_4
+         %17 = OpTypeFunction %void %S
+         %21 = OpTypeFunction %void %mat2v3float
+         %25 = OpTypeFunction %void %v3float
+         %29 = OpTypeFunction %void %float
+         %33 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_S_uint_4 = OpTypePointer Uniform %_arr_S_uint_4
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_S = OpTypePointer Uniform %S
+     %uint_1 = OpConstant %uint 1
+%_ptr_Uniform_mat2v3float = OpTypePointer Uniform %mat2v3float
+         %52 = OpConstantNull %int
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+          %a = OpFunction %void None %12
+        %a_1 = OpFunctionParameter %_arr_S_uint_4
+         %16 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %b = OpFunction %void None %17
+          %s = OpFunctionParameter %S
+         %20 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %c = OpFunction %void None %21
+          %m = OpFunctionParameter %mat2v3float
+         %24 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %d = OpFunction %void None %25
+          %v = OpFunctionParameter %v3float
+         %28 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %e = OpFunction %void None %29
+        %f_1 = OpFunctionParameter %float
+         %32 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %33
+         %35 = OpLabel
+         %39 = OpAccessChain %_ptr_Uniform__arr_S_uint_4 %u %uint_0
+         %40 = OpLoad %_arr_S_uint_4 %39
+         %36 = OpFunctionCall %void %a %40
+         %44 = OpAccessChain %_ptr_Uniform_S %u %uint_0 %int_2
+         %45 = OpLoad %S %44
+         %41 = OpFunctionCall %void %b %45
+         %49 = OpAccessChain %_ptr_Uniform_mat2v3float %u %uint_0 %int_2 %uint_1
+         %50 = OpLoad %mat2v3float %49
+         %46 = OpFunctionCall %void %c %50
+         %55 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %52 %uint_1 %int_1
+         %56 = OpLoad %v3float %55
+         %57 = OpVectorShuffle %v3float %56 %56 2 0 1
+         %51 = OpFunctionCall %void %d %57
+         %59 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %52 %uint_1 %int_1
+         %60 = OpLoad %v3float %59
+         %61 = OpVectorShuffle %v3float %60 %60 2 0 1
+         %62 = OpCompositeExtract %float %61 0
+         %58 = OpFunctionCall %void %e %62
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_fn.wgsl.expected.wgsl
new file mode 100644
index 0000000..0058849
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_fn.wgsl.expected.wgsl
@@ -0,0 +1,32 @@
+struct S {
+  before : i32,
+  m : mat2x3<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+fn a(a : array<S, 4>) {
+}
+
+fn b(s : S) {
+}
+
+fn c(m : mat2x3<f32>) {
+}
+
+fn d(v : vec3<f32>) {
+}
+
+fn e(f : f32) {
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  a(u);
+  b(u[2]);
+  c(u[2].m);
+  d(u[0].m[1].zxy);
+  e(u[0].m[1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_private.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_private.wgsl
new file mode 100644
index 0000000..510398c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_private.wgsl
@@ -0,0 +1,17 @@
+struct S {
+  before : i32,
+  m : mat2x3<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+var<private> p : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[2];
+    p[3].m = u[2].m;
+    p[1].m[0] = u[0].m[1].zxy;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_private.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..08aa42f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_private.wgsl.expected.dxc.hlsl
@@ -0,0 +1,43 @@
+struct S {
+  int before;
+  float2x3 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+static S p[4] = (S[4])0;
+
+float2x3 tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_3(buffer, (offset + 16u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 256u);
+  p[3].m = tint_symbol_3(u, 272u);
+  p[1].m[0] = asfloat(u[2].xyz).zxy;
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_private.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..08aa42f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_private.wgsl.expected.fxc.hlsl
@@ -0,0 +1,43 @@
+struct S {
+  int before;
+  float2x3 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+static S p[4] = (S[4])0;
+
+float2x3 tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_3(buffer, (offset + 16u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 256u);
+  p[3].m = tint_symbol_3(u, 272u);
+  p[1].m[0] = asfloat(u[2].xyz).zxy;
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..6c7f307
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_private.wgsl.expected.glsl
@@ -0,0 +1,47 @@
+#version 310 es
+
+struct S {
+  int before;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  mat2x3 m;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  int after;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+};
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  S inner[4];
+} u;
+
+S p[4] = S[4](S(0, 0u, 0u, 0u, mat2x3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, 0u, 0u, mat2x3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, 0u, 0u, mat2x3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, 0u, 0u, mat2x3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+void f() {
+  p = u.inner;
+  p[1] = u.inner[2];
+  p[3].m = u.inner[2].m;
+  p[1].m[0] = u.inner[0].m[1].zxy;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..40d4274
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_private.wgsl.expected.msl
@@ -0,0 +1,34 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 12> tint_pad;
+  /* 0x0010 */ float2x3 m;
+  /* 0x0030 */ tint_array<int8_t, 16> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol_1 [[buffer(0)]]) {
+  thread tint_array<S, 4> tint_symbol = {};
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[2];
+  tint_symbol[3].m = (*(tint_symbol_1))[2].m;
+  tint_symbol[1].m[0] = float3((*(tint_symbol_1))[0].m[1]).zxy;
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_private.wgsl.expected.spvasm
new file mode 100644
index 0000000..9e61a0d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_private.wgsl.expected.spvasm
@@ -0,0 +1,78 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 44
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %u "u"
+               OpName %p "p"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 16
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 16
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat2v3float = OpTypeMatrix %v3float 2
+          %S = OpTypeStruct %int %mat2v3float %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+    %u_block = OpTypeStruct %_arr_S_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_Private__arr_S_uint_4 = OpTypePointer Private %_arr_S_uint_4
+         %14 = OpConstantNull %_arr_S_uint_4
+          %p = OpVariable %_ptr_Private__arr_S_uint_4 Private %14
+       %void = OpTypeVoid
+         %15 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_S_uint_4 = OpTypePointer Uniform %_arr_S_uint_4
+      %int_1 = OpConstant %int 1
+%_ptr_Private_S = OpTypePointer Private %S
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_S = OpTypePointer Uniform %S
+      %int_3 = OpConstant %int 3
+     %uint_1 = OpConstant %uint 1
+%_ptr_Private_mat2v3float = OpTypePointer Private %mat2v3float
+%_ptr_Uniform_mat2v3float = OpTypePointer Uniform %mat2v3float
+         %37 = OpConstantNull %int
+%_ptr_Private_v3float = OpTypePointer Private %v3float
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+          %f = OpFunction %void None %15
+         %18 = OpLabel
+         %21 = OpAccessChain %_ptr_Uniform__arr_S_uint_4 %u %uint_0
+         %22 = OpLoad %_arr_S_uint_4 %21
+               OpStore %p %22
+         %25 = OpAccessChain %_ptr_Private_S %p %int_1
+         %28 = OpAccessChain %_ptr_Uniform_S %u %uint_0 %int_2
+         %29 = OpLoad %S %28
+               OpStore %25 %29
+         %33 = OpAccessChain %_ptr_Private_mat2v3float %p %int_3 %uint_1
+         %35 = OpAccessChain %_ptr_Uniform_mat2v3float %u %uint_0 %int_2 %uint_1
+         %36 = OpLoad %mat2v3float %35
+               OpStore %33 %36
+         %39 = OpAccessChain %_ptr_Private_v3float %p %int_1 %uint_1 %37
+         %41 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %37 %uint_1 %int_1
+         %42 = OpLoad %v3float %41
+         %43 = OpVectorShuffle %v3float %42 %42 2 0 1
+               OpStore %39 %43
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..70fa82f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_private.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+struct S {
+  before : i32,
+  m : mat2x3<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+var<private> p : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[2];
+  p[3].m = u[2].m;
+  p[1].m[0] = u[0].m[1].zxy;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_storage.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_storage.wgsl
new file mode 100644
index 0000000..6e1221f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_storage.wgsl
@@ -0,0 +1,17 @@
+struct S {
+  before : i32,
+  m : mat2x3<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+@group(0) @binding(1) var<storage, read_write> s : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[2];
+    s[3].m = u[2].m;
+    s[1].m[0] = u[0].m[1].zxy;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_storage.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..89eabee
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_storage.wgsl.expected.dxc.hlsl
@@ -0,0 +1,63 @@
+struct S {
+  int before;
+  float2x3 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_3(RWByteAddressBuffer buffer, uint offset, float2x3 value) {
+  buffer.Store3((offset + 0u), asuint(value[0u]));
+  buffer.Store3((offset + 16u), asuint(value[1u]));
+}
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, S value) {
+  buffer.Store((offset + 0u), asuint(value.before));
+  tint_symbol_3(buffer, (offset + 16u), value.m);
+  buffer.Store((offset + 64u), asuint(value.after));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, S value[4]) {
+  S array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 128u)), array[i]);
+    }
+  }
+}
+
+float2x3 tint_symbol_8(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+}
+
+S tint_symbol_6(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_10 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_8(buffer, (offset + 16u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_10;
+}
+
+typedef S tint_symbol_5_ret[4];
+tint_symbol_5_ret tint_symbol_5(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_6(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_5(u, 0u));
+  tint_symbol_1(s, 128u, tint_symbol_6(u, 256u));
+  tint_symbol_3(s, 400u, tint_symbol_8(u, 272u));
+  s.Store3(144u, asuint(asfloat(u[2].xyz).zxy));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_storage.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..89eabee
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_storage.wgsl.expected.fxc.hlsl
@@ -0,0 +1,63 @@
+struct S {
+  int before;
+  float2x3 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_3(RWByteAddressBuffer buffer, uint offset, float2x3 value) {
+  buffer.Store3((offset + 0u), asuint(value[0u]));
+  buffer.Store3((offset + 16u), asuint(value[1u]));
+}
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, S value) {
+  buffer.Store((offset + 0u), asuint(value.before));
+  tint_symbol_3(buffer, (offset + 16u), value.m);
+  buffer.Store((offset + 64u), asuint(value.after));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, S value[4]) {
+  S array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 128u)), array[i]);
+    }
+  }
+}
+
+float2x3 tint_symbol_8(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+}
+
+S tint_symbol_6(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_10 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_8(buffer, (offset + 16u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_10;
+}
+
+typedef S tint_symbol_5_ret[4];
+tint_symbol_5_ret tint_symbol_5(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_6(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_5(u, 0u));
+  tint_symbol_1(s, 128u, tint_symbol_6(u, 256u));
+  tint_symbol_3(s, 400u, tint_symbol_8(u, 272u));
+  s.Store3(144u, asuint(asfloat(u[2].xyz).zxy));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..00df1fa
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_storage.wgsl.expected.glsl
@@ -0,0 +1,50 @@
+#version 310 es
+
+struct S {
+  int before;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  mat2x3 m;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  int after;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+};
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  S inner[4];
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  S inner[4];
+} s;
+
+void f() {
+  s.inner = u.inner;
+  s.inner[1] = u.inner[2];
+  s.inner[3].m = u.inner[2].m;
+  s.inner[1].m[0] = u.inner[0].m[1].zxy;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..181d0e3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_storage.wgsl.expected.msl
@@ -0,0 +1,33 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 12> tint_pad;
+  /* 0x0010 */ float2x3 m;
+  /* 0x0030 */ tint_array<int8_t, 16> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+kernel void f(device tint_array<S, 4>* tint_symbol [[buffer(1)]], const constant tint_array<S, 4>* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
+  (*(tint_symbol))[3].m = (*(tint_symbol_1))[2].m;
+  (*(tint_symbol))[1].m[0] = float3((*(tint_symbol_1))[0].m[1]).zxy;
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_storage.wgsl.expected.spvasm
new file mode 100644
index 0000000..3d31ce0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_storage.wgsl.expected.spvasm
@@ -0,0 +1,81 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 45
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %u "u"
+               OpName %s "s"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 16
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 16
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %s DescriptorSet 0
+               OpDecorate %s Binding 1
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat2v3float = OpTypeMatrix %v3float 2
+          %S = OpTypeStruct %int %mat2v3float %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+    %u_block = OpTypeStruct %_arr_S_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
+          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+       %void = OpTypeVoid
+         %14 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer__arr_S_uint_4 = OpTypePointer StorageBuffer %_arr_S_uint_4
+%_ptr_Uniform__arr_S_uint_4 = OpTypePointer Uniform %_arr_S_uint_4
+      %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_S = OpTypePointer Uniform %S
+      %int_3 = OpConstant %int 3
+     %uint_1 = OpConstant %uint 1
+%_ptr_StorageBuffer_mat2v3float = OpTypePointer StorageBuffer %mat2v3float
+%_ptr_Uniform_mat2v3float = OpTypePointer Uniform %mat2v3float
+         %38 = OpConstantNull %int
+%_ptr_StorageBuffer_v3float = OpTypePointer StorageBuffer %v3float
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+          %f = OpFunction %void None %14
+         %17 = OpLabel
+         %20 = OpAccessChain %_ptr_StorageBuffer__arr_S_uint_4 %s %uint_0
+         %22 = OpAccessChain %_ptr_Uniform__arr_S_uint_4 %u %uint_0
+         %23 = OpLoad %_arr_S_uint_4 %22
+               OpStore %20 %23
+         %26 = OpAccessChain %_ptr_StorageBuffer_S %s %uint_0 %int_1
+         %29 = OpAccessChain %_ptr_Uniform_S %u %uint_0 %int_2
+         %30 = OpLoad %S %29
+               OpStore %26 %30
+         %34 = OpAccessChain %_ptr_StorageBuffer_mat2v3float %s %uint_0 %int_3 %uint_1
+         %36 = OpAccessChain %_ptr_Uniform_mat2v3float %u %uint_0 %int_2 %uint_1
+         %37 = OpLoad %mat2v3float %36
+               OpStore %34 %37
+         %40 = OpAccessChain %_ptr_StorageBuffer_v3float %s %uint_0 %int_1 %uint_1 %38
+         %42 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %38 %uint_1 %int_1
+         %43 = OpLoad %v3float %42
+         %44 = OpVectorShuffle %v3float %43 %43 2 0 1
+               OpStore %40 %44
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..06df2f7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+struct S {
+  before : i32,
+  m : mat2x3<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@group(0) @binding(1) var<storage, read_write> s : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[2];
+  s[3].m = u[2].m;
+  s[1].m[0] = u[0].m[1].zxy;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_workgroup.wgsl
new file mode 100644
index 0000000..b2bb72d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_workgroup.wgsl
@@ -0,0 +1,17 @@
+struct S {
+  before : i32,
+  m : mat2x3<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+var<workgroup> w : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[2];
+    w[3].m = u[2].m;
+    w[1].m[0] = u[0].m[1].zxy;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_workgroup.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..e2fb38a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_workgroup.wgsl.expected.dxc.hlsl
@@ -0,0 +1,59 @@
+struct S {
+  int before;
+  float2x3 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+groupshared S w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+float2x3 tint_symbol_5(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+}
+
+S tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_8 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_5(buffer, (offset + 16u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_8;
+}
+
+typedef S tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      const S tint_symbol_7 = (S)0;
+      w[i] = tint_symbol_7;
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 256u);
+  w[3].m = tint_symbol_5(u, 272u);
+  w[1].m[0] = asfloat(u[2].xyz).zxy;
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_workgroup.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..e2fb38a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_workgroup.wgsl.expected.fxc.hlsl
@@ -0,0 +1,59 @@
+struct S {
+  int before;
+  float2x3 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+groupshared S w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+float2x3 tint_symbol_5(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+}
+
+S tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_8 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_5(buffer, (offset + 16u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_8;
+}
+
+typedef S tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      const S tint_symbol_7 = (S)0;
+      w[i] = tint_symbol_7;
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 256u);
+  w[3].m = tint_symbol_5(u, 272u);
+  w[1].m[0] = asfloat(u[2].xyz).zxy;
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..2e0e12b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,55 @@
+#version 310 es
+
+struct S {
+  int before;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  mat2x3 m;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  int after;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+};
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  S inner[4];
+} u;
+
+shared S w[4];
+void f(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      uint i = idx;
+      S tint_symbol = S(0, 0u, 0u, 0u, mat2x3(vec3(0.0f), vec3(0.0f)), 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u);
+      w[i] = tint_symbol;
+    }
+  }
+  barrier();
+  w = u.inner;
+  w[1] = u.inner[2];
+  w[3].m = u.inner[2].m;
+  w[1].m[0] = u.inner[0].m[1].zxy;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..6e4d54e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,48 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 12> tint_pad;
+  /* 0x0010 */ float2x3 m;
+  /* 0x0030 */ tint_array<int8_t, 16> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+struct tint_symbol_6 {
+  tint_array<S, 4> w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup tint_array<S, 4>* const tint_symbol_1, const constant tint_array<S, 4>* const tint_symbol_2) {
+  for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+    uint const i = idx;
+    S const tint_symbol = S{};
+    (*(tint_symbol_1))[i] = tint_symbol;
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol_1) = *(tint_symbol_2);
+  (*(tint_symbol_1))[1] = (*(tint_symbol_2))[2];
+  (*(tint_symbol_1))[3].m = (*(tint_symbol_2))[2].m;
+  (*(tint_symbol_1))[1].m[0] = float3((*(tint_symbol_2))[0].m[1]).zxy;
+}
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol_5 [[buffer(0)]], threadgroup tint_symbol_6* tint_symbol_4 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup tint_array<S, 4>* const tint_symbol_3 = &((*(tint_symbol_4)).w);
+  f_inner(local_invocation_index, tint_symbol_3, tint_symbol_5);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_workgroup.wgsl.expected.spvasm
new file mode 100644
index 0000000..e510c36
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_workgroup.wgsl.expected.spvasm
@@ -0,0 +1,124 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 72
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %local_invocation_index_1 "local_invocation_index_1"
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %u "u"
+               OpName %w "w"
+               OpName %f_inner "f_inner"
+               OpName %local_invocation_index "local_invocation_index"
+               OpName %idx "idx"
+               OpName %f "f"
+               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 16
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 16
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat2v3float = OpTypeMatrix %v3float 2
+          %S = OpTypeStruct %int %mat2v3float %int
+     %uint_4 = OpConstant %uint 4
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+    %u_block = OpTypeStruct %_arr_S_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_Workgroup__arr_S_uint_4 = OpTypePointer Workgroup %_arr_S_uint_4
+          %w = OpVariable %_ptr_Workgroup__arr_S_uint_4 Workgroup
+       %void = OpTypeVoid
+         %16 = OpTypeFunction %void %uint
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %23 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Workgroup_S = OpTypePointer Workgroup %S
+         %37 = OpConstantNull %S
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+   %uint_264 = OpConstant %uint 264
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_S_uint_4 = OpTypePointer Uniform %_arr_S_uint_4
+      %int_1 = OpConstant %int 1
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_S = OpTypePointer Uniform %S
+      %int_3 = OpConstant %int 3
+%_ptr_Workgroup_mat2v3float = OpTypePointer Workgroup %mat2v3float
+%_ptr_Uniform_mat2v3float = OpTypePointer Uniform %mat2v3float
+         %60 = OpConstantNull %int
+%_ptr_Workgroup_v3float = OpTypePointer Workgroup %v3float
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+         %67 = OpTypeFunction %void
+    %f_inner = OpFunction %void None %16
+%local_invocation_index = OpFunctionParameter %uint
+         %20 = OpLabel
+        %idx = OpVariable %_ptr_Function_uint Function %23
+               OpStore %idx %local_invocation_index
+               OpBranch %24
+         %24 = OpLabel
+               OpLoopMerge %25 %26 None
+               OpBranch %27
+         %27 = OpLabel
+         %29 = OpLoad %uint %idx
+         %30 = OpULessThan %bool %29 %uint_4
+         %28 = OpLogicalNot %bool %30
+               OpSelectionMerge %32 None
+               OpBranchConditional %28 %33 %32
+         %33 = OpLabel
+               OpBranch %25
+         %32 = OpLabel
+         %34 = OpLoad %uint %idx
+         %36 = OpAccessChain %_ptr_Workgroup_S %w %34
+               OpStore %36 %37
+               OpBranch %26
+         %26 = OpLabel
+         %38 = OpLoad %uint %idx
+         %40 = OpIAdd %uint %38 %uint_1
+               OpStore %idx %40
+               OpBranch %24
+         %25 = OpLabel
+               OpControlBarrier %uint_2 %uint_2 %uint_264
+         %46 = OpAccessChain %_ptr_Uniform__arr_S_uint_4 %u %uint_0
+         %47 = OpLoad %_arr_S_uint_4 %46
+               OpStore %w %47
+         %49 = OpAccessChain %_ptr_Workgroup_S %w %int_1
+         %52 = OpAccessChain %_ptr_Uniform_S %u %uint_0 %int_2
+         %53 = OpLoad %S %52
+               OpStore %49 %53
+         %56 = OpAccessChain %_ptr_Workgroup_mat2v3float %w %int_3 %uint_1
+         %58 = OpAccessChain %_ptr_Uniform_mat2v3float %u %uint_0 %int_2 %uint_1
+         %59 = OpLoad %mat2v3float %58
+               OpStore %56 %59
+         %62 = OpAccessChain %_ptr_Workgroup_v3float %w %int_1 %uint_1 %60
+         %64 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %60 %uint_1 %int_1
+         %65 = OpLoad %v3float %64
+         %66 = OpVectorShuffle %v3float %65 %65 2 0 1
+               OpStore %62 %66
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %67
+         %69 = OpLabel
+         %71 = OpLoad %uint %local_invocation_index_1
+         %70 = OpFunctionCall %void %f_inner %71
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..9628ff9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x3_f32/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+struct S {
+  before : i32,
+  m : mat2x3<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+var<workgroup> w : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[2];
+  w[3].m = u[2].m;
+  w[1].m[0] = u[0].m[1].zxy;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/dynamic_index_via_ptr.wgsl
new file mode 100644
index 0000000..c007f9b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/dynamic_index_via_ptr.wgsl
@@ -0,0 +1,34 @@
+enable f16;
+
+struct Inner {
+  @size(64)
+  m : mat2x4<f16>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a           = &a;
+  let p_a_i         = &((*p_a)[i()]);
+  let p_a_i_a       = &((*p_a_i).a);
+  let p_a_i_a_i     = &((*p_a_i_a)[i()]);
+  let p_a_i_a_i_m   = &((*p_a_i_a_i).m);
+  let p_a_i_a_i_m_i = &((*p_a_i_a_i_m)[i()]);
+
+
+  let l_a             : array<Outer, 4> =  *p_a;
+  let l_a_i           : Outer           =  *p_a_i;
+  let l_a_i_a         : array<Inner, 4> =  *p_a_i_a;
+  let l_a_i_a_i       : Inner           =  *p_a_i_a_i;
+  let l_a_i_a_i_m     : mat2x4<f16>     =  *p_a_i_a_i_m;
+  let l_a_i_a_i_m_i   : vec4<f16>       =  *p_a_i_a_i_m_i;
+  let l_a_i_a_i_m_i_i : f16             = (*p_a_i_a_i_m_i)[i()];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..2bad103
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,88 @@
+struct Inner {
+  matrix<float16_t, 2, 4> m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 2, 4> tint_symbol_8(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+Inner tint_symbol_7(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_11 = {tint_symbol_8(buffer, (offset + 0u))};
+  return tint_symbol_11;
+}
+
+typedef Inner tint_symbol_6_ret[4];
+tint_symbol_6_ret tint_symbol_6(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_7(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_5(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_12 = {tint_symbol_6(buffer, (offset + 0u))};
+  return tint_symbol_12;
+}
+
+typedef Outer tint_symbol_4_ret[4];
+tint_symbol_4_ret tint_symbol_4(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
+      arr_1[i_2] = tint_symbol_5(buffer, (offset + (i_2 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_a_i_save = i();
+  const int p_a_i_a_i_m_i_save = i();
+  const Outer l_a[4] = tint_symbol_4(a, 0u);
+  const Outer l_a_i = tint_symbol_5(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a[4] = tint_symbol_6(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a_i = tint_symbol_7(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const matrix<float16_t, 2, 4> l_a_i_a_i_m = tint_symbol_8(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const uint scalar_offset_2 = ((((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))) + (8u * uint(p_a_i_a_i_m_i_save)))) / 4;
+  uint4 ubo_load_5 = a[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const vector<float16_t, 4> l_a_i_a_i_m_i = vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]);
+  const int tint_symbol = p_a_i_save;
+  const int tint_symbol_1 = p_a_i_a_i_save;
+  const int tint_symbol_2 = p_a_i_a_i_m_i_save;
+  const int tint_symbol_3 = i();
+  const uint scalar_offset_bytes = (((((256u * uint(tint_symbol)) + (64u * uint(tint_symbol_1))) + (8u * uint(tint_symbol_2))) + (2u * uint(tint_symbol_3))));
+  const uint scalar_offset_index = scalar_offset_bytes / 4;
+  const float16_t l_a_i_a_i_m_i_i = float16_t(f16tof32(((a[scalar_offset_index / 4][scalar_offset_index % 4] >> (scalar_offset_bytes % 4 == 0 ? 0 : 16)) & 0xFFFF)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..b92b308
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,93 @@
+SKIP: FAILED
+
+struct Inner {
+  matrix<float16_t, 2, 4> m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 2, 4> tint_symbol_8(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+Inner tint_symbol_7(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_11 = {tint_symbol_8(buffer, (offset + 0u))};
+  return tint_symbol_11;
+}
+
+typedef Inner tint_symbol_6_ret[4];
+tint_symbol_6_ret tint_symbol_6(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_7(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_5(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_12 = {tint_symbol_6(buffer, (offset + 0u))};
+  return tint_symbol_12;
+}
+
+typedef Outer tint_symbol_4_ret[4];
+tint_symbol_4_ret tint_symbol_4(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
+      arr_1[i_2] = tint_symbol_5(buffer, (offset + (i_2 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_a_i_save = i();
+  const int p_a_i_a_i_m_i_save = i();
+  const Outer l_a[4] = tint_symbol_4(a, 0u);
+  const Outer l_a_i = tint_symbol_5(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a[4] = tint_symbol_6(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a_i = tint_symbol_7(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const matrix<float16_t, 2, 4> l_a_i_a_i_m = tint_symbol_8(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const uint scalar_offset_2 = ((((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))) + (8u * uint(p_a_i_a_i_m_i_save)))) / 4;
+  uint4 ubo_load_5 = a[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const vector<float16_t, 4> l_a_i_a_i_m_i = vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]);
+  const int tint_symbol = p_a_i_save;
+  const int tint_symbol_1 = p_a_i_a_i_save;
+  const int tint_symbol_2 = p_a_i_a_i_m_i_save;
+  const int tint_symbol_3 = i();
+  const uint scalar_offset_bytes = (((((256u * uint(tint_symbol)) + (64u * uint(tint_symbol_1))) + (8u * uint(tint_symbol_2))) + (2u * uint(tint_symbol_3))));
+  const uint scalar_offset_index = scalar_offset_bytes / 4;
+  const float16_t l_a_i_a_i_m_i_i = float16_t(f16tof32(((a[scalar_offset_index / 4][scalar_offset_index % 4] >> (scalar_offset_bytes % 4 == 0 ? 0 : 16)) & 0xFFFF)));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001DE39EE1520(2,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..762fe11
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,147 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct Inner {
+  f16mat2x4 m;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+};
+
+struct Inner_std140 {
+  f16vec4 m_0;
+  f16vec4 m_1;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+};
+
+struct Outer {
+  Inner a[4];
+};
+
+struct Outer_std140 {
+  Inner_std140 a[4];
+};
+
+layout(binding = 0, std140) uniform a_block_std140_ubo {
+  Outer_std140 inner[4];
+} a;
+
+int counter = 0;
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+Inner conv_Inner(Inner_std140 val) {
+  return Inner(f16mat2x4(val.m_0, val.m_1), val.pad, val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.pad_11);
+}
+
+Inner[4] conv_arr4_Inner(Inner_std140 val[4]) {
+  Inner arr[4] = Inner[4](Inner(f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_Inner(val[i]);
+    }
+  }
+  return arr;
+}
+
+Outer conv_Outer(Outer_std140 val) {
+  return Outer(conv_arr4_Inner(val.a));
+}
+
+Outer[4] conv_arr4_Outer(Outer_std140 val[4]) {
+  Outer arr[4] = Outer[4](Outer(Inner[4](Inner(f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_Outer(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat2x4 load_a_inner_p0_a_p1_m(uint p0, uint p1) {
+  uint s_save = p0;
+  uint s_save_1 = p1;
+  return f16mat2x4(a.inner[s_save].a[s_save_1].m_0, a.inner[s_save].a[s_save_1].m_1);
+}
+
+f16vec4 load_a_inner_p0_a_p1_m_p2(uint p0, uint p1, uint p2) {
+  switch(p2) {
+    case 0u: {
+      return a.inner[p0].a[p1].m_0;
+      break;
+    }
+    case 1u: {
+      return a.inner[p0].a[p1].m_1;
+      break;
+    }
+    default: {
+      return f16vec4(0.0hf);
+      break;
+    }
+  }
+}
+
+float16_t load_a_inner_p0_a_p1_m_p2_p3(uint p0, uint p1, uint p2, uint p3) {
+  switch(p2) {
+    case 0u: {
+      return a.inner[p0].a[p1].m_0[p3];
+      break;
+    }
+    case 1u: {
+      return a.inner[p0].a[p1].m_1[p3];
+      break;
+    }
+    default: {
+      return 0.0hf;
+      break;
+    }
+  }
+}
+
+void f() {
+  Outer p_a[4] = conv_arr4_Outer(a.inner);
+  int tint_symbol = i();
+  Outer p_a_i = conv_Outer(a.inner[tint_symbol]);
+  Inner p_a_i_a[4] = conv_arr4_Inner(a.inner[tint_symbol].a);
+  int tint_symbol_1 = i();
+  Inner p_a_i_a_i = conv_Inner(a.inner[tint_symbol].a[tint_symbol_1]);
+  f16mat2x4 p_a_i_a_i_m = load_a_inner_p0_a_p1_m(uint(tint_symbol), uint(tint_symbol_1));
+  int tint_symbol_2 = i();
+  f16vec4 p_a_i_a_i_m_i = load_a_inner_p0_a_p1_m_p2(uint(tint_symbol), uint(tint_symbol_1), uint(tint_symbol_2));
+  Outer l_a[4] = conv_arr4_Outer(a.inner);
+  Outer l_a_i = conv_Outer(a.inner[tint_symbol]);
+  Inner l_a_i_a[4] = conv_arr4_Inner(a.inner[tint_symbol].a);
+  Inner l_a_i_a_i = conv_Inner(a.inner[tint_symbol].a[tint_symbol_1]);
+  f16mat2x4 l_a_i_a_i_m = load_a_inner_p0_a_p1_m(uint(tint_symbol), uint(tint_symbol_1));
+  f16vec4 l_a_i_a_i_m_i = load_a_inner_p0_a_p1_m_p2(uint(tint_symbol), uint(tint_symbol_1), uint(tint_symbol_2));
+  int tint_symbol_3 = i();
+  float16_t l_a_i_a_i_m_i_i = load_a_inner_p0_a_p1_m_p2_p3(uint(tint_symbol), uint(tint_symbol_1), uint(tint_symbol_2), uint(tint_symbol_3));
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..a4620ce
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,49 @@
+#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 Inner {
+  /* 0x0000 */ half2x4 m;
+  /* 0x0010 */ tint_array<int8_t, 48> tint_pad;
+};
+
+struct Outer {
+  /* 0x0000 */ tint_array<Inner, 4> a;
+};
+
+int i() {
+  thread int tint_symbol_4 = 0;
+  tint_symbol_4 = as_type<int>((as_type<uint>(tint_symbol_4) + as_type<uint>(1)));
+  return tint_symbol_4;
+}
+
+kernel void f(const constant tint_array<Outer, 4>* tint_symbol_5 [[buffer(0)]]) {
+  int const tint_symbol = i();
+  int const p_a_i_save = tint_symbol;
+  int const tint_symbol_1 = i();
+  int const p_a_i_a_i_save = tint_symbol_1;
+  int const tint_symbol_2 = i();
+  int const p_a_i_a_i_m_i_save = tint_symbol_2;
+  tint_array<Outer, 4> const l_a = *(tint_symbol_5);
+  Outer const l_a_i = (*(tint_symbol_5))[p_a_i_save];
+  tint_array<Inner, 4> const l_a_i_a = (*(tint_symbol_5))[p_a_i_save].a;
+  Inner const l_a_i_a_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save];
+  half2x4 const l_a_i_a_i_m = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m;
+  half4 const l_a_i_a_i_m_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save];
+  int const tint_symbol_3 = i();
+  half const l_a_i_a_i_m_i_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save][tint_symbol_3];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..d8cab36
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,310 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 193
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block_std140 "a_block_std140"
+               OpMemberName %a_block_std140 0 "inner"
+               OpName %Outer_std140 "Outer_std140"
+               OpMemberName %Outer_std140 0 "a"
+               OpName %Inner_std140 "Inner_std140"
+               OpMemberName %Inner_std140 0 "m_0"
+               OpMemberName %Inner_std140 1 "m_1"
+               OpName %a "a"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %Inner "Inner"
+               OpMemberName %Inner 0 "m"
+               OpName %conv_Inner "conv_Inner"
+               OpName %val "val"
+               OpName %conv_arr4_Inner "conv_arr4_Inner"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i_0 "i"
+               OpName %var_for_index_1 "var_for_index_1"
+               OpName %Outer "Outer"
+               OpMemberName %Outer 0 "a"
+               OpName %conv_Outer "conv_Outer"
+               OpName %val_1 "val"
+               OpName %conv_arr4_Outer "conv_arr4_Outer"
+               OpName %val_2 "val"
+               OpName %arr_0 "arr"
+               OpName %i_1 "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_a_inner_p0_a_p1_m "load_a_inner_p0_a_p1_m"
+               OpName %p0 "p0"
+               OpName %p1 "p1"
+               OpName %load_a_inner_p0_a_p1_m_p2 "load_a_inner_p0_a_p1_m_p2"
+               OpName %p0_0 "p0"
+               OpName %p1_0 "p1"
+               OpName %p2 "p2"
+               OpName %load_a_inner_p0_a_p1_m_p2_p3 "load_a_inner_p0_a_p1_m_p2_p3"
+               OpName %p0_1 "p0"
+               OpName %p1_1 "p1"
+               OpName %p2_0 "p2"
+               OpName %p3 "p3"
+               OpName %f "f"
+               OpDecorate %a_block_std140 Block
+               OpMemberDecorate %a_block_std140 0 Offset 0
+               OpMemberDecorate %Outer_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 1 Offset 8
+               OpDecorate %_arr_Inner_std140_uint_4 ArrayStride 64
+               OpDecorate %_arr_Outer_std140_uint_4 ArrayStride 256
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+               OpMemberDecorate %Inner 0 Offset 0
+               OpMemberDecorate %Inner 0 ColMajor
+               OpMemberDecorate %Inner 0 MatrixStride 8
+               OpDecorate %_arr_Inner_uint_4 ArrayStride 64
+               OpMemberDecorate %Outer 0 Offset 0
+               OpDecorate %_arr_Outer_uint_4 ArrayStride 256
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+%Inner_std140 = OpTypeStruct %v4half %v4half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_Inner_std140_uint_4 = OpTypeArray %Inner_std140 %uint_4
+%Outer_std140 = OpTypeStruct %_arr_Inner_std140_uint_4
+%_arr_Outer_std140_uint_4 = OpTypeArray %Outer_std140 %uint_4
+%a_block_std140 = OpTypeStruct %_arr_Outer_std140_uint_4
+%_ptr_Uniform_a_block_std140 = OpTypePointer Uniform %a_block_std140
+          %a = OpVariable %_ptr_Uniform_a_block_std140 Uniform
+        %int = OpTypeInt 32 1
+         %13 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %13
+         %16 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+ %mat2v4half = OpTypeMatrix %v4half 2
+      %Inner = OpTypeStruct %mat2v4half
+         %23 = OpTypeFunction %Inner %Inner_std140
+%_arr_Inner_uint_4 = OpTypeArray %Inner %uint_4
+         %33 = OpTypeFunction %_arr_Inner_uint_4 %_arr_Inner_std140_uint_4
+%_ptr_Function__arr_Inner_uint_4 = OpTypePointer Function %_arr_Inner_uint_4
+         %40 = OpConstantNull %_arr_Inner_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %43 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_Inner_std140_uint_4 = OpTypePointer Function %_arr_Inner_std140_uint_4
+         %56 = OpConstantNull %_arr_Inner_std140_uint_4
+%_ptr_Function_Inner = OpTypePointer Function %Inner
+%_ptr_Function_Inner_std140 = OpTypePointer Function %Inner_std140
+     %uint_1 = OpConstant %uint 1
+      %Outer = OpTypeStruct %_arr_Inner_uint_4
+         %69 = OpTypeFunction %Outer %Outer_std140
+%_arr_Outer_uint_4 = OpTypeArray %Outer %uint_4
+         %77 = OpTypeFunction %_arr_Outer_uint_4 %_arr_Outer_std140_uint_4
+%_ptr_Function__arr_Outer_uint_4 = OpTypePointer Function %_arr_Outer_uint_4
+         %84 = OpConstantNull %_arr_Outer_uint_4
+%_ptr_Function__arr_Outer_std140_uint_4 = OpTypePointer Function %_arr_Outer_std140_uint_4
+         %97 = OpConstantNull %_arr_Outer_std140_uint_4
+%_ptr_Function_Outer = OpTypePointer Function %Outer
+%_ptr_Function_Outer_std140 = OpTypePointer Function %Outer_std140
+        %109 = OpTypeFunction %mat2v4half %uint %uint
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_Inner_std140 = OpTypePointer Uniform %Inner_std140
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+        %126 = OpTypeFunction %v4half %uint %uint %uint
+        %140 = OpConstantNull %v4half
+        %141 = OpTypeFunction %half %uint %uint %uint %uint
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+        %157 = OpConstantNull %half
+       %void = OpTypeVoid
+        %158 = OpTypeFunction %void
+%_ptr_Uniform__arr_Outer_std140_uint_4 = OpTypePointer Uniform %_arr_Outer_std140_uint_4
+%_ptr_Uniform_Outer_std140 = OpTypePointer Uniform %Outer_std140
+%_ptr_Uniform__arr_Inner_std140_uint_4 = OpTypePointer Uniform %_arr_Inner_std140_uint_4
+          %i = OpFunction %int None %16
+         %18 = OpLabel
+         %19 = OpLoad %int %counter
+         %21 = OpIAdd %int %19 %int_1
+               OpStore %counter %21
+         %22 = OpLoad %int %counter
+               OpReturnValue %22
+               OpFunctionEnd
+ %conv_Inner = OpFunction %Inner None %23
+        %val = OpFunctionParameter %Inner_std140
+         %28 = OpLabel
+         %29 = OpCompositeExtract %v4half %val 0
+         %30 = OpCompositeExtract %v4half %val 1
+         %31 = OpCompositeConstruct %mat2v4half %29 %30
+         %32 = OpCompositeConstruct %Inner %31
+               OpReturnValue %32
+               OpFunctionEnd
+%conv_arr4_Inner = OpFunction %_arr_Inner_uint_4 None %33
+      %val_0 = OpFunctionParameter %_arr_Inner_std140_uint_4
+         %37 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_Inner_uint_4 Function %40
+        %i_0 = OpVariable %_ptr_Function_uint Function %43
+%var_for_index_1 = OpVariable %_ptr_Function__arr_Inner_std140_uint_4 Function %56
+               OpBranch %44
+         %44 = OpLabel
+               OpLoopMerge %45 %46 None
+               OpBranch %47
+         %47 = OpLabel
+         %49 = OpLoad %uint %i_0
+         %50 = OpULessThan %bool %49 %uint_4
+         %48 = OpLogicalNot %bool %50
+               OpSelectionMerge %52 None
+               OpBranchConditional %48 %53 %52
+         %53 = OpLabel
+               OpBranch %45
+         %52 = OpLabel
+               OpStore %var_for_index_1 %val_0
+         %57 = OpLoad %uint %i_0
+         %59 = OpAccessChain %_ptr_Function_Inner %arr %57
+         %61 = OpLoad %uint %i_0
+         %63 = OpAccessChain %_ptr_Function_Inner_std140 %var_for_index_1 %61
+         %64 = OpLoad %Inner_std140 %63
+         %60 = OpFunctionCall %Inner %conv_Inner %64
+               OpStore %59 %60
+               OpBranch %46
+         %46 = OpLabel
+         %65 = OpLoad %uint %i_0
+         %67 = OpIAdd %uint %65 %uint_1
+               OpStore %i_0 %67
+               OpBranch %44
+         %45 = OpLabel
+         %68 = OpLoad %_arr_Inner_uint_4 %arr
+               OpReturnValue %68
+               OpFunctionEnd
+ %conv_Outer = OpFunction %Outer None %69
+      %val_1 = OpFunctionParameter %Outer_std140
+         %73 = OpLabel
+         %75 = OpCompositeExtract %_arr_Inner_std140_uint_4 %val_1 0
+         %74 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %75
+         %76 = OpCompositeConstruct %Outer %74
+               OpReturnValue %76
+               OpFunctionEnd
+%conv_arr4_Outer = OpFunction %_arr_Outer_uint_4 None %77
+      %val_2 = OpFunctionParameter %_arr_Outer_std140_uint_4
+         %81 = OpLabel
+      %arr_0 = OpVariable %_ptr_Function__arr_Outer_uint_4 Function %84
+        %i_1 = OpVariable %_ptr_Function_uint Function %43
+%var_for_index = OpVariable %_ptr_Function__arr_Outer_std140_uint_4 Function %97
+               OpBranch %86
+         %86 = OpLabel
+               OpLoopMerge %87 %88 None
+               OpBranch %89
+         %89 = OpLabel
+         %91 = OpLoad %uint %i_1
+         %92 = OpULessThan %bool %91 %uint_4
+         %90 = OpLogicalNot %bool %92
+               OpSelectionMerge %93 None
+               OpBranchConditional %90 %94 %93
+         %94 = OpLabel
+               OpBranch %87
+         %93 = OpLabel
+               OpStore %var_for_index %val_2
+         %98 = OpLoad %uint %i_1
+        %100 = OpAccessChain %_ptr_Function_Outer %arr_0 %98
+        %102 = OpLoad %uint %i_1
+        %104 = OpAccessChain %_ptr_Function_Outer_std140 %var_for_index %102
+        %105 = OpLoad %Outer_std140 %104
+        %101 = OpFunctionCall %Outer %conv_Outer %105
+               OpStore %100 %101
+               OpBranch %88
+         %88 = OpLabel
+        %106 = OpLoad %uint %i_1
+        %107 = OpIAdd %uint %106 %uint_1
+               OpStore %i_1 %107
+               OpBranch %86
+         %87 = OpLabel
+        %108 = OpLoad %_arr_Outer_uint_4 %arr_0
+               OpReturnValue %108
+               OpFunctionEnd
+%load_a_inner_p0_a_p1_m = OpFunction %mat2v4half None %109
+         %p0 = OpFunctionParameter %uint
+         %p1 = OpFunctionParameter %uint
+        %113 = OpLabel
+        %117 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %p0 %uint_0 %p1
+        %120 = OpAccessChain %_ptr_Uniform_v4half %117 %uint_0
+        %121 = OpLoad %v4half %120
+        %123 = OpAccessChain %_ptr_Uniform_v4half %117 %uint_1
+        %124 = OpLoad %v4half %123
+        %125 = OpCompositeConstruct %mat2v4half %121 %124
+               OpReturnValue %125
+               OpFunctionEnd
+%load_a_inner_p0_a_p1_m_p2 = OpFunction %v4half None %126
+       %p0_0 = OpFunctionParameter %uint
+       %p1_0 = OpFunctionParameter %uint
+         %p2 = OpFunctionParameter %uint
+        %131 = OpLabel
+               OpSelectionMerge %132 None
+               OpSwitch %p2 %133 0 %134 1 %135
+        %134 = OpLabel
+        %136 = OpAccessChain %_ptr_Uniform_v4half %a %uint_0 %p0_0 %uint_0 %p1_0 %uint_0
+        %137 = OpLoad %v4half %136
+               OpReturnValue %137
+        %135 = OpLabel
+        %138 = OpAccessChain %_ptr_Uniform_v4half %a %uint_0 %p0_0 %uint_0 %p1_0 %uint_1
+        %139 = OpLoad %v4half %138
+               OpReturnValue %139
+        %133 = OpLabel
+               OpReturnValue %140
+        %132 = OpLabel
+               OpReturnValue %140
+               OpFunctionEnd
+%load_a_inner_p0_a_p1_m_p2_p3 = OpFunction %half None %141
+       %p0_1 = OpFunctionParameter %uint
+       %p1_1 = OpFunctionParameter %uint
+       %p2_0 = OpFunctionParameter %uint
+         %p3 = OpFunctionParameter %uint
+        %147 = OpLabel
+               OpSelectionMerge %148 None
+               OpSwitch %p2_0 %149 0 %150 1 %151
+        %150 = OpLabel
+        %153 = OpAccessChain %_ptr_Uniform_half %a %uint_0 %p0_1 %uint_0 %p1_1 %uint_0 %p3
+        %154 = OpLoad %half %153
+               OpReturnValue %154
+        %151 = OpLabel
+        %155 = OpAccessChain %_ptr_Uniform_half %a %uint_0 %p0_1 %uint_0 %p1_1 %uint_1 %p3
+        %156 = OpLoad %half %155
+               OpReturnValue %156
+        %149 = OpLabel
+               OpReturnValue %157
+        %148 = OpLabel
+               OpReturnValue %157
+               OpFunctionEnd
+          %f = OpFunction %void None %158
+        %161 = OpLabel
+        %162 = OpFunctionCall %int %i
+        %163 = OpFunctionCall %int %i
+        %164 = OpFunctionCall %int %i
+        %167 = OpAccessChain %_ptr_Uniform__arr_Outer_std140_uint_4 %a %uint_0
+        %168 = OpLoad %_arr_Outer_std140_uint_4 %167
+        %165 = OpFunctionCall %_arr_Outer_uint_4 %conv_arr4_Outer %168
+        %171 = OpAccessChain %_ptr_Uniform_Outer_std140 %a %uint_0 %162
+        %172 = OpLoad %Outer_std140 %171
+        %169 = OpFunctionCall %Outer %conv_Outer %172
+        %175 = OpAccessChain %_ptr_Uniform__arr_Inner_std140_uint_4 %a %uint_0 %162 %uint_0
+        %176 = OpLoad %_arr_Inner_std140_uint_4 %175
+        %173 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %176
+        %178 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %162 %uint_0 %163
+        %179 = OpLoad %Inner_std140 %178
+        %177 = OpFunctionCall %Inner %conv_Inner %179
+        %181 = OpBitcast %uint %162
+        %182 = OpBitcast %uint %163
+        %180 = OpFunctionCall %mat2v4half %load_a_inner_p0_a_p1_m %181 %182
+        %184 = OpBitcast %uint %162
+        %185 = OpBitcast %uint %163
+        %186 = OpBitcast %uint %164
+        %183 = OpFunctionCall %v4half %load_a_inner_p0_a_p1_m_p2 %184 %185 %186
+        %187 = OpFunctionCall %int %i
+        %189 = OpBitcast %uint %162
+        %190 = OpBitcast %uint %163
+        %191 = OpBitcast %uint %164
+        %192 = OpBitcast %uint %187
+        %188 = OpFunctionCall %half %load_a_inner_p0_a_p1_m_p2_p3 %189 %190 %191 %192
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..05398c9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,36 @@
+enable f16;
+
+struct Inner {
+  @size(64)
+  m : mat2x4<f16>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_i = &((*(p_a))[i()]);
+  let p_a_i_a = &((*(p_a_i)).a);
+  let p_a_i_a_i = &((*(p_a_i_a))[i()]);
+  let p_a_i_a_i_m = &((*(p_a_i_a_i)).m);
+  let p_a_i_a_i_m_i = &((*(p_a_i_a_i_m))[i()]);
+  let l_a : array<Outer, 4> = *(p_a);
+  let l_a_i : Outer = *(p_a_i);
+  let l_a_i_a : array<Inner, 4> = *(p_a_i_a);
+  let l_a_i_a_i : Inner = *(p_a_i_a_i);
+  let l_a_i_a_i_m : mat2x4<f16> = *(p_a_i_a_i_m);
+  let l_a_i_a_i_m_i : vec4<f16> = *(p_a_i_a_i_m_i);
+  let l_a_i_a_i_m_i_i : f16 = (*(p_a_i_a_i_m_i))[i()];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/static_index_via_ptr.wgsl
new file mode 100644
index 0000000..1f4f376
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/static_index_via_ptr.wgsl
@@ -0,0 +1,31 @@
+enable f16;
+
+struct Inner {
+  @size(64)
+  m : mat2x4<f16>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &a;
+  let p_a_3 = &((*p_a)[3]);
+  let p_a_3_a = &((*p_a_3).a);
+  let p_a_3_a_2 = &((*p_a_3_a)[2]);
+  let p_a_3_a_2_m = &((*p_a_3_a_2).m);
+  let p_a_3_a_2_m_1 = &((*p_a_3_a_2_m)[1]);
+
+
+  let l_a             : array<Outer, 4> = *p_a;
+  let l_a_3           : Outer           = *p_a_3;
+  let l_a_3_a         : array<Inner, 4> = *p_a_3_a;
+  let l_a_3_a_2       : Inner           = *p_a_3_a_2;
+  let l_a_3_a_2_m     : mat2x4<f16>     = *p_a_3_a_2_m;
+  let l_a_3_a_2_m_1   : vec4<f16>       = *p_a_3_a_2_m_1;
+  let l_a_3_a_2_m_1_0 : f16             = (*p_a_3_a_2_m_1)[0];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..03120f7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,71 @@
+struct Inner {
+  matrix<float16_t, 2, 4> m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+
+matrix<float16_t, 2, 4> tint_symbol_4(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+Inner tint_symbol_3(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_7 = {tint_symbol_4(buffer, (offset + 0u))};
+  return tint_symbol_7;
+}
+
+typedef Inner tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_3(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_1(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_8 = {tint_symbol_2(buffer, (offset + 0u))};
+  return tint_symbol_8;
+}
+
+typedef Outer tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr_1[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const Outer l_a[4] = tint_symbol(a, 0u);
+  const Outer l_a_3 = tint_symbol_1(a, 768u);
+  const Inner l_a_3_a[4] = tint_symbol_2(a, 768u);
+  const Inner l_a_3_a_2 = tint_symbol_3(a, 896u);
+  const matrix<float16_t, 2, 4> l_a_3_a_2_m = tint_symbol_4(a, 896u);
+  uint2 ubo_load_4 = a[56].zw;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const vector<float16_t, 4> l_a_3_a_2_m_1 = vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]);
+  const float16_t l_a_3_a_2_m_1_0 = float16_t(f16tof32(((a[56].z) & 0xFFFF)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..39aab69
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,76 @@
+SKIP: FAILED
+
+struct Inner {
+  matrix<float16_t, 2, 4> m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+
+matrix<float16_t, 2, 4> tint_symbol_4(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+Inner tint_symbol_3(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_7 = {tint_symbol_4(buffer, (offset + 0u))};
+  return tint_symbol_7;
+}
+
+typedef Inner tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_3(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_1(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_8 = {tint_symbol_2(buffer, (offset + 0u))};
+  return tint_symbol_8;
+}
+
+typedef Outer tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr_1[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const Outer l_a[4] = tint_symbol(a, 0u);
+  const Outer l_a_3 = tint_symbol_1(a, 768u);
+  const Inner l_a_3_a[4] = tint_symbol_2(a, 768u);
+  const Inner l_a_3_a_2 = tint_symbol_3(a, 896u);
+  const matrix<float16_t, 2, 4> l_a_3_a_2_m = tint_symbol_4(a, 896u);
+  uint2 ubo_load_4 = a[56].zw;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const vector<float16_t, 4> l_a_3_a_2_m_1 = vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]);
+  const float16_t l_a_3_a_2_m_1_0 = float16_t(f16tof32(((a[56].z) & 0xFFFF)));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001CF0BABD660(2,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/static_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..659e661
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/static_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,101 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct Inner {
+  f16mat2x4 m;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+};
+
+struct Inner_std140 {
+  f16vec4 m_0;
+  f16vec4 m_1;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+};
+
+struct Outer {
+  Inner a[4];
+};
+
+struct Outer_std140 {
+  Inner_std140 a[4];
+};
+
+layout(binding = 0, std140) uniform a_block_std140_ubo {
+  Outer_std140 inner[4];
+} a;
+
+Inner conv_Inner(Inner_std140 val) {
+  return Inner(f16mat2x4(val.m_0, val.m_1), val.pad, val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.pad_11);
+}
+
+Inner[4] conv_arr4_Inner(Inner_std140 val[4]) {
+  Inner arr[4] = Inner[4](Inner(f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_Inner(val[i]);
+    }
+  }
+  return arr;
+}
+
+Outer conv_Outer(Outer_std140 val) {
+  return Outer(conv_arr4_Inner(val.a));
+}
+
+Outer[4] conv_arr4_Outer(Outer_std140 val[4]) {
+  Outer arr[4] = Outer[4](Outer(Inner[4](Inner(f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_Outer(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat2x4 load_a_inner_3_a_2_m() {
+  return f16mat2x4(a.inner[3u].a[2u].m_0, a.inner[3u].a[2u].m_1);
+}
+
+void f() {
+  Outer p_a[4] = conv_arr4_Outer(a.inner);
+  Outer p_a_3 = conv_Outer(a.inner[3u]);
+  Inner p_a_3_a[4] = conv_arr4_Inner(a.inner[3u].a);
+  Inner p_a_3_a_2 = conv_Inner(a.inner[3u].a[2u]);
+  f16mat2x4 p_a_3_a_2_m = load_a_inner_3_a_2_m();
+  f16vec4 p_a_3_a_2_m_1 = a.inner[3u].a[2u].m_1;
+  Outer l_a[4] = conv_arr4_Outer(a.inner);
+  Outer l_a_3 = conv_Outer(a.inner[3u]);
+  Inner l_a_3_a[4] = conv_arr4_Inner(a.inner[3u].a);
+  Inner l_a_3_a_2 = conv_Inner(a.inner[3u].a[2u]);
+  f16mat2x4 l_a_3_a_2_m = load_a_inner_3_a_2_m();
+  f16vec4 l_a_3_a_2_m_1 = a.inner[3u].a[2u].m_1;
+  float16_t l_a_3_a_2_m_1_0 = a.inner[3u].a[2u].m_1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/static_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..937cb3a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/static_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,36 @@
+#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 Inner {
+  /* 0x0000 */ half2x4 m;
+  /* 0x0010 */ tint_array<int8_t, 48> tint_pad;
+};
+
+struct Outer {
+  /* 0x0000 */ tint_array<Inner, 4> a;
+};
+
+kernel void f(const constant tint_array<Outer, 4>* tint_symbol [[buffer(0)]]) {
+  tint_array<Outer, 4> const l_a = *(tint_symbol);
+  Outer const l_a_3 = (*(tint_symbol))[3];
+  tint_array<Inner, 4> const l_a_3_a = (*(tint_symbol))[3].a;
+  Inner const l_a_3_a_2 = (*(tint_symbol))[3].a[2];
+  half2x4 const l_a_3_a_2_m = (*(tint_symbol))[3].a[2].m;
+  half4 const l_a_3_a_2_m_1 = (*(tint_symbol))[3].a[2].m[1];
+  half const l_a_3_a_2_m_1_0 = (*(tint_symbol))[3].a[2].m[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/static_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..a07d9ae
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/static_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,227 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 140
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block_std140 "a_block_std140"
+               OpMemberName %a_block_std140 0 "inner"
+               OpName %Outer_std140 "Outer_std140"
+               OpMemberName %Outer_std140 0 "a"
+               OpName %Inner_std140 "Inner_std140"
+               OpMemberName %Inner_std140 0 "m_0"
+               OpMemberName %Inner_std140 1 "m_1"
+               OpName %a "a"
+               OpName %Inner "Inner"
+               OpMemberName %Inner 0 "m"
+               OpName %conv_Inner "conv_Inner"
+               OpName %val "val"
+               OpName %conv_arr4_Inner "conv_arr4_Inner"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index_1 "var_for_index_1"
+               OpName %Outer "Outer"
+               OpMemberName %Outer 0 "a"
+               OpName %conv_Outer "conv_Outer"
+               OpName %val_1 "val"
+               OpName %conv_arr4_Outer "conv_arr4_Outer"
+               OpName %val_2 "val"
+               OpName %arr_0 "arr"
+               OpName %i_0 "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_a_inner_3_a_2_m "load_a_inner_3_a_2_m"
+               OpName %f "f"
+               OpDecorate %a_block_std140 Block
+               OpMemberDecorate %a_block_std140 0 Offset 0
+               OpMemberDecorate %Outer_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 1 Offset 8
+               OpDecorate %_arr_Inner_std140_uint_4 ArrayStride 64
+               OpDecorate %_arr_Outer_std140_uint_4 ArrayStride 256
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+               OpMemberDecorate %Inner 0 Offset 0
+               OpMemberDecorate %Inner 0 ColMajor
+               OpMemberDecorate %Inner 0 MatrixStride 8
+               OpDecorate %_arr_Inner_uint_4 ArrayStride 64
+               OpMemberDecorate %Outer 0 Offset 0
+               OpDecorate %_arr_Outer_uint_4 ArrayStride 256
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+%Inner_std140 = OpTypeStruct %v4half %v4half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_Inner_std140_uint_4 = OpTypeArray %Inner_std140 %uint_4
+%Outer_std140 = OpTypeStruct %_arr_Inner_std140_uint_4
+%_arr_Outer_std140_uint_4 = OpTypeArray %Outer_std140 %uint_4
+%a_block_std140 = OpTypeStruct %_arr_Outer_std140_uint_4
+%_ptr_Uniform_a_block_std140 = OpTypePointer Uniform %a_block_std140
+          %a = OpVariable %_ptr_Uniform_a_block_std140 Uniform
+ %mat2v4half = OpTypeMatrix %v4half 2
+      %Inner = OpTypeStruct %mat2v4half
+         %12 = OpTypeFunction %Inner %Inner_std140
+%_arr_Inner_uint_4 = OpTypeArray %Inner %uint_4
+         %22 = OpTypeFunction %_arr_Inner_uint_4 %_arr_Inner_std140_uint_4
+%_ptr_Function__arr_Inner_uint_4 = OpTypePointer Function %_arr_Inner_uint_4
+         %29 = OpConstantNull %_arr_Inner_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %32 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_Inner_std140_uint_4 = OpTypePointer Function %_arr_Inner_std140_uint_4
+         %45 = OpConstantNull %_arr_Inner_std140_uint_4
+%_ptr_Function_Inner = OpTypePointer Function %Inner
+%_ptr_Function_Inner_std140 = OpTypePointer Function %Inner_std140
+     %uint_1 = OpConstant %uint 1
+      %Outer = OpTypeStruct %_arr_Inner_uint_4
+         %58 = OpTypeFunction %Outer %Outer_std140
+%_arr_Outer_uint_4 = OpTypeArray %Outer %uint_4
+         %66 = OpTypeFunction %_arr_Outer_uint_4 %_arr_Outer_std140_uint_4
+%_ptr_Function__arr_Outer_uint_4 = OpTypePointer Function %_arr_Outer_uint_4
+         %73 = OpConstantNull %_arr_Outer_uint_4
+%_ptr_Function__arr_Outer_std140_uint_4 = OpTypePointer Function %_arr_Outer_std140_uint_4
+         %86 = OpConstantNull %_arr_Outer_std140_uint_4
+%_ptr_Function_Outer = OpTypePointer Function %Outer
+%_ptr_Function_Outer_std140 = OpTypePointer Function %Outer_std140
+         %98 = OpTypeFunction %mat2v4half
+     %uint_0 = OpConstant %uint 0
+     %uint_3 = OpConstant %uint 3
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_Inner_std140 = OpTypePointer Uniform %Inner_std140
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+       %void = OpTypeVoid
+        %115 = OpTypeFunction %void
+%_ptr_Uniform__arr_Outer_std140_uint_4 = OpTypePointer Uniform %_arr_Outer_std140_uint_4
+%_ptr_Uniform_Outer_std140 = OpTypePointer Uniform %Outer_std140
+%_ptr_Uniform__arr_Inner_std140_uint_4 = OpTypePointer Uniform %_arr_Inner_std140_uint_4
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+ %conv_Inner = OpFunction %Inner None %12
+        %val = OpFunctionParameter %Inner_std140
+         %17 = OpLabel
+         %18 = OpCompositeExtract %v4half %val 0
+         %19 = OpCompositeExtract %v4half %val 1
+         %20 = OpCompositeConstruct %mat2v4half %18 %19
+         %21 = OpCompositeConstruct %Inner %20
+               OpReturnValue %21
+               OpFunctionEnd
+%conv_arr4_Inner = OpFunction %_arr_Inner_uint_4 None %22
+      %val_0 = OpFunctionParameter %_arr_Inner_std140_uint_4
+         %26 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_Inner_uint_4 Function %29
+          %i = OpVariable %_ptr_Function_uint Function %32
+%var_for_index_1 = OpVariable %_ptr_Function__arr_Inner_std140_uint_4 Function %45
+               OpBranch %33
+         %33 = OpLabel
+               OpLoopMerge %34 %35 None
+               OpBranch %36
+         %36 = OpLabel
+         %38 = OpLoad %uint %i
+         %39 = OpULessThan %bool %38 %uint_4
+         %37 = OpLogicalNot %bool %39
+               OpSelectionMerge %41 None
+               OpBranchConditional %37 %42 %41
+         %42 = OpLabel
+               OpBranch %34
+         %41 = OpLabel
+               OpStore %var_for_index_1 %val_0
+         %46 = OpLoad %uint %i
+         %48 = OpAccessChain %_ptr_Function_Inner %arr %46
+         %50 = OpLoad %uint %i
+         %52 = OpAccessChain %_ptr_Function_Inner_std140 %var_for_index_1 %50
+         %53 = OpLoad %Inner_std140 %52
+         %49 = OpFunctionCall %Inner %conv_Inner %53
+               OpStore %48 %49
+               OpBranch %35
+         %35 = OpLabel
+         %54 = OpLoad %uint %i
+         %56 = OpIAdd %uint %54 %uint_1
+               OpStore %i %56
+               OpBranch %33
+         %34 = OpLabel
+         %57 = OpLoad %_arr_Inner_uint_4 %arr
+               OpReturnValue %57
+               OpFunctionEnd
+ %conv_Outer = OpFunction %Outer None %58
+      %val_1 = OpFunctionParameter %Outer_std140
+         %62 = OpLabel
+         %64 = OpCompositeExtract %_arr_Inner_std140_uint_4 %val_1 0
+         %63 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %64
+         %65 = OpCompositeConstruct %Outer %63
+               OpReturnValue %65
+               OpFunctionEnd
+%conv_arr4_Outer = OpFunction %_arr_Outer_uint_4 None %66
+      %val_2 = OpFunctionParameter %_arr_Outer_std140_uint_4
+         %70 = OpLabel
+      %arr_0 = OpVariable %_ptr_Function__arr_Outer_uint_4 Function %73
+        %i_0 = OpVariable %_ptr_Function_uint Function %32
+%var_for_index = OpVariable %_ptr_Function__arr_Outer_std140_uint_4 Function %86
+               OpBranch %75
+         %75 = OpLabel
+               OpLoopMerge %76 %77 None
+               OpBranch %78
+         %78 = OpLabel
+         %80 = OpLoad %uint %i_0
+         %81 = OpULessThan %bool %80 %uint_4
+         %79 = OpLogicalNot %bool %81
+               OpSelectionMerge %82 None
+               OpBranchConditional %79 %83 %82
+         %83 = OpLabel
+               OpBranch %76
+         %82 = OpLabel
+               OpStore %var_for_index %val_2
+         %87 = OpLoad %uint %i_0
+         %89 = OpAccessChain %_ptr_Function_Outer %arr_0 %87
+         %91 = OpLoad %uint %i_0
+         %93 = OpAccessChain %_ptr_Function_Outer_std140 %var_for_index %91
+         %94 = OpLoad %Outer_std140 %93
+         %90 = OpFunctionCall %Outer %conv_Outer %94
+               OpStore %89 %90
+               OpBranch %77
+         %77 = OpLabel
+         %95 = OpLoad %uint %i_0
+         %96 = OpIAdd %uint %95 %uint_1
+               OpStore %i_0 %96
+               OpBranch %75
+         %76 = OpLabel
+         %97 = OpLoad %_arr_Outer_uint_4 %arr_0
+               OpReturnValue %97
+               OpFunctionEnd
+%load_a_inner_3_a_2_m = OpFunction %mat2v4half None %98
+        %100 = OpLabel
+        %106 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %uint_3 %uint_0 %uint_2
+        %109 = OpAccessChain %_ptr_Uniform_v4half %106 %uint_0
+        %110 = OpLoad %v4half %109
+        %112 = OpAccessChain %_ptr_Uniform_v4half %106 %uint_1
+        %113 = OpLoad %v4half %112
+        %114 = OpCompositeConstruct %mat2v4half %110 %113
+               OpReturnValue %114
+               OpFunctionEnd
+          %f = OpFunction %void None %115
+        %118 = OpLabel
+        %121 = OpAccessChain %_ptr_Uniform__arr_Outer_std140_uint_4 %a %uint_0
+        %122 = OpLoad %_arr_Outer_std140_uint_4 %121
+        %119 = OpFunctionCall %_arr_Outer_uint_4 %conv_arr4_Outer %122
+        %125 = OpAccessChain %_ptr_Uniform_Outer_std140 %a %uint_0 %uint_3
+        %126 = OpLoad %Outer_std140 %125
+        %123 = OpFunctionCall %Outer %conv_Outer %126
+        %129 = OpAccessChain %_ptr_Uniform__arr_Inner_std140_uint_4 %a %uint_0 %uint_3 %uint_0
+        %130 = OpLoad %_arr_Inner_std140_uint_4 %129
+        %127 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %130
+        %132 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %uint_3 %uint_0 %uint_2
+        %133 = OpLoad %Inner_std140 %132
+        %131 = OpFunctionCall %Inner %conv_Inner %133
+        %134 = OpFunctionCall %mat2v4half %load_a_inner_3_a_2_m
+        %135 = OpAccessChain %_ptr_Uniform_v4half %a %uint_0 %uint_3 %uint_0 %uint_2 %uint_1
+        %136 = OpLoad %v4half %135
+        %138 = OpAccessChain %_ptr_Uniform_half %a %uint_0 %uint_3 %uint_0 %uint_2 %uint_1 %32
+        %139 = OpLoad %half %138
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/static_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..8115149
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/static_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,29 @@
+enable f16;
+
+struct Inner {
+  @size(64)
+  m : mat2x4<f16>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_3 = &((*(p_a))[3]);
+  let p_a_3_a = &((*(p_a_3)).a);
+  let p_a_3_a_2 = &((*(p_a_3_a))[2]);
+  let p_a_3_a_2_m = &((*(p_a_3_a_2)).m);
+  let p_a_3_a_2_m_1 = &((*(p_a_3_a_2_m))[1]);
+  let l_a : array<Outer, 4> = *(p_a);
+  let l_a_3 : Outer = *(p_a_3);
+  let l_a_3_a : array<Inner, 4> = *(p_a_3_a);
+  let l_a_3_a_2 : Inner = *(p_a_3_a_2);
+  let l_a_3_a_2_m : mat2x4<f16> = *(p_a_3_a_2_m);
+  let l_a_3_a_2_m_1 : vec4<f16> = *(p_a_3_a_2_m_1);
+  let l_a_3_a_2_m_1_0 : f16 = (*(p_a_3_a_2_m_1))[0];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_builtin.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_builtin.wgsl
new file mode 100644
index 0000000..767220f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_builtin.wgsl
@@ -0,0 +1,17 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat2x4<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    let t = transpose(u[2].m);
+    let l = length(u[0].m[1].ywxz);
+    let a = abs(u[0].m[1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_builtin.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..2244be6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_builtin.wgsl.expected.dxc.hlsl
@@ -0,0 +1,31 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+matrix<float16_t, 2, 4> tint_symbol(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 4, 2> t = transpose(tint_symbol(u, 264u));
+  uint2 ubo_load_4 = u[1].xy;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const float16_t l = length(vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]).ywxz);
+  uint2 ubo_load_5 = u[1].xy;
+  vector<float16_t, 2> ubo_load_5_xz = vector<float16_t, 2>(f16tof32(ubo_load_5 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_5_yw = vector<float16_t, 2>(f16tof32(ubo_load_5 >> 16));
+  const float16_t a = abs(vector<float16_t, 4>(ubo_load_5_xz[0], ubo_load_5_yw[0], ubo_load_5_xz[1], ubo_load_5_yw[1]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_builtin.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..523b5b4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_builtin.wgsl.expected.fxc.hlsl
@@ -0,0 +1,36 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+matrix<float16_t, 2, 4> tint_symbol(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 4, 2> t = transpose(tint_symbol(u, 264u));
+  uint2 ubo_load_4 = u[1].xy;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const float16_t l = length(vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]).ywxz);
+  uint2 ubo_load_5 = u[1].xy;
+  vector<float16_t, 2> ubo_load_5_xz = vector<float16_t, 2>(f16tof32(ubo_load_5 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_5_yw = vector<float16_t, 2>(f16tof32(ubo_load_5 >> 16));
+  const float16_t a = abs(vector<float16_t, 4>(ubo_load_5_xz[0], ubo_load_5_yw[0], ubo_load_5_xz[1], ubo_load_5_yw[1]).ywxz.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000002535B2A2420(5,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_builtin.wgsl.expected.glsl
new file mode 100644
index 0000000..e6f6933
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_builtin.wgsl.expected.glsl
@@ -0,0 +1,87 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct S {
+  int before;
+  uint pad;
+  f16mat2x4 m;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  int after;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+};
+
+struct S_std140 {
+  int before;
+  uint pad;
+  f16vec4 m_0;
+  f16vec4 m_1;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  int after;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+f16mat2x4 load_u_inner_2_m() {
+  return f16mat2x4(u.inner[2u].m_0, u.inner[2u].m_1);
+}
+
+void f() {
+  f16mat4x2 t = transpose(load_u_inner_2_m());
+  float16_t l = length(u.inner[0u].m_1.ywxz);
+  float16_t a = abs(u.inner[0u].m_1.ywxz[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_builtin.wgsl.expected.msl
new file mode 100644
index 0000000..4be54f8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_builtin.wgsl.expected.msl
@@ -0,0 +1,32 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0008 */ half2x4 m;
+  /* 0x0018 */ tint_array<int8_t, 40> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol [[buffer(0)]]) {
+  half4x2 const t = transpose((*(tint_symbol))[2].m);
+  half const l = length(half4((*(tint_symbol))[0].m[1]).ywxz);
+  half const a = fabs(half4((*(tint_symbol))[0].m[1]).ywxz[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_builtin.wgsl.expected.spvasm
new file mode 100644
index 0000000..3017e98
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_builtin.wgsl.expected.spvasm
@@ -0,0 +1,81 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 48
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+         %38 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "after"
+               OpName %u "u"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 8
+               OpMemberDecorate %S_std140 2 Offset 16
+               OpMemberDecorate %S_std140 3 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+   %S_std140 = OpTypeStruct %int %v4half %v4half %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat2v4half = OpTypeMatrix %v4half 2
+         %11 = OpTypeFunction %mat2v4half
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+     %uint_1 = OpConstant %uint 1
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+       %void = OpTypeVoid
+         %29 = OpTypeFunction %void
+     %v2half = OpTypeVector %half 2
+ %mat4v2half = OpTypeMatrix %v2half 4
+         %39 = OpConstantNull %uint
+%load_u_inner_2_m = OpFunction %mat2v4half None %11
+         %14 = OpLabel
+         %19 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %23 = OpAccessChain %_ptr_Uniform_v4half %19 %uint_1
+         %24 = OpLoad %v4half %23
+         %26 = OpAccessChain %_ptr_Uniform_v4half %19 %uint_2
+         %27 = OpLoad %v4half %26
+         %28 = OpCompositeConstruct %mat2v4half %24 %27
+               OpReturnValue %28
+               OpFunctionEnd
+          %f = OpFunction %void None %29
+         %32 = OpLabel
+         %36 = OpFunctionCall %mat2v4half %load_u_inner_2_m
+         %33 = OpTranspose %mat4v2half %36
+         %40 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0 %39 %uint_2
+         %41 = OpLoad %v4half %40
+         %42 = OpVectorShuffle %v4half %41 %41 1 3 0 2
+         %37 = OpExtInst %half %38 Length %42
+         %44 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0 %39 %uint_2
+         %45 = OpLoad %v4half %44
+         %46 = OpVectorShuffle %v4half %45 %45 1 3 0 2
+         %47 = OpCompositeExtract %half %46 0
+         %43 = OpExtInst %half %38 FAbs %47
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_builtin.wgsl.expected.wgsl
new file mode 100644
index 0000000..e979bf8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_builtin.wgsl.expected.wgsl
@@ -0,0 +1,17 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat2x4<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let t = transpose(u[2].m);
+  let l = length(u[0].m[1].ywxz);
+  let a = abs(u[0].m[1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_fn.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_fn.wgsl
new file mode 100644
index 0000000..c5e4554
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_fn.wgsl
@@ -0,0 +1,25 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat2x4<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+fn a(a : array<S, 4>) {}
+fn b(s : S) {}
+fn c(m : mat2x4<f16>) {}
+fn d(v : vec4<f16>) {}
+fn e(f : f16) {}
+
+@compute @workgroup_size(1)
+fn f() {
+    a(u);
+    b(u[2]);
+    c(u[2].m);
+    d(u[0].m[1].ywxz);
+    e(u[0].m[1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_fn.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..8c5270f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_fn.wgsl.expected.dxc.hlsl
@@ -0,0 +1,72 @@
+struct S {
+  int before;
+  matrix<float16_t, 2, 4> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(matrix<float16_t, 2, 4> m) {
+}
+
+void d(vector<float16_t, 4> v) {
+}
+
+void e(float16_t f_1) {
+}
+
+matrix<float16_t, 2, 4> tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 256u));
+  c(tint_symbol_3(u, 264u));
+  uint2 ubo_load_4 = u[1].xy;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  d(vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]).ywxz);
+  uint2 ubo_load_5 = u[1].xy;
+  vector<float16_t, 2> ubo_load_5_xz = vector<float16_t, 2>(f16tof32(ubo_load_5 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_5_yw = vector<float16_t, 2>(f16tof32(ubo_load_5 >> 16));
+  e(vector<float16_t, 4>(ubo_load_5_xz[0], ubo_load_5_yw[0], ubo_load_5_xz[1], ubo_load_5_yw[1]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_fn.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..226da64
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_fn.wgsl.expected.fxc.hlsl
@@ -0,0 +1,77 @@
+SKIP: FAILED
+
+struct S {
+  int before;
+  matrix<float16_t, 2, 4> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(matrix<float16_t, 2, 4> m) {
+}
+
+void d(vector<float16_t, 4> v) {
+}
+
+void e(float16_t f_1) {
+}
+
+matrix<float16_t, 2, 4> tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 256u));
+  c(tint_symbol_3(u, 264u));
+  uint2 ubo_load_4 = u[1].xy;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  d(vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]).ywxz);
+  uint2 ubo_load_5 = u[1].xy;
+  vector<float16_t, 2> ubo_load_5_xz = vector<float16_t, 2>(f16tof32(ubo_load_5 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_5_yw = vector<float16_t, 2>(f16tof32(ubo_load_5 >> 16));
+  e(vector<float16_t, 4>(ubo_load_5_xz[0], ubo_load_5_yw[0], ubo_load_5_xz[1], ubo_load_5_yw[1]).ywxz.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001B118E73590(3,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_fn.wgsl.expected.glsl
new file mode 100644
index 0000000..20e586a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_fn.wgsl.expected.glsl
@@ -0,0 +1,118 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct S {
+  int before;
+  uint pad;
+  f16mat2x4 m;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  int after;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+};
+
+struct S_std140 {
+  int before;
+  uint pad;
+  f16vec4 m_0;
+  f16vec4 m_1;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  int after;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(f16mat2x4 m) {
+}
+
+void d(f16vec4 v) {
+}
+
+void e(float16_t f_1) {
+}
+
+S conv_S(S_std140 val) {
+  return S(val.before, val.pad, f16mat2x4(val.m_0, val.m_1), val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.after, val.pad_11, val.pad_12, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21, val.pad_22, val.pad_23, val.pad_24, val.pad_25);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, 0u, f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat2x4 load_u_inner_2_m() {
+  return f16mat2x4(u.inner[2u].m_0, u.inner[2u].m_1);
+}
+
+void f() {
+  a(conv_arr4_S(u.inner));
+  b(conv_S(u.inner[2u]));
+  c(load_u_inner_2_m());
+  d(u.inner[0u].m_1.ywxz);
+  e(u.inner[0u].m_1.ywxz[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_fn.wgsl.expected.msl
new file mode 100644
index 0000000..d555b48
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_fn.wgsl.expected.msl
@@ -0,0 +1,49 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0008 */ half2x4 m;
+  /* 0x0018 */ tint_array<int8_t, 40> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+void a(tint_array<S, 4> a_1) {
+}
+
+void b(S s) {
+}
+
+void c(half2x4 m) {
+}
+
+void d(half4 v) {
+}
+
+void e(half f_1) {
+}
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol [[buffer(0)]]) {
+  a(*(tint_symbol));
+  b((*(tint_symbol))[2]);
+  c((*(tint_symbol))[2].m);
+  d(half4((*(tint_symbol))[0].m[1]).ywxz);
+  e(half4((*(tint_symbol))[0].m[1]).ywxz[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_fn.wgsl.expected.spvasm
new file mode 100644
index 0000000..da8c5de
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_fn.wgsl.expected.spvasm
@@ -0,0 +1,204 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 119
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "after"
+               OpName %u "u"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %a "a"
+               OpName %a_1 "a_1"
+               OpName %b "b"
+               OpName %s "s"
+               OpName %c "c"
+               OpName %m "m"
+               OpName %d "d"
+               OpName %v "v"
+               OpName %e "e"
+               OpName %f_1 "f_1"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 8
+               OpMemberDecorate %S_std140 2 Offset 16
+               OpMemberDecorate %S_std140 3 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 8
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 8
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+   %S_std140 = OpTypeStruct %int %v4half %v4half %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+       %void = OpTypeVoid
+ %mat2v4half = OpTypeMatrix %v4half 2
+          %S = OpTypeStruct %int %mat2v4half %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+         %11 = OpTypeFunction %void %_arr_S_uint_4
+         %19 = OpTypeFunction %void %S
+         %23 = OpTypeFunction %void %mat2v4half
+         %27 = OpTypeFunction %void %v4half
+         %31 = OpTypeFunction %void %half
+         %35 = OpTypeFunction %S %S_std140
+         %45 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+         %51 = OpConstantNull %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %54 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %67 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %80 = OpTypeFunction %mat2v4half
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+         %96 = OpTypeFunction %void
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+          %a = OpFunction %void None %11
+        %a_1 = OpFunctionParameter %_arr_S_uint_4
+         %18 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %b = OpFunction %void None %19
+          %s = OpFunctionParameter %S
+         %22 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %c = OpFunction %void None %23
+          %m = OpFunctionParameter %mat2v4half
+         %26 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %d = OpFunction %void None %27
+          %v = OpFunctionParameter %v4half
+         %30 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %e = OpFunction %void None %31
+        %f_1 = OpFunctionParameter %half
+         %34 = OpLabel
+               OpReturn
+               OpFunctionEnd
+     %conv_S = OpFunction %S None %35
+        %val = OpFunctionParameter %S_std140
+         %38 = OpLabel
+         %39 = OpCompositeExtract %int %val 0
+         %40 = OpCompositeExtract %v4half %val 1
+         %41 = OpCompositeExtract %v4half %val 2
+         %42 = OpCompositeConstruct %mat2v4half %40 %41
+         %43 = OpCompositeExtract %int %val 3
+         %44 = OpCompositeConstruct %S %39 %42 %43
+               OpReturnValue %44
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %45
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %48 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %51
+          %i = OpVariable %_ptr_Function_uint Function %54
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %67
+               OpBranch %55
+         %55 = OpLabel
+               OpLoopMerge %56 %57 None
+               OpBranch %58
+         %58 = OpLabel
+         %60 = OpLoad %uint %i
+         %61 = OpULessThan %bool %60 %uint_4
+         %59 = OpLogicalNot %bool %61
+               OpSelectionMerge %63 None
+               OpBranchConditional %59 %64 %63
+         %64 = OpLabel
+               OpBranch %56
+         %63 = OpLabel
+               OpStore %var_for_index %val_0
+         %68 = OpLoad %uint %i
+         %70 = OpAccessChain %_ptr_Function_S %arr %68
+         %72 = OpLoad %uint %i
+         %74 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %72
+         %75 = OpLoad %S_std140 %74
+         %71 = OpFunctionCall %S %conv_S %75
+               OpStore %70 %71
+               OpBranch %57
+         %57 = OpLabel
+         %76 = OpLoad %uint %i
+         %78 = OpIAdd %uint %76 %uint_1
+               OpStore %i %78
+               OpBranch %55
+         %56 = OpLabel
+         %79 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %79
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat2v4half None %80
+         %82 = OpLabel
+         %87 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %90 = OpAccessChain %_ptr_Uniform_v4half %87 %uint_1
+         %91 = OpLoad %v4half %90
+         %93 = OpAccessChain %_ptr_Uniform_v4half %87 %uint_2
+         %94 = OpLoad %v4half %93
+         %95 = OpCompositeConstruct %mat2v4half %91 %94
+               OpReturnValue %95
+               OpFunctionEnd
+          %f = OpFunction %void None %96
+         %98 = OpLabel
+        %102 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+        %103 = OpLoad %_arr_S_std140_uint_4 %102
+        %100 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %103
+         %99 = OpFunctionCall %void %a %100
+        %106 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+        %107 = OpLoad %S_std140 %106
+        %105 = OpFunctionCall %S %conv_S %107
+        %104 = OpFunctionCall %void %b %105
+        %109 = OpFunctionCall %mat2v4half %load_u_inner_2_m
+        %108 = OpFunctionCall %void %c %109
+        %111 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0 %54 %uint_2
+        %112 = OpLoad %v4half %111
+        %113 = OpVectorShuffle %v4half %112 %112 1 3 0 2
+        %110 = OpFunctionCall %void %d %113
+        %115 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0 %54 %uint_2
+        %116 = OpLoad %v4half %115
+        %117 = OpVectorShuffle %v4half %116 %116 1 3 0 2
+        %118 = OpCompositeExtract %half %117 0
+        %114 = OpFunctionCall %void %e %118
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_fn.wgsl.expected.wgsl
new file mode 100644
index 0000000..6a3e9ac
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_fn.wgsl.expected.wgsl
@@ -0,0 +1,34 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat2x4<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+fn a(a : array<S, 4>) {
+}
+
+fn b(s : S) {
+}
+
+fn c(m : mat2x4<f16>) {
+}
+
+fn d(v : vec4<f16>) {
+}
+
+fn e(f : f16) {
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  a(u);
+  b(u[2]);
+  c(u[2].m);
+  d(u[0].m[1].ywxz);
+  e(u[0].m[1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_private.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_private.wgsl
new file mode 100644
index 0000000..c7e8bbe
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_private.wgsl
@@ -0,0 +1,19 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat2x4<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+var<private> p : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[2];
+    p[3].m = u[2].m;
+    p[1].m[0] = u[0].m[1].ywxz;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_private.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..e1907c3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_private.wgsl.expected.dxc.hlsl
@@ -0,0 +1,54 @@
+struct S {
+  int before;
+  matrix<float16_t, 2, 4> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+static S p[4] = (S[4])0;
+
+matrix<float16_t, 2, 4> tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 256u);
+  p[3].m = tint_symbol_3(u, 264u);
+  uint2 ubo_load_4 = u[1].xy;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  p[1].m[0] = vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]).ywxz;
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_private.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..2e389d7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_private.wgsl.expected.fxc.hlsl
@@ -0,0 +1,59 @@
+SKIP: FAILED
+
+struct S {
+  int before;
+  matrix<float16_t, 2, 4> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+static S p[4] = (S[4])0;
+
+matrix<float16_t, 2, 4> tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 256u);
+  p[3].m = tint_symbol_3(u, 264u);
+  uint2 ubo_load_4 = u[1].xy;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  p[1].m[0] = vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]).ywxz;
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000012E5540B3A0(3,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..24c839a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_private.wgsl.expected.glsl
@@ -0,0 +1,103 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct S {
+  int before;
+  uint pad;
+  f16mat2x4 m;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  int after;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+};
+
+struct S_std140 {
+  int before;
+  uint pad;
+  f16vec4 m_0;
+  f16vec4 m_1;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  int after;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+S p[4] = S[4](S(0, 0u, f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+S conv_S(S_std140 val) {
+  return S(val.before, val.pad, f16mat2x4(val.m_0, val.m_1), val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.after, val.pad_11, val.pad_12, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21, val.pad_22, val.pad_23, val.pad_24, val.pad_25);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, 0u, f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat2x4 load_u_inner_2_m() {
+  return f16mat2x4(u.inner[2u].m_0, u.inner[2u].m_1);
+}
+
+void f() {
+  p = conv_arr4_S(u.inner);
+  p[1] = conv_S(u.inner[2u]);
+  p[3].m = load_u_inner_2_m();
+  p[1].m[0] = u.inner[0u].m_1.ywxz;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..c25d4bb
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_private.wgsl.expected.msl
@@ -0,0 +1,34 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0008 */ half2x4 m;
+  /* 0x0018 */ tint_array<int8_t, 40> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol_1 [[buffer(0)]]) {
+  thread tint_array<S, 4> tint_symbol = {};
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[2];
+  tint_symbol[3].m = (*(tint_symbol_1))[2].m;
+  tint_symbol[1].m[0] = half4((*(tint_symbol_1))[0].m[1]).ywxz;
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_private.wgsl.expected.spvasm
new file mode 100644
index 0000000..0d6a9d2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_private.wgsl.expected.spvasm
@@ -0,0 +1,171 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 101
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "after"
+               OpName %u "u"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %p "p"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 8
+               OpMemberDecorate %S_std140 2 Offset 16
+               OpMemberDecorate %S_std140 3 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 8
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 8
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+   %S_std140 = OpTypeStruct %int %v4half %v4half %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat2v4half = OpTypeMatrix %v4half 2
+          %S = OpTypeStruct %int %mat2v4half %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+%_ptr_Private__arr_S_uint_4 = OpTypePointer Private %_arr_S_uint_4
+         %16 = OpConstantNull %_arr_S_uint_4
+          %p = OpVariable %_ptr_Private__arr_S_uint_4 Private %16
+         %17 = OpTypeFunction %S %S_std140
+         %27 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %35 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %48 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %61 = OpTypeFunction %mat2v4half
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+       %void = OpTypeVoid
+         %77 = OpTypeFunction %void
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+      %int_1 = OpConstant %int 1
+%_ptr_Private_S = OpTypePointer Private %S
+      %int_3 = OpConstant %int 3
+%_ptr_Private_mat2v4half = OpTypePointer Private %mat2v4half
+         %95 = OpConstantNull %int
+%_ptr_Private_v4half = OpTypePointer Private %v4half
+     %conv_S = OpFunction %S None %17
+        %val = OpFunctionParameter %S_std140
+         %20 = OpLabel
+         %21 = OpCompositeExtract %int %val 0
+         %22 = OpCompositeExtract %v4half %val 1
+         %23 = OpCompositeExtract %v4half %val 2
+         %24 = OpCompositeConstruct %mat2v4half %22 %23
+         %25 = OpCompositeExtract %int %val 3
+         %26 = OpCompositeConstruct %S %21 %24 %25
+               OpReturnValue %26
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %27
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %30 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %16
+          %i = OpVariable %_ptr_Function_uint Function %35
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %48
+               OpBranch %36
+         %36 = OpLabel
+               OpLoopMerge %37 %38 None
+               OpBranch %39
+         %39 = OpLabel
+         %41 = OpLoad %uint %i
+         %42 = OpULessThan %bool %41 %uint_4
+         %40 = OpLogicalNot %bool %42
+               OpSelectionMerge %44 None
+               OpBranchConditional %40 %45 %44
+         %45 = OpLabel
+               OpBranch %37
+         %44 = OpLabel
+               OpStore %var_for_index %val_0
+         %49 = OpLoad %uint %i
+         %51 = OpAccessChain %_ptr_Function_S %arr %49
+         %53 = OpLoad %uint %i
+         %55 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %53
+         %56 = OpLoad %S_std140 %55
+         %52 = OpFunctionCall %S %conv_S %56
+               OpStore %51 %52
+               OpBranch %38
+         %38 = OpLabel
+         %57 = OpLoad %uint %i
+         %59 = OpIAdd %uint %57 %uint_1
+               OpStore %i %59
+               OpBranch %36
+         %37 = OpLabel
+         %60 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %60
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat2v4half None %61
+         %63 = OpLabel
+         %68 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %71 = OpAccessChain %_ptr_Uniform_v4half %68 %uint_1
+         %72 = OpLoad %v4half %71
+         %74 = OpAccessChain %_ptr_Uniform_v4half %68 %uint_2
+         %75 = OpLoad %v4half %74
+         %76 = OpCompositeConstruct %mat2v4half %72 %75
+               OpReturnValue %76
+               OpFunctionEnd
+          %f = OpFunction %void None %77
+         %80 = OpLabel
+         %83 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+         %84 = OpLoad %_arr_S_std140_uint_4 %83
+         %81 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %84
+               OpStore %p %81
+         %87 = OpAccessChain %_ptr_Private_S %p %int_1
+         %89 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %90 = OpLoad %S_std140 %89
+         %88 = OpFunctionCall %S %conv_S %90
+               OpStore %87 %88
+         %93 = OpAccessChain %_ptr_Private_mat2v4half %p %int_3 %uint_1
+         %94 = OpFunctionCall %mat2v4half %load_u_inner_2_m
+               OpStore %93 %94
+         %97 = OpAccessChain %_ptr_Private_v4half %p %int_1 %uint_1 %95
+         %98 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0 %35 %uint_2
+         %99 = OpLoad %v4half %98
+        %100 = OpVectorShuffle %v4half %99 %99 1 3 0 2
+               OpStore %97 %100
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..786eded
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_private.wgsl.expected.wgsl
@@ -0,0 +1,20 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat2x4<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+var<private> p : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[2];
+  p[3].m = u[2].m;
+  p[1].m[0] = u[0].m[1].ywxz;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_storage.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_storage.wgsl
new file mode 100644
index 0000000..1f8799d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_storage.wgsl
@@ -0,0 +1,19 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat2x4<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+@group(0) @binding(1) var<storage, read_write> s : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[2];
+    s[3].m = u[2].m;
+    s[1].m[0] = u[0].m[1].ywxz;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_storage.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..10a3807
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_storage.wgsl.expected.dxc.hlsl
@@ -0,0 +1,74 @@
+struct S {
+  int before;
+  matrix<float16_t, 2, 4> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_3(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 2, 4> value) {
+  buffer.Store<vector<float16_t, 4> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 8u), value[1u]);
+}
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, S value) {
+  buffer.Store((offset + 0u), asuint(value.before));
+  tint_symbol_3(buffer, (offset + 8u), value.m);
+  buffer.Store((offset + 64u), asuint(value.after));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, S value[4]) {
+  S array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 128u)), array[i]);
+    }
+  }
+}
+
+matrix<float16_t, 2, 4> tint_symbol_8(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+S tint_symbol_6(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_10 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_8(buffer, (offset + 8u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_10;
+}
+
+typedef S tint_symbol_5_ret[4];
+tint_symbol_5_ret tint_symbol_5(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_6(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_5(u, 0u));
+  tint_symbol_1(s, 128u, tint_symbol_6(u, 256u));
+  tint_symbol_3(s, 392u, tint_symbol_8(u, 264u));
+  uint2 ubo_load_4 = u[1].xy;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  s.Store<vector<float16_t, 4> >(136u, vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]).ywxz);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_storage.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..371bd43
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_storage.wgsl.expected.fxc.hlsl
@@ -0,0 +1,79 @@
+SKIP: FAILED
+
+struct S {
+  int before;
+  matrix<float16_t, 2, 4> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_3(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 2, 4> value) {
+  buffer.Store<vector<float16_t, 4> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 8u), value[1u]);
+}
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, S value) {
+  buffer.Store((offset + 0u), asuint(value.before));
+  tint_symbol_3(buffer, (offset + 8u), value.m);
+  buffer.Store((offset + 64u), asuint(value.after));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, S value[4]) {
+  S array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 128u)), array[i]);
+    }
+  }
+}
+
+matrix<float16_t, 2, 4> tint_symbol_8(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+S tint_symbol_6(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_10 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_8(buffer, (offset + 8u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_10;
+}
+
+typedef S tint_symbol_5_ret[4];
+tint_symbol_5_ret tint_symbol_5(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_6(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_5(u, 0u));
+  tint_symbol_1(s, 128u, tint_symbol_6(u, 256u));
+  tint_symbol_3(s, 392u, tint_symbol_8(u, 264u));
+  uint2 ubo_load_4 = u[1].xy;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  s.Store<vector<float16_t, 4> >(136u, vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]).ywxz);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x00000270F5E70100(3,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..e8dce94
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_storage.wgsl.expected.glsl
@@ -0,0 +1,106 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct S {
+  int before;
+  uint pad;
+  f16mat2x4 m;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  int after;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+};
+
+struct S_std140 {
+  int before;
+  uint pad;
+  f16vec4 m_0;
+  f16vec4 m_1;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  int after;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  S inner[4];
+} s;
+
+S conv_S(S_std140 val) {
+  return S(val.before, val.pad, f16mat2x4(val.m_0, val.m_1), val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.after, val.pad_11, val.pad_12, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21, val.pad_22, val.pad_23, val.pad_24, val.pad_25);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, 0u, f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat2x4 load_u_inner_2_m() {
+  return f16mat2x4(u.inner[2u].m_0, u.inner[2u].m_1);
+}
+
+void f() {
+  s.inner = conv_arr4_S(u.inner);
+  s.inner[1] = conv_S(u.inner[2u]);
+  s.inner[3].m = load_u_inner_2_m();
+  s.inner[1].m[0] = u.inner[0u].m_1.ywxz;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..3b7a3c3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_storage.wgsl.expected.msl
@@ -0,0 +1,33 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0008 */ half2x4 m;
+  /* 0x0018 */ tint_array<int8_t, 40> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+kernel void f(device tint_array<S, 4>* tint_symbol [[buffer(1)]], const constant tint_array<S, 4>* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
+  (*(tint_symbol))[3].m = (*(tint_symbol_1))[2].m;
+  (*(tint_symbol))[1].m[0] = half4((*(tint_symbol_1))[0].m[1]).ywxz;
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_storage.wgsl.expected.spvasm
new file mode 100644
index 0000000..6f415cb
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_storage.wgsl.expected.spvasm
@@ -0,0 +1,180 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 104
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "after"
+               OpName %u "u"
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %s "s"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 8
+               OpMemberDecorate %S_std140 2 Offset 16
+               OpMemberDecorate %S_std140 3 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 8
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 8
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+               OpDecorate %s DescriptorSet 0
+               OpDecorate %s Binding 1
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+   %S_std140 = OpTypeStruct %int %v4half %v4half %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat2v4half = OpTypeMatrix %v4half 2
+          %S = OpTypeStruct %int %mat2v4half %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+    %u_block = OpTypeStruct %_arr_S_uint_4
+%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
+          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+         %17 = OpTypeFunction %S %S_std140
+         %27 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+         %33 = OpConstantNull %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %36 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %49 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %62 = OpTypeFunction %mat2v4half
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+       %void = OpTypeVoid
+         %78 = OpTypeFunction %void
+%_ptr_StorageBuffer__arr_S_uint_4 = OpTypePointer StorageBuffer %_arr_S_uint_4
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+      %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
+      %int_3 = OpConstant %int 3
+%_ptr_StorageBuffer_mat2v4half = OpTypePointer StorageBuffer %mat2v4half
+         %98 = OpConstantNull %int
+%_ptr_StorageBuffer_v4half = OpTypePointer StorageBuffer %v4half
+     %conv_S = OpFunction %S None %17
+        %val = OpFunctionParameter %S_std140
+         %20 = OpLabel
+         %21 = OpCompositeExtract %int %val 0
+         %22 = OpCompositeExtract %v4half %val 1
+         %23 = OpCompositeExtract %v4half %val 2
+         %24 = OpCompositeConstruct %mat2v4half %22 %23
+         %25 = OpCompositeExtract %int %val 3
+         %26 = OpCompositeConstruct %S %21 %24 %25
+               OpReturnValue %26
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %27
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %30 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %33
+          %i = OpVariable %_ptr_Function_uint Function %36
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %49
+               OpBranch %37
+         %37 = OpLabel
+               OpLoopMerge %38 %39 None
+               OpBranch %40
+         %40 = OpLabel
+         %42 = OpLoad %uint %i
+         %43 = OpULessThan %bool %42 %uint_4
+         %41 = OpLogicalNot %bool %43
+               OpSelectionMerge %45 None
+               OpBranchConditional %41 %46 %45
+         %46 = OpLabel
+               OpBranch %38
+         %45 = OpLabel
+               OpStore %var_for_index %val_0
+         %50 = OpLoad %uint %i
+         %52 = OpAccessChain %_ptr_Function_S %arr %50
+         %54 = OpLoad %uint %i
+         %56 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %54
+         %57 = OpLoad %S_std140 %56
+         %53 = OpFunctionCall %S %conv_S %57
+               OpStore %52 %53
+               OpBranch %39
+         %39 = OpLabel
+         %58 = OpLoad %uint %i
+         %60 = OpIAdd %uint %58 %uint_1
+               OpStore %i %60
+               OpBranch %37
+         %38 = OpLabel
+         %61 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %61
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat2v4half None %62
+         %64 = OpLabel
+         %69 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %72 = OpAccessChain %_ptr_Uniform_v4half %69 %uint_1
+         %73 = OpLoad %v4half %72
+         %75 = OpAccessChain %_ptr_Uniform_v4half %69 %uint_2
+         %76 = OpLoad %v4half %75
+         %77 = OpCompositeConstruct %mat2v4half %73 %76
+               OpReturnValue %77
+               OpFunctionEnd
+          %f = OpFunction %void None %78
+         %81 = OpLabel
+         %83 = OpAccessChain %_ptr_StorageBuffer__arr_S_uint_4 %s %uint_0
+         %86 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+         %87 = OpLoad %_arr_S_std140_uint_4 %86
+         %84 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %87
+               OpStore %83 %84
+         %90 = OpAccessChain %_ptr_StorageBuffer_S %s %uint_0 %int_1
+         %92 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %93 = OpLoad %S_std140 %92
+         %91 = OpFunctionCall %S %conv_S %93
+               OpStore %90 %91
+         %96 = OpAccessChain %_ptr_StorageBuffer_mat2v4half %s %uint_0 %int_3 %uint_1
+         %97 = OpFunctionCall %mat2v4half %load_u_inner_2_m
+               OpStore %96 %97
+        %100 = OpAccessChain %_ptr_StorageBuffer_v4half %s %uint_0 %int_1 %uint_1 %98
+        %101 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0 %36 %uint_2
+        %102 = OpLoad %v4half %101
+        %103 = OpVectorShuffle %v4half %102 %102 1 3 0 2
+               OpStore %100 %103
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..827edf0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,20 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat2x4<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@group(0) @binding(1) var<storage, read_write> s : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[2];
+  s[3].m = u[2].m;
+  s[1].m[0] = u[0].m[1].ywxz;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_workgroup.wgsl
new file mode 100644
index 0000000..0af4994
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_workgroup.wgsl
@@ -0,0 +1,19 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat2x4<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+var<workgroup> w : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[2];
+    w[3].m = u[2].m;
+    w[1].m[0] = u[0].m[1].ywxz;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_workgroup.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..e57c69b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_workgroup.wgsl.expected.dxc.hlsl
@@ -0,0 +1,70 @@
+struct S {
+  int before;
+  matrix<float16_t, 2, 4> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+groupshared S w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 2, 4> tint_symbol_5(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+S tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_8 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_5(buffer, (offset + 8u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_8;
+}
+
+typedef S tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      const S tint_symbol_7 = (S)0;
+      w[i] = tint_symbol_7;
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 256u);
+  w[3].m = tint_symbol_5(u, 264u);
+  uint2 ubo_load_4 = u[1].xy;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  w[1].m[0] = vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]).ywxz;
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_workgroup.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..d2b1283
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_workgroup.wgsl.expected.fxc.hlsl
@@ -0,0 +1,75 @@
+SKIP: FAILED
+
+struct S {
+  int before;
+  matrix<float16_t, 2, 4> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+groupshared S w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 2, 4> tint_symbol_5(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+S tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_8 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_5(buffer, (offset + 8u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_8;
+}
+
+typedef S tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      const S tint_symbol_7 = (S)0;
+      w[i] = tint_symbol_7;
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 256u);
+  w[3].m = tint_symbol_5(u, 264u);
+  uint2 ubo_load_4 = u[1].xy;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  w[1].m[0] = vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]).ywxz;
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001B747E825C0(3,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..d8f581b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,111 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct S {
+  int before;
+  uint pad;
+  f16mat2x4 m;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  int after;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+};
+
+struct S_std140 {
+  int before;
+  uint pad;
+  f16vec4 m_0;
+  f16vec4 m_1;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  int after;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+shared S w[4];
+S conv_S(S_std140 val) {
+  return S(val.before, val.pad, f16mat2x4(val.m_0, val.m_1), val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.after, val.pad_11, val.pad_12, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21, val.pad_22, val.pad_23, val.pad_24, val.pad_25);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, 0u, f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat2x4 load_u_inner_2_m() {
+  return f16mat2x4(u.inner[2u].m_0, u.inner[2u].m_1);
+}
+
+void f(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      uint i = idx;
+      S tint_symbol = S(0, 0u, f16mat2x4(f16vec4(0.0hf), f16vec4(0.0hf)), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u);
+      w[i] = tint_symbol;
+    }
+  }
+  barrier();
+  w = conv_arr4_S(u.inner);
+  w[1] = conv_S(u.inner[2u]);
+  w[3].m = load_u_inner_2_m();
+  w[1].m[0] = u.inner[0u].m_1.ywxz;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..0e256d8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,48 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0008 */ half2x4 m;
+  /* 0x0018 */ tint_array<int8_t, 40> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+struct tint_symbol_6 {
+  tint_array<S, 4> w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup tint_array<S, 4>* const tint_symbol_1, const constant tint_array<S, 4>* const tint_symbol_2) {
+  for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+    uint const i = idx;
+    S const tint_symbol = S{};
+    (*(tint_symbol_1))[i] = tint_symbol;
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol_1) = *(tint_symbol_2);
+  (*(tint_symbol_1))[1] = (*(tint_symbol_2))[2];
+  (*(tint_symbol_1))[3].m = (*(tint_symbol_2))[2].m;
+  (*(tint_symbol_1))[1].m[0] = half4((*(tint_symbol_2))[0].m[1]).ywxz;
+}
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol_5 [[buffer(0)]], threadgroup tint_symbol_6* tint_symbol_4 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup tint_array<S, 4>* const tint_symbol_3 = &((*(tint_symbol_4)).w);
+  f_inner(local_invocation_index, tint_symbol_3, tint_symbol_5);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_workgroup.wgsl.expected.spvasm
new file mode 100644
index 0000000..81a811f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_workgroup.wgsl.expected.spvasm
@@ -0,0 +1,214 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 126
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %local_invocation_index_1 "local_invocation_index_1"
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "after"
+               OpName %u "u"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %w "w"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f_inner "f_inner"
+               OpName %local_invocation_index "local_invocation_index"
+               OpName %idx "idx"
+               OpName %f "f"
+               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 8
+               OpMemberDecorate %S_std140 2 Offset 16
+               OpMemberDecorate %S_std140 3 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 8
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 8
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+   %S_std140 = OpTypeStruct %int %v4half %v4half %int
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat2v4half = OpTypeMatrix %v4half 2
+          %S = OpTypeStruct %int %mat2v4half %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+%_ptr_Workgroup__arr_S_uint_4 = OpTypePointer Workgroup %_arr_S_uint_4
+          %w = OpVariable %_ptr_Workgroup__arr_S_uint_4 Workgroup
+         %18 = OpTypeFunction %S %S_std140
+         %28 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+         %34 = OpConstantNull %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %37 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %50 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %63 = OpTypeFunction %mat2v4half
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+       %void = OpTypeVoid
+         %79 = OpTypeFunction %void %uint
+%_ptr_Workgroup_S = OpTypePointer Workgroup %S
+         %97 = OpConstantNull %S
+   %uint_264 = OpConstant %uint 264
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+      %int_1 = OpConstant %int 1
+      %int_3 = OpConstant %int 3
+%_ptr_Workgroup_mat2v4half = OpTypePointer Workgroup %mat2v4half
+        %115 = OpConstantNull %int
+%_ptr_Workgroup_v4half = OpTypePointer Workgroup %v4half
+        %121 = OpTypeFunction %void
+     %conv_S = OpFunction %S None %18
+        %val = OpFunctionParameter %S_std140
+         %21 = OpLabel
+         %22 = OpCompositeExtract %int %val 0
+         %23 = OpCompositeExtract %v4half %val 1
+         %24 = OpCompositeExtract %v4half %val 2
+         %25 = OpCompositeConstruct %mat2v4half %23 %24
+         %26 = OpCompositeExtract %int %val 3
+         %27 = OpCompositeConstruct %S %22 %25 %26
+               OpReturnValue %27
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %28
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %31 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %34
+          %i = OpVariable %_ptr_Function_uint Function %37
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %50
+               OpBranch %38
+         %38 = OpLabel
+               OpLoopMerge %39 %40 None
+               OpBranch %41
+         %41 = OpLabel
+         %43 = OpLoad %uint %i
+         %44 = OpULessThan %bool %43 %uint_4
+         %42 = OpLogicalNot %bool %44
+               OpSelectionMerge %46 None
+               OpBranchConditional %42 %47 %46
+         %47 = OpLabel
+               OpBranch %39
+         %46 = OpLabel
+               OpStore %var_for_index %val_0
+         %51 = OpLoad %uint %i
+         %53 = OpAccessChain %_ptr_Function_S %arr %51
+         %55 = OpLoad %uint %i
+         %57 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %55
+         %58 = OpLoad %S_std140 %57
+         %54 = OpFunctionCall %S %conv_S %58
+               OpStore %53 %54
+               OpBranch %40
+         %40 = OpLabel
+         %59 = OpLoad %uint %i
+         %61 = OpIAdd %uint %59 %uint_1
+               OpStore %i %61
+               OpBranch %38
+         %39 = OpLabel
+         %62 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %62
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat2v4half None %63
+         %65 = OpLabel
+         %70 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %73 = OpAccessChain %_ptr_Uniform_v4half %70 %uint_1
+         %74 = OpLoad %v4half %73
+         %76 = OpAccessChain %_ptr_Uniform_v4half %70 %uint_2
+         %77 = OpLoad %v4half %76
+         %78 = OpCompositeConstruct %mat2v4half %74 %77
+               OpReturnValue %78
+               OpFunctionEnd
+    %f_inner = OpFunction %void None %79
+%local_invocation_index = OpFunctionParameter %uint
+         %83 = OpLabel
+        %idx = OpVariable %_ptr_Function_uint Function %37
+               OpStore %idx %local_invocation_index
+               OpBranch %85
+         %85 = OpLabel
+               OpLoopMerge %86 %87 None
+               OpBranch %88
+         %88 = OpLabel
+         %90 = OpLoad %uint %idx
+         %91 = OpULessThan %bool %90 %uint_4
+         %89 = OpLogicalNot %bool %91
+               OpSelectionMerge %92 None
+               OpBranchConditional %89 %93 %92
+         %93 = OpLabel
+               OpBranch %86
+         %92 = OpLabel
+         %94 = OpLoad %uint %idx
+         %96 = OpAccessChain %_ptr_Workgroup_S %w %94
+               OpStore %96 %97
+               OpBranch %87
+         %87 = OpLabel
+         %98 = OpLoad %uint %idx
+         %99 = OpIAdd %uint %98 %uint_1
+               OpStore %idx %99
+               OpBranch %85
+         %86 = OpLabel
+               OpControlBarrier %uint_2 %uint_2 %uint_264
+        %104 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+        %105 = OpLoad %_arr_S_std140_uint_4 %104
+        %102 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %105
+               OpStore %w %102
+        %107 = OpAccessChain %_ptr_Workgroup_S %w %int_1
+        %109 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+        %110 = OpLoad %S_std140 %109
+        %108 = OpFunctionCall %S %conv_S %110
+               OpStore %107 %108
+        %113 = OpAccessChain %_ptr_Workgroup_mat2v4half %w %int_3 %uint_1
+        %114 = OpFunctionCall %mat2v4half %load_u_inner_2_m
+               OpStore %113 %114
+        %117 = OpAccessChain %_ptr_Workgroup_v4half %w %int_1 %uint_1 %115
+        %118 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0 %37 %uint_2
+        %119 = OpLoad %v4half %118
+        %120 = OpVectorShuffle %v4half %119 %119 1 3 0 2
+               OpStore %117 %120
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %121
+        %123 = OpLabel
+        %125 = OpLoad %uint %local_invocation_index_1
+        %124 = OpFunctionCall %void %f_inner %125
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..4a6de68
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f16/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,20 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat2x4<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+var<workgroup> w : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[2];
+  w[3].m = u[2].m;
+  w[1].m[0] = u[0].m[1].ywxz;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/dynamic_index_via_ptr.wgsl
new file mode 100644
index 0000000..a36d6af
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/dynamic_index_via_ptr.wgsl
@@ -0,0 +1,32 @@
+struct Inner {
+  @size(64)
+  m : mat2x4<f32>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a           = &a;
+  let p_a_i         = &((*p_a)[i()]);
+  let p_a_i_a       = &((*p_a_i).a);
+  let p_a_i_a_i     = &((*p_a_i_a)[i()]);
+  let p_a_i_a_i_m   = &((*p_a_i_a_i).m);
+  let p_a_i_a_i_m_i = &((*p_a_i_a_i_m)[i()]);
+
+
+  let l_a             : array<Outer, 4> =  *p_a;
+  let l_a_i           : Outer           =  *p_a_i;
+  let l_a_i_a         : array<Inner, 4> =  *p_a_i_a;
+  let l_a_i_a_i       : Inner           =  *p_a_i_a_i;
+  let l_a_i_a_i_m     : mat2x4<f32>     =  *p_a_i_a_i_m;
+  let l_a_i_a_i_m_i   : vec4<f32>       =  *p_a_i_a_i_m_i;
+  let l_a_i_a_i_m_i_i : f32             = (*p_a_i_a_i_m_i)[i()];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..0d53f5d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,75 @@
+struct Inner {
+  float2x4 m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float2x4 tint_symbol_8(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+Inner tint_symbol_7(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_11 = {tint_symbol_8(buffer, (offset + 0u))};
+  return tint_symbol_11;
+}
+
+typedef Inner tint_symbol_6_ret[4];
+tint_symbol_6_ret tint_symbol_6(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_7(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_5(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_12 = {tint_symbol_6(buffer, (offset + 0u))};
+  return tint_symbol_12;
+}
+
+typedef Outer tint_symbol_4_ret[4];
+tint_symbol_4_ret tint_symbol_4(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
+      arr_1[i_2] = tint_symbol_5(buffer, (offset + (i_2 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_a_i_save = i();
+  const int p_a_i_a_i_m_i_save = i();
+  const Outer l_a[4] = tint_symbol_4(a, 0u);
+  const Outer l_a_i = tint_symbol_5(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a[4] = tint_symbol_6(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a_i = tint_symbol_7(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const float2x4 l_a_i_a_i_m = tint_symbol_8(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const uint scalar_offset_2 = ((((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))) + (16u * uint(p_a_i_a_i_m_i_save)))) / 4;
+  const float4 l_a_i_a_i_m_i = asfloat(a[scalar_offset_2 / 4]);
+  const int tint_symbol = p_a_i_save;
+  const int tint_symbol_1 = p_a_i_a_i_save;
+  const int tint_symbol_2 = p_a_i_a_i_m_i_save;
+  const int tint_symbol_3 = i();
+  const uint scalar_offset_3 = (((((256u * uint(tint_symbol)) + (64u * uint(tint_symbol_1))) + (16u * uint(tint_symbol_2))) + (4u * uint(tint_symbol_3)))) / 4;
+  const float l_a_i_a_i_m_i_i = asfloat(a[scalar_offset_3 / 4][scalar_offset_3 % 4]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..0d53f5d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,75 @@
+struct Inner {
+  float2x4 m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float2x4 tint_symbol_8(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+Inner tint_symbol_7(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_11 = {tint_symbol_8(buffer, (offset + 0u))};
+  return tint_symbol_11;
+}
+
+typedef Inner tint_symbol_6_ret[4];
+tint_symbol_6_ret tint_symbol_6(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_7(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_5(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_12 = {tint_symbol_6(buffer, (offset + 0u))};
+  return tint_symbol_12;
+}
+
+typedef Outer tint_symbol_4_ret[4];
+tint_symbol_4_ret tint_symbol_4(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
+      arr_1[i_2] = tint_symbol_5(buffer, (offset + (i_2 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_a_i_save = i();
+  const int p_a_i_a_i_m_i_save = i();
+  const Outer l_a[4] = tint_symbol_4(a, 0u);
+  const Outer l_a_i = tint_symbol_5(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a[4] = tint_symbol_6(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a_i = tint_symbol_7(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const float2x4 l_a_i_a_i_m = tint_symbol_8(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const uint scalar_offset_2 = ((((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))) + (16u * uint(p_a_i_a_i_m_i_save)))) / 4;
+  const float4 l_a_i_a_i_m_i = asfloat(a[scalar_offset_2 / 4]);
+  const int tint_symbol = p_a_i_save;
+  const int tint_symbol_1 = p_a_i_a_i_save;
+  const int tint_symbol_2 = p_a_i_a_i_m_i_save;
+  const int tint_symbol_3 = i();
+  const uint scalar_offset_3 = (((((256u * uint(tint_symbol)) + (64u * uint(tint_symbol_1))) + (16u * uint(tint_symbol_2))) + (4u * uint(tint_symbol_3)))) / 4;
+  const float l_a_i_a_i_m_i_i = asfloat(a[scalar_offset_3 / 4][scalar_offset_3 % 4]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..5503c5a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,50 @@
+#version 310 es
+
+struct Inner {
+  mat2x4 m;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+};
+
+struct Outer {
+  Inner a[4];
+};
+
+layout(binding = 0, std140) uniform a_block_ubo {
+  Outer inner[4];
+} a;
+
+int counter = 0;
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+void f() {
+  int tint_symbol = i();
+  int p_a_i_save = tint_symbol;
+  int tint_symbol_1 = i();
+  int p_a_i_a_i_save = tint_symbol_1;
+  int tint_symbol_2 = i();
+  int p_a_i_a_i_m_i_save = tint_symbol_2;
+  Outer l_a[4] = a.inner;
+  Outer l_a_i = a.inner[p_a_i_save];
+  Inner l_a_i_a[4] = a.inner[p_a_i_save].a;
+  Inner l_a_i_a_i = a.inner[p_a_i_save].a[p_a_i_a_i_save];
+  mat2x4 l_a_i_a_i_m = a.inner[p_a_i_save].a[p_a_i_a_i_save].m;
+  vec4 l_a_i_a_i_m_i = a.inner[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save];
+  int tint_symbol_3 = i();
+  float l_a_i_a_i_m_i_i = a.inner[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save][tint_symbol_3];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..6092bcc
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,49 @@
+#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 Inner {
+  /* 0x0000 */ float2x4 m;
+  /* 0x0020 */ tint_array<int8_t, 32> tint_pad;
+};
+
+struct Outer {
+  /* 0x0000 */ tint_array<Inner, 4> a;
+};
+
+int i() {
+  thread int tint_symbol_4 = 0;
+  tint_symbol_4 = as_type<int>((as_type<uint>(tint_symbol_4) + as_type<uint>(1)));
+  return tint_symbol_4;
+}
+
+kernel void f(const constant tint_array<Outer, 4>* tint_symbol_5 [[buffer(0)]]) {
+  int const tint_symbol = i();
+  int const p_a_i_save = tint_symbol;
+  int const tint_symbol_1 = i();
+  int const p_a_i_a_i_save = tint_symbol_1;
+  int const tint_symbol_2 = i();
+  int const p_a_i_a_i_m_i_save = tint_symbol_2;
+  tint_array<Outer, 4> const l_a = *(tint_symbol_5);
+  Outer const l_a_i = (*(tint_symbol_5))[p_a_i_save];
+  tint_array<Inner, 4> const l_a_i_a = (*(tint_symbol_5))[p_a_i_save].a;
+  Inner const l_a_i_a_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save];
+  float2x4 const l_a_i_a_i_m = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m;
+  float4 const l_a_i_a_i_m_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save];
+  int const tint_symbol_3 = i();
+  float const l_a_i_a_i_m_i_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save][tint_symbol_3];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..3fd6f76
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,88 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 54
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block "a_block"
+               OpMemberName %a_block 0 "inner"
+               OpName %Outer "Outer"
+               OpMemberName %Outer 0 "a"
+               OpName %Inner "Inner"
+               OpMemberName %Inner 0 "m"
+               OpName %a "a"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %f "f"
+               OpDecorate %a_block Block
+               OpMemberDecorate %a_block 0 Offset 0
+               OpMemberDecorate %Outer 0 Offset 0
+               OpMemberDecorate %Inner 0 Offset 0
+               OpMemberDecorate %Inner 0 ColMajor
+               OpMemberDecorate %Inner 0 MatrixStride 16
+               OpDecorate %_arr_Inner_uint_4 ArrayStride 64
+               OpDecorate %_arr_Outer_uint_4 ArrayStride 256
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat2v4float = OpTypeMatrix %v4float 2
+      %Inner = OpTypeStruct %mat2v4float
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_Inner_uint_4 = OpTypeArray %Inner %uint_4
+      %Outer = OpTypeStruct %_arr_Inner_uint_4
+%_arr_Outer_uint_4 = OpTypeArray %Outer %uint_4
+    %a_block = OpTypeStruct %_arr_Outer_uint_4
+%_ptr_Uniform_a_block = OpTypePointer Uniform %a_block
+          %a = OpVariable %_ptr_Uniform_a_block Uniform
+        %int = OpTypeInt 32 1
+         %14 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %14
+         %17 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+       %void = OpTypeVoid
+         %24 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_Outer_uint_4 = OpTypePointer Uniform %_arr_Outer_uint_4
+%_ptr_Uniform_Outer = OpTypePointer Uniform %Outer
+%_ptr_Uniform__arr_Inner_uint_4 = OpTypePointer Uniform %_arr_Inner_uint_4
+%_ptr_Uniform_Inner = OpTypePointer Uniform %Inner
+%_ptr_Uniform_mat2v4float = OpTypePointer Uniform %mat2v4float
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+          %i = OpFunction %int None %17
+         %19 = OpLabel
+         %20 = OpLoad %int %counter
+         %22 = OpIAdd %int %20 %int_1
+               OpStore %counter %22
+         %23 = OpLoad %int %counter
+               OpReturnValue %23
+               OpFunctionEnd
+          %f = OpFunction %void None %24
+         %27 = OpLabel
+         %28 = OpFunctionCall %int %i
+         %29 = OpFunctionCall %int %i
+         %30 = OpFunctionCall %int %i
+         %33 = OpAccessChain %_ptr_Uniform__arr_Outer_uint_4 %a %uint_0
+         %34 = OpLoad %_arr_Outer_uint_4 %33
+         %36 = OpAccessChain %_ptr_Uniform_Outer %a %uint_0 %28
+         %37 = OpLoad %Outer %36
+         %39 = OpAccessChain %_ptr_Uniform__arr_Inner_uint_4 %a %uint_0 %28 %uint_0
+         %40 = OpLoad %_arr_Inner_uint_4 %39
+         %42 = OpAccessChain %_ptr_Uniform_Inner %a %uint_0 %28 %uint_0 %29
+         %43 = OpLoad %Inner %42
+         %45 = OpAccessChain %_ptr_Uniform_mat2v4float %a %uint_0 %28 %uint_0 %29 %uint_0
+         %46 = OpLoad %mat2v4float %45
+         %48 = OpAccessChain %_ptr_Uniform_v4float %a %uint_0 %28 %uint_0 %29 %uint_0 %30
+         %49 = OpLoad %v4float %48
+         %50 = OpFunctionCall %int %i
+         %52 = OpAccessChain %_ptr_Uniform_float %a %uint_0 %28 %uint_0 %29 %uint_0 %30 %50
+         %53 = OpLoad %float %52
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..6ae9702
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,34 @@
+struct Inner {
+  @size(64)
+  m : mat2x4<f32>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_i = &((*(p_a))[i()]);
+  let p_a_i_a = &((*(p_a_i)).a);
+  let p_a_i_a_i = &((*(p_a_i_a))[i()]);
+  let p_a_i_a_i_m = &((*(p_a_i_a_i)).m);
+  let p_a_i_a_i_m_i = &((*(p_a_i_a_i_m))[i()]);
+  let l_a : array<Outer, 4> = *(p_a);
+  let l_a_i : Outer = *(p_a_i);
+  let l_a_i_a : array<Inner, 4> = *(p_a_i_a);
+  let l_a_i_a_i : Inner = *(p_a_i_a_i);
+  let l_a_i_a_i_m : mat2x4<f32> = *(p_a_i_a_i_m);
+  let l_a_i_a_i_m_i : vec4<f32> = *(p_a_i_a_i_m_i);
+  let l_a_i_a_i_m_i_i : f32 = (*(p_a_i_a_i_m_i))[i()];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/static_index_via_ptr.wgsl
new file mode 100644
index 0000000..4ae3bd0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/static_index_via_ptr.wgsl
@@ -0,0 +1,29 @@
+struct Inner {
+  @size(64)
+  m : mat2x4<f32>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &a;
+  let p_a_3 = &((*p_a)[3]);
+  let p_a_3_a = &((*p_a_3).a);
+  let p_a_3_a_2 = &((*p_a_3_a)[2]);
+  let p_a_3_a_2_m = &((*p_a_3_a_2).m);
+  let p_a_3_a_2_m_1 = &((*p_a_3_a_2_m)[1]);
+
+
+  let l_a             : array<Outer, 4> = *p_a;
+  let l_a_3           : Outer           = *p_a_3;
+  let l_a_3_a         : array<Inner, 4> = *p_a_3_a;
+  let l_a_3_a_2       : Inner           = *p_a_3_a_2;
+  let l_a_3_a_2_m     : mat2x4<f32>     = *p_a_3_a_2_m;
+  let l_a_3_a_2_m_1   : vec4<f32>       = *p_a_3_a_2_m_1;
+  let l_a_3_a_2_m_1_0 : f32             = (*p_a_3_a_2_m_1)[0];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..9b489d1
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,60 @@
+struct Inner {
+  float2x4 m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+
+float2x4 tint_symbol_4(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+Inner tint_symbol_3(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_7 = {tint_symbol_4(buffer, (offset + 0u))};
+  return tint_symbol_7;
+}
+
+typedef Inner tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_3(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_1(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_8 = {tint_symbol_2(buffer, (offset + 0u))};
+  return tint_symbol_8;
+}
+
+typedef Outer tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr_1[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const Outer l_a[4] = tint_symbol(a, 0u);
+  const Outer l_a_3 = tint_symbol_1(a, 768u);
+  const Inner l_a_3_a[4] = tint_symbol_2(a, 768u);
+  const Inner l_a_3_a_2 = tint_symbol_3(a, 896u);
+  const float2x4 l_a_3_a_2_m = tint_symbol_4(a, 896u);
+  const float4 l_a_3_a_2_m_1 = asfloat(a[57]);
+  const float l_a_3_a_2_m_1_0 = asfloat(a[57].x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..9b489d1
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,60 @@
+struct Inner {
+  float2x4 m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+
+float2x4 tint_symbol_4(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+Inner tint_symbol_3(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_7 = {tint_symbol_4(buffer, (offset + 0u))};
+  return tint_symbol_7;
+}
+
+typedef Inner tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_3(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_1(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_8 = {tint_symbol_2(buffer, (offset + 0u))};
+  return tint_symbol_8;
+}
+
+typedef Outer tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr_1[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const Outer l_a[4] = tint_symbol(a, 0u);
+  const Outer l_a_3 = tint_symbol_1(a, 768u);
+  const Inner l_a_3_a[4] = tint_symbol_2(a, 768u);
+  const Inner l_a_3_a_2 = tint_symbol_3(a, 896u);
+  const float2x4 l_a_3_a_2_m = tint_symbol_4(a, 896u);
+  const float4 l_a_3_a_2_m_1 = asfloat(a[57]);
+  const float l_a_3_a_2_m_1_0 = asfloat(a[57].x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/static_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..d832c5c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/static_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,37 @@
+#version 310 es
+
+struct Inner {
+  mat2x4 m;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+};
+
+struct Outer {
+  Inner a[4];
+};
+
+layout(binding = 0, std140) uniform a_block_ubo {
+  Outer inner[4];
+} a;
+
+void f() {
+  Outer l_a[4] = a.inner;
+  Outer l_a_3 = a.inner[3];
+  Inner l_a_3_a[4] = a.inner[3].a;
+  Inner l_a_3_a_2 = a.inner[3].a[2];
+  mat2x4 l_a_3_a_2_m = a.inner[3].a[2].m;
+  vec4 l_a_3_a_2_m_1 = a.inner[3].a[2].m[1];
+  float l_a_3_a_2_m_1_0 = a.inner[3].a[2].m[1][0];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/static_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..cf252cb
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/static_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,36 @@
+#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 Inner {
+  /* 0x0000 */ float2x4 m;
+  /* 0x0020 */ tint_array<int8_t, 32> tint_pad;
+};
+
+struct Outer {
+  /* 0x0000 */ tint_array<Inner, 4> a;
+};
+
+kernel void f(const constant tint_array<Outer, 4>* tint_symbol [[buffer(0)]]) {
+  tint_array<Outer, 4> const l_a = *(tint_symbol);
+  Outer const l_a_3 = (*(tint_symbol))[3];
+  tint_array<Inner, 4> const l_a_3_a = (*(tint_symbol))[3].a;
+  Inner const l_a_3_a_2 = (*(tint_symbol))[3].a[2];
+  float2x4 const l_a_3_a_2_m = (*(tint_symbol))[3].a[2].m;
+  float4 const l_a_3_a_2_m_1 = (*(tint_symbol))[3].a[2].m[1];
+  float const l_a_3_a_2_m_1_0 = (*(tint_symbol))[3].a[2].m[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/static_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..1d899cf
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/static_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,73 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 44
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block "a_block"
+               OpMemberName %a_block 0 "inner"
+               OpName %Outer "Outer"
+               OpMemberName %Outer 0 "a"
+               OpName %Inner "Inner"
+               OpMemberName %Inner 0 "m"
+               OpName %a "a"
+               OpName %f "f"
+               OpDecorate %a_block Block
+               OpMemberDecorate %a_block 0 Offset 0
+               OpMemberDecorate %Outer 0 Offset 0
+               OpMemberDecorate %Inner 0 Offset 0
+               OpMemberDecorate %Inner 0 ColMajor
+               OpMemberDecorate %Inner 0 MatrixStride 16
+               OpDecorate %_arr_Inner_uint_4 ArrayStride 64
+               OpDecorate %_arr_Outer_uint_4 ArrayStride 256
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat2v4float = OpTypeMatrix %v4float 2
+      %Inner = OpTypeStruct %mat2v4float
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_Inner_uint_4 = OpTypeArray %Inner %uint_4
+      %Outer = OpTypeStruct %_arr_Inner_uint_4
+%_arr_Outer_uint_4 = OpTypeArray %Outer %uint_4
+    %a_block = OpTypeStruct %_arr_Outer_uint_4
+%_ptr_Uniform_a_block = OpTypePointer Uniform %a_block
+          %a = OpVariable %_ptr_Uniform_a_block Uniform
+       %void = OpTypeVoid
+         %13 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_Outer_uint_4 = OpTypePointer Uniform %_arr_Outer_uint_4
+        %int = OpTypeInt 32 1
+      %int_3 = OpConstant %int 3
+%_ptr_Uniform_Outer = OpTypePointer Uniform %Outer
+%_ptr_Uniform__arr_Inner_uint_4 = OpTypePointer Uniform %_arr_Inner_uint_4
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_Inner = OpTypePointer Uniform %Inner
+%_ptr_Uniform_mat2v4float = OpTypePointer Uniform %mat2v4float
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+         %40 = OpConstantNull %int
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+          %f = OpFunction %void None %13
+         %16 = OpLabel
+         %19 = OpAccessChain %_ptr_Uniform__arr_Outer_uint_4 %a %uint_0
+         %20 = OpLoad %_arr_Outer_uint_4 %19
+         %24 = OpAccessChain %_ptr_Uniform_Outer %a %uint_0 %int_3
+         %25 = OpLoad %Outer %24
+         %27 = OpAccessChain %_ptr_Uniform__arr_Inner_uint_4 %a %uint_0 %int_3 %uint_0
+         %28 = OpLoad %_arr_Inner_uint_4 %27
+         %31 = OpAccessChain %_ptr_Uniform_Inner %a %uint_0 %int_3 %uint_0 %int_2
+         %32 = OpLoad %Inner %31
+         %34 = OpAccessChain %_ptr_Uniform_mat2v4float %a %uint_0 %int_3 %uint_0 %int_2 %uint_0
+         %35 = OpLoad %mat2v4float %34
+         %38 = OpAccessChain %_ptr_Uniform_v4float %a %uint_0 %int_3 %uint_0 %int_2 %uint_0 %int_1
+         %39 = OpLoad %v4float %38
+         %42 = OpAccessChain %_ptr_Uniform_float %a %uint_0 %int_3 %uint_0 %int_2 %uint_0 %int_1 %40
+         %43 = OpLoad %float %42
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/static_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..c29901f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/static_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,27 @@
+struct Inner {
+  @size(64)
+  m : mat2x4<f32>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_3 = &((*(p_a))[3]);
+  let p_a_3_a = &((*(p_a_3)).a);
+  let p_a_3_a_2 = &((*(p_a_3_a))[2]);
+  let p_a_3_a_2_m = &((*(p_a_3_a_2)).m);
+  let p_a_3_a_2_m_1 = &((*(p_a_3_a_2_m))[1]);
+  let l_a : array<Outer, 4> = *(p_a);
+  let l_a_3 : Outer = *(p_a_3);
+  let l_a_3_a : array<Inner, 4> = *(p_a_3_a);
+  let l_a_3_a_2 : Inner = *(p_a_3_a_2);
+  let l_a_3_a_2_m : mat2x4<f32> = *(p_a_3_a_2_m);
+  let l_a_3_a_2_m_1 : vec4<f32> = *(p_a_3_a_2_m_1);
+  let l_a_3_a_2_m_1_0 : f32 = (*(p_a_3_a_2_m_1))[0];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_builtin.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_builtin.wgsl
new file mode 100644
index 0000000..10fd2f2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_builtin.wgsl
@@ -0,0 +1,15 @@
+struct S {
+  before : i32,
+  m : mat2x4<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    let t = transpose(u[2].m);
+    let l = length(u[0].m[1].ywxz);
+    let a = abs(u[0].m[1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_builtin.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..c7ea341
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_builtin.wgsl.expected.dxc.hlsl
@@ -0,0 +1,17 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+float2x4 tint_symbol(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float4x2 t = transpose(tint_symbol(u, 272u));
+  const float l = length(asfloat(u[2]).ywxz);
+  const float a = abs(asfloat(u[2]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_builtin.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..c7ea341
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_builtin.wgsl.expected.fxc.hlsl
@@ -0,0 +1,17 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+float2x4 tint_symbol(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float4x2 t = transpose(tint_symbol(u, 272u));
+  const float l = length(asfloat(u[2]).ywxz);
+  const float a = abs(asfloat(u[2]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_builtin.wgsl.expected.glsl
new file mode 100644
index 0000000..21be319
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_builtin.wgsl.expected.glsl
@@ -0,0 +1,45 @@
+#version 310 es
+
+struct S {
+  int before;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  mat2x4 m;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  int after;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+};
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  S inner[4];
+} u;
+
+void f() {
+  mat4x2 t = transpose(u.inner[2].m);
+  float l = length(u.inner[0].m[1].ywxz);
+  float a = abs(u.inner[0].m[1].ywxz.x);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_builtin.wgsl.expected.msl
new file mode 100644
index 0000000..5b9dd4c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_builtin.wgsl.expected.msl
@@ -0,0 +1,32 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 12> tint_pad;
+  /* 0x0010 */ float2x4 m;
+  /* 0x0030 */ tint_array<int8_t, 16> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol [[buffer(0)]]) {
+  float4x2 const t = transpose((*(tint_symbol))[2].m);
+  float const l = length(float4((*(tint_symbol))[0].m[1]).ywxz);
+  float const a = fabs(float4((*(tint_symbol))[0].m[1]).ywxz[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_builtin.wgsl.expected.spvasm
new file mode 100644
index 0000000..e9d901a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_builtin.wgsl.expected.spvasm
@@ -0,0 +1,67 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 38
+; Schema: 0
+               OpCapability Shader
+         %26 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %u "u"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 16
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 16
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat2v4float = OpTypeMatrix %v4float 2
+          %S = OpTypeStruct %int %mat2v4float %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+    %u_block = OpTypeStruct %_arr_S_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+         %12 = OpTypeFunction %void
+    %v2float = OpTypeVector %float 2
+%mat4v2float = OpTypeMatrix %v2float 4
+     %uint_0 = OpConstant %uint 0
+      %int_2 = OpConstant %int 2
+     %uint_1 = OpConstant %uint 1
+%_ptr_Uniform_mat2v4float = OpTypePointer Uniform %mat2v4float
+         %27 = OpConstantNull %int
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+          %f = OpFunction %void None %12
+         %15 = OpLabel
+         %23 = OpAccessChain %_ptr_Uniform_mat2v4float %u %uint_0 %int_2 %uint_1
+         %24 = OpLoad %mat2v4float %23
+         %16 = OpTranspose %mat4v2float %24
+         %30 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %27 %uint_1 %int_1
+         %31 = OpLoad %v4float %30
+         %32 = OpVectorShuffle %v4float %31 %31 1 3 0 2
+         %25 = OpExtInst %float %26 Length %32
+         %34 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %27 %uint_1 %int_1
+         %35 = OpLoad %v4float %34
+         %36 = OpVectorShuffle %v4float %35 %35 1 3 0 2
+         %37 = OpCompositeExtract %float %36 0
+         %33 = OpExtInst %float %26 FAbs %37
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_builtin.wgsl.expected.wgsl
new file mode 100644
index 0000000..d6255d0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_builtin.wgsl.expected.wgsl
@@ -0,0 +1,15 @@
+struct S {
+  before : i32,
+  m : mat2x4<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let t = transpose(u[2].m);
+  let l = length(u[0].m[1].ywxz);
+  let a = abs(u[0].m[1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_fn.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_fn.wgsl
new file mode 100644
index 0000000..7a8c874
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_fn.wgsl
@@ -0,0 +1,23 @@
+struct S {
+  before : i32,
+  m : mat2x4<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+fn a(a : array<S, 4>) {}
+fn b(s : S) {}
+fn c(m : mat2x4<f32>) {}
+fn d(v : vec4<f32>) {}
+fn e(f : f32) {}
+
+@compute @workgroup_size(1)
+fn f() {
+    a(u);
+    b(u[2]);
+    c(u[2].m);
+    d(u[0].m[1].ywxz);
+    e(u[0].m[1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_fn.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..c3c6996
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_fn.wgsl.expected.dxc.hlsl
@@ -0,0 +1,58 @@
+struct S {
+  int before;
+  float2x4 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(float2x4 m) {
+}
+
+void d(float4 v) {
+}
+
+void e(float f_1) {
+}
+
+float2x4 tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_3(buffer, (offset + 16u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 256u));
+  c(tint_symbol_3(u, 272u));
+  d(asfloat(u[2]).ywxz);
+  e(asfloat(u[2]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_fn.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..c3c6996
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_fn.wgsl.expected.fxc.hlsl
@@ -0,0 +1,58 @@
+struct S {
+  int before;
+  float2x4 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(float2x4 m) {
+}
+
+void d(float4 v) {
+}
+
+void e(float f_1) {
+}
+
+float2x4 tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_3(buffer, (offset + 16u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 256u));
+  c(tint_symbol_3(u, 272u));
+  d(asfloat(u[2]).ywxz);
+  e(asfloat(u[2]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_fn.wgsl.expected.glsl
new file mode 100644
index 0000000..4085677
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_fn.wgsl.expected.glsl
@@ -0,0 +1,62 @@
+#version 310 es
+
+struct S {
+  int before;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  mat2x4 m;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  int after;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+};
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  S inner[4];
+} u;
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(mat2x4 m) {
+}
+
+void d(vec4 v) {
+}
+
+void e(float f_1) {
+}
+
+void f() {
+  a(u.inner);
+  b(u.inner[2]);
+  c(u.inner[2].m);
+  d(u.inner[0].m[1].ywxz);
+  e(u.inner[0].m[1].ywxz.x);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_fn.wgsl.expected.msl
new file mode 100644
index 0000000..1914a9d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_fn.wgsl.expected.msl
@@ -0,0 +1,49 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 12> tint_pad;
+  /* 0x0010 */ float2x4 m;
+  /* 0x0030 */ tint_array<int8_t, 16> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+void a(tint_array<S, 4> a_1) {
+}
+
+void b(S s) {
+}
+
+void c(float2x4 m) {
+}
+
+void d(float4 v) {
+}
+
+void e(float f_1) {
+}
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol [[buffer(0)]]) {
+  a(*(tint_symbol));
+  b((*(tint_symbol))[2]);
+  c((*(tint_symbol))[2].m);
+  d(float4((*(tint_symbol))[0].m[1]).ywxz);
+  e(float4((*(tint_symbol))[0].m[1]).ywxz[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_fn.wgsl.expected.spvasm
new file mode 100644
index 0000000..5904072
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_fn.wgsl.expected.spvasm
@@ -0,0 +1,112 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 63
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %u "u"
+               OpName %a "a"
+               OpName %a_1 "a_1"
+               OpName %b "b"
+               OpName %s "s"
+               OpName %c "c"
+               OpName %m "m"
+               OpName %d "d"
+               OpName %v "v"
+               OpName %e "e"
+               OpName %f_1 "f_1"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 16
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 16
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat2v4float = OpTypeMatrix %v4float 2
+          %S = OpTypeStruct %int %mat2v4float %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+    %u_block = OpTypeStruct %_arr_S_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+         %12 = OpTypeFunction %void %_arr_S_uint_4
+         %17 = OpTypeFunction %void %S
+         %21 = OpTypeFunction %void %mat2v4float
+         %25 = OpTypeFunction %void %v4float
+         %29 = OpTypeFunction %void %float
+         %33 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_S_uint_4 = OpTypePointer Uniform %_arr_S_uint_4
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_S = OpTypePointer Uniform %S
+     %uint_1 = OpConstant %uint 1
+%_ptr_Uniform_mat2v4float = OpTypePointer Uniform %mat2v4float
+         %52 = OpConstantNull %int
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+          %a = OpFunction %void None %12
+        %a_1 = OpFunctionParameter %_arr_S_uint_4
+         %16 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %b = OpFunction %void None %17
+          %s = OpFunctionParameter %S
+         %20 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %c = OpFunction %void None %21
+          %m = OpFunctionParameter %mat2v4float
+         %24 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %d = OpFunction %void None %25
+          %v = OpFunctionParameter %v4float
+         %28 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %e = OpFunction %void None %29
+        %f_1 = OpFunctionParameter %float
+         %32 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %33
+         %35 = OpLabel
+         %39 = OpAccessChain %_ptr_Uniform__arr_S_uint_4 %u %uint_0
+         %40 = OpLoad %_arr_S_uint_4 %39
+         %36 = OpFunctionCall %void %a %40
+         %44 = OpAccessChain %_ptr_Uniform_S %u %uint_0 %int_2
+         %45 = OpLoad %S %44
+         %41 = OpFunctionCall %void %b %45
+         %49 = OpAccessChain %_ptr_Uniform_mat2v4float %u %uint_0 %int_2 %uint_1
+         %50 = OpLoad %mat2v4float %49
+         %46 = OpFunctionCall %void %c %50
+         %55 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %52 %uint_1 %int_1
+         %56 = OpLoad %v4float %55
+         %57 = OpVectorShuffle %v4float %56 %56 1 3 0 2
+         %51 = OpFunctionCall %void %d %57
+         %59 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %52 %uint_1 %int_1
+         %60 = OpLoad %v4float %59
+         %61 = OpVectorShuffle %v4float %60 %60 1 3 0 2
+         %62 = OpCompositeExtract %float %61 0
+         %58 = OpFunctionCall %void %e %62
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_fn.wgsl.expected.wgsl
new file mode 100644
index 0000000..1422e88
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_fn.wgsl.expected.wgsl
@@ -0,0 +1,32 @@
+struct S {
+  before : i32,
+  m : mat2x4<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+fn a(a : array<S, 4>) {
+}
+
+fn b(s : S) {
+}
+
+fn c(m : mat2x4<f32>) {
+}
+
+fn d(v : vec4<f32>) {
+}
+
+fn e(f : f32) {
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  a(u);
+  b(u[2]);
+  c(u[2].m);
+  d(u[0].m[1].ywxz);
+  e(u[0].m[1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_private.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_private.wgsl
new file mode 100644
index 0000000..c8add56
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_private.wgsl
@@ -0,0 +1,17 @@
+struct S {
+  before : i32,
+  m : mat2x4<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+var<private> p : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[2];
+    p[3].m = u[2].m;
+    p[1].m[0] = u[0].m[1].ywxz;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_private.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..55acd61
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_private.wgsl.expected.dxc.hlsl
@@ -0,0 +1,43 @@
+struct S {
+  int before;
+  float2x4 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+static S p[4] = (S[4])0;
+
+float2x4 tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_3(buffer, (offset + 16u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 256u);
+  p[3].m = tint_symbol_3(u, 272u);
+  p[1].m[0] = asfloat(u[2]).ywxz;
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_private.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..55acd61
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_private.wgsl.expected.fxc.hlsl
@@ -0,0 +1,43 @@
+struct S {
+  int before;
+  float2x4 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+static S p[4] = (S[4])0;
+
+float2x4 tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_3(buffer, (offset + 16u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 256u);
+  p[3].m = tint_symbol_3(u, 272u);
+  p[1].m[0] = asfloat(u[2]).ywxz;
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..4ac335c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_private.wgsl.expected.glsl
@@ -0,0 +1,47 @@
+#version 310 es
+
+struct S {
+  int before;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  mat2x4 m;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  int after;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+};
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  S inner[4];
+} u;
+
+S p[4] = S[4](S(0, 0u, 0u, 0u, mat2x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, 0u, 0u, mat2x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, 0u, 0u, mat2x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, 0u, 0u, mat2x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+void f() {
+  p = u.inner;
+  p[1] = u.inner[2];
+  p[3].m = u.inner[2].m;
+  p[1].m[0] = u.inner[0].m[1].ywxz;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..4732140
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_private.wgsl.expected.msl
@@ -0,0 +1,34 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 12> tint_pad;
+  /* 0x0010 */ float2x4 m;
+  /* 0x0030 */ tint_array<int8_t, 16> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol_1 [[buffer(0)]]) {
+  thread tint_array<S, 4> tint_symbol = {};
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[2];
+  tint_symbol[3].m = (*(tint_symbol_1))[2].m;
+  tint_symbol[1].m[0] = float4((*(tint_symbol_1))[0].m[1]).ywxz;
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_private.wgsl.expected.spvasm
new file mode 100644
index 0000000..43b3c76
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_private.wgsl.expected.spvasm
@@ -0,0 +1,78 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 44
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %u "u"
+               OpName %p "p"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 16
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 16
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat2v4float = OpTypeMatrix %v4float 2
+          %S = OpTypeStruct %int %mat2v4float %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+    %u_block = OpTypeStruct %_arr_S_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_Private__arr_S_uint_4 = OpTypePointer Private %_arr_S_uint_4
+         %14 = OpConstantNull %_arr_S_uint_4
+          %p = OpVariable %_ptr_Private__arr_S_uint_4 Private %14
+       %void = OpTypeVoid
+         %15 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_S_uint_4 = OpTypePointer Uniform %_arr_S_uint_4
+      %int_1 = OpConstant %int 1
+%_ptr_Private_S = OpTypePointer Private %S
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_S = OpTypePointer Uniform %S
+      %int_3 = OpConstant %int 3
+     %uint_1 = OpConstant %uint 1
+%_ptr_Private_mat2v4float = OpTypePointer Private %mat2v4float
+%_ptr_Uniform_mat2v4float = OpTypePointer Uniform %mat2v4float
+         %37 = OpConstantNull %int
+%_ptr_Private_v4float = OpTypePointer Private %v4float
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+          %f = OpFunction %void None %15
+         %18 = OpLabel
+         %21 = OpAccessChain %_ptr_Uniform__arr_S_uint_4 %u %uint_0
+         %22 = OpLoad %_arr_S_uint_4 %21
+               OpStore %p %22
+         %25 = OpAccessChain %_ptr_Private_S %p %int_1
+         %28 = OpAccessChain %_ptr_Uniform_S %u %uint_0 %int_2
+         %29 = OpLoad %S %28
+               OpStore %25 %29
+         %33 = OpAccessChain %_ptr_Private_mat2v4float %p %int_3 %uint_1
+         %35 = OpAccessChain %_ptr_Uniform_mat2v4float %u %uint_0 %int_2 %uint_1
+         %36 = OpLoad %mat2v4float %35
+               OpStore %33 %36
+         %39 = OpAccessChain %_ptr_Private_v4float %p %int_1 %uint_1 %37
+         %41 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %37 %uint_1 %int_1
+         %42 = OpLoad %v4float %41
+         %43 = OpVectorShuffle %v4float %42 %42 1 3 0 2
+               OpStore %39 %43
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..34d2f9a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_private.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+struct S {
+  before : i32,
+  m : mat2x4<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+var<private> p : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[2];
+  p[3].m = u[2].m;
+  p[1].m[0] = u[0].m[1].ywxz;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_storage.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_storage.wgsl
new file mode 100644
index 0000000..075fc8a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_storage.wgsl
@@ -0,0 +1,17 @@
+struct S {
+  before : i32,
+  m : mat2x4<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+@group(0) @binding(1) var<storage, read_write> s : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[2];
+    s[3].m = u[2].m;
+    s[1].m[0] = u[0].m[1].ywxz;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_storage.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..2146713
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_storage.wgsl.expected.dxc.hlsl
@@ -0,0 +1,63 @@
+struct S {
+  int before;
+  float2x4 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_3(RWByteAddressBuffer buffer, uint offset, float2x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+}
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, S value) {
+  buffer.Store((offset + 0u), asuint(value.before));
+  tint_symbol_3(buffer, (offset + 16u), value.m);
+  buffer.Store((offset + 64u), asuint(value.after));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, S value[4]) {
+  S array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 128u)), array[i]);
+    }
+  }
+}
+
+float2x4 tint_symbol_8(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+S tint_symbol_6(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_10 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_8(buffer, (offset + 16u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_10;
+}
+
+typedef S tint_symbol_5_ret[4];
+tint_symbol_5_ret tint_symbol_5(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_6(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_5(u, 0u));
+  tint_symbol_1(s, 128u, tint_symbol_6(u, 256u));
+  tint_symbol_3(s, 400u, tint_symbol_8(u, 272u));
+  s.Store4(144u, asuint(asfloat(u[2]).ywxz));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_storage.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..2146713
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_storage.wgsl.expected.fxc.hlsl
@@ -0,0 +1,63 @@
+struct S {
+  int before;
+  float2x4 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_3(RWByteAddressBuffer buffer, uint offset, float2x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+}
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, S value) {
+  buffer.Store((offset + 0u), asuint(value.before));
+  tint_symbol_3(buffer, (offset + 16u), value.m);
+  buffer.Store((offset + 64u), asuint(value.after));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, S value[4]) {
+  S array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 128u)), array[i]);
+    }
+  }
+}
+
+float2x4 tint_symbol_8(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+S tint_symbol_6(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_10 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_8(buffer, (offset + 16u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_10;
+}
+
+typedef S tint_symbol_5_ret[4];
+tint_symbol_5_ret tint_symbol_5(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_6(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_5(u, 0u));
+  tint_symbol_1(s, 128u, tint_symbol_6(u, 256u));
+  tint_symbol_3(s, 400u, tint_symbol_8(u, 272u));
+  s.Store4(144u, asuint(asfloat(u[2]).ywxz));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..d3082c7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_storage.wgsl.expected.glsl
@@ -0,0 +1,50 @@
+#version 310 es
+
+struct S {
+  int before;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  mat2x4 m;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  int after;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+};
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  S inner[4];
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  S inner[4];
+} s;
+
+void f() {
+  s.inner = u.inner;
+  s.inner[1] = u.inner[2];
+  s.inner[3].m = u.inner[2].m;
+  s.inner[1].m[0] = u.inner[0].m[1].ywxz;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..b3cd658
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_storage.wgsl.expected.msl
@@ -0,0 +1,33 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 12> tint_pad;
+  /* 0x0010 */ float2x4 m;
+  /* 0x0030 */ tint_array<int8_t, 16> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+kernel void f(device tint_array<S, 4>* tint_symbol [[buffer(1)]], const constant tint_array<S, 4>* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
+  (*(tint_symbol))[3].m = (*(tint_symbol_1))[2].m;
+  (*(tint_symbol))[1].m[0] = float4((*(tint_symbol_1))[0].m[1]).ywxz;
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_storage.wgsl.expected.spvasm
new file mode 100644
index 0000000..5ba1ccb
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_storage.wgsl.expected.spvasm
@@ -0,0 +1,81 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 45
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %u "u"
+               OpName %s "s"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 16
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 16
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %s DescriptorSet 0
+               OpDecorate %s Binding 1
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat2v4float = OpTypeMatrix %v4float 2
+          %S = OpTypeStruct %int %mat2v4float %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+    %u_block = OpTypeStruct %_arr_S_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
+          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+       %void = OpTypeVoid
+         %14 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer__arr_S_uint_4 = OpTypePointer StorageBuffer %_arr_S_uint_4
+%_ptr_Uniform__arr_S_uint_4 = OpTypePointer Uniform %_arr_S_uint_4
+      %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_S = OpTypePointer Uniform %S
+      %int_3 = OpConstant %int 3
+     %uint_1 = OpConstant %uint 1
+%_ptr_StorageBuffer_mat2v4float = OpTypePointer StorageBuffer %mat2v4float
+%_ptr_Uniform_mat2v4float = OpTypePointer Uniform %mat2v4float
+         %38 = OpConstantNull %int
+%_ptr_StorageBuffer_v4float = OpTypePointer StorageBuffer %v4float
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+          %f = OpFunction %void None %14
+         %17 = OpLabel
+         %20 = OpAccessChain %_ptr_StorageBuffer__arr_S_uint_4 %s %uint_0
+         %22 = OpAccessChain %_ptr_Uniform__arr_S_uint_4 %u %uint_0
+         %23 = OpLoad %_arr_S_uint_4 %22
+               OpStore %20 %23
+         %26 = OpAccessChain %_ptr_StorageBuffer_S %s %uint_0 %int_1
+         %29 = OpAccessChain %_ptr_Uniform_S %u %uint_0 %int_2
+         %30 = OpLoad %S %29
+               OpStore %26 %30
+         %34 = OpAccessChain %_ptr_StorageBuffer_mat2v4float %s %uint_0 %int_3 %uint_1
+         %36 = OpAccessChain %_ptr_Uniform_mat2v4float %u %uint_0 %int_2 %uint_1
+         %37 = OpLoad %mat2v4float %36
+               OpStore %34 %37
+         %40 = OpAccessChain %_ptr_StorageBuffer_v4float %s %uint_0 %int_1 %uint_1 %38
+         %42 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %38 %uint_1 %int_1
+         %43 = OpLoad %v4float %42
+         %44 = OpVectorShuffle %v4float %43 %43 1 3 0 2
+               OpStore %40 %44
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..ff82416
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+struct S {
+  before : i32,
+  m : mat2x4<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@group(0) @binding(1) var<storage, read_write> s : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[2];
+  s[3].m = u[2].m;
+  s[1].m[0] = u[0].m[1].ywxz;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_workgroup.wgsl
new file mode 100644
index 0000000..93675a8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_workgroup.wgsl
@@ -0,0 +1,17 @@
+struct S {
+  before : i32,
+  m : mat2x4<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+var<workgroup> w : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[2];
+    w[3].m = u[2].m;
+    w[1].m[0] = u[0].m[1].ywxz;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_workgroup.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..9f23bf3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_workgroup.wgsl.expected.dxc.hlsl
@@ -0,0 +1,59 @@
+struct S {
+  int before;
+  float2x4 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+groupshared S w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+float2x4 tint_symbol_5(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+S tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_8 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_5(buffer, (offset + 16u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_8;
+}
+
+typedef S tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      const S tint_symbol_7 = (S)0;
+      w[i] = tint_symbol_7;
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 256u);
+  w[3].m = tint_symbol_5(u, 272u);
+  w[1].m[0] = asfloat(u[2]).ywxz;
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_workgroup.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..9f23bf3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_workgroup.wgsl.expected.fxc.hlsl
@@ -0,0 +1,59 @@
+struct S {
+  int before;
+  float2x4 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+groupshared S w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+float2x4 tint_symbol_5(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+S tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 64u)) / 4;
+  const S tint_symbol_8 = {asint(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), tint_symbol_5(buffer, (offset + 16u)), asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4])};
+  return tint_symbol_8;
+}
+
+typedef S tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      const S tint_symbol_7 = (S)0;
+      w[i] = tint_symbol_7;
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 256u);
+  w[3].m = tint_symbol_5(u, 272u);
+  w[1].m[0] = asfloat(u[2]).ywxz;
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..c16c8ff
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,55 @@
+#version 310 es
+
+struct S {
+  int before;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  mat2x4 m;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  int after;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+};
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  S inner[4];
+} u;
+
+shared S w[4];
+void f(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      uint i = idx;
+      S tint_symbol = S(0, 0u, 0u, 0u, mat2x4(vec4(0.0f), vec4(0.0f)), 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u);
+      w[i] = tint_symbol;
+    }
+  }
+  barrier();
+  w = u.inner;
+  w[1] = u.inner[2];
+  w[3].m = u.inner[2].m;
+  w[1].m[0] = u.inner[0].m[1].ywxz;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..d3138fa
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,48 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 12> tint_pad;
+  /* 0x0010 */ float2x4 m;
+  /* 0x0030 */ tint_array<int8_t, 16> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+struct tint_symbol_6 {
+  tint_array<S, 4> w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup tint_array<S, 4>* const tint_symbol_1, const constant tint_array<S, 4>* const tint_symbol_2) {
+  for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+    uint const i = idx;
+    S const tint_symbol = S{};
+    (*(tint_symbol_1))[i] = tint_symbol;
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol_1) = *(tint_symbol_2);
+  (*(tint_symbol_1))[1] = (*(tint_symbol_2))[2];
+  (*(tint_symbol_1))[3].m = (*(tint_symbol_2))[2].m;
+  (*(tint_symbol_1))[1].m[0] = float4((*(tint_symbol_2))[0].m[1]).ywxz;
+}
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol_5 [[buffer(0)]], threadgroup tint_symbol_6* tint_symbol_4 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup tint_array<S, 4>* const tint_symbol_3 = &((*(tint_symbol_4)).w);
+  f_inner(local_invocation_index, tint_symbol_3, tint_symbol_5);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_workgroup.wgsl.expected.spvasm
new file mode 100644
index 0000000..ddf908d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_workgroup.wgsl.expected.spvasm
@@ -0,0 +1,124 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 72
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %local_invocation_index_1 "local_invocation_index_1"
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %u "u"
+               OpName %w "w"
+               OpName %f_inner "f_inner"
+               OpName %local_invocation_index "local_invocation_index"
+               OpName %idx "idx"
+               OpName %f "f"
+               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 16
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 16
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat2v4float = OpTypeMatrix %v4float 2
+          %S = OpTypeStruct %int %mat2v4float %int
+     %uint_4 = OpConstant %uint 4
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+    %u_block = OpTypeStruct %_arr_S_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_Workgroup__arr_S_uint_4 = OpTypePointer Workgroup %_arr_S_uint_4
+          %w = OpVariable %_ptr_Workgroup__arr_S_uint_4 Workgroup
+       %void = OpTypeVoid
+         %16 = OpTypeFunction %void %uint
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %23 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Workgroup_S = OpTypePointer Workgroup %S
+         %37 = OpConstantNull %S
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+   %uint_264 = OpConstant %uint 264
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_S_uint_4 = OpTypePointer Uniform %_arr_S_uint_4
+      %int_1 = OpConstant %int 1
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_S = OpTypePointer Uniform %S
+      %int_3 = OpConstant %int 3
+%_ptr_Workgroup_mat2v4float = OpTypePointer Workgroup %mat2v4float
+%_ptr_Uniform_mat2v4float = OpTypePointer Uniform %mat2v4float
+         %60 = OpConstantNull %int
+%_ptr_Workgroup_v4float = OpTypePointer Workgroup %v4float
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+         %67 = OpTypeFunction %void
+    %f_inner = OpFunction %void None %16
+%local_invocation_index = OpFunctionParameter %uint
+         %20 = OpLabel
+        %idx = OpVariable %_ptr_Function_uint Function %23
+               OpStore %idx %local_invocation_index
+               OpBranch %24
+         %24 = OpLabel
+               OpLoopMerge %25 %26 None
+               OpBranch %27
+         %27 = OpLabel
+         %29 = OpLoad %uint %idx
+         %30 = OpULessThan %bool %29 %uint_4
+         %28 = OpLogicalNot %bool %30
+               OpSelectionMerge %32 None
+               OpBranchConditional %28 %33 %32
+         %33 = OpLabel
+               OpBranch %25
+         %32 = OpLabel
+         %34 = OpLoad %uint %idx
+         %36 = OpAccessChain %_ptr_Workgroup_S %w %34
+               OpStore %36 %37
+               OpBranch %26
+         %26 = OpLabel
+         %38 = OpLoad %uint %idx
+         %40 = OpIAdd %uint %38 %uint_1
+               OpStore %idx %40
+               OpBranch %24
+         %25 = OpLabel
+               OpControlBarrier %uint_2 %uint_2 %uint_264
+         %46 = OpAccessChain %_ptr_Uniform__arr_S_uint_4 %u %uint_0
+         %47 = OpLoad %_arr_S_uint_4 %46
+               OpStore %w %47
+         %49 = OpAccessChain %_ptr_Workgroup_S %w %int_1
+         %52 = OpAccessChain %_ptr_Uniform_S %u %uint_0 %int_2
+         %53 = OpLoad %S %52
+               OpStore %49 %53
+         %56 = OpAccessChain %_ptr_Workgroup_mat2v4float %w %int_3 %uint_1
+         %58 = OpAccessChain %_ptr_Uniform_mat2v4float %u %uint_0 %int_2 %uint_1
+         %59 = OpLoad %mat2v4float %58
+               OpStore %56 %59
+         %62 = OpAccessChain %_ptr_Workgroup_v4float %w %int_1 %uint_1 %60
+         %64 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %60 %uint_1 %int_1
+         %65 = OpLoad %v4float %64
+         %66 = OpVectorShuffle %v4float %65 %65 1 3 0 2
+               OpStore %62 %66
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %67
+         %69 = OpLabel
+         %71 = OpLoad %uint %local_invocation_index_1
+         %70 = OpFunctionCall %void %f_inner %71
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..7f37f49
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat2x4_f32/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+struct S {
+  before : i32,
+  m : mat2x4<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+var<workgroup> w : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[2];
+  w[3].m = u[2].m;
+  w[1].m[0] = u[0].m[1].ywxz;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x2/dynamic_index_via_ptr.wgsl
deleted file mode 100644
index 92c91a8..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/dynamic_index_via_ptr.wgsl
+++ /dev/null
@@ -1,31 +0,0 @@
-struct Inner {
-  @size(64) m : mat3x2<f32>,
-}
-
-struct Outer {
-  a : array<Inner, 4>,
-}
-
-@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
-
-var<private> counter = 0;
-fn i() -> i32 { counter++; return counter; }
-
-@compute @workgroup_size(1)
-fn f() {
-  let p_a           = &a;
-  let p_a_i         = &((*p_a)[i()]);
-  let p_a_i_a       = &((*p_a_i).a);
-  let p_a_i_a_i     = &((*p_a_i_a)[i()]);
-  let p_a_i_a_i_m   = &((*p_a_i_a_i).m);
-  let p_a_i_a_i_m_i = &((*p_a_i_a_i_m)[i()]);
-
-
-  let l_a             : array<Outer, 4> =  *p_a;
-  let l_a_i           : Outer           =  *p_a_i;
-  let l_a_i_a         : array<Inner, 4> =  *p_a_i_a;
-  let l_a_i_a_i       : Inner           =  *p_a_i_a_i;
-  let l_a_i_a_i_m     : mat3x2<f32>     =  *p_a_i_a_i_m;
-  let l_a_i_a_i_m_i   : vec2<f32>       =  *p_a_i_a_i_m_i;
-  let l_a_i_a_i_m_i_i : f32             = (*p_a_i_a_i_m_i)[i()];
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x2/static_index_via_ptr.wgsl
deleted file mode 100644
index d6e6f10..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/static_index_via_ptr.wgsl
+++ /dev/null
@@ -1,28 +0,0 @@
-struct Inner {
-  @size(64) m : mat3x2<f32>,
-}
-
-struct Outer {
-  a : array<Inner, 4>,
-}
-
-@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
-
-@compute @workgroup_size(1)
-fn f() {
-  let p_a = &a;
-  let p_a_3 = &((*p_a)[3]);
-  let p_a_3_a = &((*p_a_3).a);
-  let p_a_3_a_2 = &((*p_a_3_a)[2]);
-  let p_a_3_a_2_m = &((*p_a_3_a_2).m);
-  let p_a_3_a_2_m_1 = &((*p_a_3_a_2_m)[1]);
-
-
-  let l_a             : array<Outer, 4> = *p_a;
-  let l_a_3           : Outer           = *p_a_3;
-  let l_a_3_a         : array<Inner, 4> = *p_a_3_a;
-  let l_a_3_a_2       : Inner           = *p_a_3_a_2;
-  let l_a_3_a_2_m     : mat3x2<f32>     = *p_a_3_a_2_m;
-  let l_a_3_a_2_m_1   : vec2<f32>       = *p_a_3_a_2_m_1;
-  let l_a_3_a_2_m_1_0 : f32             = (*p_a_3_a_2_m_1)[0];
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/to_builtin.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x2/to_builtin.wgsl
deleted file mode 100644
index 48cde20..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/to_builtin.wgsl
+++ /dev/null
@@ -1,14 +0,0 @@
-struct S {
-  before : i32,
-  @size(32) m : mat3x2<f32>,
-  after : i32,
-}
-
-@group(0) @binding(0) var<uniform> u : array<S, 4>;
-
-@compute @workgroup_size(1)
-fn f() {
-    let t = transpose(u[2].m);
-    let l = length(u[0].m[1].yx);
-    let a = abs(u[0].m[1].yx.x);
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x2/to_builtin.wgsl.expected.dxc.hlsl
deleted file mode 100644
index 9f083f6..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/to_builtin.wgsl.expected.dxc.hlsl
+++ /dev/null
@@ -1,21 +0,0 @@
-cbuffer cbuffer_u : register(b0, space0) {
-  uint4 u[12];
-};
-
-float3x2 tint_symbol(uint4 buffer[12], uint offset) {
-  const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset / 4];
-  const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
-  const uint scalar_offset_2 = ((offset + 16u)) / 4;
-  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
-  return float3x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)));
-}
-
-[numthreads(1, 1, 1)]
-void f() {
-  const float2x3 t = transpose(tint_symbol(u, 104u));
-  const float l = length(asfloat(u[1].xy).yx);
-  const float a = abs(asfloat(u[1].xy).yx.x);
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x2/to_builtin.wgsl.expected.fxc.hlsl
deleted file mode 100644
index 9f083f6..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/to_builtin.wgsl.expected.fxc.hlsl
+++ /dev/null
@@ -1,21 +0,0 @@
-cbuffer cbuffer_u : register(b0, space0) {
-  uint4 u[12];
-};
-
-float3x2 tint_symbol(uint4 buffer[12], uint offset) {
-  const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset / 4];
-  const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
-  const uint scalar_offset_2 = ((offset + 16u)) / 4;
-  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
-  return float3x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)));
-}
-
-[numthreads(1, 1, 1)]
-void f() {
-  const float2x3 t = transpose(tint_symbol(u, 104u));
-  const float l = length(asfloat(u[1].xy).yx);
-  const float a = abs(asfloat(u[1].xy).yx.x);
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x2/to_builtin.wgsl.expected.glsl
deleted file mode 100644
index 93a683e..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/to_builtin.wgsl.expected.glsl
+++ /dev/null
@@ -1,43 +0,0 @@
-#version 310 es
-
-struct S {
-  int before;
-  uint pad;
-  mat3x2 m;
-  uint pad_1;
-  uint pad_2;
-  int after;
-  uint pad_3;
-};
-
-struct S_std140 {
-  int before;
-  uint pad;
-  vec2 m_0;
-  vec2 m_1;
-  vec2 m_2;
-  uint pad_1;
-  uint pad_2;
-  int after;
-  uint pad_3;
-};
-
-layout(binding = 0, std140) uniform u_block_std140_ubo {
-  S_std140 inner[4];
-} u;
-
-mat3x2 load_u_inner_2_m() {
-  return mat3x2(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2);
-}
-
-void f() {
-  mat2x3 t = transpose(load_u_inner_2_m());
-  float l = length(u.inner[0u].m_1.yx);
-  float a = abs(u.inner[0u].m_1.yx[0u]);
-}
-
-layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
-void main() {
-  f();
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x2/to_builtin.wgsl.expected.msl
deleted file mode 100644
index a65b7f0..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/to_builtin.wgsl.expected.msl
+++ /dev/null
@@ -1,32 +0,0 @@
-#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 S {
-  /* 0x0000 */ int before;
-  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
-  /* 0x0008 */ float3x2 m;
-  /* 0x0020 */ tint_array<int8_t, 8> tint_pad_1;
-  /* 0x0028 */ int after;
-  /* 0x002c */ tint_array<int8_t, 4> tint_pad_2;
-};
-
-kernel void f(const constant tint_array<S, 4>* tint_symbol [[buffer(0)]]) {
-  float2x3 const t = transpose((*(tint_symbol))[2].m);
-  float const l = length(float2((*(tint_symbol))[0].m[1]).yx);
-  float const a = fabs(float2((*(tint_symbol))[0].m[1]).yx[0]);
-  return;
-}
-
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x2/to_builtin.wgsl.expected.spvasm
deleted file mode 100644
index ab0ed96..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/to_builtin.wgsl.expected.spvasm
+++ /dev/null
@@ -1,82 +0,0 @@
-; SPIR-V
-; Version: 1.3
-; Generator: Google Tint Compiler; 0
-; Bound: 52
-; Schema: 0
-               OpCapability Shader
-         %42 = OpExtInstImport "GLSL.std.450"
-               OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %f "f"
-               OpExecutionMode %f LocalSize 1 1 1
-               OpName %u_block_std140 "u_block_std140"
-               OpMemberName %u_block_std140 0 "inner"
-               OpName %S_std140 "S_std140"
-               OpMemberName %S_std140 0 "before"
-               OpMemberName %S_std140 1 "m_0"
-               OpMemberName %S_std140 2 "m_1"
-               OpMemberName %S_std140 3 "m_2"
-               OpMemberName %S_std140 4 "after"
-               OpName %u "u"
-               OpName %load_u_inner_2_m "load_u_inner_2_m"
-               OpName %f "f"
-               OpDecorate %u_block_std140 Block
-               OpMemberDecorate %u_block_std140 0 Offset 0
-               OpMemberDecorate %S_std140 0 Offset 0
-               OpMemberDecorate %S_std140 1 Offset 8
-               OpMemberDecorate %S_std140 2 Offset 16
-               OpMemberDecorate %S_std140 3 Offset 24
-               OpMemberDecorate %S_std140 4 Offset 40
-               OpDecorate %_arr_S_std140_uint_4 ArrayStride 48
-               OpDecorate %u NonWritable
-               OpDecorate %u DescriptorSet 0
-               OpDecorate %u Binding 0
-        %int = OpTypeInt 32 1
-      %float = OpTypeFloat 32
-    %v2float = OpTypeVector %float 2
-   %S_std140 = OpTypeStruct %int %v2float %v2float %v2float %int
-       %uint = OpTypeInt 32 0
-     %uint_4 = OpConstant %uint 4
-%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
-%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
-%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
-          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
-%mat3v2float = OpTypeMatrix %v2float 3
-         %11 = OpTypeFunction %mat3v2float
-     %uint_0 = OpConstant %uint 0
-     %uint_2 = OpConstant %uint 2
-%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
-     %uint_1 = OpConstant %uint 1
-%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
-     %uint_3 = OpConstant %uint 3
-       %void = OpTypeVoid
-         %33 = OpTypeFunction %void
-    %v3float = OpTypeVector %float 3
-%mat2v3float = OpTypeMatrix %v3float 2
-         %43 = OpConstantNull %uint
-%load_u_inner_2_m = OpFunction %mat3v2float None %11
-         %14 = OpLabel
-         %19 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
-         %23 = OpAccessChain %_ptr_Uniform_v2float %19 %uint_1
-         %24 = OpLoad %v2float %23
-         %26 = OpAccessChain %_ptr_Uniform_v2float %19 %uint_2
-         %27 = OpLoad %v2float %26
-         %30 = OpAccessChain %_ptr_Uniform_v2float %19 %uint_3
-         %31 = OpLoad %v2float %30
-         %32 = OpCompositeConstruct %mat3v2float %24 %27 %31
-               OpReturnValue %32
-               OpFunctionEnd
-          %f = OpFunction %void None %33
-         %36 = OpLabel
-         %40 = OpFunctionCall %mat3v2float %load_u_inner_2_m
-         %37 = OpTranspose %mat2v3float %40
-         %44 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %43 %uint_2
-         %45 = OpLoad %v2float %44
-         %46 = OpVectorShuffle %v2float %45 %45 1 0
-         %41 = OpExtInst %float %42 Length %46
-         %48 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %43 %uint_2
-         %49 = OpLoad %v2float %48
-         %50 = OpVectorShuffle %v2float %49 %49 1 0
-         %51 = OpCompositeExtract %float %50 0
-         %47 = OpExtInst %float %42 FAbs %51
-               OpReturn
-               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x2/to_builtin.wgsl.expected.wgsl
deleted file mode 100644
index 5f718b3..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/to_builtin.wgsl.expected.wgsl
+++ /dev/null
@@ -1,15 +0,0 @@
-struct S {
-  before : i32,
-  @size(32)
-  m : mat3x2<f32>,
-  after : i32,
-}
-
-@group(0) @binding(0) var<uniform> u : array<S, 4>;
-
-@compute @workgroup_size(1)
-fn f() {
-  let t = transpose(u[2].m);
-  let l = length(u[0].m[1].yx);
-  let a = abs(u[0].m[1].yx.x);
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/to_fn.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x2/to_fn.wgsl
deleted file mode 100644
index 2248b39..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/to_fn.wgsl
+++ /dev/null
@@ -1,22 +0,0 @@
-struct S {
-  before : i32,
-  @size(64) m : mat3x2<f32>,
-  after : i32,
-}
-
-@group(0) @binding(0) var<uniform> u : array<S, 4>;
-
-fn a(a : array<S, 4>) {}
-fn b(s : S) {}
-fn c(m : mat3x2<f32>) {}
-fn d(v : vec2<f32>) {}
-fn e(f : f32) {}
-
-@compute @workgroup_size(1)
-fn f() {
-    a(u);
-    b(u[2]);
-    c(u[2].m);
-    d(u[0].m[1].yx);
-    e(u[0].m[1].yx.x);
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x2/to_fn.wgsl.expected.dxc.hlsl
deleted file mode 100644
index 8474d05..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/to_fn.wgsl.expected.dxc.hlsl
+++ /dev/null
@@ -1,62 +0,0 @@
-struct S {
-  int before;
-  float3x2 m;
-  int after;
-};
-
-cbuffer cbuffer_u : register(b0, space0) {
-  uint4 u[20];
-};
-
-void a(S a_1[4]) {
-}
-
-void b(S s) {
-}
-
-void c(float3x2 m) {
-}
-
-void d(float2 v) {
-}
-
-void e(float f_1) {
-}
-
-float3x2 tint_symbol_3(uint4 buffer[20], uint offset) {
-  const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset / 4];
-  const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
-  const uint scalar_offset_2 = ((offset + 16u)) / 4;
-  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
-  return float3x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)));
-}
-
-S tint_symbol_1(uint4 buffer[20], uint offset) {
-  const uint scalar_offset_3 = ((offset + 0u)) / 4;
-  const uint scalar_offset_4 = ((offset + 72u)) / 4;
-  const S tint_symbol_5 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
-  return tint_symbol_5;
-}
-
-typedef S tint_symbol_ret[4];
-tint_symbol_ret tint_symbol(uint4 buffer[20], uint offset) {
-  S arr[4] = (S[4])0;
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      arr[i] = tint_symbol_1(buffer, (offset + (i * 80u)));
-    }
-  }
-  return arr;
-}
-
-[numthreads(1, 1, 1)]
-void f() {
-  a(tint_symbol(u, 0u));
-  b(tint_symbol_1(u, 160u));
-  c(tint_symbol_3(u, 168u));
-  d(asfloat(u[1].xy).yx);
-  e(asfloat(u[1].xy).yx.x);
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x2/to_fn.wgsl.expected.fxc.hlsl
deleted file mode 100644
index 8474d05..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/to_fn.wgsl.expected.fxc.hlsl
+++ /dev/null
@@ -1,62 +0,0 @@
-struct S {
-  int before;
-  float3x2 m;
-  int after;
-};
-
-cbuffer cbuffer_u : register(b0, space0) {
-  uint4 u[20];
-};
-
-void a(S a_1[4]) {
-}
-
-void b(S s) {
-}
-
-void c(float3x2 m) {
-}
-
-void d(float2 v) {
-}
-
-void e(float f_1) {
-}
-
-float3x2 tint_symbol_3(uint4 buffer[20], uint offset) {
-  const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset / 4];
-  const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
-  const uint scalar_offset_2 = ((offset + 16u)) / 4;
-  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
-  return float3x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)));
-}
-
-S tint_symbol_1(uint4 buffer[20], uint offset) {
-  const uint scalar_offset_3 = ((offset + 0u)) / 4;
-  const uint scalar_offset_4 = ((offset + 72u)) / 4;
-  const S tint_symbol_5 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
-  return tint_symbol_5;
-}
-
-typedef S tint_symbol_ret[4];
-tint_symbol_ret tint_symbol(uint4 buffer[20], uint offset) {
-  S arr[4] = (S[4])0;
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      arr[i] = tint_symbol_1(buffer, (offset + (i * 80u)));
-    }
-  }
-  return arr;
-}
-
-[numthreads(1, 1, 1)]
-void f() {
-  a(tint_symbol(u, 0u));
-  b(tint_symbol_1(u, 160u));
-  c(tint_symbol_3(u, 168u));
-  d(asfloat(u[1].xy).yx);
-  e(asfloat(u[1].xy).yx.x);
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x2/to_fn.wgsl.expected.glsl
deleted file mode 100644
index 41ff2a8..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/to_fn.wgsl.expected.glsl
+++ /dev/null
@@ -1,90 +0,0 @@
-#version 310 es
-
-struct S {
-  int before;
-  uint pad;
-  mat3x2 m;
-  uint pad_1;
-  uint pad_2;
-  uint pad_3;
-  uint pad_4;
-  uint pad_5;
-  uint pad_6;
-  uint pad_7;
-  uint pad_8;
-  uint pad_9;
-  uint pad_10;
-  int after;
-  uint pad_11;
-};
-
-struct S_std140 {
-  int before;
-  uint pad;
-  vec2 m_0;
-  vec2 m_1;
-  vec2 m_2;
-  uint pad_1;
-  uint pad_2;
-  uint pad_3;
-  uint pad_4;
-  uint pad_5;
-  uint pad_6;
-  uint pad_7;
-  uint pad_8;
-  uint pad_9;
-  uint pad_10;
-  int after;
-  uint pad_11;
-};
-
-layout(binding = 0, std140) uniform u_block_std140_ubo {
-  S_std140 inner[4];
-} u;
-
-void a(S a_1[4]) {
-}
-
-void b(S s) {
-}
-
-void c(mat3x2 m) {
-}
-
-void d(vec2 v) {
-}
-
-void e(float f_1) {
-}
-
-S conv_S(S_std140 val) {
-  return S(val.before, val.pad, mat3x2(val.m_0, val.m_1, val.m_2), val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.after, val.pad_11);
-}
-
-S[4] conv_arr4_S(S_std140 val[4]) {
-  S arr[4] = S[4](S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u), S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u), S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u), S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u));
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      arr[i] = conv_S(val[i]);
-    }
-  }
-  return arr;
-}
-
-mat3x2 load_u_inner_2_m() {
-  return mat3x2(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2);
-}
-
-void f() {
-  a(conv_arr4_S(u.inner));
-  b(conv_S(u.inner[2u]));
-  c(load_u_inner_2_m());
-  d(u.inner[0u].m_1.yx);
-  e(u.inner[0u].m_1.yx[0u]);
-}
-
-layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
-void main() {
-  f();
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x2/to_fn.wgsl.expected.msl
deleted file mode 100644
index 9247913..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/to_fn.wgsl.expected.msl
+++ /dev/null
@@ -1,49 +0,0 @@
-#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 S {
-  /* 0x0000 */ int before;
-  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
-  /* 0x0008 */ float3x2 m;
-  /* 0x0020 */ tint_array<int8_t, 40> tint_pad_1;
-  /* 0x0048 */ int after;
-  /* 0x004c */ tint_array<int8_t, 4> tint_pad_2;
-};
-
-void a(tint_array<S, 4> a_1) {
-}
-
-void b(S s) {
-}
-
-void c(float3x2 m) {
-}
-
-void d(float2 v) {
-}
-
-void e(float f_1) {
-}
-
-kernel void f(const constant tint_array<S, 4>* tint_symbol [[buffer(0)]]) {
-  a(*(tint_symbol));
-  b((*(tint_symbol))[2]);
-  c((*(tint_symbol))[2].m);
-  d(float2((*(tint_symbol))[0].m[1]).yx);
-  e(float2((*(tint_symbol))[0].m[1]).yx[0]);
-  return;
-}
-
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x2/to_fn.wgsl.expected.spvasm
deleted file mode 100644
index e7483d2..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/to_fn.wgsl.expected.spvasm
+++ /dev/null
@@ -1,206 +0,0 @@
-; SPIR-V
-; Version: 1.3
-; Generator: Google Tint Compiler; 0
-; Bound: 124
-; Schema: 0
-               OpCapability Shader
-               OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %f "f"
-               OpExecutionMode %f LocalSize 1 1 1
-               OpName %u_block_std140 "u_block_std140"
-               OpMemberName %u_block_std140 0 "inner"
-               OpName %S_std140 "S_std140"
-               OpMemberName %S_std140 0 "before"
-               OpMemberName %S_std140 1 "m_0"
-               OpMemberName %S_std140 2 "m_1"
-               OpMemberName %S_std140 3 "m_2"
-               OpMemberName %S_std140 4 "after"
-               OpName %u "u"
-               OpName %S "S"
-               OpMemberName %S 0 "before"
-               OpMemberName %S 1 "m"
-               OpMemberName %S 2 "after"
-               OpName %a "a"
-               OpName %a_1 "a_1"
-               OpName %b "b"
-               OpName %s "s"
-               OpName %c "c"
-               OpName %m "m"
-               OpName %d "d"
-               OpName %v "v"
-               OpName %e "e"
-               OpName %f_1 "f_1"
-               OpName %conv_S "conv_S"
-               OpName %val "val"
-               OpName %conv_arr4_S "conv_arr4_S"
-               OpName %val_0 "val"
-               OpName %arr "arr"
-               OpName %i "i"
-               OpName %var_for_index "var_for_index"
-               OpName %load_u_inner_2_m "load_u_inner_2_m"
-               OpName %f "f"
-               OpDecorate %u_block_std140 Block
-               OpMemberDecorate %u_block_std140 0 Offset 0
-               OpMemberDecorate %S_std140 0 Offset 0
-               OpMemberDecorate %S_std140 1 Offset 8
-               OpMemberDecorate %S_std140 2 Offset 16
-               OpMemberDecorate %S_std140 3 Offset 24
-               OpMemberDecorate %S_std140 4 Offset 72
-               OpDecorate %_arr_S_std140_uint_4 ArrayStride 80
-               OpDecorate %u NonWritable
-               OpDecorate %u DescriptorSet 0
-               OpDecorate %u Binding 0
-               OpMemberDecorate %S 0 Offset 0
-               OpMemberDecorate %S 1 Offset 8
-               OpMemberDecorate %S 1 ColMajor
-               OpMemberDecorate %S 1 MatrixStride 8
-               OpMemberDecorate %S 2 Offset 72
-               OpDecorate %_arr_S_uint_4 ArrayStride 80
-        %int = OpTypeInt 32 1
-      %float = OpTypeFloat 32
-    %v2float = OpTypeVector %float 2
-   %S_std140 = OpTypeStruct %int %v2float %v2float %v2float %int
-       %uint = OpTypeInt 32 0
-     %uint_4 = OpConstant %uint 4
-%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
-%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
-%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
-          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
-       %void = OpTypeVoid
-%mat3v2float = OpTypeMatrix %v2float 3
-          %S = OpTypeStruct %int %mat3v2float %int
-%_arr_S_uint_4 = OpTypeArray %S %uint_4
-         %11 = OpTypeFunction %void %_arr_S_uint_4
-         %19 = OpTypeFunction %void %S
-         %23 = OpTypeFunction %void %mat3v2float
-         %27 = OpTypeFunction %void %v2float
-         %31 = OpTypeFunction %void %float
-         %35 = OpTypeFunction %S %S_std140
-         %46 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
-%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
-         %52 = OpConstantNull %_arr_S_uint_4
-%_ptr_Function_uint = OpTypePointer Function %uint
-         %55 = OpConstantNull %uint
-       %bool = OpTypeBool
-%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
-         %68 = OpConstantNull %_arr_S_std140_uint_4
-%_ptr_Function_S = OpTypePointer Function %S
-%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
-     %uint_1 = OpConstant %uint 1
-         %81 = OpTypeFunction %mat3v2float
-     %uint_0 = OpConstant %uint 0
-     %uint_2 = OpConstant %uint 2
-%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
-%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
-     %uint_3 = OpConstant %uint 3
-        %101 = OpTypeFunction %void
-%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
-          %a = OpFunction %void None %11
-        %a_1 = OpFunctionParameter %_arr_S_uint_4
-         %18 = OpLabel
-               OpReturn
-               OpFunctionEnd
-          %b = OpFunction %void None %19
-          %s = OpFunctionParameter %S
-         %22 = OpLabel
-               OpReturn
-               OpFunctionEnd
-          %c = OpFunction %void None %23
-          %m = OpFunctionParameter %mat3v2float
-         %26 = OpLabel
-               OpReturn
-               OpFunctionEnd
-          %d = OpFunction %void None %27
-          %v = OpFunctionParameter %v2float
-         %30 = OpLabel
-               OpReturn
-               OpFunctionEnd
-          %e = OpFunction %void None %31
-        %f_1 = OpFunctionParameter %float
-         %34 = OpLabel
-               OpReturn
-               OpFunctionEnd
-     %conv_S = OpFunction %S None %35
-        %val = OpFunctionParameter %S_std140
-         %38 = OpLabel
-         %39 = OpCompositeExtract %int %val 0
-         %40 = OpCompositeExtract %v2float %val 1
-         %41 = OpCompositeExtract %v2float %val 2
-         %42 = OpCompositeExtract %v2float %val 3
-         %43 = OpCompositeConstruct %mat3v2float %40 %41 %42
-         %44 = OpCompositeExtract %int %val 4
-         %45 = OpCompositeConstruct %S %39 %43 %44
-               OpReturnValue %45
-               OpFunctionEnd
-%conv_arr4_S = OpFunction %_arr_S_uint_4 None %46
-      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
-         %49 = OpLabel
-        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %52
-          %i = OpVariable %_ptr_Function_uint Function %55
-%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %68
-               OpBranch %56
-         %56 = OpLabel
-               OpLoopMerge %57 %58 None
-               OpBranch %59
-         %59 = OpLabel
-         %61 = OpLoad %uint %i
-         %62 = OpULessThan %bool %61 %uint_4
-         %60 = OpLogicalNot %bool %62
-               OpSelectionMerge %64 None
-               OpBranchConditional %60 %65 %64
-         %65 = OpLabel
-               OpBranch %57
-         %64 = OpLabel
-               OpStore %var_for_index %val_0
-         %69 = OpLoad %uint %i
-         %71 = OpAccessChain %_ptr_Function_S %arr %69
-         %73 = OpLoad %uint %i
-         %75 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %73
-         %76 = OpLoad %S_std140 %75
-         %72 = OpFunctionCall %S %conv_S %76
-               OpStore %71 %72
-               OpBranch %58
-         %58 = OpLabel
-         %77 = OpLoad %uint %i
-         %79 = OpIAdd %uint %77 %uint_1
-               OpStore %i %79
-               OpBranch %56
-         %57 = OpLabel
-         %80 = OpLoad %_arr_S_uint_4 %arr
-               OpReturnValue %80
-               OpFunctionEnd
-%load_u_inner_2_m = OpFunction %mat3v2float None %81
-         %83 = OpLabel
-         %88 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
-         %91 = OpAccessChain %_ptr_Uniform_v2float %88 %uint_1
-         %92 = OpLoad %v2float %91
-         %94 = OpAccessChain %_ptr_Uniform_v2float %88 %uint_2
-         %95 = OpLoad %v2float %94
-         %98 = OpAccessChain %_ptr_Uniform_v2float %88 %uint_3
-         %99 = OpLoad %v2float %98
-        %100 = OpCompositeConstruct %mat3v2float %92 %95 %99
-               OpReturnValue %100
-               OpFunctionEnd
-          %f = OpFunction %void None %101
-        %103 = OpLabel
-        %107 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
-        %108 = OpLoad %_arr_S_std140_uint_4 %107
-        %105 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %108
-        %104 = OpFunctionCall %void %a %105
-        %111 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
-        %112 = OpLoad %S_std140 %111
-        %110 = OpFunctionCall %S %conv_S %112
-        %109 = OpFunctionCall %void %b %110
-        %114 = OpFunctionCall %mat3v2float %load_u_inner_2_m
-        %113 = OpFunctionCall %void %c %114
-        %116 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %55 %uint_2
-        %117 = OpLoad %v2float %116
-        %118 = OpVectorShuffle %v2float %117 %117 1 0
-        %115 = OpFunctionCall %void %d %118
-        %120 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %55 %uint_2
-        %121 = OpLoad %v2float %120
-        %122 = OpVectorShuffle %v2float %121 %121 1 0
-        %123 = OpCompositeExtract %float %122 0
-        %119 = OpFunctionCall %void %e %123
-               OpReturn
-               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x2/to_fn.wgsl.expected.wgsl
deleted file mode 100644
index b7ca757..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/to_fn.wgsl.expected.wgsl
+++ /dev/null
@@ -1,32 +0,0 @@
-struct S {
-  before : i32,
-  @size(64)
-  m : mat3x2<f32>,
-  after : i32,
-}
-
-@group(0) @binding(0) var<uniform> u : array<S, 4>;
-
-fn a(a : array<S, 4>) {
-}
-
-fn b(s : S) {
-}
-
-fn c(m : mat3x2<f32>) {
-}
-
-fn d(v : vec2<f32>) {
-}
-
-fn e(f : f32) {
-}
-
-@compute @workgroup_size(1)
-fn f() {
-  a(u);
-  b(u[2]);
-  c(u[2].m);
-  d(u[0].m[1].yx);
-  e(u[0].m[1].yx.x);
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/to_private.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x2/to_private.wgsl
deleted file mode 100644
index be13ffc..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/to_private.wgsl
+++ /dev/null
@@ -1,16 +0,0 @@
-struct S {
-  before : i32,
-  @size(64) m : mat3x2<f32>,
-  after : i32,
-}
-
-@group(0) @binding(0) var<uniform> u : array<S, 4>;
-var<private> p : array<S, 4>;
-
-@compute @workgroup_size(1)
-fn f() {
-    p = u;
-    p[1] = u[2];
-    p[3].m = u[2].m;
-    p[1].m[0] = u[0].m[1].yx;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x2/to_private.wgsl.expected.dxc.hlsl
deleted file mode 100644
index e1c3960..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/to_private.wgsl.expected.dxc.hlsl
+++ /dev/null
@@ -1,47 +0,0 @@
-struct S {
-  int before;
-  float3x2 m;
-  int after;
-};
-
-cbuffer cbuffer_u : register(b0, space0) {
-  uint4 u[20];
-};
-static S p[4] = (S[4])0;
-
-float3x2 tint_symbol_3(uint4 buffer[20], uint offset) {
-  const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset / 4];
-  const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
-  const uint scalar_offset_2 = ((offset + 16u)) / 4;
-  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
-  return float3x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)));
-}
-
-S tint_symbol_1(uint4 buffer[20], uint offset) {
-  const uint scalar_offset_3 = ((offset + 0u)) / 4;
-  const uint scalar_offset_4 = ((offset + 72u)) / 4;
-  const S tint_symbol_5 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
-  return tint_symbol_5;
-}
-
-typedef S tint_symbol_ret[4];
-tint_symbol_ret tint_symbol(uint4 buffer[20], uint offset) {
-  S arr[4] = (S[4])0;
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      arr[i] = tint_symbol_1(buffer, (offset + (i * 80u)));
-    }
-  }
-  return arr;
-}
-
-[numthreads(1, 1, 1)]
-void f() {
-  p = tint_symbol(u, 0u);
-  p[1] = tint_symbol_1(u, 160u);
-  p[3].m = tint_symbol_3(u, 168u);
-  p[1].m[0] = asfloat(u[1].xy).yx;
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x2/to_private.wgsl.expected.fxc.hlsl
deleted file mode 100644
index e1c3960..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/to_private.wgsl.expected.fxc.hlsl
+++ /dev/null
@@ -1,47 +0,0 @@
-struct S {
-  int before;
-  float3x2 m;
-  int after;
-};
-
-cbuffer cbuffer_u : register(b0, space0) {
-  uint4 u[20];
-};
-static S p[4] = (S[4])0;
-
-float3x2 tint_symbol_3(uint4 buffer[20], uint offset) {
-  const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset / 4];
-  const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
-  const uint scalar_offset_2 = ((offset + 16u)) / 4;
-  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
-  return float3x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)));
-}
-
-S tint_symbol_1(uint4 buffer[20], uint offset) {
-  const uint scalar_offset_3 = ((offset + 0u)) / 4;
-  const uint scalar_offset_4 = ((offset + 72u)) / 4;
-  const S tint_symbol_5 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
-  return tint_symbol_5;
-}
-
-typedef S tint_symbol_ret[4];
-tint_symbol_ret tint_symbol(uint4 buffer[20], uint offset) {
-  S arr[4] = (S[4])0;
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      arr[i] = tint_symbol_1(buffer, (offset + (i * 80u)));
-    }
-  }
-  return arr;
-}
-
-[numthreads(1, 1, 1)]
-void f() {
-  p = tint_symbol(u, 0u);
-  p[1] = tint_symbol_1(u, 160u);
-  p[3].m = tint_symbol_3(u, 168u);
-  p[1].m[0] = asfloat(u[1].xy).yx;
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x2/to_private.wgsl.expected.glsl
deleted file mode 100644
index 7c90023..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/to_private.wgsl.expected.glsl
+++ /dev/null
@@ -1,75 +0,0 @@
-#version 310 es
-
-struct S {
-  int before;
-  uint pad;
-  mat3x2 m;
-  uint pad_1;
-  uint pad_2;
-  uint pad_3;
-  uint pad_4;
-  uint pad_5;
-  uint pad_6;
-  uint pad_7;
-  uint pad_8;
-  uint pad_9;
-  uint pad_10;
-  int after;
-  uint pad_11;
-};
-
-struct S_std140 {
-  int before;
-  uint pad;
-  vec2 m_0;
-  vec2 m_1;
-  vec2 m_2;
-  uint pad_1;
-  uint pad_2;
-  uint pad_3;
-  uint pad_4;
-  uint pad_5;
-  uint pad_6;
-  uint pad_7;
-  uint pad_8;
-  uint pad_9;
-  uint pad_10;
-  int after;
-  uint pad_11;
-};
-
-layout(binding = 0, std140) uniform u_block_std140_ubo {
-  S_std140 inner[4];
-} u;
-
-S p[4] = S[4](S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u), S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u), S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u), S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u));
-S conv_S(S_std140 val) {
-  return S(val.before, val.pad, mat3x2(val.m_0, val.m_1, val.m_2), val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.after, val.pad_11);
-}
-
-S[4] conv_arr4_S(S_std140 val[4]) {
-  S arr[4] = S[4](S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u), S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u), S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u), S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u));
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      arr[i] = conv_S(val[i]);
-    }
-  }
-  return arr;
-}
-
-mat3x2 load_u_inner_2_m() {
-  return mat3x2(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2);
-}
-
-void f() {
-  p = conv_arr4_S(u.inner);
-  p[1] = conv_S(u.inner[2u]);
-  p[3].m = load_u_inner_2_m();
-  p[1].m[0] = u.inner[0u].m_1.yx;
-}
-
-layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
-void main() {
-  f();
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x2/to_private.wgsl.expected.msl
deleted file mode 100644
index 2e60d0f..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/to_private.wgsl.expected.msl
+++ /dev/null
@@ -1,34 +0,0 @@
-#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 S {
-  /* 0x0000 */ int before;
-  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
-  /* 0x0008 */ float3x2 m;
-  /* 0x0020 */ tint_array<int8_t, 40> tint_pad_1;
-  /* 0x0048 */ int after;
-  /* 0x004c */ tint_array<int8_t, 4> tint_pad_2;
-};
-
-kernel void f(const constant tint_array<S, 4>* tint_symbol_1 [[buffer(0)]]) {
-  thread tint_array<S, 4> tint_symbol = {};
-  tint_symbol = *(tint_symbol_1);
-  tint_symbol[1] = (*(tint_symbol_1))[2];
-  tint_symbol[3].m = (*(tint_symbol_1))[2].m;
-  tint_symbol[1].m[0] = float2((*(tint_symbol_1))[0].m[1]).yx;
-  return;
-}
-
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x2/to_private.wgsl.expected.spvasm
deleted file mode 100644
index 4cadc2f..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/to_private.wgsl.expected.spvasm
+++ /dev/null
@@ -1,173 +0,0 @@
-; SPIR-V
-; Version: 1.3
-; Generator: Google Tint Compiler; 0
-; Bound: 106
-; Schema: 0
-               OpCapability Shader
-               OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %f "f"
-               OpExecutionMode %f LocalSize 1 1 1
-               OpName %u_block_std140 "u_block_std140"
-               OpMemberName %u_block_std140 0 "inner"
-               OpName %S_std140 "S_std140"
-               OpMemberName %S_std140 0 "before"
-               OpMemberName %S_std140 1 "m_0"
-               OpMemberName %S_std140 2 "m_1"
-               OpMemberName %S_std140 3 "m_2"
-               OpMemberName %S_std140 4 "after"
-               OpName %u "u"
-               OpName %S "S"
-               OpMemberName %S 0 "before"
-               OpMemberName %S 1 "m"
-               OpMemberName %S 2 "after"
-               OpName %p "p"
-               OpName %conv_S "conv_S"
-               OpName %val "val"
-               OpName %conv_arr4_S "conv_arr4_S"
-               OpName %val_0 "val"
-               OpName %arr "arr"
-               OpName %i "i"
-               OpName %var_for_index "var_for_index"
-               OpName %load_u_inner_2_m "load_u_inner_2_m"
-               OpName %f "f"
-               OpDecorate %u_block_std140 Block
-               OpMemberDecorate %u_block_std140 0 Offset 0
-               OpMemberDecorate %S_std140 0 Offset 0
-               OpMemberDecorate %S_std140 1 Offset 8
-               OpMemberDecorate %S_std140 2 Offset 16
-               OpMemberDecorate %S_std140 3 Offset 24
-               OpMemberDecorate %S_std140 4 Offset 72
-               OpDecorate %_arr_S_std140_uint_4 ArrayStride 80
-               OpDecorate %u NonWritable
-               OpDecorate %u DescriptorSet 0
-               OpDecorate %u Binding 0
-               OpMemberDecorate %S 0 Offset 0
-               OpMemberDecorate %S 1 Offset 8
-               OpMemberDecorate %S 1 ColMajor
-               OpMemberDecorate %S 1 MatrixStride 8
-               OpMemberDecorate %S 2 Offset 72
-               OpDecorate %_arr_S_uint_4 ArrayStride 80
-        %int = OpTypeInt 32 1
-      %float = OpTypeFloat 32
-    %v2float = OpTypeVector %float 2
-   %S_std140 = OpTypeStruct %int %v2float %v2float %v2float %int
-       %uint = OpTypeInt 32 0
-     %uint_4 = OpConstant %uint 4
-%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
-%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
-%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
-          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
-%mat3v2float = OpTypeMatrix %v2float 3
-          %S = OpTypeStruct %int %mat3v2float %int
-%_arr_S_uint_4 = OpTypeArray %S %uint_4
-%_ptr_Private__arr_S_uint_4 = OpTypePointer Private %_arr_S_uint_4
-         %16 = OpConstantNull %_arr_S_uint_4
-          %p = OpVariable %_ptr_Private__arr_S_uint_4 Private %16
-         %17 = OpTypeFunction %S %S_std140
-         %28 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
-%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
-%_ptr_Function_uint = OpTypePointer Function %uint
-         %36 = OpConstantNull %uint
-       %bool = OpTypeBool
-%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
-         %49 = OpConstantNull %_arr_S_std140_uint_4
-%_ptr_Function_S = OpTypePointer Function %S
-%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
-     %uint_1 = OpConstant %uint 1
-         %62 = OpTypeFunction %mat3v2float
-     %uint_0 = OpConstant %uint 0
-     %uint_2 = OpConstant %uint 2
-%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
-%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
-     %uint_3 = OpConstant %uint 3
-       %void = OpTypeVoid
-         %82 = OpTypeFunction %void
-%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
-      %int_1 = OpConstant %int 1
-%_ptr_Private_S = OpTypePointer Private %S
-      %int_3 = OpConstant %int 3
-%_ptr_Private_mat3v2float = OpTypePointer Private %mat3v2float
-        %100 = OpConstantNull %int
-%_ptr_Private_v2float = OpTypePointer Private %v2float
-     %conv_S = OpFunction %S None %17
-        %val = OpFunctionParameter %S_std140
-         %20 = OpLabel
-         %21 = OpCompositeExtract %int %val 0
-         %22 = OpCompositeExtract %v2float %val 1
-         %23 = OpCompositeExtract %v2float %val 2
-         %24 = OpCompositeExtract %v2float %val 3
-         %25 = OpCompositeConstruct %mat3v2float %22 %23 %24
-         %26 = OpCompositeExtract %int %val 4
-         %27 = OpCompositeConstruct %S %21 %25 %26
-               OpReturnValue %27
-               OpFunctionEnd
-%conv_arr4_S = OpFunction %_arr_S_uint_4 None %28
-      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
-         %31 = OpLabel
-        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %16
-          %i = OpVariable %_ptr_Function_uint Function %36
-%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %49
-               OpBranch %37
-         %37 = OpLabel
-               OpLoopMerge %38 %39 None
-               OpBranch %40
-         %40 = OpLabel
-         %42 = OpLoad %uint %i
-         %43 = OpULessThan %bool %42 %uint_4
-         %41 = OpLogicalNot %bool %43
-               OpSelectionMerge %45 None
-               OpBranchConditional %41 %46 %45
-         %46 = OpLabel
-               OpBranch %38
-         %45 = OpLabel
-               OpStore %var_for_index %val_0
-         %50 = OpLoad %uint %i
-         %52 = OpAccessChain %_ptr_Function_S %arr %50
-         %54 = OpLoad %uint %i
-         %56 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %54
-         %57 = OpLoad %S_std140 %56
-         %53 = OpFunctionCall %S %conv_S %57
-               OpStore %52 %53
-               OpBranch %39
-         %39 = OpLabel
-         %58 = OpLoad %uint %i
-         %60 = OpIAdd %uint %58 %uint_1
-               OpStore %i %60
-               OpBranch %37
-         %38 = OpLabel
-         %61 = OpLoad %_arr_S_uint_4 %arr
-               OpReturnValue %61
-               OpFunctionEnd
-%load_u_inner_2_m = OpFunction %mat3v2float None %62
-         %64 = OpLabel
-         %69 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
-         %72 = OpAccessChain %_ptr_Uniform_v2float %69 %uint_1
-         %73 = OpLoad %v2float %72
-         %75 = OpAccessChain %_ptr_Uniform_v2float %69 %uint_2
-         %76 = OpLoad %v2float %75
-         %79 = OpAccessChain %_ptr_Uniform_v2float %69 %uint_3
-         %80 = OpLoad %v2float %79
-         %81 = OpCompositeConstruct %mat3v2float %73 %76 %80
-               OpReturnValue %81
-               OpFunctionEnd
-          %f = OpFunction %void None %82
-         %85 = OpLabel
-         %88 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
-         %89 = OpLoad %_arr_S_std140_uint_4 %88
-         %86 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %89
-               OpStore %p %86
-         %92 = OpAccessChain %_ptr_Private_S %p %int_1
-         %94 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
-         %95 = OpLoad %S_std140 %94
-         %93 = OpFunctionCall %S %conv_S %95
-               OpStore %92 %93
-         %98 = OpAccessChain %_ptr_Private_mat3v2float %p %int_3 %uint_1
-         %99 = OpFunctionCall %mat3v2float %load_u_inner_2_m
-               OpStore %98 %99
-        %102 = OpAccessChain %_ptr_Private_v2float %p %int_1 %uint_1 %100
-        %103 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %36 %uint_2
-        %104 = OpLoad %v2float %103
-        %105 = OpVectorShuffle %v2float %104 %104 1 0
-               OpStore %102 %105
-               OpReturn
-               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x2/to_private.wgsl.expected.wgsl
deleted file mode 100644
index b0ff478..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/to_private.wgsl.expected.wgsl
+++ /dev/null
@@ -1,18 +0,0 @@
-struct S {
-  before : i32,
-  @size(64)
-  m : mat3x2<f32>,
-  after : i32,
-}
-
-@group(0) @binding(0) var<uniform> u : array<S, 4>;
-
-var<private> p : array<S, 4>;
-
-@compute @workgroup_size(1)
-fn f() {
-  p = u;
-  p[1] = u[2];
-  p[3].m = u[2].m;
-  p[1].m[0] = u[0].m[1].yx;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/to_storage.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x2/to_storage.wgsl
deleted file mode 100644
index 4848e4a..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/to_storage.wgsl
+++ /dev/null
@@ -1,16 +0,0 @@
-struct S {
-  before : i32,
-  @size(64) m : mat3x2<f32>,
-  after : i32,
-}
-
-@group(0) @binding(0) var<uniform> u : array<S, 4>;
-@group(0) @binding(1) var<storage, read_write> s : array<S, 4>;
-
-@compute @workgroup_size(1)
-fn f() {
-    s = u;
-    s[1] = u[2];
-    s[3].m = u[2].m;
-    s[1].m[0] = u[0].m[1].yx;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x2/to_storage.wgsl.expected.dxc.hlsl
deleted file mode 100644
index 4cf6e38..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/to_storage.wgsl.expected.dxc.hlsl
+++ /dev/null
@@ -1,68 +0,0 @@
-struct S {
-  int before;
-  float3x2 m;
-  int after;
-};
-
-cbuffer cbuffer_u : register(b0, space0) {
-  uint4 u[20];
-};
-RWByteAddressBuffer s : register(u1, space0);
-
-void tint_symbol_3(RWByteAddressBuffer buffer, uint offset, float3x2 value) {
-  buffer.Store2((offset + 0u), asuint(value[0u]));
-  buffer.Store2((offset + 8u), asuint(value[1u]));
-  buffer.Store2((offset + 16u), asuint(value[2u]));
-}
-
-void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, S value) {
-  buffer.Store((offset + 0u), asuint(value.before));
-  tint_symbol_3(buffer, (offset + 8u), value.m);
-  buffer.Store((offset + 72u), asuint(value.after));
-}
-
-void tint_symbol(RWByteAddressBuffer buffer, uint offset, S value[4]) {
-  S array[4] = value;
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      tint_symbol_1(buffer, (offset + (i * 80u)), array[i]);
-    }
-  }
-}
-
-float3x2 tint_symbol_8(uint4 buffer[20], uint offset) {
-  const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset / 4];
-  const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
-  const uint scalar_offset_2 = ((offset + 16u)) / 4;
-  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
-  return float3x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)));
-}
-
-S tint_symbol_6(uint4 buffer[20], uint offset) {
-  const uint scalar_offset_3 = ((offset + 0u)) / 4;
-  const uint scalar_offset_4 = ((offset + 72u)) / 4;
-  const S tint_symbol_10 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_8(buffer, (offset + 8u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
-  return tint_symbol_10;
-}
-
-typedef S tint_symbol_5_ret[4];
-tint_symbol_5_ret tint_symbol_5(uint4 buffer[20], uint offset) {
-  S arr[4] = (S[4])0;
-  {
-    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
-      arr[i_1] = tint_symbol_6(buffer, (offset + (i_1 * 80u)));
-    }
-  }
-  return arr;
-}
-
-[numthreads(1, 1, 1)]
-void f() {
-  tint_symbol(s, 0u, tint_symbol_5(u, 0u));
-  tint_symbol_1(s, 80u, tint_symbol_6(u, 160u));
-  tint_symbol_3(s, 248u, tint_symbol_8(u, 168u));
-  s.Store2(88u, asuint(asfloat(u[1].xy).yx));
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x2/to_storage.wgsl.expected.fxc.hlsl
deleted file mode 100644
index 4cf6e38..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/to_storage.wgsl.expected.fxc.hlsl
+++ /dev/null
@@ -1,68 +0,0 @@
-struct S {
-  int before;
-  float3x2 m;
-  int after;
-};
-
-cbuffer cbuffer_u : register(b0, space0) {
-  uint4 u[20];
-};
-RWByteAddressBuffer s : register(u1, space0);
-
-void tint_symbol_3(RWByteAddressBuffer buffer, uint offset, float3x2 value) {
-  buffer.Store2((offset + 0u), asuint(value[0u]));
-  buffer.Store2((offset + 8u), asuint(value[1u]));
-  buffer.Store2((offset + 16u), asuint(value[2u]));
-}
-
-void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, S value) {
-  buffer.Store((offset + 0u), asuint(value.before));
-  tint_symbol_3(buffer, (offset + 8u), value.m);
-  buffer.Store((offset + 72u), asuint(value.after));
-}
-
-void tint_symbol(RWByteAddressBuffer buffer, uint offset, S value[4]) {
-  S array[4] = value;
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      tint_symbol_1(buffer, (offset + (i * 80u)), array[i]);
-    }
-  }
-}
-
-float3x2 tint_symbol_8(uint4 buffer[20], uint offset) {
-  const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset / 4];
-  const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
-  const uint scalar_offset_2 = ((offset + 16u)) / 4;
-  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
-  return float3x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)));
-}
-
-S tint_symbol_6(uint4 buffer[20], uint offset) {
-  const uint scalar_offset_3 = ((offset + 0u)) / 4;
-  const uint scalar_offset_4 = ((offset + 72u)) / 4;
-  const S tint_symbol_10 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_8(buffer, (offset + 8u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
-  return tint_symbol_10;
-}
-
-typedef S tint_symbol_5_ret[4];
-tint_symbol_5_ret tint_symbol_5(uint4 buffer[20], uint offset) {
-  S arr[4] = (S[4])0;
-  {
-    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
-      arr[i_1] = tint_symbol_6(buffer, (offset + (i_1 * 80u)));
-    }
-  }
-  return arr;
-}
-
-[numthreads(1, 1, 1)]
-void f() {
-  tint_symbol(s, 0u, tint_symbol_5(u, 0u));
-  tint_symbol_1(s, 80u, tint_symbol_6(u, 160u));
-  tint_symbol_3(s, 248u, tint_symbol_8(u, 168u));
-  s.Store2(88u, asuint(asfloat(u[1].xy).yx));
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x2/to_storage.wgsl.expected.glsl
deleted file mode 100644
index 4013cf5..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/to_storage.wgsl.expected.glsl
+++ /dev/null
@@ -1,78 +0,0 @@
-#version 310 es
-
-struct S {
-  int before;
-  uint pad;
-  mat3x2 m;
-  uint pad_1;
-  uint pad_2;
-  uint pad_3;
-  uint pad_4;
-  uint pad_5;
-  uint pad_6;
-  uint pad_7;
-  uint pad_8;
-  uint pad_9;
-  uint pad_10;
-  int after;
-  uint pad_11;
-};
-
-struct S_std140 {
-  int before;
-  uint pad;
-  vec2 m_0;
-  vec2 m_1;
-  vec2 m_2;
-  uint pad_1;
-  uint pad_2;
-  uint pad_3;
-  uint pad_4;
-  uint pad_5;
-  uint pad_6;
-  uint pad_7;
-  uint pad_8;
-  uint pad_9;
-  uint pad_10;
-  int after;
-  uint pad_11;
-};
-
-layout(binding = 0, std140) uniform u_block_std140_ubo {
-  S_std140 inner[4];
-} u;
-
-layout(binding = 1, std430) buffer u_block_ssbo {
-  S inner[4];
-} s;
-
-S conv_S(S_std140 val) {
-  return S(val.before, val.pad, mat3x2(val.m_0, val.m_1, val.m_2), val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.after, val.pad_11);
-}
-
-S[4] conv_arr4_S(S_std140 val[4]) {
-  S arr[4] = S[4](S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u), S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u), S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u), S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u));
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      arr[i] = conv_S(val[i]);
-    }
-  }
-  return arr;
-}
-
-mat3x2 load_u_inner_2_m() {
-  return mat3x2(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2);
-}
-
-void f() {
-  s.inner = conv_arr4_S(u.inner);
-  s.inner[1] = conv_S(u.inner[2u]);
-  s.inner[3].m = load_u_inner_2_m();
-  s.inner[1].m[0] = u.inner[0u].m_1.yx;
-}
-
-layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
-void main() {
-  f();
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x2/to_storage.wgsl.expected.msl
deleted file mode 100644
index 0ee4e4c..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/to_storage.wgsl.expected.msl
+++ /dev/null
@@ -1,33 +0,0 @@
-#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 S {
-  /* 0x0000 */ int before;
-  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
-  /* 0x0008 */ float3x2 m;
-  /* 0x0020 */ tint_array<int8_t, 40> tint_pad_1;
-  /* 0x0048 */ int after;
-  /* 0x004c */ tint_array<int8_t, 4> tint_pad_2;
-};
-
-kernel void f(device tint_array<S, 4>* tint_symbol [[buffer(1)]], const constant tint_array<S, 4>* tint_symbol_1 [[buffer(0)]]) {
-  *(tint_symbol) = *(tint_symbol_1);
-  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
-  (*(tint_symbol))[3].m = (*(tint_symbol_1))[2].m;
-  (*(tint_symbol))[1].m[0] = float2((*(tint_symbol_1))[0].m[1]).yx;
-  return;
-}
-
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x2/to_storage.wgsl.expected.spvasm
deleted file mode 100644
index 93ef04f..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/to_storage.wgsl.expected.spvasm
+++ /dev/null
@@ -1,182 +0,0 @@
-; SPIR-V
-; Version: 1.3
-; Generator: Google Tint Compiler; 0
-; Bound: 109
-; Schema: 0
-               OpCapability Shader
-               OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %f "f"
-               OpExecutionMode %f LocalSize 1 1 1
-               OpName %u_block_std140 "u_block_std140"
-               OpMemberName %u_block_std140 0 "inner"
-               OpName %S_std140 "S_std140"
-               OpMemberName %S_std140 0 "before"
-               OpMemberName %S_std140 1 "m_0"
-               OpMemberName %S_std140 2 "m_1"
-               OpMemberName %S_std140 3 "m_2"
-               OpMemberName %S_std140 4 "after"
-               OpName %u "u"
-               OpName %u_block "u_block"
-               OpMemberName %u_block 0 "inner"
-               OpName %S "S"
-               OpMemberName %S 0 "before"
-               OpMemberName %S 1 "m"
-               OpMemberName %S 2 "after"
-               OpName %s "s"
-               OpName %conv_S "conv_S"
-               OpName %val "val"
-               OpName %conv_arr4_S "conv_arr4_S"
-               OpName %val_0 "val"
-               OpName %arr "arr"
-               OpName %i "i"
-               OpName %var_for_index "var_for_index"
-               OpName %load_u_inner_2_m "load_u_inner_2_m"
-               OpName %f "f"
-               OpDecorate %u_block_std140 Block
-               OpMemberDecorate %u_block_std140 0 Offset 0
-               OpMemberDecorate %S_std140 0 Offset 0
-               OpMemberDecorate %S_std140 1 Offset 8
-               OpMemberDecorate %S_std140 2 Offset 16
-               OpMemberDecorate %S_std140 3 Offset 24
-               OpMemberDecorate %S_std140 4 Offset 72
-               OpDecorate %_arr_S_std140_uint_4 ArrayStride 80
-               OpDecorate %u NonWritable
-               OpDecorate %u DescriptorSet 0
-               OpDecorate %u Binding 0
-               OpDecorate %u_block Block
-               OpMemberDecorate %u_block 0 Offset 0
-               OpMemberDecorate %S 0 Offset 0
-               OpMemberDecorate %S 1 Offset 8
-               OpMemberDecorate %S 1 ColMajor
-               OpMemberDecorate %S 1 MatrixStride 8
-               OpMemberDecorate %S 2 Offset 72
-               OpDecorate %_arr_S_uint_4 ArrayStride 80
-               OpDecorate %s DescriptorSet 0
-               OpDecorate %s Binding 1
-        %int = OpTypeInt 32 1
-      %float = OpTypeFloat 32
-    %v2float = OpTypeVector %float 2
-   %S_std140 = OpTypeStruct %int %v2float %v2float %v2float %int
-       %uint = OpTypeInt 32 0
-     %uint_4 = OpConstant %uint 4
-%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
-%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
-%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
-          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
-%mat3v2float = OpTypeMatrix %v2float 3
-          %S = OpTypeStruct %int %mat3v2float %int
-%_arr_S_uint_4 = OpTypeArray %S %uint_4
-    %u_block = OpTypeStruct %_arr_S_uint_4
-%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
-          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
-         %17 = OpTypeFunction %S %S_std140
-         %28 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
-%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
-         %34 = OpConstantNull %_arr_S_uint_4
-%_ptr_Function_uint = OpTypePointer Function %uint
-         %37 = OpConstantNull %uint
-       %bool = OpTypeBool
-%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
-         %50 = OpConstantNull %_arr_S_std140_uint_4
-%_ptr_Function_S = OpTypePointer Function %S
-%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
-     %uint_1 = OpConstant %uint 1
-         %63 = OpTypeFunction %mat3v2float
-     %uint_0 = OpConstant %uint 0
-     %uint_2 = OpConstant %uint 2
-%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
-%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
-     %uint_3 = OpConstant %uint 3
-       %void = OpTypeVoid
-         %83 = OpTypeFunction %void
-%_ptr_StorageBuffer__arr_S_uint_4 = OpTypePointer StorageBuffer %_arr_S_uint_4
-%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
-      %int_1 = OpConstant %int 1
-%_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
-      %int_3 = OpConstant %int 3
-%_ptr_StorageBuffer_mat3v2float = OpTypePointer StorageBuffer %mat3v2float
-        %103 = OpConstantNull %int
-%_ptr_StorageBuffer_v2float = OpTypePointer StorageBuffer %v2float
-     %conv_S = OpFunction %S None %17
-        %val = OpFunctionParameter %S_std140
-         %20 = OpLabel
-         %21 = OpCompositeExtract %int %val 0
-         %22 = OpCompositeExtract %v2float %val 1
-         %23 = OpCompositeExtract %v2float %val 2
-         %24 = OpCompositeExtract %v2float %val 3
-         %25 = OpCompositeConstruct %mat3v2float %22 %23 %24
-         %26 = OpCompositeExtract %int %val 4
-         %27 = OpCompositeConstruct %S %21 %25 %26
-               OpReturnValue %27
-               OpFunctionEnd
-%conv_arr4_S = OpFunction %_arr_S_uint_4 None %28
-      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
-         %31 = OpLabel
-        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %34
-          %i = OpVariable %_ptr_Function_uint Function %37
-%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %50
-               OpBranch %38
-         %38 = OpLabel
-               OpLoopMerge %39 %40 None
-               OpBranch %41
-         %41 = OpLabel
-         %43 = OpLoad %uint %i
-         %44 = OpULessThan %bool %43 %uint_4
-         %42 = OpLogicalNot %bool %44
-               OpSelectionMerge %46 None
-               OpBranchConditional %42 %47 %46
-         %47 = OpLabel
-               OpBranch %39
-         %46 = OpLabel
-               OpStore %var_for_index %val_0
-         %51 = OpLoad %uint %i
-         %53 = OpAccessChain %_ptr_Function_S %arr %51
-         %55 = OpLoad %uint %i
-         %57 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %55
-         %58 = OpLoad %S_std140 %57
-         %54 = OpFunctionCall %S %conv_S %58
-               OpStore %53 %54
-               OpBranch %40
-         %40 = OpLabel
-         %59 = OpLoad %uint %i
-         %61 = OpIAdd %uint %59 %uint_1
-               OpStore %i %61
-               OpBranch %38
-         %39 = OpLabel
-         %62 = OpLoad %_arr_S_uint_4 %arr
-               OpReturnValue %62
-               OpFunctionEnd
-%load_u_inner_2_m = OpFunction %mat3v2float None %63
-         %65 = OpLabel
-         %70 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
-         %73 = OpAccessChain %_ptr_Uniform_v2float %70 %uint_1
-         %74 = OpLoad %v2float %73
-         %76 = OpAccessChain %_ptr_Uniform_v2float %70 %uint_2
-         %77 = OpLoad %v2float %76
-         %80 = OpAccessChain %_ptr_Uniform_v2float %70 %uint_3
-         %81 = OpLoad %v2float %80
-         %82 = OpCompositeConstruct %mat3v2float %74 %77 %81
-               OpReturnValue %82
-               OpFunctionEnd
-          %f = OpFunction %void None %83
-         %86 = OpLabel
-         %88 = OpAccessChain %_ptr_StorageBuffer__arr_S_uint_4 %s %uint_0
-         %91 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
-         %92 = OpLoad %_arr_S_std140_uint_4 %91
-         %89 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %92
-               OpStore %88 %89
-         %95 = OpAccessChain %_ptr_StorageBuffer_S %s %uint_0 %int_1
-         %97 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
-         %98 = OpLoad %S_std140 %97
-         %96 = OpFunctionCall %S %conv_S %98
-               OpStore %95 %96
-        %101 = OpAccessChain %_ptr_StorageBuffer_mat3v2float %s %uint_0 %int_3 %uint_1
-        %102 = OpFunctionCall %mat3v2float %load_u_inner_2_m
-               OpStore %101 %102
-        %105 = OpAccessChain %_ptr_StorageBuffer_v2float %s %uint_0 %int_1 %uint_1 %103
-        %106 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %37 %uint_2
-        %107 = OpLoad %v2float %106
-        %108 = OpVectorShuffle %v2float %107 %107 1 0
-               OpStore %105 %108
-               OpReturn
-               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x2/to_storage.wgsl.expected.wgsl
deleted file mode 100644
index 56b0f84..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/to_storage.wgsl.expected.wgsl
+++ /dev/null
@@ -1,18 +0,0 @@
-struct S {
-  before : i32,
-  @size(64)
-  m : mat3x2<f32>,
-  after : i32,
-}
-
-@group(0) @binding(0) var<uniform> u : array<S, 4>;
-
-@group(0) @binding(1) var<storage, read_write> s : array<S, 4>;
-
-@compute @workgroup_size(1)
-fn f() {
-  s = u;
-  s[1] = u[2];
-  s[3].m = u[2].m;
-  s[1].m[0] = u[0].m[1].yx;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x2/to_workgroup.wgsl
deleted file mode 100644
index 282f12d..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/to_workgroup.wgsl
+++ /dev/null
@@ -1,16 +0,0 @@
-struct S {
-  before : i32,
-  @size(64) m : mat3x2<f32>,
-  after : i32,
-}
-
-@group(0) @binding(0) var<uniform> u : array<S, 4>;
-var<workgroup> w : array<S, 4>;
-
-@compute @workgroup_size(1)
-fn f() {
-    w = u;
-    w[1] = u[2];
-    w[3].m = u[2].m;
-    w[1].m[0] = u[0].m[1].yx;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x2/to_workgroup.wgsl.expected.dxc.hlsl
deleted file mode 100644
index 1da5b98..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/to_workgroup.wgsl.expected.dxc.hlsl
+++ /dev/null
@@ -1,63 +0,0 @@
-struct S {
-  int before;
-  float3x2 m;
-  int after;
-};
-
-cbuffer cbuffer_u : register(b0, space0) {
-  uint4 u[20];
-};
-groupshared S w[4];
-
-struct tint_symbol_1 {
-  uint local_invocation_index : SV_GroupIndex;
-};
-
-float3x2 tint_symbol_5(uint4 buffer[20], uint offset) {
-  const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset / 4];
-  const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
-  const uint scalar_offset_2 = ((offset + 16u)) / 4;
-  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
-  return float3x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)));
-}
-
-S tint_symbol_3(uint4 buffer[20], uint offset) {
-  const uint scalar_offset_3 = ((offset + 0u)) / 4;
-  const uint scalar_offset_4 = ((offset + 72u)) / 4;
-  const S tint_symbol_8 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_5(buffer, (offset + 8u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
-  return tint_symbol_8;
-}
-
-typedef S tint_symbol_2_ret[4];
-tint_symbol_2_ret tint_symbol_2(uint4 buffer[20], uint offset) {
-  S arr[4] = (S[4])0;
-  {
-    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
-      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 80u)));
-    }
-  }
-  return arr;
-}
-
-void f_inner(uint local_invocation_index) {
-  {
-    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
-      const uint i = idx;
-      const S tint_symbol_7 = (S)0;
-      w[i] = tint_symbol_7;
-    }
-  }
-  GroupMemoryBarrierWithGroupSync();
-  w = tint_symbol_2(u, 0u);
-  w[1] = tint_symbol_3(u, 160u);
-  w[3].m = tint_symbol_5(u, 168u);
-  w[1].m[0] = asfloat(u[1].xy).yx;
-}
-
-[numthreads(1, 1, 1)]
-void f(tint_symbol_1 tint_symbol) {
-  f_inner(tint_symbol.local_invocation_index);
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x2/to_workgroup.wgsl.expected.fxc.hlsl
deleted file mode 100644
index 1da5b98..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/to_workgroup.wgsl.expected.fxc.hlsl
+++ /dev/null
@@ -1,63 +0,0 @@
-struct S {
-  int before;
-  float3x2 m;
-  int after;
-};
-
-cbuffer cbuffer_u : register(b0, space0) {
-  uint4 u[20];
-};
-groupshared S w[4];
-
-struct tint_symbol_1 {
-  uint local_invocation_index : SV_GroupIndex;
-};
-
-float3x2 tint_symbol_5(uint4 buffer[20], uint offset) {
-  const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset / 4];
-  const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
-  const uint scalar_offset_2 = ((offset + 16u)) / 4;
-  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
-  return float3x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)));
-}
-
-S tint_symbol_3(uint4 buffer[20], uint offset) {
-  const uint scalar_offset_3 = ((offset + 0u)) / 4;
-  const uint scalar_offset_4 = ((offset + 72u)) / 4;
-  const S tint_symbol_8 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_5(buffer, (offset + 8u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
-  return tint_symbol_8;
-}
-
-typedef S tint_symbol_2_ret[4];
-tint_symbol_2_ret tint_symbol_2(uint4 buffer[20], uint offset) {
-  S arr[4] = (S[4])0;
-  {
-    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
-      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 80u)));
-    }
-  }
-  return arr;
-}
-
-void f_inner(uint local_invocation_index) {
-  {
-    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
-      const uint i = idx;
-      const S tint_symbol_7 = (S)0;
-      w[i] = tint_symbol_7;
-    }
-  }
-  GroupMemoryBarrierWithGroupSync();
-  w = tint_symbol_2(u, 0u);
-  w[1] = tint_symbol_3(u, 160u);
-  w[3].m = tint_symbol_5(u, 168u);
-  w[1].m[0] = asfloat(u[1].xy).yx;
-}
-
-[numthreads(1, 1, 1)]
-void f(tint_symbol_1 tint_symbol) {
-  f_inner(tint_symbol.local_invocation_index);
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x2/to_workgroup.wgsl.expected.glsl
deleted file mode 100644
index 9c72f93..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/to_workgroup.wgsl.expected.glsl
+++ /dev/null
@@ -1,83 +0,0 @@
-#version 310 es
-
-struct S {
-  int before;
-  uint pad;
-  mat3x2 m;
-  uint pad_1;
-  uint pad_2;
-  uint pad_3;
-  uint pad_4;
-  uint pad_5;
-  uint pad_6;
-  uint pad_7;
-  uint pad_8;
-  uint pad_9;
-  uint pad_10;
-  int after;
-  uint pad_11;
-};
-
-struct S_std140 {
-  int before;
-  uint pad;
-  vec2 m_0;
-  vec2 m_1;
-  vec2 m_2;
-  uint pad_1;
-  uint pad_2;
-  uint pad_3;
-  uint pad_4;
-  uint pad_5;
-  uint pad_6;
-  uint pad_7;
-  uint pad_8;
-  uint pad_9;
-  uint pad_10;
-  int after;
-  uint pad_11;
-};
-
-layout(binding = 0, std140) uniform u_block_std140_ubo {
-  S_std140 inner[4];
-} u;
-
-shared S w[4];
-S conv_S(S_std140 val) {
-  return S(val.before, val.pad, mat3x2(val.m_0, val.m_1, val.m_2), val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.after, val.pad_11);
-}
-
-S[4] conv_arr4_S(S_std140 val[4]) {
-  S arr[4] = S[4](S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u), S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u), S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u), S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u));
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      arr[i] = conv_S(val[i]);
-    }
-  }
-  return arr;
-}
-
-mat3x2 load_u_inner_2_m() {
-  return mat3x2(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2);
-}
-
-void f(uint local_invocation_index) {
-  {
-    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
-      uint i = idx;
-      S tint_symbol = S(0, 0u, mat3x2(vec2(0.0f), vec2(0.0f), vec2(0.0f)), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u);
-      w[i] = tint_symbol;
-    }
-  }
-  barrier();
-  w = conv_arr4_S(u.inner);
-  w[1] = conv_S(u.inner[2u]);
-  w[3].m = load_u_inner_2_m();
-  w[1].m[0] = u.inner[0u].m_1.yx;
-}
-
-layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
-void main() {
-  f(gl_LocalInvocationIndex);
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x2/to_workgroup.wgsl.expected.msl
deleted file mode 100644
index 97de8a8..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/to_workgroup.wgsl.expected.msl
+++ /dev/null
@@ -1,48 +0,0 @@
-#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 S {
-  /* 0x0000 */ int before;
-  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
-  /* 0x0008 */ float3x2 m;
-  /* 0x0020 */ tint_array<int8_t, 40> tint_pad_1;
-  /* 0x0048 */ int after;
-  /* 0x004c */ tint_array<int8_t, 4> tint_pad_2;
-};
-
-struct tint_symbol_6 {
-  tint_array<S, 4> w;
-};
-
-void f_inner(uint local_invocation_index, threadgroup tint_array<S, 4>* const tint_symbol_1, const constant tint_array<S, 4>* const tint_symbol_2) {
-  for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
-    uint const i = idx;
-    S const tint_symbol = S{};
-    (*(tint_symbol_1))[i] = tint_symbol;
-  }
-  threadgroup_barrier(mem_flags::mem_threadgroup);
-  *(tint_symbol_1) = *(tint_symbol_2);
-  (*(tint_symbol_1))[1] = (*(tint_symbol_2))[2];
-  (*(tint_symbol_1))[3].m = (*(tint_symbol_2))[2].m;
-  (*(tint_symbol_1))[1].m[0] = float2((*(tint_symbol_2))[0].m[1]).yx;
-}
-
-kernel void f(const constant tint_array<S, 4>* tint_symbol_5 [[buffer(0)]], threadgroup tint_symbol_6* tint_symbol_4 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
-  threadgroup tint_array<S, 4>* const tint_symbol_3 = &((*(tint_symbol_4)).w);
-  f_inner(local_invocation_index, tint_symbol_3, tint_symbol_5);
-  return;
-}
-
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x2/to_workgroup.wgsl.expected.spvasm
deleted file mode 100644
index be09c71..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/to_workgroup.wgsl.expected.spvasm
+++ /dev/null
@@ -1,216 +0,0 @@
-; SPIR-V
-; Version: 1.3
-; Generator: Google Tint Compiler; 0
-; Bound: 131
-; Schema: 0
-               OpCapability Shader
-               OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
-               OpExecutionMode %f LocalSize 1 1 1
-               OpName %local_invocation_index_1 "local_invocation_index_1"
-               OpName %u_block_std140 "u_block_std140"
-               OpMemberName %u_block_std140 0 "inner"
-               OpName %S_std140 "S_std140"
-               OpMemberName %S_std140 0 "before"
-               OpMemberName %S_std140 1 "m_0"
-               OpMemberName %S_std140 2 "m_1"
-               OpMemberName %S_std140 3 "m_2"
-               OpMemberName %S_std140 4 "after"
-               OpName %u "u"
-               OpName %S "S"
-               OpMemberName %S 0 "before"
-               OpMemberName %S 1 "m"
-               OpMemberName %S 2 "after"
-               OpName %w "w"
-               OpName %conv_S "conv_S"
-               OpName %val "val"
-               OpName %conv_arr4_S "conv_arr4_S"
-               OpName %val_0 "val"
-               OpName %arr "arr"
-               OpName %i "i"
-               OpName %var_for_index "var_for_index"
-               OpName %load_u_inner_2_m "load_u_inner_2_m"
-               OpName %f_inner "f_inner"
-               OpName %local_invocation_index "local_invocation_index"
-               OpName %idx "idx"
-               OpName %f "f"
-               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
-               OpDecorate %u_block_std140 Block
-               OpMemberDecorate %u_block_std140 0 Offset 0
-               OpMemberDecorate %S_std140 0 Offset 0
-               OpMemberDecorate %S_std140 1 Offset 8
-               OpMemberDecorate %S_std140 2 Offset 16
-               OpMemberDecorate %S_std140 3 Offset 24
-               OpMemberDecorate %S_std140 4 Offset 72
-               OpDecorate %_arr_S_std140_uint_4 ArrayStride 80
-               OpDecorate %u NonWritable
-               OpDecorate %u DescriptorSet 0
-               OpDecorate %u Binding 0
-               OpMemberDecorate %S 0 Offset 0
-               OpMemberDecorate %S 1 Offset 8
-               OpMemberDecorate %S 1 ColMajor
-               OpMemberDecorate %S 1 MatrixStride 8
-               OpMemberDecorate %S 2 Offset 72
-               OpDecorate %_arr_S_uint_4 ArrayStride 80
-       %uint = OpTypeInt 32 0
-%_ptr_Input_uint = OpTypePointer Input %uint
-%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
-        %int = OpTypeInt 32 1
-      %float = OpTypeFloat 32
-    %v2float = OpTypeVector %float 2
-   %S_std140 = OpTypeStruct %int %v2float %v2float %v2float %int
-     %uint_4 = OpConstant %uint 4
-%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
-%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
-%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
-          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
-%mat3v2float = OpTypeMatrix %v2float 3
-          %S = OpTypeStruct %int %mat3v2float %int
-%_arr_S_uint_4 = OpTypeArray %S %uint_4
-%_ptr_Workgroup__arr_S_uint_4 = OpTypePointer Workgroup %_arr_S_uint_4
-          %w = OpVariable %_ptr_Workgroup__arr_S_uint_4 Workgroup
-         %18 = OpTypeFunction %S %S_std140
-         %29 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
-%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
-         %35 = OpConstantNull %_arr_S_uint_4
-%_ptr_Function_uint = OpTypePointer Function %uint
-         %38 = OpConstantNull %uint
-       %bool = OpTypeBool
-%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
-         %51 = OpConstantNull %_arr_S_std140_uint_4
-%_ptr_Function_S = OpTypePointer Function %S
-%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
-     %uint_1 = OpConstant %uint 1
-         %64 = OpTypeFunction %mat3v2float
-     %uint_0 = OpConstant %uint 0
-     %uint_2 = OpConstant %uint 2
-%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
-%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
-     %uint_3 = OpConstant %uint 3
-       %void = OpTypeVoid
-         %84 = OpTypeFunction %void %uint
-%_ptr_Workgroup_S = OpTypePointer Workgroup %S
-        %102 = OpConstantNull %S
-   %uint_264 = OpConstant %uint 264
-%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
-      %int_1 = OpConstant %int 1
-      %int_3 = OpConstant %int 3
-%_ptr_Workgroup_mat3v2float = OpTypePointer Workgroup %mat3v2float
-        %120 = OpConstantNull %int
-%_ptr_Workgroup_v2float = OpTypePointer Workgroup %v2float
-        %126 = OpTypeFunction %void
-     %conv_S = OpFunction %S None %18
-        %val = OpFunctionParameter %S_std140
-         %21 = OpLabel
-         %22 = OpCompositeExtract %int %val 0
-         %23 = OpCompositeExtract %v2float %val 1
-         %24 = OpCompositeExtract %v2float %val 2
-         %25 = OpCompositeExtract %v2float %val 3
-         %26 = OpCompositeConstruct %mat3v2float %23 %24 %25
-         %27 = OpCompositeExtract %int %val 4
-         %28 = OpCompositeConstruct %S %22 %26 %27
-               OpReturnValue %28
-               OpFunctionEnd
-%conv_arr4_S = OpFunction %_arr_S_uint_4 None %29
-      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
-         %32 = OpLabel
-        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %35
-          %i = OpVariable %_ptr_Function_uint Function %38
-%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %51
-               OpBranch %39
-         %39 = OpLabel
-               OpLoopMerge %40 %41 None
-               OpBranch %42
-         %42 = OpLabel
-         %44 = OpLoad %uint %i
-         %45 = OpULessThan %bool %44 %uint_4
-         %43 = OpLogicalNot %bool %45
-               OpSelectionMerge %47 None
-               OpBranchConditional %43 %48 %47
-         %48 = OpLabel
-               OpBranch %40
-         %47 = OpLabel
-               OpStore %var_for_index %val_0
-         %52 = OpLoad %uint %i
-         %54 = OpAccessChain %_ptr_Function_S %arr %52
-         %56 = OpLoad %uint %i
-         %58 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %56
-         %59 = OpLoad %S_std140 %58
-         %55 = OpFunctionCall %S %conv_S %59
-               OpStore %54 %55
-               OpBranch %41
-         %41 = OpLabel
-         %60 = OpLoad %uint %i
-         %62 = OpIAdd %uint %60 %uint_1
-               OpStore %i %62
-               OpBranch %39
-         %40 = OpLabel
-         %63 = OpLoad %_arr_S_uint_4 %arr
-               OpReturnValue %63
-               OpFunctionEnd
-%load_u_inner_2_m = OpFunction %mat3v2float None %64
-         %66 = OpLabel
-         %71 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
-         %74 = OpAccessChain %_ptr_Uniform_v2float %71 %uint_1
-         %75 = OpLoad %v2float %74
-         %77 = OpAccessChain %_ptr_Uniform_v2float %71 %uint_2
-         %78 = OpLoad %v2float %77
-         %81 = OpAccessChain %_ptr_Uniform_v2float %71 %uint_3
-         %82 = OpLoad %v2float %81
-         %83 = OpCompositeConstruct %mat3v2float %75 %78 %82
-               OpReturnValue %83
-               OpFunctionEnd
-    %f_inner = OpFunction %void None %84
-%local_invocation_index = OpFunctionParameter %uint
-         %88 = OpLabel
-        %idx = OpVariable %_ptr_Function_uint Function %38
-               OpStore %idx %local_invocation_index
-               OpBranch %90
-         %90 = OpLabel
-               OpLoopMerge %91 %92 None
-               OpBranch %93
-         %93 = OpLabel
-         %95 = OpLoad %uint %idx
-         %96 = OpULessThan %bool %95 %uint_4
-         %94 = OpLogicalNot %bool %96
-               OpSelectionMerge %97 None
-               OpBranchConditional %94 %98 %97
-         %98 = OpLabel
-               OpBranch %91
-         %97 = OpLabel
-         %99 = OpLoad %uint %idx
-        %101 = OpAccessChain %_ptr_Workgroup_S %w %99
-               OpStore %101 %102
-               OpBranch %92
-         %92 = OpLabel
-        %103 = OpLoad %uint %idx
-        %104 = OpIAdd %uint %103 %uint_1
-               OpStore %idx %104
-               OpBranch %90
-         %91 = OpLabel
-               OpControlBarrier %uint_2 %uint_2 %uint_264
-        %109 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
-        %110 = OpLoad %_arr_S_std140_uint_4 %109
-        %107 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %110
-               OpStore %w %107
-        %112 = OpAccessChain %_ptr_Workgroup_S %w %int_1
-        %114 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
-        %115 = OpLoad %S_std140 %114
-        %113 = OpFunctionCall %S %conv_S %115
-               OpStore %112 %113
-        %118 = OpAccessChain %_ptr_Workgroup_mat3v2float %w %int_3 %uint_1
-        %119 = OpFunctionCall %mat3v2float %load_u_inner_2_m
-               OpStore %118 %119
-        %122 = OpAccessChain %_ptr_Workgroup_v2float %w %int_1 %uint_1 %120
-        %123 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %38 %uint_2
-        %124 = OpLoad %v2float %123
-        %125 = OpVectorShuffle %v2float %124 %124 1 0
-               OpStore %122 %125
-               OpReturn
-               OpFunctionEnd
-          %f = OpFunction %void None %126
-        %128 = OpLabel
-        %130 = OpLoad %uint %local_invocation_index_1
-        %129 = OpFunctionCall %void %f_inner %130
-               OpReturn
-               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x2/to_workgroup.wgsl.expected.wgsl
deleted file mode 100644
index 286d523..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat3x2/to_workgroup.wgsl.expected.wgsl
+++ /dev/null
@@ -1,18 +0,0 @@
-struct S {
-  before : i32,
-  @size(64)
-  m : mat3x2<f32>,
-  after : i32,
-}
-
-@group(0) @binding(0) var<uniform> u : array<S, 4>;
-
-var<workgroup> w : array<S, 4>;
-
-@compute @workgroup_size(1)
-fn f() {
-  w = u;
-  w[1] = u[2];
-  w[3].m = u[2].m;
-  w[1].m[0] = u[0].m[1].yx;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/dynamic_index_via_ptr.wgsl
new file mode 100644
index 0000000..8404ee4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/dynamic_index_via_ptr.wgsl
@@ -0,0 +1,34 @@
+enable f16;
+
+struct Inner {
+  @size(64)
+  m : mat3x2<f16>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a           = &a;
+  let p_a_i         = &((*p_a)[i()]);
+  let p_a_i_a       = &((*p_a_i).a);
+  let p_a_i_a_i     = &((*p_a_i_a)[i()]);
+  let p_a_i_a_i_m   = &((*p_a_i_a_i).m);
+  let p_a_i_a_i_m_i = &((*p_a_i_a_i_m)[i()]);
+
+
+  let l_a             : array<Outer, 4> =  *p_a;
+  let l_a_i           : Outer           =  *p_a_i;
+  let l_a_i_a         : array<Inner, 4> =  *p_a_i_a;
+  let l_a_i_a_i       : Inner           =  *p_a_i_a_i;
+  let l_a_i_a_i_m     : mat3x2<f16>     =  *p_a_i_a_i_m;
+  let l_a_i_a_i_m_i   : vec2<f16>       =  *p_a_i_a_i_m_i;
+  let l_a_i_a_i_m_i_i : f16             = (*p_a_i_a_i_m_i)[i()];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..33c5e7a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,81 @@
+struct Inner {
+  matrix<float16_t, 3, 2> m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 3, 2> tint_symbol_8(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  return matrix<float16_t, 3, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))));
+}
+
+Inner tint_symbol_7(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_11 = {tint_symbol_8(buffer, (offset + 0u))};
+  return tint_symbol_11;
+}
+
+typedef Inner tint_symbol_6_ret[4];
+tint_symbol_6_ret tint_symbol_6(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_7(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_5(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_12 = {tint_symbol_6(buffer, (offset + 0u))};
+  return tint_symbol_12;
+}
+
+typedef Outer tint_symbol_4_ret[4];
+tint_symbol_4_ret tint_symbol_4(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
+      arr_1[i_2] = tint_symbol_5(buffer, (offset + (i_2 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_a_i_save = i();
+  const int p_a_i_a_i_m_i_save = i();
+  const Outer l_a[4] = tint_symbol_4(a, 0u);
+  const Outer l_a_i = tint_symbol_5(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a[4] = tint_symbol_6(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a_i = tint_symbol_7(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const matrix<float16_t, 3, 2> l_a_i_a_i_m = tint_symbol_8(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const uint scalar_offset_3 = ((((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))) + (4u * uint(p_a_i_a_i_m_i_save)))) / 4;
+  uint ubo_load_3 = a[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  const vector<float16_t, 2> l_a_i_a_i_m_i = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16)));
+  const int tint_symbol = p_a_i_save;
+  const int tint_symbol_1 = p_a_i_a_i_save;
+  const int tint_symbol_2 = p_a_i_a_i_m_i_save;
+  const int tint_symbol_3 = i();
+  const uint scalar_offset_bytes = (((((256u * uint(tint_symbol)) + (64u * uint(tint_symbol_1))) + (4u * uint(tint_symbol_2))) + (2u * uint(tint_symbol_3))));
+  const uint scalar_offset_index = scalar_offset_bytes / 4;
+  const float16_t l_a_i_a_i_m_i_i = float16_t(f16tof32(((a[scalar_offset_index / 4][scalar_offset_index % 4] >> (scalar_offset_bytes % 4 == 0 ? 0 : 16)) & 0xFFFF)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..f9dc319
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,86 @@
+SKIP: FAILED
+
+struct Inner {
+  matrix<float16_t, 3, 2> m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 3, 2> tint_symbol_8(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  return matrix<float16_t, 3, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))));
+}
+
+Inner tint_symbol_7(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_11 = {tint_symbol_8(buffer, (offset + 0u))};
+  return tint_symbol_11;
+}
+
+typedef Inner tint_symbol_6_ret[4];
+tint_symbol_6_ret tint_symbol_6(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_7(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_5(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_12 = {tint_symbol_6(buffer, (offset + 0u))};
+  return tint_symbol_12;
+}
+
+typedef Outer tint_symbol_4_ret[4];
+tint_symbol_4_ret tint_symbol_4(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
+      arr_1[i_2] = tint_symbol_5(buffer, (offset + (i_2 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_a_i_save = i();
+  const int p_a_i_a_i_m_i_save = i();
+  const Outer l_a[4] = tint_symbol_4(a, 0u);
+  const Outer l_a_i = tint_symbol_5(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a[4] = tint_symbol_6(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a_i = tint_symbol_7(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const matrix<float16_t, 3, 2> l_a_i_a_i_m = tint_symbol_8(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const uint scalar_offset_3 = ((((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))) + (4u * uint(p_a_i_a_i_m_i_save)))) / 4;
+  uint ubo_load_3 = a[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  const vector<float16_t, 2> l_a_i_a_i_m_i = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16)));
+  const int tint_symbol = p_a_i_save;
+  const int tint_symbol_1 = p_a_i_a_i_save;
+  const int tint_symbol_2 = p_a_i_a_i_m_i_save;
+  const int tint_symbol_3 = i();
+  const uint scalar_offset_bytes = (((((256u * uint(tint_symbol)) + (64u * uint(tint_symbol_1))) + (4u * uint(tint_symbol_2))) + (2u * uint(tint_symbol_3))));
+  const uint scalar_offset_index = scalar_offset_bytes / 4;
+  const float16_t l_a_i_a_i_m_i_i = float16_t(f16tof32(((a[scalar_offset_index / 4][scalar_offset_index % 4] >> (scalar_offset_bytes % 4 == 0 ? 0 : 16)) & 0xFFFF)));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000002078397D2F0(2,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/dynamic_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..369aa2b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,158 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct Inner {
+  f16mat3x2 m;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+};
+
+struct Inner_std140 {
+  f16vec2 m_0;
+  f16vec2 m_1;
+  f16vec2 m_2;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+};
+
+struct Outer {
+  Inner a[4];
+};
+
+struct Outer_std140 {
+  Inner_std140 a[4];
+};
+
+layout(binding = 0, std140) uniform a_block_std140_ubo {
+  Outer_std140 inner[4];
+} a;
+
+int counter = 0;
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+Inner conv_Inner(Inner_std140 val) {
+  return Inner(f16mat3x2(val.m_0, val.m_1, val.m_2), val.pad, val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.pad_11, val.pad_12);
+}
+
+Inner[4] conv_arr4_Inner(Inner_std140 val[4]) {
+  Inner arr[4] = Inner[4](Inner(f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_Inner(val[i]);
+    }
+  }
+  return arr;
+}
+
+Outer conv_Outer(Outer_std140 val) {
+  return Outer(conv_arr4_Inner(val.a));
+}
+
+Outer[4] conv_arr4_Outer(Outer_std140 val[4]) {
+  Outer arr[4] = Outer[4](Outer(Inner[4](Inner(f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_Outer(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat3x2 load_a_inner_p0_a_p1_m(uint p0, uint p1) {
+  uint s_save = p0;
+  uint s_save_1 = p1;
+  return f16mat3x2(a.inner[s_save].a[s_save_1].m_0, a.inner[s_save].a[s_save_1].m_1, a.inner[s_save].a[s_save_1].m_2);
+}
+
+f16vec2 load_a_inner_p0_a_p1_m_p2(uint p0, uint p1, uint p2) {
+  switch(p2) {
+    case 0u: {
+      return a.inner[p0].a[p1].m_0;
+      break;
+    }
+    case 1u: {
+      return a.inner[p0].a[p1].m_1;
+      break;
+    }
+    case 2u: {
+      return a.inner[p0].a[p1].m_2;
+      break;
+    }
+    default: {
+      return f16vec2(0.0hf);
+      break;
+    }
+  }
+}
+
+float16_t load_a_inner_p0_a_p1_m_p2_p3(uint p0, uint p1, uint p2, uint p3) {
+  switch(p2) {
+    case 0u: {
+      return a.inner[p0].a[p1].m_0[p3];
+      break;
+    }
+    case 1u: {
+      return a.inner[p0].a[p1].m_1[p3];
+      break;
+    }
+    case 2u: {
+      return a.inner[p0].a[p1].m_2[p3];
+      break;
+    }
+    default: {
+      return 0.0hf;
+      break;
+    }
+  }
+}
+
+void f() {
+  Outer p_a[4] = conv_arr4_Outer(a.inner);
+  int tint_symbol = i();
+  Outer p_a_i = conv_Outer(a.inner[tint_symbol]);
+  Inner p_a_i_a[4] = conv_arr4_Inner(a.inner[tint_symbol].a);
+  int tint_symbol_1 = i();
+  Inner p_a_i_a_i = conv_Inner(a.inner[tint_symbol].a[tint_symbol_1]);
+  f16mat3x2 p_a_i_a_i_m = load_a_inner_p0_a_p1_m(uint(tint_symbol), uint(tint_symbol_1));
+  int tint_symbol_2 = i();
+  f16vec2 p_a_i_a_i_m_i = load_a_inner_p0_a_p1_m_p2(uint(tint_symbol), uint(tint_symbol_1), uint(tint_symbol_2));
+  Outer l_a[4] = conv_arr4_Outer(a.inner);
+  Outer l_a_i = conv_Outer(a.inner[tint_symbol]);
+  Inner l_a_i_a[4] = conv_arr4_Inner(a.inner[tint_symbol].a);
+  Inner l_a_i_a_i = conv_Inner(a.inner[tint_symbol].a[tint_symbol_1]);
+  f16mat3x2 l_a_i_a_i_m = load_a_inner_p0_a_p1_m(uint(tint_symbol), uint(tint_symbol_1));
+  f16vec2 l_a_i_a_i_m_i = load_a_inner_p0_a_p1_m_p2(uint(tint_symbol), uint(tint_symbol_1), uint(tint_symbol_2));
+  int tint_symbol_3 = i();
+  float16_t l_a_i_a_i_m_i_i = load_a_inner_p0_a_p1_m_p2_p3(uint(tint_symbol), uint(tint_symbol_1), uint(tint_symbol_2), uint(tint_symbol_3));
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/dynamic_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..322fa8e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/dynamic_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,49 @@
+#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 Inner {
+  /* 0x0000 */ half3x2 m;
+  /* 0x000c */ tint_array<int8_t, 52> tint_pad;
+};
+
+struct Outer {
+  /* 0x0000 */ tint_array<Inner, 4> a;
+};
+
+int i() {
+  thread int tint_symbol_4 = 0;
+  tint_symbol_4 = as_type<int>((as_type<uint>(tint_symbol_4) + as_type<uint>(1)));
+  return tint_symbol_4;
+}
+
+kernel void f(const constant tint_array<Outer, 4>* tint_symbol_5 [[buffer(0)]]) {
+  int const tint_symbol = i();
+  int const p_a_i_save = tint_symbol;
+  int const tint_symbol_1 = i();
+  int const p_a_i_a_i_save = tint_symbol_1;
+  int const tint_symbol_2 = i();
+  int const p_a_i_a_i_m_i_save = tint_symbol_2;
+  tint_array<Outer, 4> const l_a = *(tint_symbol_5);
+  Outer const l_a_i = (*(tint_symbol_5))[p_a_i_save];
+  tint_array<Inner, 4> const l_a_i_a = (*(tint_symbol_5))[p_a_i_save].a;
+  Inner const l_a_i_a_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save];
+  half3x2 const l_a_i_a_i_m = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m;
+  half2 const l_a_i_a_i_m_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save];
+  int const tint_symbol_3 = i();
+  half const l_a_i_a_i_m_i_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save][tint_symbol_3];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..c17857d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,324 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 204
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block_std140 "a_block_std140"
+               OpMemberName %a_block_std140 0 "inner"
+               OpName %Outer_std140 "Outer_std140"
+               OpMemberName %Outer_std140 0 "a"
+               OpName %Inner_std140 "Inner_std140"
+               OpMemberName %Inner_std140 0 "m_0"
+               OpMemberName %Inner_std140 1 "m_1"
+               OpMemberName %Inner_std140 2 "m_2"
+               OpName %a "a"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %Inner "Inner"
+               OpMemberName %Inner 0 "m"
+               OpName %conv_Inner "conv_Inner"
+               OpName %val "val"
+               OpName %conv_arr4_Inner "conv_arr4_Inner"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i_0 "i"
+               OpName %var_for_index_1 "var_for_index_1"
+               OpName %Outer "Outer"
+               OpMemberName %Outer 0 "a"
+               OpName %conv_Outer "conv_Outer"
+               OpName %val_1 "val"
+               OpName %conv_arr4_Outer "conv_arr4_Outer"
+               OpName %val_2 "val"
+               OpName %arr_0 "arr"
+               OpName %i_1 "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_a_inner_p0_a_p1_m "load_a_inner_p0_a_p1_m"
+               OpName %p0 "p0"
+               OpName %p1 "p1"
+               OpName %load_a_inner_p0_a_p1_m_p2 "load_a_inner_p0_a_p1_m_p2"
+               OpName %p0_0 "p0"
+               OpName %p1_0 "p1"
+               OpName %p2 "p2"
+               OpName %load_a_inner_p0_a_p1_m_p2_p3 "load_a_inner_p0_a_p1_m_p2_p3"
+               OpName %p0_1 "p0"
+               OpName %p1_1 "p1"
+               OpName %p2_0 "p2"
+               OpName %p3 "p3"
+               OpName %f "f"
+               OpDecorate %a_block_std140 Block
+               OpMemberDecorate %a_block_std140 0 Offset 0
+               OpMemberDecorate %Outer_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 1 Offset 4
+               OpMemberDecorate %Inner_std140 2 Offset 8
+               OpDecorate %_arr_Inner_std140_uint_4 ArrayStride 64
+               OpDecorate %_arr_Outer_std140_uint_4 ArrayStride 256
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+               OpMemberDecorate %Inner 0 Offset 0
+               OpMemberDecorate %Inner 0 ColMajor
+               OpMemberDecorate %Inner 0 MatrixStride 4
+               OpDecorate %_arr_Inner_uint_4 ArrayStride 64
+               OpMemberDecorate %Outer 0 Offset 0
+               OpDecorate %_arr_Outer_uint_4 ArrayStride 256
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+%Inner_std140 = OpTypeStruct %v2half %v2half %v2half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_Inner_std140_uint_4 = OpTypeArray %Inner_std140 %uint_4
+%Outer_std140 = OpTypeStruct %_arr_Inner_std140_uint_4
+%_arr_Outer_std140_uint_4 = OpTypeArray %Outer_std140 %uint_4
+%a_block_std140 = OpTypeStruct %_arr_Outer_std140_uint_4
+%_ptr_Uniform_a_block_std140 = OpTypePointer Uniform %a_block_std140
+          %a = OpVariable %_ptr_Uniform_a_block_std140 Uniform
+        %int = OpTypeInt 32 1
+         %13 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %13
+         %16 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+ %mat3v2half = OpTypeMatrix %v2half 3
+      %Inner = OpTypeStruct %mat3v2half
+         %23 = OpTypeFunction %Inner %Inner_std140
+%_arr_Inner_uint_4 = OpTypeArray %Inner %uint_4
+         %34 = OpTypeFunction %_arr_Inner_uint_4 %_arr_Inner_std140_uint_4
+%_ptr_Function__arr_Inner_uint_4 = OpTypePointer Function %_arr_Inner_uint_4
+         %41 = OpConstantNull %_arr_Inner_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %44 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_Inner_std140_uint_4 = OpTypePointer Function %_arr_Inner_std140_uint_4
+         %57 = OpConstantNull %_arr_Inner_std140_uint_4
+%_ptr_Function_Inner = OpTypePointer Function %Inner
+%_ptr_Function_Inner_std140 = OpTypePointer Function %Inner_std140
+     %uint_1 = OpConstant %uint 1
+      %Outer = OpTypeStruct %_arr_Inner_uint_4
+         %70 = OpTypeFunction %Outer %Outer_std140
+%_arr_Outer_uint_4 = OpTypeArray %Outer %uint_4
+         %78 = OpTypeFunction %_arr_Outer_uint_4 %_arr_Outer_std140_uint_4
+%_ptr_Function__arr_Outer_uint_4 = OpTypePointer Function %_arr_Outer_uint_4
+         %85 = OpConstantNull %_arr_Outer_uint_4
+%_ptr_Function__arr_Outer_std140_uint_4 = OpTypePointer Function %_arr_Outer_std140_uint_4
+         %98 = OpConstantNull %_arr_Outer_std140_uint_4
+%_ptr_Function_Outer = OpTypePointer Function %Outer
+%_ptr_Function_Outer_std140 = OpTypePointer Function %Outer_std140
+        %110 = OpTypeFunction %mat3v2half %uint %uint
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_Inner_std140 = OpTypePointer Uniform %Inner_std140
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+     %uint_2 = OpConstant %uint 2
+        %131 = OpTypeFunction %v2half %uint %uint %uint
+        %148 = OpConstantNull %v2half
+        %149 = OpTypeFunction %half %uint %uint %uint %uint
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+        %168 = OpConstantNull %half
+       %void = OpTypeVoid
+        %169 = OpTypeFunction %void
+%_ptr_Uniform__arr_Outer_std140_uint_4 = OpTypePointer Uniform %_arr_Outer_std140_uint_4
+%_ptr_Uniform_Outer_std140 = OpTypePointer Uniform %Outer_std140
+%_ptr_Uniform__arr_Inner_std140_uint_4 = OpTypePointer Uniform %_arr_Inner_std140_uint_4
+          %i = OpFunction %int None %16
+         %18 = OpLabel
+         %19 = OpLoad %int %counter
+         %21 = OpIAdd %int %19 %int_1
+               OpStore %counter %21
+         %22 = OpLoad %int %counter
+               OpReturnValue %22
+               OpFunctionEnd
+ %conv_Inner = OpFunction %Inner None %23
+        %val = OpFunctionParameter %Inner_std140
+         %28 = OpLabel
+         %29 = OpCompositeExtract %v2half %val 0
+         %30 = OpCompositeExtract %v2half %val 1
+         %31 = OpCompositeExtract %v2half %val 2
+         %32 = OpCompositeConstruct %mat3v2half %29 %30 %31
+         %33 = OpCompositeConstruct %Inner %32
+               OpReturnValue %33
+               OpFunctionEnd
+%conv_arr4_Inner = OpFunction %_arr_Inner_uint_4 None %34
+      %val_0 = OpFunctionParameter %_arr_Inner_std140_uint_4
+         %38 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_Inner_uint_4 Function %41
+        %i_0 = OpVariable %_ptr_Function_uint Function %44
+%var_for_index_1 = OpVariable %_ptr_Function__arr_Inner_std140_uint_4 Function %57
+               OpBranch %45
+         %45 = OpLabel
+               OpLoopMerge %46 %47 None
+               OpBranch %48
+         %48 = OpLabel
+         %50 = OpLoad %uint %i_0
+         %51 = OpULessThan %bool %50 %uint_4
+         %49 = OpLogicalNot %bool %51
+               OpSelectionMerge %53 None
+               OpBranchConditional %49 %54 %53
+         %54 = OpLabel
+               OpBranch %46
+         %53 = OpLabel
+               OpStore %var_for_index_1 %val_0
+         %58 = OpLoad %uint %i_0
+         %60 = OpAccessChain %_ptr_Function_Inner %arr %58
+         %62 = OpLoad %uint %i_0
+         %64 = OpAccessChain %_ptr_Function_Inner_std140 %var_for_index_1 %62
+         %65 = OpLoad %Inner_std140 %64
+         %61 = OpFunctionCall %Inner %conv_Inner %65
+               OpStore %60 %61
+               OpBranch %47
+         %47 = OpLabel
+         %66 = OpLoad %uint %i_0
+         %68 = OpIAdd %uint %66 %uint_1
+               OpStore %i_0 %68
+               OpBranch %45
+         %46 = OpLabel
+         %69 = OpLoad %_arr_Inner_uint_4 %arr
+               OpReturnValue %69
+               OpFunctionEnd
+ %conv_Outer = OpFunction %Outer None %70
+      %val_1 = OpFunctionParameter %Outer_std140
+         %74 = OpLabel
+         %76 = OpCompositeExtract %_arr_Inner_std140_uint_4 %val_1 0
+         %75 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %76
+         %77 = OpCompositeConstruct %Outer %75
+               OpReturnValue %77
+               OpFunctionEnd
+%conv_arr4_Outer = OpFunction %_arr_Outer_uint_4 None %78
+      %val_2 = OpFunctionParameter %_arr_Outer_std140_uint_4
+         %82 = OpLabel
+      %arr_0 = OpVariable %_ptr_Function__arr_Outer_uint_4 Function %85
+        %i_1 = OpVariable %_ptr_Function_uint Function %44
+%var_for_index = OpVariable %_ptr_Function__arr_Outer_std140_uint_4 Function %98
+               OpBranch %87
+         %87 = OpLabel
+               OpLoopMerge %88 %89 None
+               OpBranch %90
+         %90 = OpLabel
+         %92 = OpLoad %uint %i_1
+         %93 = OpULessThan %bool %92 %uint_4
+         %91 = OpLogicalNot %bool %93
+               OpSelectionMerge %94 None
+               OpBranchConditional %91 %95 %94
+         %95 = OpLabel
+               OpBranch %88
+         %94 = OpLabel
+               OpStore %var_for_index %val_2
+         %99 = OpLoad %uint %i_1
+        %101 = OpAccessChain %_ptr_Function_Outer %arr_0 %99
+        %103 = OpLoad %uint %i_1
+        %105 = OpAccessChain %_ptr_Function_Outer_std140 %var_for_index %103
+        %106 = OpLoad %Outer_std140 %105
+        %102 = OpFunctionCall %Outer %conv_Outer %106
+               OpStore %101 %102
+               OpBranch %89
+         %89 = OpLabel
+        %107 = OpLoad %uint %i_1
+        %108 = OpIAdd %uint %107 %uint_1
+               OpStore %i_1 %108
+               OpBranch %87
+         %88 = OpLabel
+        %109 = OpLoad %_arr_Outer_uint_4 %arr_0
+               OpReturnValue %109
+               OpFunctionEnd
+%load_a_inner_p0_a_p1_m = OpFunction %mat3v2half None %110
+         %p0 = OpFunctionParameter %uint
+         %p1 = OpFunctionParameter %uint
+        %114 = OpLabel
+        %118 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %p0 %uint_0 %p1
+        %121 = OpAccessChain %_ptr_Uniform_v2half %118 %uint_0
+        %122 = OpLoad %v2half %121
+        %124 = OpAccessChain %_ptr_Uniform_v2half %118 %uint_1
+        %125 = OpLoad %v2half %124
+        %128 = OpAccessChain %_ptr_Uniform_v2half %118 %uint_2
+        %129 = OpLoad %v2half %128
+        %130 = OpCompositeConstruct %mat3v2half %122 %125 %129
+               OpReturnValue %130
+               OpFunctionEnd
+%load_a_inner_p0_a_p1_m_p2 = OpFunction %v2half None %131
+       %p0_0 = OpFunctionParameter %uint
+       %p1_0 = OpFunctionParameter %uint
+         %p2 = OpFunctionParameter %uint
+        %136 = OpLabel
+               OpSelectionMerge %137 None
+               OpSwitch %p2 %138 0 %139 1 %140 2 %141
+        %139 = OpLabel
+        %142 = OpAccessChain %_ptr_Uniform_v2half %a %uint_0 %p0_0 %uint_0 %p1_0 %uint_0
+        %143 = OpLoad %v2half %142
+               OpReturnValue %143
+        %140 = OpLabel
+        %144 = OpAccessChain %_ptr_Uniform_v2half %a %uint_0 %p0_0 %uint_0 %p1_0 %uint_1
+        %145 = OpLoad %v2half %144
+               OpReturnValue %145
+        %141 = OpLabel
+        %146 = OpAccessChain %_ptr_Uniform_v2half %a %uint_0 %p0_0 %uint_0 %p1_0 %uint_2
+        %147 = OpLoad %v2half %146
+               OpReturnValue %147
+        %138 = OpLabel
+               OpReturnValue %148
+        %137 = OpLabel
+               OpReturnValue %148
+               OpFunctionEnd
+%load_a_inner_p0_a_p1_m_p2_p3 = OpFunction %half None %149
+       %p0_1 = OpFunctionParameter %uint
+       %p1_1 = OpFunctionParameter %uint
+       %p2_0 = OpFunctionParameter %uint
+         %p3 = OpFunctionParameter %uint
+        %155 = OpLabel
+               OpSelectionMerge %156 None
+               OpSwitch %p2_0 %157 0 %158 1 %159 2 %160
+        %158 = OpLabel
+        %162 = OpAccessChain %_ptr_Uniform_half %a %uint_0 %p0_1 %uint_0 %p1_1 %uint_0 %p3
+        %163 = OpLoad %half %162
+               OpReturnValue %163
+        %159 = OpLabel
+        %164 = OpAccessChain %_ptr_Uniform_half %a %uint_0 %p0_1 %uint_0 %p1_1 %uint_1 %p3
+        %165 = OpLoad %half %164
+               OpReturnValue %165
+        %160 = OpLabel
+        %166 = OpAccessChain %_ptr_Uniform_half %a %uint_0 %p0_1 %uint_0 %p1_1 %uint_2 %p3
+        %167 = OpLoad %half %166
+               OpReturnValue %167
+        %157 = OpLabel
+               OpReturnValue %168
+        %156 = OpLabel
+               OpReturnValue %168
+               OpFunctionEnd
+          %f = OpFunction %void None %169
+        %172 = OpLabel
+        %173 = OpFunctionCall %int %i
+        %174 = OpFunctionCall %int %i
+        %175 = OpFunctionCall %int %i
+        %178 = OpAccessChain %_ptr_Uniform__arr_Outer_std140_uint_4 %a %uint_0
+        %179 = OpLoad %_arr_Outer_std140_uint_4 %178
+        %176 = OpFunctionCall %_arr_Outer_uint_4 %conv_arr4_Outer %179
+        %182 = OpAccessChain %_ptr_Uniform_Outer_std140 %a %uint_0 %173
+        %183 = OpLoad %Outer_std140 %182
+        %180 = OpFunctionCall %Outer %conv_Outer %183
+        %186 = OpAccessChain %_ptr_Uniform__arr_Inner_std140_uint_4 %a %uint_0 %173 %uint_0
+        %187 = OpLoad %_arr_Inner_std140_uint_4 %186
+        %184 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %187
+        %189 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %173 %uint_0 %174
+        %190 = OpLoad %Inner_std140 %189
+        %188 = OpFunctionCall %Inner %conv_Inner %190
+        %192 = OpBitcast %uint %173
+        %193 = OpBitcast %uint %174
+        %191 = OpFunctionCall %mat3v2half %load_a_inner_p0_a_p1_m %192 %193
+        %195 = OpBitcast %uint %173
+        %196 = OpBitcast %uint %174
+        %197 = OpBitcast %uint %175
+        %194 = OpFunctionCall %v2half %load_a_inner_p0_a_p1_m_p2 %195 %196 %197
+        %198 = OpFunctionCall %int %i
+        %200 = OpBitcast %uint %173
+        %201 = OpBitcast %uint %174
+        %202 = OpBitcast %uint %175
+        %203 = OpBitcast %uint %198
+        %199 = OpFunctionCall %half %load_a_inner_p0_a_p1_m_p2_p3 %200 %201 %202 %203
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..9ffd10c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,36 @@
+enable f16;
+
+struct Inner {
+  @size(64)
+  m : mat3x2<f16>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_i = &((*(p_a))[i()]);
+  let p_a_i_a = &((*(p_a_i)).a);
+  let p_a_i_a_i = &((*(p_a_i_a))[i()]);
+  let p_a_i_a_i_m = &((*(p_a_i_a_i)).m);
+  let p_a_i_a_i_m_i = &((*(p_a_i_a_i_m))[i()]);
+  let l_a : array<Outer, 4> = *(p_a);
+  let l_a_i : Outer = *(p_a_i);
+  let l_a_i_a : array<Inner, 4> = *(p_a_i_a);
+  let l_a_i_a_i : Inner = *(p_a_i_a_i);
+  let l_a_i_a_i_m : mat3x2<f16> = *(p_a_i_a_i_m);
+  let l_a_i_a_i_m_i : vec2<f16> = *(p_a_i_a_i_m_i);
+  let l_a_i_a_i_m_i_i : f16 = (*(p_a_i_a_i_m_i))[i()];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/static_index_via_ptr.wgsl
new file mode 100644
index 0000000..59e2db0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/static_index_via_ptr.wgsl
@@ -0,0 +1,31 @@
+enable f16;
+
+struct Inner {
+  @size(64)
+  m : mat3x2<f16>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &a;
+  let p_a_3 = &((*p_a)[3]);
+  let p_a_3_a = &((*p_a_3).a);
+  let p_a_3_a_2 = &((*p_a_3_a)[2]);
+  let p_a_3_a_2_m = &((*p_a_3_a_2).m);
+  let p_a_3_a_2_m_1 = &((*p_a_3_a_2_m)[1]);
+
+
+  let l_a             : array<Outer, 4> = *p_a;
+  let l_a_3           : Outer           = *p_a_3;
+  let l_a_3_a         : array<Inner, 4> = *p_a_3_a;
+  let l_a_3_a_2       : Inner           = *p_a_3_a_2;
+  let l_a_3_a_2_m     : mat3x2<f16>     = *p_a_3_a_2_m;
+  let l_a_3_a_2_m_1   : vec2<f16>       = *p_a_3_a_2_m_1;
+  let l_a_3_a_2_m_1_0 : f16             = (*p_a_3_a_2_m_1)[0];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..551b533
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,65 @@
+struct Inner {
+  matrix<float16_t, 3, 2> m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+
+matrix<float16_t, 3, 2> tint_symbol_4(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  return matrix<float16_t, 3, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))));
+}
+
+Inner tint_symbol_3(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_7 = {tint_symbol_4(buffer, (offset + 0u))};
+  return tint_symbol_7;
+}
+
+typedef Inner tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_3(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_1(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_8 = {tint_symbol_2(buffer, (offset + 0u))};
+  return tint_symbol_8;
+}
+
+typedef Outer tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr_1[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const Outer l_a[4] = tint_symbol(a, 0u);
+  const Outer l_a_3 = tint_symbol_1(a, 768u);
+  const Inner l_a_3_a[4] = tint_symbol_2(a, 768u);
+  const Inner l_a_3_a_2 = tint_symbol_3(a, 896u);
+  const matrix<float16_t, 3, 2> l_a_3_a_2_m = tint_symbol_4(a, 896u);
+  uint ubo_load_3 = a[56].y;
+  const vector<float16_t, 2> l_a_3_a_2_m_1 = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16)));
+  const float16_t l_a_3_a_2_m_1_0 = float16_t(f16tof32(((a[56].y) & 0xFFFF)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..c63a31e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,70 @@
+SKIP: FAILED
+
+struct Inner {
+  matrix<float16_t, 3, 2> m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+
+matrix<float16_t, 3, 2> tint_symbol_4(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  return matrix<float16_t, 3, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))));
+}
+
+Inner tint_symbol_3(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_7 = {tint_symbol_4(buffer, (offset + 0u))};
+  return tint_symbol_7;
+}
+
+typedef Inner tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_3(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_1(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_8 = {tint_symbol_2(buffer, (offset + 0u))};
+  return tint_symbol_8;
+}
+
+typedef Outer tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr_1[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const Outer l_a[4] = tint_symbol(a, 0u);
+  const Outer l_a_3 = tint_symbol_1(a, 768u);
+  const Inner l_a_3_a[4] = tint_symbol_2(a, 768u);
+  const Inner l_a_3_a_2 = tint_symbol_3(a, 896u);
+  const matrix<float16_t, 3, 2> l_a_3_a_2_m = tint_symbol_4(a, 896u);
+  uint ubo_load_3 = a[56].y;
+  const vector<float16_t, 2> l_a_3_a_2_m_1 = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16)));
+  const float16_t l_a_3_a_2_m_1_0 = float16_t(f16tof32(((a[56].y) & 0xFFFF)));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x00000229471C1EC0(2,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/static_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..987efda
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/static_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,104 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct Inner {
+  f16mat3x2 m;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+};
+
+struct Inner_std140 {
+  f16vec2 m_0;
+  f16vec2 m_1;
+  f16vec2 m_2;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+};
+
+struct Outer {
+  Inner a[4];
+};
+
+struct Outer_std140 {
+  Inner_std140 a[4];
+};
+
+layout(binding = 0, std140) uniform a_block_std140_ubo {
+  Outer_std140 inner[4];
+} a;
+
+Inner conv_Inner(Inner_std140 val) {
+  return Inner(f16mat3x2(val.m_0, val.m_1, val.m_2), val.pad, val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.pad_11, val.pad_12);
+}
+
+Inner[4] conv_arr4_Inner(Inner_std140 val[4]) {
+  Inner arr[4] = Inner[4](Inner(f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_Inner(val[i]);
+    }
+  }
+  return arr;
+}
+
+Outer conv_Outer(Outer_std140 val) {
+  return Outer(conv_arr4_Inner(val.a));
+}
+
+Outer[4] conv_arr4_Outer(Outer_std140 val[4]) {
+  Outer arr[4] = Outer[4](Outer(Inner[4](Inner(f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_Outer(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat3x2 load_a_inner_3_a_2_m() {
+  return f16mat3x2(a.inner[3u].a[2u].m_0, a.inner[3u].a[2u].m_1, a.inner[3u].a[2u].m_2);
+}
+
+void f() {
+  Outer p_a[4] = conv_arr4_Outer(a.inner);
+  Outer p_a_3 = conv_Outer(a.inner[3u]);
+  Inner p_a_3_a[4] = conv_arr4_Inner(a.inner[3u].a);
+  Inner p_a_3_a_2 = conv_Inner(a.inner[3u].a[2u]);
+  f16mat3x2 p_a_3_a_2_m = load_a_inner_3_a_2_m();
+  f16vec2 p_a_3_a_2_m_1 = a.inner[3u].a[2u].m_1;
+  Outer l_a[4] = conv_arr4_Outer(a.inner);
+  Outer l_a_3 = conv_Outer(a.inner[3u]);
+  Inner l_a_3_a[4] = conv_arr4_Inner(a.inner[3u].a);
+  Inner l_a_3_a_2 = conv_Inner(a.inner[3u].a[2u]);
+  f16mat3x2 l_a_3_a_2_m = load_a_inner_3_a_2_m();
+  f16vec2 l_a_3_a_2_m_1 = a.inner[3u].a[2u].m_1;
+  float16_t l_a_3_a_2_m_1_0 = a.inner[3u].a[2u].m_1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/static_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..40a5b61
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/static_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,36 @@
+#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 Inner {
+  /* 0x0000 */ half3x2 m;
+  /* 0x000c */ tint_array<int8_t, 52> tint_pad;
+};
+
+struct Outer {
+  /* 0x0000 */ tint_array<Inner, 4> a;
+};
+
+kernel void f(const constant tint_array<Outer, 4>* tint_symbol [[buffer(0)]]) {
+  tint_array<Outer, 4> const l_a = *(tint_symbol);
+  Outer const l_a_3 = (*(tint_symbol))[3];
+  tint_array<Inner, 4> const l_a_3_a = (*(tint_symbol))[3].a;
+  Inner const l_a_3_a_2 = (*(tint_symbol))[3].a[2];
+  half3x2 const l_a_3_a_2_m = (*(tint_symbol))[3].a[2].m;
+  half2 const l_a_3_a_2_m_1 = (*(tint_symbol))[3].a[2].m[1];
+  half const l_a_3_a_2_m_1_0 = (*(tint_symbol))[3].a[2].m[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/static_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..9044e1f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/static_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,232 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 144
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block_std140 "a_block_std140"
+               OpMemberName %a_block_std140 0 "inner"
+               OpName %Outer_std140 "Outer_std140"
+               OpMemberName %Outer_std140 0 "a"
+               OpName %Inner_std140 "Inner_std140"
+               OpMemberName %Inner_std140 0 "m_0"
+               OpMemberName %Inner_std140 1 "m_1"
+               OpMemberName %Inner_std140 2 "m_2"
+               OpName %a "a"
+               OpName %Inner "Inner"
+               OpMemberName %Inner 0 "m"
+               OpName %conv_Inner "conv_Inner"
+               OpName %val "val"
+               OpName %conv_arr4_Inner "conv_arr4_Inner"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index_1 "var_for_index_1"
+               OpName %Outer "Outer"
+               OpMemberName %Outer 0 "a"
+               OpName %conv_Outer "conv_Outer"
+               OpName %val_1 "val"
+               OpName %conv_arr4_Outer "conv_arr4_Outer"
+               OpName %val_2 "val"
+               OpName %arr_0 "arr"
+               OpName %i_0 "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_a_inner_3_a_2_m "load_a_inner_3_a_2_m"
+               OpName %f "f"
+               OpDecorate %a_block_std140 Block
+               OpMemberDecorate %a_block_std140 0 Offset 0
+               OpMemberDecorate %Outer_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 1 Offset 4
+               OpMemberDecorate %Inner_std140 2 Offset 8
+               OpDecorate %_arr_Inner_std140_uint_4 ArrayStride 64
+               OpDecorate %_arr_Outer_std140_uint_4 ArrayStride 256
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+               OpMemberDecorate %Inner 0 Offset 0
+               OpMemberDecorate %Inner 0 ColMajor
+               OpMemberDecorate %Inner 0 MatrixStride 4
+               OpDecorate %_arr_Inner_uint_4 ArrayStride 64
+               OpMemberDecorate %Outer 0 Offset 0
+               OpDecorate %_arr_Outer_uint_4 ArrayStride 256
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+%Inner_std140 = OpTypeStruct %v2half %v2half %v2half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_Inner_std140_uint_4 = OpTypeArray %Inner_std140 %uint_4
+%Outer_std140 = OpTypeStruct %_arr_Inner_std140_uint_4
+%_arr_Outer_std140_uint_4 = OpTypeArray %Outer_std140 %uint_4
+%a_block_std140 = OpTypeStruct %_arr_Outer_std140_uint_4
+%_ptr_Uniform_a_block_std140 = OpTypePointer Uniform %a_block_std140
+          %a = OpVariable %_ptr_Uniform_a_block_std140 Uniform
+ %mat3v2half = OpTypeMatrix %v2half 3
+      %Inner = OpTypeStruct %mat3v2half
+         %12 = OpTypeFunction %Inner %Inner_std140
+%_arr_Inner_uint_4 = OpTypeArray %Inner %uint_4
+         %23 = OpTypeFunction %_arr_Inner_uint_4 %_arr_Inner_std140_uint_4
+%_ptr_Function__arr_Inner_uint_4 = OpTypePointer Function %_arr_Inner_uint_4
+         %30 = OpConstantNull %_arr_Inner_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %33 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_Inner_std140_uint_4 = OpTypePointer Function %_arr_Inner_std140_uint_4
+         %46 = OpConstantNull %_arr_Inner_std140_uint_4
+%_ptr_Function_Inner = OpTypePointer Function %Inner
+%_ptr_Function_Inner_std140 = OpTypePointer Function %Inner_std140
+     %uint_1 = OpConstant %uint 1
+      %Outer = OpTypeStruct %_arr_Inner_uint_4
+         %59 = OpTypeFunction %Outer %Outer_std140
+%_arr_Outer_uint_4 = OpTypeArray %Outer %uint_4
+         %67 = OpTypeFunction %_arr_Outer_uint_4 %_arr_Outer_std140_uint_4
+%_ptr_Function__arr_Outer_uint_4 = OpTypePointer Function %_arr_Outer_uint_4
+         %74 = OpConstantNull %_arr_Outer_uint_4
+%_ptr_Function__arr_Outer_std140_uint_4 = OpTypePointer Function %_arr_Outer_std140_uint_4
+         %87 = OpConstantNull %_arr_Outer_std140_uint_4
+%_ptr_Function_Outer = OpTypePointer Function %Outer
+%_ptr_Function_Outer_std140 = OpTypePointer Function %Outer_std140
+         %99 = OpTypeFunction %mat3v2half
+     %uint_0 = OpConstant %uint 0
+     %uint_3 = OpConstant %uint 3
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_Inner_std140 = OpTypePointer Uniform %Inner_std140
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+       %void = OpTypeVoid
+        %119 = OpTypeFunction %void
+%_ptr_Uniform__arr_Outer_std140_uint_4 = OpTypePointer Uniform %_arr_Outer_std140_uint_4
+%_ptr_Uniform_Outer_std140 = OpTypePointer Uniform %Outer_std140
+%_ptr_Uniform__arr_Inner_std140_uint_4 = OpTypePointer Uniform %_arr_Inner_std140_uint_4
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+ %conv_Inner = OpFunction %Inner None %12
+        %val = OpFunctionParameter %Inner_std140
+         %17 = OpLabel
+         %18 = OpCompositeExtract %v2half %val 0
+         %19 = OpCompositeExtract %v2half %val 1
+         %20 = OpCompositeExtract %v2half %val 2
+         %21 = OpCompositeConstruct %mat3v2half %18 %19 %20
+         %22 = OpCompositeConstruct %Inner %21
+               OpReturnValue %22
+               OpFunctionEnd
+%conv_arr4_Inner = OpFunction %_arr_Inner_uint_4 None %23
+      %val_0 = OpFunctionParameter %_arr_Inner_std140_uint_4
+         %27 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_Inner_uint_4 Function %30
+          %i = OpVariable %_ptr_Function_uint Function %33
+%var_for_index_1 = OpVariable %_ptr_Function__arr_Inner_std140_uint_4 Function %46
+               OpBranch %34
+         %34 = OpLabel
+               OpLoopMerge %35 %36 None
+               OpBranch %37
+         %37 = OpLabel
+         %39 = OpLoad %uint %i
+         %40 = OpULessThan %bool %39 %uint_4
+         %38 = OpLogicalNot %bool %40
+               OpSelectionMerge %42 None
+               OpBranchConditional %38 %43 %42
+         %43 = OpLabel
+               OpBranch %35
+         %42 = OpLabel
+               OpStore %var_for_index_1 %val_0
+         %47 = OpLoad %uint %i
+         %49 = OpAccessChain %_ptr_Function_Inner %arr %47
+         %51 = OpLoad %uint %i
+         %53 = OpAccessChain %_ptr_Function_Inner_std140 %var_for_index_1 %51
+         %54 = OpLoad %Inner_std140 %53
+         %50 = OpFunctionCall %Inner %conv_Inner %54
+               OpStore %49 %50
+               OpBranch %36
+         %36 = OpLabel
+         %55 = OpLoad %uint %i
+         %57 = OpIAdd %uint %55 %uint_1
+               OpStore %i %57
+               OpBranch %34
+         %35 = OpLabel
+         %58 = OpLoad %_arr_Inner_uint_4 %arr
+               OpReturnValue %58
+               OpFunctionEnd
+ %conv_Outer = OpFunction %Outer None %59
+      %val_1 = OpFunctionParameter %Outer_std140
+         %63 = OpLabel
+         %65 = OpCompositeExtract %_arr_Inner_std140_uint_4 %val_1 0
+         %64 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %65
+         %66 = OpCompositeConstruct %Outer %64
+               OpReturnValue %66
+               OpFunctionEnd
+%conv_arr4_Outer = OpFunction %_arr_Outer_uint_4 None %67
+      %val_2 = OpFunctionParameter %_arr_Outer_std140_uint_4
+         %71 = OpLabel
+      %arr_0 = OpVariable %_ptr_Function__arr_Outer_uint_4 Function %74
+        %i_0 = OpVariable %_ptr_Function_uint Function %33
+%var_for_index = OpVariable %_ptr_Function__arr_Outer_std140_uint_4 Function %87
+               OpBranch %76
+         %76 = OpLabel
+               OpLoopMerge %77 %78 None
+               OpBranch %79
+         %79 = OpLabel
+         %81 = OpLoad %uint %i_0
+         %82 = OpULessThan %bool %81 %uint_4
+         %80 = OpLogicalNot %bool %82
+               OpSelectionMerge %83 None
+               OpBranchConditional %80 %84 %83
+         %84 = OpLabel
+               OpBranch %77
+         %83 = OpLabel
+               OpStore %var_for_index %val_2
+         %88 = OpLoad %uint %i_0
+         %90 = OpAccessChain %_ptr_Function_Outer %arr_0 %88
+         %92 = OpLoad %uint %i_0
+         %94 = OpAccessChain %_ptr_Function_Outer_std140 %var_for_index %92
+         %95 = OpLoad %Outer_std140 %94
+         %91 = OpFunctionCall %Outer %conv_Outer %95
+               OpStore %90 %91
+               OpBranch %78
+         %78 = OpLabel
+         %96 = OpLoad %uint %i_0
+         %97 = OpIAdd %uint %96 %uint_1
+               OpStore %i_0 %97
+               OpBranch %76
+         %77 = OpLabel
+         %98 = OpLoad %_arr_Outer_uint_4 %arr_0
+               OpReturnValue %98
+               OpFunctionEnd
+%load_a_inner_3_a_2_m = OpFunction %mat3v2half None %99
+        %101 = OpLabel
+        %107 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %uint_3 %uint_0 %uint_2
+        %110 = OpAccessChain %_ptr_Uniform_v2half %107 %uint_0
+        %111 = OpLoad %v2half %110
+        %113 = OpAccessChain %_ptr_Uniform_v2half %107 %uint_1
+        %114 = OpLoad %v2half %113
+        %116 = OpAccessChain %_ptr_Uniform_v2half %107 %uint_2
+        %117 = OpLoad %v2half %116
+        %118 = OpCompositeConstruct %mat3v2half %111 %114 %117
+               OpReturnValue %118
+               OpFunctionEnd
+          %f = OpFunction %void None %119
+        %122 = OpLabel
+        %125 = OpAccessChain %_ptr_Uniform__arr_Outer_std140_uint_4 %a %uint_0
+        %126 = OpLoad %_arr_Outer_std140_uint_4 %125
+        %123 = OpFunctionCall %_arr_Outer_uint_4 %conv_arr4_Outer %126
+        %129 = OpAccessChain %_ptr_Uniform_Outer_std140 %a %uint_0 %uint_3
+        %130 = OpLoad %Outer_std140 %129
+        %127 = OpFunctionCall %Outer %conv_Outer %130
+        %133 = OpAccessChain %_ptr_Uniform__arr_Inner_std140_uint_4 %a %uint_0 %uint_3 %uint_0
+        %134 = OpLoad %_arr_Inner_std140_uint_4 %133
+        %131 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %134
+        %136 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %uint_3 %uint_0 %uint_2
+        %137 = OpLoad %Inner_std140 %136
+        %135 = OpFunctionCall %Inner %conv_Inner %137
+        %138 = OpFunctionCall %mat3v2half %load_a_inner_3_a_2_m
+        %139 = OpAccessChain %_ptr_Uniform_v2half %a %uint_0 %uint_3 %uint_0 %uint_2 %uint_1
+        %140 = OpLoad %v2half %139
+        %142 = OpAccessChain %_ptr_Uniform_half %a %uint_0 %uint_3 %uint_0 %uint_2 %uint_1 %33
+        %143 = OpLoad %half %142
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/static_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..d4fcf32
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/static_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,29 @@
+enable f16;
+
+struct Inner {
+  @size(64)
+  m : mat3x2<f16>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_3 = &((*(p_a))[3]);
+  let p_a_3_a = &((*(p_a_3)).a);
+  let p_a_3_a_2 = &((*(p_a_3_a))[2]);
+  let p_a_3_a_2_m = &((*(p_a_3_a_2)).m);
+  let p_a_3_a_2_m_1 = &((*(p_a_3_a_2_m))[1]);
+  let l_a : array<Outer, 4> = *(p_a);
+  let l_a_3 : Outer = *(p_a_3);
+  let l_a_3_a : array<Inner, 4> = *(p_a_3_a);
+  let l_a_3_a_2 : Inner = *(p_a_3_a_2);
+  let l_a_3_a_2_m : mat3x2<f16> = *(p_a_3_a_2_m);
+  let l_a_3_a_2_m_1 : vec2<f16> = *(p_a_3_a_2_m_1);
+  let l_a_3_a_2_m_1_0 : f16 = (*(p_a_3_a_2_m_1))[0];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_builtin.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_builtin.wgsl
new file mode 100644
index 0000000..6a87ef8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_builtin.wgsl
@@ -0,0 +1,17 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat3x2<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    let t = transpose(u[2].m);
+    let l = length(u[0].m[1].yx);
+    let a = abs(u[0].m[1].yx.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_builtin.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..3dfa58d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_builtin.wgsl.expected.dxc.hlsl
@@ -0,0 +1,23 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+matrix<float16_t, 3, 2> tint_symbol(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  return matrix<float16_t, 3, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 2, 3> t = transpose(tint_symbol(u, 260u));
+  uint ubo_load_3 = u[0].z;
+  const float16_t l = length(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))).yx);
+  uint ubo_load_4 = u[0].z;
+  const float16_t a = abs(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16))).yx.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_builtin.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..a1c36ac
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_builtin.wgsl.expected.fxc.hlsl
@@ -0,0 +1,28 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+matrix<float16_t, 3, 2> tint_symbol(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  return matrix<float16_t, 3, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 2, 3> t = transpose(tint_symbol(u, 260u));
+  uint ubo_load_3 = u[0].z;
+  const float16_t l = length(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))).yx);
+  uint ubo_load_4 = u[0].z;
+  const float16_t a = abs(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16))).yx.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001CB6BBFDD80(5,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_builtin.wgsl.expected.glsl
new file mode 100644
index 0000000..0f1b4ab
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_builtin.wgsl.expected.glsl
@@ -0,0 +1,90 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct S {
+  int before;
+  f16mat3x2 m;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  int after;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+  uint pad_26;
+};
+
+struct S_std140 {
+  int before;
+  f16vec2 m_0;
+  f16vec2 m_1;
+  f16vec2 m_2;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  int after;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+  uint pad_26;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+f16mat3x2 load_u_inner_2_m() {
+  return f16mat3x2(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2);
+}
+
+void f() {
+  f16mat2x3 t = transpose(load_u_inner_2_m());
+  float16_t l = length(u.inner[0u].m_1.yx);
+  float16_t a = abs(u.inner[0u].m_1.yx[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_builtin.wgsl.expected.msl
new file mode 100644
index 0000000..d2ab552
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_builtin.wgsl.expected.msl
@@ -0,0 +1,31 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ half3x2 m;
+  /* 0x0010 */ tint_array<int8_t, 48> tint_pad;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_1;
+};
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol [[buffer(0)]]) {
+  half2x3 const t = transpose((*(tint_symbol))[2].m);
+  half const l = length(half2((*(tint_symbol))[0].m[1]).yx);
+  half const a = fabs(half2((*(tint_symbol))[0].m[1]).yx[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_builtin.wgsl.expected.spvasm
new file mode 100644
index 0000000..e4c71b7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_builtin.wgsl.expected.spvasm
@@ -0,0 +1,86 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 52
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+         %42 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "m_2"
+               OpMemberName %S_std140 4 "after"
+               OpName %u "u"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 4
+               OpMemberDecorate %S_std140 2 Offset 8
+               OpMemberDecorate %S_std140 3 Offset 12
+               OpMemberDecorate %S_std140 4 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+   %S_std140 = OpTypeStruct %int %v2half %v2half %v2half %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat3v2half = OpTypeMatrix %v2half 3
+         %11 = OpTypeFunction %mat3v2half
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+     %uint_1 = OpConstant %uint 1
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %33 = OpTypeFunction %void
+     %v3half = OpTypeVector %half 3
+ %mat2v3half = OpTypeMatrix %v3half 2
+         %43 = OpConstantNull %uint
+%load_u_inner_2_m = OpFunction %mat3v2half None %11
+         %14 = OpLabel
+         %19 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %23 = OpAccessChain %_ptr_Uniform_v2half %19 %uint_1
+         %24 = OpLoad %v2half %23
+         %26 = OpAccessChain %_ptr_Uniform_v2half %19 %uint_2
+         %27 = OpLoad %v2half %26
+         %30 = OpAccessChain %_ptr_Uniform_v2half %19 %uint_3
+         %31 = OpLoad %v2half %30
+         %32 = OpCompositeConstruct %mat3v2half %24 %27 %31
+               OpReturnValue %32
+               OpFunctionEnd
+          %f = OpFunction %void None %33
+         %36 = OpLabel
+         %40 = OpFunctionCall %mat3v2half %load_u_inner_2_m
+         %37 = OpTranspose %mat2v3half %40
+         %44 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0 %43 %uint_2
+         %45 = OpLoad %v2half %44
+         %46 = OpVectorShuffle %v2half %45 %45 1 0
+         %41 = OpExtInst %half %42 Length %46
+         %48 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0 %43 %uint_2
+         %49 = OpLoad %v2half %48
+         %50 = OpVectorShuffle %v2half %49 %49 1 0
+         %51 = OpCompositeExtract %half %50 0
+         %47 = OpExtInst %half %42 FAbs %51
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_builtin.wgsl.expected.wgsl
new file mode 100644
index 0000000..53dbf9f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_builtin.wgsl.expected.wgsl
@@ -0,0 +1,17 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat3x2<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let t = transpose(u[2].m);
+  let l = length(u[0].m[1].yx);
+  let a = abs(u[0].m[1].yx.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_fn.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_fn.wgsl
new file mode 100644
index 0000000..35cae28
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_fn.wgsl
@@ -0,0 +1,25 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat3x2<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+fn a(a : array<S, 4>) {}
+fn b(s : S) {}
+fn c(m : mat3x2<f16>) {}
+fn d(v : vec2<f16>) {}
+fn e(f : f16) {}
+
+@compute @workgroup_size(1)
+fn f() {
+    a(u);
+    b(u[2]);
+    c(u[2].m);
+    d(u[0].m[1].yx);
+    e(u[0].m[1].yx.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_fn.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..b0b76cc
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_fn.wgsl.expected.dxc.hlsl
@@ -0,0 +1,64 @@
+struct S {
+  int before;
+  matrix<float16_t, 3, 2> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(matrix<float16_t, 3, 2> m) {
+}
+
+void d(vector<float16_t, 2> v) {
+}
+
+void e(float16_t f_1) {
+}
+
+matrix<float16_t, 3, 2> tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  return matrix<float16_t, 3, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_3(buffer, (offset + 4u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 256u));
+  c(tint_symbol_3(u, 260u));
+  uint ubo_load_3 = u[0].z;
+  d(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))).yx);
+  uint ubo_load_4 = u[0].z;
+  e(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16))).yx.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_fn.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..f295aea
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_fn.wgsl.expected.fxc.hlsl
@@ -0,0 +1,69 @@
+SKIP: FAILED
+
+struct S {
+  int before;
+  matrix<float16_t, 3, 2> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(matrix<float16_t, 3, 2> m) {
+}
+
+void d(vector<float16_t, 2> v) {
+}
+
+void e(float16_t f_1) {
+}
+
+matrix<float16_t, 3, 2> tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  return matrix<float16_t, 3, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_3(buffer, (offset + 4u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 256u));
+  c(tint_symbol_3(u, 260u));
+  uint ubo_load_3 = u[0].z;
+  d(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))).yx);
+  uint ubo_load_4 = u[0].z;
+  e(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16))).yx.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000017A6DD8FA30(3,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_fn.wgsl.expected.glsl
new file mode 100644
index 0000000..41a3d44
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_fn.wgsl.expected.glsl
@@ -0,0 +1,121 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct S {
+  int before;
+  f16mat3x2 m;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  int after;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+  uint pad_26;
+};
+
+struct S_std140 {
+  int before;
+  f16vec2 m_0;
+  f16vec2 m_1;
+  f16vec2 m_2;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  int after;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+  uint pad_26;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(f16mat3x2 m) {
+}
+
+void d(f16vec2 v) {
+}
+
+void e(float16_t f_1) {
+}
+
+S conv_S(S_std140 val) {
+  return S(val.before, f16mat3x2(val.m_0, val.m_1, val.m_2), val.pad, val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.pad_11, val.after, val.pad_12, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21, val.pad_22, val.pad_23, val.pad_24, val.pad_25, val.pad_26);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat3x2 load_u_inner_2_m() {
+  return f16mat3x2(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2);
+}
+
+void f() {
+  a(conv_arr4_S(u.inner));
+  b(conv_S(u.inner[2u]));
+  c(load_u_inner_2_m());
+  d(u.inner[0u].m_1.yx);
+  e(u.inner[0u].m_1.yx[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_fn.wgsl.expected.msl
new file mode 100644
index 0000000..f0a5dce
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_fn.wgsl.expected.msl
@@ -0,0 +1,48 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ half3x2 m;
+  /* 0x0010 */ tint_array<int8_t, 48> tint_pad;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_1;
+};
+
+void a(tint_array<S, 4> a_1) {
+}
+
+void b(S s) {
+}
+
+void c(half3x2 m) {
+}
+
+void d(half2 v) {
+}
+
+void e(half f_1) {
+}
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol [[buffer(0)]]) {
+  a(*(tint_symbol));
+  b((*(tint_symbol))[2]);
+  c((*(tint_symbol))[2].m);
+  d(half2((*(tint_symbol))[0].m[1]).yx);
+  e(half2((*(tint_symbol))[0].m[1]).yx[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_fn.wgsl.expected.spvasm
new file mode 100644
index 0000000..b77ef16
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_fn.wgsl.expected.spvasm
@@ -0,0 +1,210 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 124
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "m_2"
+               OpMemberName %S_std140 4 "after"
+               OpName %u "u"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %a "a"
+               OpName %a_1 "a_1"
+               OpName %b "b"
+               OpName %s "s"
+               OpName %c "c"
+               OpName %m "m"
+               OpName %d "d"
+               OpName %v "v"
+               OpName %e "e"
+               OpName %f_1 "f_1"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 4
+               OpMemberDecorate %S_std140 2 Offset 8
+               OpMemberDecorate %S_std140 3 Offset 12
+               OpMemberDecorate %S_std140 4 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 4
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 4
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+   %S_std140 = OpTypeStruct %int %v2half %v2half %v2half %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+       %void = OpTypeVoid
+ %mat3v2half = OpTypeMatrix %v2half 3
+          %S = OpTypeStruct %int %mat3v2half %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+         %11 = OpTypeFunction %void %_arr_S_uint_4
+         %19 = OpTypeFunction %void %S
+         %23 = OpTypeFunction %void %mat3v2half
+         %27 = OpTypeFunction %void %v2half
+         %31 = OpTypeFunction %void %half
+         %35 = OpTypeFunction %S %S_std140
+         %46 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+         %52 = OpConstantNull %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %55 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %68 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %81 = OpTypeFunction %mat3v2half
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+     %uint_3 = OpConstant %uint 3
+        %101 = OpTypeFunction %void
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+          %a = OpFunction %void None %11
+        %a_1 = OpFunctionParameter %_arr_S_uint_4
+         %18 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %b = OpFunction %void None %19
+          %s = OpFunctionParameter %S
+         %22 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %c = OpFunction %void None %23
+          %m = OpFunctionParameter %mat3v2half
+         %26 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %d = OpFunction %void None %27
+          %v = OpFunctionParameter %v2half
+         %30 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %e = OpFunction %void None %31
+        %f_1 = OpFunctionParameter %half
+         %34 = OpLabel
+               OpReturn
+               OpFunctionEnd
+     %conv_S = OpFunction %S None %35
+        %val = OpFunctionParameter %S_std140
+         %38 = OpLabel
+         %39 = OpCompositeExtract %int %val 0
+         %40 = OpCompositeExtract %v2half %val 1
+         %41 = OpCompositeExtract %v2half %val 2
+         %42 = OpCompositeExtract %v2half %val 3
+         %43 = OpCompositeConstruct %mat3v2half %40 %41 %42
+         %44 = OpCompositeExtract %int %val 4
+         %45 = OpCompositeConstruct %S %39 %43 %44
+               OpReturnValue %45
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %46
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %49 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %52
+          %i = OpVariable %_ptr_Function_uint Function %55
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %68
+               OpBranch %56
+         %56 = OpLabel
+               OpLoopMerge %57 %58 None
+               OpBranch %59
+         %59 = OpLabel
+         %61 = OpLoad %uint %i
+         %62 = OpULessThan %bool %61 %uint_4
+         %60 = OpLogicalNot %bool %62
+               OpSelectionMerge %64 None
+               OpBranchConditional %60 %65 %64
+         %65 = OpLabel
+               OpBranch %57
+         %64 = OpLabel
+               OpStore %var_for_index %val_0
+         %69 = OpLoad %uint %i
+         %71 = OpAccessChain %_ptr_Function_S %arr %69
+         %73 = OpLoad %uint %i
+         %75 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %73
+         %76 = OpLoad %S_std140 %75
+         %72 = OpFunctionCall %S %conv_S %76
+               OpStore %71 %72
+               OpBranch %58
+         %58 = OpLabel
+         %77 = OpLoad %uint %i
+         %79 = OpIAdd %uint %77 %uint_1
+               OpStore %i %79
+               OpBranch %56
+         %57 = OpLabel
+         %80 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %80
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat3v2half None %81
+         %83 = OpLabel
+         %88 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %91 = OpAccessChain %_ptr_Uniform_v2half %88 %uint_1
+         %92 = OpLoad %v2half %91
+         %94 = OpAccessChain %_ptr_Uniform_v2half %88 %uint_2
+         %95 = OpLoad %v2half %94
+         %98 = OpAccessChain %_ptr_Uniform_v2half %88 %uint_3
+         %99 = OpLoad %v2half %98
+        %100 = OpCompositeConstruct %mat3v2half %92 %95 %99
+               OpReturnValue %100
+               OpFunctionEnd
+          %f = OpFunction %void None %101
+        %103 = OpLabel
+        %107 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+        %108 = OpLoad %_arr_S_std140_uint_4 %107
+        %105 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %108
+        %104 = OpFunctionCall %void %a %105
+        %111 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+        %112 = OpLoad %S_std140 %111
+        %110 = OpFunctionCall %S %conv_S %112
+        %109 = OpFunctionCall %void %b %110
+        %114 = OpFunctionCall %mat3v2half %load_u_inner_2_m
+        %113 = OpFunctionCall %void %c %114
+        %116 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0 %55 %uint_2
+        %117 = OpLoad %v2half %116
+        %118 = OpVectorShuffle %v2half %117 %117 1 0
+        %115 = OpFunctionCall %void %d %118
+        %120 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0 %55 %uint_2
+        %121 = OpLoad %v2half %120
+        %122 = OpVectorShuffle %v2half %121 %121 1 0
+        %123 = OpCompositeExtract %half %122 0
+        %119 = OpFunctionCall %void %e %123
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_fn.wgsl.expected.wgsl
new file mode 100644
index 0000000..42d9a06
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_fn.wgsl.expected.wgsl
@@ -0,0 +1,34 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat3x2<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+fn a(a : array<S, 4>) {
+}
+
+fn b(s : S) {
+}
+
+fn c(m : mat3x2<f16>) {
+}
+
+fn d(v : vec2<f16>) {
+}
+
+fn e(f : f16) {
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  a(u);
+  b(u[2]);
+  c(u[2].m);
+  d(u[0].m[1].yx);
+  e(u[0].m[1].yx.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_private.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_private.wgsl
new file mode 100644
index 0000000..f41ffc6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_private.wgsl
@@ -0,0 +1,19 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat3x2<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+var<private> p : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[2];
+    p[3].m = u[2].m;
+    p[1].m[0] = u[0].m[1].yx;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_private.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..ebcb896
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_private.wgsl.expected.dxc.hlsl
@@ -0,0 +1,48 @@
+struct S {
+  int before;
+  matrix<float16_t, 3, 2> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+static S p[4] = (S[4])0;
+
+matrix<float16_t, 3, 2> tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  return matrix<float16_t, 3, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_3(buffer, (offset + 4u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 256u);
+  p[3].m = tint_symbol_3(u, 260u);
+  uint ubo_load_3 = u[0].z;
+  p[1].m[0] = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))).yx;
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_private.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..5ad13cb
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_private.wgsl.expected.fxc.hlsl
@@ -0,0 +1,53 @@
+SKIP: FAILED
+
+struct S {
+  int before;
+  matrix<float16_t, 3, 2> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+static S p[4] = (S[4])0;
+
+matrix<float16_t, 3, 2> tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  return matrix<float16_t, 3, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_3(buffer, (offset + 4u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 256u);
+  p[3].m = tint_symbol_3(u, 260u);
+  uint ubo_load_3 = u[0].z;
+  p[1].m[0] = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))).yx;
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000022E1691F8F0(3,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..c986125
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_private.wgsl.expected.glsl
@@ -0,0 +1,106 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct S {
+  int before;
+  f16mat3x2 m;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  int after;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+  uint pad_26;
+};
+
+struct S_std140 {
+  int before;
+  f16vec2 m_0;
+  f16vec2 m_1;
+  f16vec2 m_2;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  int after;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+  uint pad_26;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+S p[4] = S[4](S(0, f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+S conv_S(S_std140 val) {
+  return S(val.before, f16mat3x2(val.m_0, val.m_1, val.m_2), val.pad, val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.pad_11, val.after, val.pad_12, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21, val.pad_22, val.pad_23, val.pad_24, val.pad_25, val.pad_26);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat3x2 load_u_inner_2_m() {
+  return f16mat3x2(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2);
+}
+
+void f() {
+  p = conv_arr4_S(u.inner);
+  p[1] = conv_S(u.inner[2u]);
+  p[3].m = load_u_inner_2_m();
+  p[1].m[0] = u.inner[0u].m_1.yx;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..52627dc
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_private.wgsl.expected.msl
@@ -0,0 +1,33 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ half3x2 m;
+  /* 0x0010 */ tint_array<int8_t, 48> tint_pad;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_1;
+};
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol_1 [[buffer(0)]]) {
+  thread tint_array<S, 4> tint_symbol = {};
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[2];
+  tint_symbol[3].m = (*(tint_symbol_1))[2].m;
+  tint_symbol[1].m[0] = half2((*(tint_symbol_1))[0].m[1]).yx;
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_private.wgsl.expected.spvasm
new file mode 100644
index 0000000..caa8191
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_private.wgsl.expected.spvasm
@@ -0,0 +1,177 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 106
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "m_2"
+               OpMemberName %S_std140 4 "after"
+               OpName %u "u"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %p "p"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 4
+               OpMemberDecorate %S_std140 2 Offset 8
+               OpMemberDecorate %S_std140 3 Offset 12
+               OpMemberDecorate %S_std140 4 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 4
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 4
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+   %S_std140 = OpTypeStruct %int %v2half %v2half %v2half %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat3v2half = OpTypeMatrix %v2half 3
+          %S = OpTypeStruct %int %mat3v2half %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+%_ptr_Private__arr_S_uint_4 = OpTypePointer Private %_arr_S_uint_4
+         %16 = OpConstantNull %_arr_S_uint_4
+          %p = OpVariable %_ptr_Private__arr_S_uint_4 Private %16
+         %17 = OpTypeFunction %S %S_std140
+         %28 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %36 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %49 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %62 = OpTypeFunction %mat3v2half
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %82 = OpTypeFunction %void
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+      %int_1 = OpConstant %int 1
+%_ptr_Private_S = OpTypePointer Private %S
+      %int_3 = OpConstant %int 3
+%_ptr_Private_mat3v2half = OpTypePointer Private %mat3v2half
+        %100 = OpConstantNull %int
+%_ptr_Private_v2half = OpTypePointer Private %v2half
+     %conv_S = OpFunction %S None %17
+        %val = OpFunctionParameter %S_std140
+         %20 = OpLabel
+         %21 = OpCompositeExtract %int %val 0
+         %22 = OpCompositeExtract %v2half %val 1
+         %23 = OpCompositeExtract %v2half %val 2
+         %24 = OpCompositeExtract %v2half %val 3
+         %25 = OpCompositeConstruct %mat3v2half %22 %23 %24
+         %26 = OpCompositeExtract %int %val 4
+         %27 = OpCompositeConstruct %S %21 %25 %26
+               OpReturnValue %27
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %28
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %31 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %16
+          %i = OpVariable %_ptr_Function_uint Function %36
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %49
+               OpBranch %37
+         %37 = OpLabel
+               OpLoopMerge %38 %39 None
+               OpBranch %40
+         %40 = OpLabel
+         %42 = OpLoad %uint %i
+         %43 = OpULessThan %bool %42 %uint_4
+         %41 = OpLogicalNot %bool %43
+               OpSelectionMerge %45 None
+               OpBranchConditional %41 %46 %45
+         %46 = OpLabel
+               OpBranch %38
+         %45 = OpLabel
+               OpStore %var_for_index %val_0
+         %50 = OpLoad %uint %i
+         %52 = OpAccessChain %_ptr_Function_S %arr %50
+         %54 = OpLoad %uint %i
+         %56 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %54
+         %57 = OpLoad %S_std140 %56
+         %53 = OpFunctionCall %S %conv_S %57
+               OpStore %52 %53
+               OpBranch %39
+         %39 = OpLabel
+         %58 = OpLoad %uint %i
+         %60 = OpIAdd %uint %58 %uint_1
+               OpStore %i %60
+               OpBranch %37
+         %38 = OpLabel
+         %61 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %61
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat3v2half None %62
+         %64 = OpLabel
+         %69 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %72 = OpAccessChain %_ptr_Uniform_v2half %69 %uint_1
+         %73 = OpLoad %v2half %72
+         %75 = OpAccessChain %_ptr_Uniform_v2half %69 %uint_2
+         %76 = OpLoad %v2half %75
+         %79 = OpAccessChain %_ptr_Uniform_v2half %69 %uint_3
+         %80 = OpLoad %v2half %79
+         %81 = OpCompositeConstruct %mat3v2half %73 %76 %80
+               OpReturnValue %81
+               OpFunctionEnd
+          %f = OpFunction %void None %82
+         %85 = OpLabel
+         %88 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+         %89 = OpLoad %_arr_S_std140_uint_4 %88
+         %86 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %89
+               OpStore %p %86
+         %92 = OpAccessChain %_ptr_Private_S %p %int_1
+         %94 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %95 = OpLoad %S_std140 %94
+         %93 = OpFunctionCall %S %conv_S %95
+               OpStore %92 %93
+         %98 = OpAccessChain %_ptr_Private_mat3v2half %p %int_3 %uint_1
+         %99 = OpFunctionCall %mat3v2half %load_u_inner_2_m
+               OpStore %98 %99
+        %102 = OpAccessChain %_ptr_Private_v2half %p %int_1 %uint_1 %100
+        %103 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0 %36 %uint_2
+        %104 = OpLoad %v2half %103
+        %105 = OpVectorShuffle %v2half %104 %104 1 0
+               OpStore %102 %105
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..9ee7dbd
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_private.wgsl.expected.wgsl
@@ -0,0 +1,20 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat3x2<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+var<private> p : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[2];
+  p[3].m = u[2].m;
+  p[1].m[0] = u[0].m[1].yx;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_storage.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_storage.wgsl
new file mode 100644
index 0000000..49b2e45
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_storage.wgsl
@@ -0,0 +1,19 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat3x2<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+@group(0) @binding(1) var<storage, read_write> s : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[2];
+    s[3].m = u[2].m;
+    s[1].m[0] = u[0].m[1].yx;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_storage.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..0a5e75f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_storage.wgsl.expected.dxc.hlsl
@@ -0,0 +1,69 @@
+struct S {
+  int before;
+  matrix<float16_t, 3, 2> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_3(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 3, 2> value) {
+  buffer.Store<vector<float16_t, 2> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 4u), value[1u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 8u), value[2u]);
+}
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, S value) {
+  buffer.Store((offset + 0u), asuint(value.before));
+  tint_symbol_3(buffer, (offset + 4u), value.m);
+  buffer.Store((offset + 64u), asuint(value.after));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, S value[4]) {
+  S array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 128u)), array[i]);
+    }
+  }
+}
+
+matrix<float16_t, 3, 2> tint_symbol_8(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  return matrix<float16_t, 3, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))));
+}
+
+S tint_symbol_6(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_10 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_8(buffer, (offset + 4u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_10;
+}
+
+typedef S tint_symbol_5_ret[4];
+tint_symbol_5_ret tint_symbol_5(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_6(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_5(u, 0u));
+  tint_symbol_1(s, 128u, tint_symbol_6(u, 256u));
+  tint_symbol_3(s, 388u, tint_symbol_8(u, 260u));
+  uint ubo_load_3 = u[0].z;
+  s.Store<vector<float16_t, 2> >(132u, vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))).yx);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_storage.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..2de9430
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_storage.wgsl.expected.fxc.hlsl
@@ -0,0 +1,74 @@
+SKIP: FAILED
+
+struct S {
+  int before;
+  matrix<float16_t, 3, 2> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_3(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 3, 2> value) {
+  buffer.Store<vector<float16_t, 2> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 4u), value[1u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 8u), value[2u]);
+}
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, S value) {
+  buffer.Store((offset + 0u), asuint(value.before));
+  tint_symbol_3(buffer, (offset + 4u), value.m);
+  buffer.Store((offset + 64u), asuint(value.after));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, S value[4]) {
+  S array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 128u)), array[i]);
+    }
+  }
+}
+
+matrix<float16_t, 3, 2> tint_symbol_8(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  return matrix<float16_t, 3, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))));
+}
+
+S tint_symbol_6(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_10 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_8(buffer, (offset + 4u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_10;
+}
+
+typedef S tint_symbol_5_ret[4];
+tint_symbol_5_ret tint_symbol_5(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_6(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_5(u, 0u));
+  tint_symbol_1(s, 128u, tint_symbol_6(u, 256u));
+  tint_symbol_3(s, 388u, tint_symbol_8(u, 260u));
+  uint ubo_load_3 = u[0].z;
+  s.Store<vector<float16_t, 2> >(132u, vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))).yx);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001BBE330BB00(3,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..0718809
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_storage.wgsl.expected.glsl
@@ -0,0 +1,109 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct S {
+  int before;
+  f16mat3x2 m;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  int after;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+  uint pad_26;
+};
+
+struct S_std140 {
+  int before;
+  f16vec2 m_0;
+  f16vec2 m_1;
+  f16vec2 m_2;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  int after;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+  uint pad_26;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  S inner[4];
+} s;
+
+S conv_S(S_std140 val) {
+  return S(val.before, f16mat3x2(val.m_0, val.m_1, val.m_2), val.pad, val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.pad_11, val.after, val.pad_12, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21, val.pad_22, val.pad_23, val.pad_24, val.pad_25, val.pad_26);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat3x2 load_u_inner_2_m() {
+  return f16mat3x2(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2);
+}
+
+void f() {
+  s.inner = conv_arr4_S(u.inner);
+  s.inner[1] = conv_S(u.inner[2u]);
+  s.inner[3].m = load_u_inner_2_m();
+  s.inner[1].m[0] = u.inner[0u].m_1.yx;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..6f7653d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_storage.wgsl.expected.msl
@@ -0,0 +1,32 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ half3x2 m;
+  /* 0x0010 */ tint_array<int8_t, 48> tint_pad;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_1;
+};
+
+kernel void f(device tint_array<S, 4>* tint_symbol [[buffer(1)]], const constant tint_array<S, 4>* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
+  (*(tint_symbol))[3].m = (*(tint_symbol_1))[2].m;
+  (*(tint_symbol))[1].m[0] = half2((*(tint_symbol_1))[0].m[1]).yx;
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_storage.wgsl.expected.spvasm
new file mode 100644
index 0000000..08e1b0d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_storage.wgsl.expected.spvasm
@@ -0,0 +1,186 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 109
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "m_2"
+               OpMemberName %S_std140 4 "after"
+               OpName %u "u"
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %s "s"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 4
+               OpMemberDecorate %S_std140 2 Offset 8
+               OpMemberDecorate %S_std140 3 Offset 12
+               OpMemberDecorate %S_std140 4 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 4
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 4
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+               OpDecorate %s DescriptorSet 0
+               OpDecorate %s Binding 1
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+   %S_std140 = OpTypeStruct %int %v2half %v2half %v2half %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat3v2half = OpTypeMatrix %v2half 3
+          %S = OpTypeStruct %int %mat3v2half %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+    %u_block = OpTypeStruct %_arr_S_uint_4
+%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
+          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+         %17 = OpTypeFunction %S %S_std140
+         %28 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+         %34 = OpConstantNull %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %37 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %50 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %63 = OpTypeFunction %mat3v2half
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %83 = OpTypeFunction %void
+%_ptr_StorageBuffer__arr_S_uint_4 = OpTypePointer StorageBuffer %_arr_S_uint_4
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+      %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
+      %int_3 = OpConstant %int 3
+%_ptr_StorageBuffer_mat3v2half = OpTypePointer StorageBuffer %mat3v2half
+        %103 = OpConstantNull %int
+%_ptr_StorageBuffer_v2half = OpTypePointer StorageBuffer %v2half
+     %conv_S = OpFunction %S None %17
+        %val = OpFunctionParameter %S_std140
+         %20 = OpLabel
+         %21 = OpCompositeExtract %int %val 0
+         %22 = OpCompositeExtract %v2half %val 1
+         %23 = OpCompositeExtract %v2half %val 2
+         %24 = OpCompositeExtract %v2half %val 3
+         %25 = OpCompositeConstruct %mat3v2half %22 %23 %24
+         %26 = OpCompositeExtract %int %val 4
+         %27 = OpCompositeConstruct %S %21 %25 %26
+               OpReturnValue %27
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %28
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %31 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %34
+          %i = OpVariable %_ptr_Function_uint Function %37
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %50
+               OpBranch %38
+         %38 = OpLabel
+               OpLoopMerge %39 %40 None
+               OpBranch %41
+         %41 = OpLabel
+         %43 = OpLoad %uint %i
+         %44 = OpULessThan %bool %43 %uint_4
+         %42 = OpLogicalNot %bool %44
+               OpSelectionMerge %46 None
+               OpBranchConditional %42 %47 %46
+         %47 = OpLabel
+               OpBranch %39
+         %46 = OpLabel
+               OpStore %var_for_index %val_0
+         %51 = OpLoad %uint %i
+         %53 = OpAccessChain %_ptr_Function_S %arr %51
+         %55 = OpLoad %uint %i
+         %57 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %55
+         %58 = OpLoad %S_std140 %57
+         %54 = OpFunctionCall %S %conv_S %58
+               OpStore %53 %54
+               OpBranch %40
+         %40 = OpLabel
+         %59 = OpLoad %uint %i
+         %61 = OpIAdd %uint %59 %uint_1
+               OpStore %i %61
+               OpBranch %38
+         %39 = OpLabel
+         %62 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %62
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat3v2half None %63
+         %65 = OpLabel
+         %70 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %73 = OpAccessChain %_ptr_Uniform_v2half %70 %uint_1
+         %74 = OpLoad %v2half %73
+         %76 = OpAccessChain %_ptr_Uniform_v2half %70 %uint_2
+         %77 = OpLoad %v2half %76
+         %80 = OpAccessChain %_ptr_Uniform_v2half %70 %uint_3
+         %81 = OpLoad %v2half %80
+         %82 = OpCompositeConstruct %mat3v2half %74 %77 %81
+               OpReturnValue %82
+               OpFunctionEnd
+          %f = OpFunction %void None %83
+         %86 = OpLabel
+         %88 = OpAccessChain %_ptr_StorageBuffer__arr_S_uint_4 %s %uint_0
+         %91 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+         %92 = OpLoad %_arr_S_std140_uint_4 %91
+         %89 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %92
+               OpStore %88 %89
+         %95 = OpAccessChain %_ptr_StorageBuffer_S %s %uint_0 %int_1
+         %97 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %98 = OpLoad %S_std140 %97
+         %96 = OpFunctionCall %S %conv_S %98
+               OpStore %95 %96
+        %101 = OpAccessChain %_ptr_StorageBuffer_mat3v2half %s %uint_0 %int_3 %uint_1
+        %102 = OpFunctionCall %mat3v2half %load_u_inner_2_m
+               OpStore %101 %102
+        %105 = OpAccessChain %_ptr_StorageBuffer_v2half %s %uint_0 %int_1 %uint_1 %103
+        %106 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0 %37 %uint_2
+        %107 = OpLoad %v2half %106
+        %108 = OpVectorShuffle %v2half %107 %107 1 0
+               OpStore %105 %108
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..cfab5f9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,20 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat3x2<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@group(0) @binding(1) var<storage, read_write> s : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[2];
+  s[3].m = u[2].m;
+  s[1].m[0] = u[0].m[1].yx;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_workgroup.wgsl
new file mode 100644
index 0000000..0b2ba99
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_workgroup.wgsl
@@ -0,0 +1,19 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat3x2<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+var<workgroup> w : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[2];
+    w[3].m = u[2].m;
+    w[1].m[0] = u[0].m[1].yx;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_workgroup.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..9b84706
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_workgroup.wgsl.expected.dxc.hlsl
@@ -0,0 +1,64 @@
+struct S {
+  int before;
+  matrix<float16_t, 3, 2> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+groupshared S w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 3, 2> tint_symbol_5(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  return matrix<float16_t, 3, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))));
+}
+
+S tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_8 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_5(buffer, (offset + 4u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_8;
+}
+
+typedef S tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      const S tint_symbol_7 = (S)0;
+      w[i] = tint_symbol_7;
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 256u);
+  w[3].m = tint_symbol_5(u, 260u);
+  uint ubo_load_3 = u[0].z;
+  w[1].m[0] = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))).yx;
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_workgroup.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..2378569
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_workgroup.wgsl.expected.fxc.hlsl
@@ -0,0 +1,69 @@
+SKIP: FAILED
+
+struct S {
+  int before;
+  matrix<float16_t, 3, 2> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+groupshared S w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 3, 2> tint_symbol_5(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  return matrix<float16_t, 3, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))));
+}
+
+S tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_8 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_5(buffer, (offset + 4u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_8;
+}
+
+typedef S tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      const S tint_symbol_7 = (S)0;
+      w[i] = tint_symbol_7;
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 256u);
+  w[3].m = tint_symbol_5(u, 260u);
+  uint ubo_load_3 = u[0].z;
+  w[1].m[0] = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))).yx;
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x00000194753403B0(3,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..0a5ebca2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,114 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct S {
+  int before;
+  f16mat3x2 m;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  int after;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+  uint pad_26;
+};
+
+struct S_std140 {
+  int before;
+  f16vec2 m_0;
+  f16vec2 m_1;
+  f16vec2 m_2;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  int after;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+  uint pad_26;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+shared S w[4];
+S conv_S(S_std140 val) {
+  return S(val.before, f16mat3x2(val.m_0, val.m_1, val.m_2), val.pad, val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.pad_11, val.after, val.pad_12, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21, val.pad_22, val.pad_23, val.pad_24, val.pad_25, val.pad_26);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat3x2 load_u_inner_2_m() {
+  return f16mat3x2(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2);
+}
+
+void f(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      uint i = idx;
+      S tint_symbol = S(0, f16mat3x2(f16vec2(0.0hf), f16vec2(0.0hf), f16vec2(0.0hf)), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u);
+      w[i] = tint_symbol;
+    }
+  }
+  barrier();
+  w = conv_arr4_S(u.inner);
+  w[1] = conv_S(u.inner[2u]);
+  w[3].m = load_u_inner_2_m();
+  w[1].m[0] = u.inner[0u].m_1.yx;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..1ebcfae
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,47 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ half3x2 m;
+  /* 0x0010 */ tint_array<int8_t, 48> tint_pad;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_1;
+};
+
+struct tint_symbol_6 {
+  tint_array<S, 4> w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup tint_array<S, 4>* const tint_symbol_1, const constant tint_array<S, 4>* const tint_symbol_2) {
+  for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+    uint const i = idx;
+    S const tint_symbol = S{};
+    (*(tint_symbol_1))[i] = tint_symbol;
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol_1) = *(tint_symbol_2);
+  (*(tint_symbol_1))[1] = (*(tint_symbol_2))[2];
+  (*(tint_symbol_1))[3].m = (*(tint_symbol_2))[2].m;
+  (*(tint_symbol_1))[1].m[0] = half2((*(tint_symbol_2))[0].m[1]).yx;
+}
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol_5 [[buffer(0)]], threadgroup tint_symbol_6* tint_symbol_4 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup tint_array<S, 4>* const tint_symbol_3 = &((*(tint_symbol_4)).w);
+  f_inner(local_invocation_index, tint_symbol_3, tint_symbol_5);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_workgroup.wgsl.expected.spvasm
new file mode 100644
index 0000000..359d3ae
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_workgroup.wgsl.expected.spvasm
@@ -0,0 +1,220 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 131
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %local_invocation_index_1 "local_invocation_index_1"
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "m_2"
+               OpMemberName %S_std140 4 "after"
+               OpName %u "u"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %w "w"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f_inner "f_inner"
+               OpName %local_invocation_index "local_invocation_index"
+               OpName %idx "idx"
+               OpName %f "f"
+               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 4
+               OpMemberDecorate %S_std140 2 Offset 8
+               OpMemberDecorate %S_std140 3 Offset 12
+               OpMemberDecorate %S_std140 4 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 4
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 4
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+   %S_std140 = OpTypeStruct %int %v2half %v2half %v2half %int
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat3v2half = OpTypeMatrix %v2half 3
+          %S = OpTypeStruct %int %mat3v2half %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+%_ptr_Workgroup__arr_S_uint_4 = OpTypePointer Workgroup %_arr_S_uint_4
+          %w = OpVariable %_ptr_Workgroup__arr_S_uint_4 Workgroup
+         %18 = OpTypeFunction %S %S_std140
+         %29 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+         %35 = OpConstantNull %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %38 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %51 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %64 = OpTypeFunction %mat3v2half
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %84 = OpTypeFunction %void %uint
+%_ptr_Workgroup_S = OpTypePointer Workgroup %S
+        %102 = OpConstantNull %S
+   %uint_264 = OpConstant %uint 264
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+      %int_1 = OpConstant %int 1
+      %int_3 = OpConstant %int 3
+%_ptr_Workgroup_mat3v2half = OpTypePointer Workgroup %mat3v2half
+        %120 = OpConstantNull %int
+%_ptr_Workgroup_v2half = OpTypePointer Workgroup %v2half
+        %126 = OpTypeFunction %void
+     %conv_S = OpFunction %S None %18
+        %val = OpFunctionParameter %S_std140
+         %21 = OpLabel
+         %22 = OpCompositeExtract %int %val 0
+         %23 = OpCompositeExtract %v2half %val 1
+         %24 = OpCompositeExtract %v2half %val 2
+         %25 = OpCompositeExtract %v2half %val 3
+         %26 = OpCompositeConstruct %mat3v2half %23 %24 %25
+         %27 = OpCompositeExtract %int %val 4
+         %28 = OpCompositeConstruct %S %22 %26 %27
+               OpReturnValue %28
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %29
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %32 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %35
+          %i = OpVariable %_ptr_Function_uint Function %38
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %51
+               OpBranch %39
+         %39 = OpLabel
+               OpLoopMerge %40 %41 None
+               OpBranch %42
+         %42 = OpLabel
+         %44 = OpLoad %uint %i
+         %45 = OpULessThan %bool %44 %uint_4
+         %43 = OpLogicalNot %bool %45
+               OpSelectionMerge %47 None
+               OpBranchConditional %43 %48 %47
+         %48 = OpLabel
+               OpBranch %40
+         %47 = OpLabel
+               OpStore %var_for_index %val_0
+         %52 = OpLoad %uint %i
+         %54 = OpAccessChain %_ptr_Function_S %arr %52
+         %56 = OpLoad %uint %i
+         %58 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %56
+         %59 = OpLoad %S_std140 %58
+         %55 = OpFunctionCall %S %conv_S %59
+               OpStore %54 %55
+               OpBranch %41
+         %41 = OpLabel
+         %60 = OpLoad %uint %i
+         %62 = OpIAdd %uint %60 %uint_1
+               OpStore %i %62
+               OpBranch %39
+         %40 = OpLabel
+         %63 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %63
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat3v2half None %64
+         %66 = OpLabel
+         %71 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %74 = OpAccessChain %_ptr_Uniform_v2half %71 %uint_1
+         %75 = OpLoad %v2half %74
+         %77 = OpAccessChain %_ptr_Uniform_v2half %71 %uint_2
+         %78 = OpLoad %v2half %77
+         %81 = OpAccessChain %_ptr_Uniform_v2half %71 %uint_3
+         %82 = OpLoad %v2half %81
+         %83 = OpCompositeConstruct %mat3v2half %75 %78 %82
+               OpReturnValue %83
+               OpFunctionEnd
+    %f_inner = OpFunction %void None %84
+%local_invocation_index = OpFunctionParameter %uint
+         %88 = OpLabel
+        %idx = OpVariable %_ptr_Function_uint Function %38
+               OpStore %idx %local_invocation_index
+               OpBranch %90
+         %90 = OpLabel
+               OpLoopMerge %91 %92 None
+               OpBranch %93
+         %93 = OpLabel
+         %95 = OpLoad %uint %idx
+         %96 = OpULessThan %bool %95 %uint_4
+         %94 = OpLogicalNot %bool %96
+               OpSelectionMerge %97 None
+               OpBranchConditional %94 %98 %97
+         %98 = OpLabel
+               OpBranch %91
+         %97 = OpLabel
+         %99 = OpLoad %uint %idx
+        %101 = OpAccessChain %_ptr_Workgroup_S %w %99
+               OpStore %101 %102
+               OpBranch %92
+         %92 = OpLabel
+        %103 = OpLoad %uint %idx
+        %104 = OpIAdd %uint %103 %uint_1
+               OpStore %idx %104
+               OpBranch %90
+         %91 = OpLabel
+               OpControlBarrier %uint_2 %uint_2 %uint_264
+        %109 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+        %110 = OpLoad %_arr_S_std140_uint_4 %109
+        %107 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %110
+               OpStore %w %107
+        %112 = OpAccessChain %_ptr_Workgroup_S %w %int_1
+        %114 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+        %115 = OpLoad %S_std140 %114
+        %113 = OpFunctionCall %S %conv_S %115
+               OpStore %112 %113
+        %118 = OpAccessChain %_ptr_Workgroup_mat3v2half %w %int_3 %uint_1
+        %119 = OpFunctionCall %mat3v2half %load_u_inner_2_m
+               OpStore %118 %119
+        %122 = OpAccessChain %_ptr_Workgroup_v2half %w %int_1 %uint_1 %120
+        %123 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0 %38 %uint_2
+        %124 = OpLoad %v2half %123
+        %125 = OpVectorShuffle %v2half %124 %124 1 0
+               OpStore %122 %125
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %126
+        %128 = OpLabel
+        %130 = OpLoad %uint %local_invocation_index_1
+        %129 = OpFunctionCall %void %f_inner %130
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..9042e63
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f16/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,20 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat3x2<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+var<workgroup> w : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[2];
+  w[3].m = u[2].m;
+  w[1].m[0] = u[0].m[1].yx;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f32/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/dynamic_index_via_ptr.wgsl
new file mode 100644
index 0000000..310b316
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/dynamic_index_via_ptr.wgsl
@@ -0,0 +1,32 @@
+struct Inner {
+  @size(64)
+  m : mat3x2<f32>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a           = &a;
+  let p_a_i         = &((*p_a)[i()]);
+  let p_a_i_a       = &((*p_a_i).a);
+  let p_a_i_a_i     = &((*p_a_i_a)[i()]);
+  let p_a_i_a_i_m   = &((*p_a_i_a_i).m);
+  let p_a_i_a_i_m_i = &((*p_a_i_a_i_m)[i()]);
+
+
+  let l_a             : array<Outer, 4> =  *p_a;
+  let l_a_i           : Outer           =  *p_a_i;
+  let l_a_i_a         : array<Inner, 4> =  *p_a_i_a;
+  let l_a_i_a_i       : Inner           =  *p_a_i_a_i;
+  let l_a_i_a_i_m     : mat3x2<f32>     =  *p_a_i_a_i_m;
+  let l_a_i_a_i_m_i   : vec2<f32>       =  *p_a_i_a_i_m_i;
+  let l_a_i_a_i_m_i_i : f32             = (*p_a_i_a_i_m_i)[i()];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/struct/mat3x2/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/uniform/std140/struct/mat3x2_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/struct/mat3x2/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/uniform/std140/struct/mat3x2_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/dynamic_index_via_ptr.wgsl.expected.glsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/struct/mat3x2/dynamic_index_via_ptr.wgsl.expected.glsl
rename to test/tint/buffer/uniform/std140/struct/mat3x2_f32/dynamic_index_via_ptr.wgsl.expected.glsl
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/dynamic_index_via_ptr.wgsl.expected.msl
similarity index 100%
rename from test/tint/buffer/uniform/std140/struct/mat3x2/dynamic_index_via_ptr.wgsl.expected.msl
rename to test/tint/buffer/uniform/std140/struct/mat3x2_f32/dynamic_index_via_ptr.wgsl.expected.msl
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/uniform/std140/struct/mat3x2/dynamic_index_via_ptr.wgsl.expected.spvasm
rename to test/tint/buffer/uniform/std140/struct/mat3x2_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/struct/mat3x2/dynamic_index_via_ptr.wgsl.expected.wgsl
rename to test/tint/buffer/uniform/std140/struct/mat3x2_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f32/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/static_index_via_ptr.wgsl
new file mode 100644
index 0000000..172fe38
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/static_index_via_ptr.wgsl
@@ -0,0 +1,29 @@
+struct Inner {
+  @size(64)
+  m : mat3x2<f32>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &a;
+  let p_a_3 = &((*p_a)[3]);
+  let p_a_3_a = &((*p_a_3).a);
+  let p_a_3_a_2 = &((*p_a_3_a)[2]);
+  let p_a_3_a_2_m = &((*p_a_3_a_2).m);
+  let p_a_3_a_2_m_1 = &((*p_a_3_a_2_m)[1]);
+
+
+  let l_a             : array<Outer, 4> = *p_a;
+  let l_a_3           : Outer           = *p_a_3;
+  let l_a_3_a         : array<Inner, 4> = *p_a_3_a;
+  let l_a_3_a_2       : Inner           = *p_a_3_a_2;
+  let l_a_3_a_2_m     : mat3x2<f32>     = *p_a_3_a_2_m;
+  let l_a_3_a_2_m_1   : vec2<f32>       = *p_a_3_a_2_m_1;
+  let l_a_3_a_2_m_1_0 : f32             = (*p_a_3_a_2_m_1)[0];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/struct/mat3x2/static_index_via_ptr.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/uniform/std140/struct/mat3x2_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/struct/mat3x2/static_index_via_ptr.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/uniform/std140/struct/mat3x2_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/static_index_via_ptr.wgsl.expected.glsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/struct/mat3x2/static_index_via_ptr.wgsl.expected.glsl
rename to test/tint/buffer/uniform/std140/struct/mat3x2_f32/static_index_via_ptr.wgsl.expected.glsl
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/static_index_via_ptr.wgsl.expected.msl
similarity index 100%
rename from test/tint/buffer/uniform/std140/struct/mat3x2/static_index_via_ptr.wgsl.expected.msl
rename to test/tint/buffer/uniform/std140/struct/mat3x2_f32/static_index_via_ptr.wgsl.expected.msl
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/static_index_via_ptr.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/uniform/std140/struct/mat3x2/static_index_via_ptr.wgsl.expected.spvasm
rename to test/tint/buffer/uniform/std140/struct/mat3x2_f32/static_index_via_ptr.wgsl.expected.spvasm
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/static_index_via_ptr.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/struct/mat3x2/static_index_via_ptr.wgsl.expected.wgsl
rename to test/tint/buffer/uniform/std140/struct/mat3x2_f32/static_index_via_ptr.wgsl.expected.wgsl
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_builtin.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_builtin.wgsl
new file mode 100644
index 0000000..5a167ce
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_builtin.wgsl
@@ -0,0 +1,15 @@
+struct S {
+  before : i32,
+  m : mat3x2<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    let t = transpose(u[2].m);
+    let l = length(u[0].m[1].yx);
+    let a = abs(u[0].m[1].yx.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_builtin.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..2f2a028
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_builtin.wgsl.expected.dxc.hlsl
@@ -0,0 +1,21 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+float3x2 tint_symbol(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
+  return float3x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float2x3 t = transpose(tint_symbol(u, 264u));
+  const float l = length(asfloat(u[1].xy).yx);
+  const float a = abs(asfloat(u[1].xy).yx.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_builtin.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..2f2a028
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_builtin.wgsl.expected.fxc.hlsl
@@ -0,0 +1,21 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+float3x2 tint_symbol(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
+  return float3x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float2x3 t = transpose(tint_symbol(u, 264u));
+  const float l = length(asfloat(u[1].xy).yx);
+  const float a = abs(asfloat(u[1].xy).yx.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_builtin.wgsl.expected.glsl
new file mode 100644
index 0000000..f891a29
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_builtin.wgsl.expected.glsl
@@ -0,0 +1,83 @@
+#version 310 es
+
+struct S {
+  int before;
+  uint pad;
+  mat3x2 m;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  int after;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+};
+
+struct S_std140 {
+  int before;
+  uint pad;
+  vec2 m_0;
+  vec2 m_1;
+  vec2 m_2;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  int after;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+mat3x2 load_u_inner_2_m() {
+  return mat3x2(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2);
+}
+
+void f() {
+  mat2x3 t = transpose(load_u_inner_2_m());
+  float l = length(u.inner[0u].m_1.yx);
+  float a = abs(u.inner[0u].m_1.yx[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_builtin.wgsl.expected.msl
new file mode 100644
index 0000000..d42da49
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_builtin.wgsl.expected.msl
@@ -0,0 +1,32 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0008 */ float3x2 m;
+  /* 0x0020 */ tint_array<int8_t, 32> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol [[buffer(0)]]) {
+  float2x3 const t = transpose((*(tint_symbol))[2].m);
+  float const l = length(float2((*(tint_symbol))[0].m[1]).yx);
+  float const a = fabs(float2((*(tint_symbol))[0].m[1]).yx[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_builtin.wgsl.expected.spvasm
new file mode 100644
index 0000000..76771a7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_builtin.wgsl.expected.spvasm
@@ -0,0 +1,82 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 52
+; Schema: 0
+               OpCapability Shader
+         %42 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "m_2"
+               OpMemberName %S_std140 4 "after"
+               OpName %u "u"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 8
+               OpMemberDecorate %S_std140 2 Offset 16
+               OpMemberDecorate %S_std140 3 Offset 24
+               OpMemberDecorate %S_std140 4 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v2float = OpTypeVector %float 2
+   %S_std140 = OpTypeStruct %int %v2float %v2float %v2float %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+%mat3v2float = OpTypeMatrix %v2float 3
+         %11 = OpTypeFunction %mat3v2float
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+     %uint_1 = OpConstant %uint 1
+%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %33 = OpTypeFunction %void
+    %v3float = OpTypeVector %float 3
+%mat2v3float = OpTypeMatrix %v3float 2
+         %43 = OpConstantNull %uint
+%load_u_inner_2_m = OpFunction %mat3v2float None %11
+         %14 = OpLabel
+         %19 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %23 = OpAccessChain %_ptr_Uniform_v2float %19 %uint_1
+         %24 = OpLoad %v2float %23
+         %26 = OpAccessChain %_ptr_Uniform_v2float %19 %uint_2
+         %27 = OpLoad %v2float %26
+         %30 = OpAccessChain %_ptr_Uniform_v2float %19 %uint_3
+         %31 = OpLoad %v2float %30
+         %32 = OpCompositeConstruct %mat3v2float %24 %27 %31
+               OpReturnValue %32
+               OpFunctionEnd
+          %f = OpFunction %void None %33
+         %36 = OpLabel
+         %40 = OpFunctionCall %mat3v2float %load_u_inner_2_m
+         %37 = OpTranspose %mat2v3float %40
+         %44 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %43 %uint_2
+         %45 = OpLoad %v2float %44
+         %46 = OpVectorShuffle %v2float %45 %45 1 0
+         %41 = OpExtInst %float %42 Length %46
+         %48 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %43 %uint_2
+         %49 = OpLoad %v2float %48
+         %50 = OpVectorShuffle %v2float %49 %49 1 0
+         %51 = OpCompositeExtract %float %50 0
+         %47 = OpExtInst %float %42 FAbs %51
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_builtin.wgsl.expected.wgsl
new file mode 100644
index 0000000..345182e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_builtin.wgsl.expected.wgsl
@@ -0,0 +1,15 @@
+struct S {
+  before : i32,
+  m : mat3x2<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let t = transpose(u[2].m);
+  let l = length(u[0].m[1].yx);
+  let a = abs(u[0].m[1].yx.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_fn.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_fn.wgsl
new file mode 100644
index 0000000..66e7dbb
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_fn.wgsl
@@ -0,0 +1,23 @@
+struct S {
+  before : i32,
+  m : mat3x2<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+fn a(a : array<S, 4>) {}
+fn b(s : S) {}
+fn c(m : mat3x2<f32>) {}
+fn d(v : vec2<f32>) {}
+fn e(f : f32) {}
+
+@compute @workgroup_size(1)
+fn f() {
+    a(u);
+    b(u[2]);
+    c(u[2].m);
+    d(u[0].m[1].yx);
+    e(u[0].m[1].yx.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_fn.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..0e79198
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_fn.wgsl.expected.dxc.hlsl
@@ -0,0 +1,62 @@
+struct S {
+  int before;
+  float3x2 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(float3x2 m) {
+}
+
+void d(float2 v) {
+}
+
+void e(float f_1) {
+}
+
+float3x2 tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
+  return float3x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 256u));
+  c(tint_symbol_3(u, 264u));
+  d(asfloat(u[1].xy).yx);
+  e(asfloat(u[1].xy).yx.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_fn.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..0e79198
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_fn.wgsl.expected.fxc.hlsl
@@ -0,0 +1,62 @@
+struct S {
+  int before;
+  float3x2 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(float3x2 m) {
+}
+
+void d(float2 v) {
+}
+
+void e(float f_1) {
+}
+
+float3x2 tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
+  return float3x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 256u));
+  c(tint_symbol_3(u, 264u));
+  d(asfloat(u[1].xy).yx);
+  e(asfloat(u[1].xy).yx.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_fn.wgsl.expected.glsl
new file mode 100644
index 0000000..d71345c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_fn.wgsl.expected.glsl
@@ -0,0 +1,114 @@
+#version 310 es
+
+struct S {
+  int before;
+  uint pad;
+  mat3x2 m;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  int after;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+};
+
+struct S_std140 {
+  int before;
+  uint pad;
+  vec2 m_0;
+  vec2 m_1;
+  vec2 m_2;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  int after;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(mat3x2 m) {
+}
+
+void d(vec2 v) {
+}
+
+void e(float f_1) {
+}
+
+S conv_S(S_std140 val) {
+  return S(val.before, val.pad, mat3x2(val.m_0, val.m_1, val.m_2), val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.after, val.pad_9, val.pad_10, val.pad_11, val.pad_12, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21, val.pad_22, val.pad_23);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+mat3x2 load_u_inner_2_m() {
+  return mat3x2(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2);
+}
+
+void f() {
+  a(conv_arr4_S(u.inner));
+  b(conv_S(u.inner[2u]));
+  c(load_u_inner_2_m());
+  d(u.inner[0u].m_1.yx);
+  e(u.inner[0u].m_1.yx[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_fn.wgsl.expected.msl
new file mode 100644
index 0000000..c42c800
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_fn.wgsl.expected.msl
@@ -0,0 +1,49 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0008 */ float3x2 m;
+  /* 0x0020 */ tint_array<int8_t, 32> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+void a(tint_array<S, 4> a_1) {
+}
+
+void b(S s) {
+}
+
+void c(float3x2 m) {
+}
+
+void d(float2 v) {
+}
+
+void e(float f_1) {
+}
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol [[buffer(0)]]) {
+  a(*(tint_symbol));
+  b((*(tint_symbol))[2]);
+  c((*(tint_symbol))[2].m);
+  d(float2((*(tint_symbol))[0].m[1]).yx);
+  e(float2((*(tint_symbol))[0].m[1]).yx[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_fn.wgsl.expected.spvasm
new file mode 100644
index 0000000..43e3bea
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_fn.wgsl.expected.spvasm
@@ -0,0 +1,206 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 124
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "m_2"
+               OpMemberName %S_std140 4 "after"
+               OpName %u "u"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %a "a"
+               OpName %a_1 "a_1"
+               OpName %b "b"
+               OpName %s "s"
+               OpName %c "c"
+               OpName %m "m"
+               OpName %d "d"
+               OpName %v "v"
+               OpName %e "e"
+               OpName %f_1 "f_1"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 8
+               OpMemberDecorate %S_std140 2 Offset 16
+               OpMemberDecorate %S_std140 3 Offset 24
+               OpMemberDecorate %S_std140 4 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 8
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 8
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v2float = OpTypeVector %float 2
+   %S_std140 = OpTypeStruct %int %v2float %v2float %v2float %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+       %void = OpTypeVoid
+%mat3v2float = OpTypeMatrix %v2float 3
+          %S = OpTypeStruct %int %mat3v2float %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+         %11 = OpTypeFunction %void %_arr_S_uint_4
+         %19 = OpTypeFunction %void %S
+         %23 = OpTypeFunction %void %mat3v2float
+         %27 = OpTypeFunction %void %v2float
+         %31 = OpTypeFunction %void %float
+         %35 = OpTypeFunction %S %S_std140
+         %46 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+         %52 = OpConstantNull %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %55 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %68 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %81 = OpTypeFunction %mat3v2float
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
+     %uint_3 = OpConstant %uint 3
+        %101 = OpTypeFunction %void
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+          %a = OpFunction %void None %11
+        %a_1 = OpFunctionParameter %_arr_S_uint_4
+         %18 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %b = OpFunction %void None %19
+          %s = OpFunctionParameter %S
+         %22 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %c = OpFunction %void None %23
+          %m = OpFunctionParameter %mat3v2float
+         %26 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %d = OpFunction %void None %27
+          %v = OpFunctionParameter %v2float
+         %30 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %e = OpFunction %void None %31
+        %f_1 = OpFunctionParameter %float
+         %34 = OpLabel
+               OpReturn
+               OpFunctionEnd
+     %conv_S = OpFunction %S None %35
+        %val = OpFunctionParameter %S_std140
+         %38 = OpLabel
+         %39 = OpCompositeExtract %int %val 0
+         %40 = OpCompositeExtract %v2float %val 1
+         %41 = OpCompositeExtract %v2float %val 2
+         %42 = OpCompositeExtract %v2float %val 3
+         %43 = OpCompositeConstruct %mat3v2float %40 %41 %42
+         %44 = OpCompositeExtract %int %val 4
+         %45 = OpCompositeConstruct %S %39 %43 %44
+               OpReturnValue %45
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %46
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %49 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %52
+          %i = OpVariable %_ptr_Function_uint Function %55
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %68
+               OpBranch %56
+         %56 = OpLabel
+               OpLoopMerge %57 %58 None
+               OpBranch %59
+         %59 = OpLabel
+         %61 = OpLoad %uint %i
+         %62 = OpULessThan %bool %61 %uint_4
+         %60 = OpLogicalNot %bool %62
+               OpSelectionMerge %64 None
+               OpBranchConditional %60 %65 %64
+         %65 = OpLabel
+               OpBranch %57
+         %64 = OpLabel
+               OpStore %var_for_index %val_0
+         %69 = OpLoad %uint %i
+         %71 = OpAccessChain %_ptr_Function_S %arr %69
+         %73 = OpLoad %uint %i
+         %75 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %73
+         %76 = OpLoad %S_std140 %75
+         %72 = OpFunctionCall %S %conv_S %76
+               OpStore %71 %72
+               OpBranch %58
+         %58 = OpLabel
+         %77 = OpLoad %uint %i
+         %79 = OpIAdd %uint %77 %uint_1
+               OpStore %i %79
+               OpBranch %56
+         %57 = OpLabel
+         %80 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %80
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat3v2float None %81
+         %83 = OpLabel
+         %88 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %91 = OpAccessChain %_ptr_Uniform_v2float %88 %uint_1
+         %92 = OpLoad %v2float %91
+         %94 = OpAccessChain %_ptr_Uniform_v2float %88 %uint_2
+         %95 = OpLoad %v2float %94
+         %98 = OpAccessChain %_ptr_Uniform_v2float %88 %uint_3
+         %99 = OpLoad %v2float %98
+        %100 = OpCompositeConstruct %mat3v2float %92 %95 %99
+               OpReturnValue %100
+               OpFunctionEnd
+          %f = OpFunction %void None %101
+        %103 = OpLabel
+        %107 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+        %108 = OpLoad %_arr_S_std140_uint_4 %107
+        %105 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %108
+        %104 = OpFunctionCall %void %a %105
+        %111 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+        %112 = OpLoad %S_std140 %111
+        %110 = OpFunctionCall %S %conv_S %112
+        %109 = OpFunctionCall %void %b %110
+        %114 = OpFunctionCall %mat3v2float %load_u_inner_2_m
+        %113 = OpFunctionCall %void %c %114
+        %116 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %55 %uint_2
+        %117 = OpLoad %v2float %116
+        %118 = OpVectorShuffle %v2float %117 %117 1 0
+        %115 = OpFunctionCall %void %d %118
+        %120 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %55 %uint_2
+        %121 = OpLoad %v2float %120
+        %122 = OpVectorShuffle %v2float %121 %121 1 0
+        %123 = OpCompositeExtract %float %122 0
+        %119 = OpFunctionCall %void %e %123
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_fn.wgsl.expected.wgsl
new file mode 100644
index 0000000..f6aaf33
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_fn.wgsl.expected.wgsl
@@ -0,0 +1,32 @@
+struct S {
+  before : i32,
+  m : mat3x2<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+fn a(a : array<S, 4>) {
+}
+
+fn b(s : S) {
+}
+
+fn c(m : mat3x2<f32>) {
+}
+
+fn d(v : vec2<f32>) {
+}
+
+fn e(f : f32) {
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  a(u);
+  b(u[2]);
+  c(u[2].m);
+  d(u[0].m[1].yx);
+  e(u[0].m[1].yx.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_private.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_private.wgsl
new file mode 100644
index 0000000..4ffe77c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_private.wgsl
@@ -0,0 +1,17 @@
+struct S {
+  before : i32,
+  m : mat3x2<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+var<private> p : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[2];
+    p[3].m = u[2].m;
+    p[1].m[0] = u[0].m[1].yx;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_private.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..5a5e8b1
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_private.wgsl.expected.dxc.hlsl
@@ -0,0 +1,47 @@
+struct S {
+  int before;
+  float3x2 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+static S p[4] = (S[4])0;
+
+float3x2 tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
+  return float3x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 256u);
+  p[3].m = tint_symbol_3(u, 264u);
+  p[1].m[0] = asfloat(u[1].xy).yx;
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_private.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..5a5e8b1
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_private.wgsl.expected.fxc.hlsl
@@ -0,0 +1,47 @@
+struct S {
+  int before;
+  float3x2 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+static S p[4] = (S[4])0;
+
+float3x2 tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
+  return float3x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 256u);
+  p[3].m = tint_symbol_3(u, 264u);
+  p[1].m[0] = asfloat(u[1].xy).yx;
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..75d3a4a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_private.wgsl.expected.glsl
@@ -0,0 +1,99 @@
+#version 310 es
+
+struct S {
+  int before;
+  uint pad;
+  mat3x2 m;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  int after;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+};
+
+struct S_std140 {
+  int before;
+  uint pad;
+  vec2 m_0;
+  vec2 m_1;
+  vec2 m_2;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  int after;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+S p[4] = S[4](S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+S conv_S(S_std140 val) {
+  return S(val.before, val.pad, mat3x2(val.m_0, val.m_1, val.m_2), val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.after, val.pad_9, val.pad_10, val.pad_11, val.pad_12, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21, val.pad_22, val.pad_23);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+mat3x2 load_u_inner_2_m() {
+  return mat3x2(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2);
+}
+
+void f() {
+  p = conv_arr4_S(u.inner);
+  p[1] = conv_S(u.inner[2u]);
+  p[3].m = load_u_inner_2_m();
+  p[1].m[0] = u.inner[0u].m_1.yx;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..deefeba
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_private.wgsl.expected.msl
@@ -0,0 +1,34 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0008 */ float3x2 m;
+  /* 0x0020 */ tint_array<int8_t, 32> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol_1 [[buffer(0)]]) {
+  thread tint_array<S, 4> tint_symbol = {};
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[2];
+  tint_symbol[3].m = (*(tint_symbol_1))[2].m;
+  tint_symbol[1].m[0] = float2((*(tint_symbol_1))[0].m[1]).yx;
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_private.wgsl.expected.spvasm
new file mode 100644
index 0000000..e74eeb1
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_private.wgsl.expected.spvasm
@@ -0,0 +1,173 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 106
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "m_2"
+               OpMemberName %S_std140 4 "after"
+               OpName %u "u"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %p "p"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 8
+               OpMemberDecorate %S_std140 2 Offset 16
+               OpMemberDecorate %S_std140 3 Offset 24
+               OpMemberDecorate %S_std140 4 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 8
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 8
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v2float = OpTypeVector %float 2
+   %S_std140 = OpTypeStruct %int %v2float %v2float %v2float %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+%mat3v2float = OpTypeMatrix %v2float 3
+          %S = OpTypeStruct %int %mat3v2float %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+%_ptr_Private__arr_S_uint_4 = OpTypePointer Private %_arr_S_uint_4
+         %16 = OpConstantNull %_arr_S_uint_4
+          %p = OpVariable %_ptr_Private__arr_S_uint_4 Private %16
+         %17 = OpTypeFunction %S %S_std140
+         %28 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %36 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %49 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %62 = OpTypeFunction %mat3v2float
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %82 = OpTypeFunction %void
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+      %int_1 = OpConstant %int 1
+%_ptr_Private_S = OpTypePointer Private %S
+      %int_3 = OpConstant %int 3
+%_ptr_Private_mat3v2float = OpTypePointer Private %mat3v2float
+        %100 = OpConstantNull %int
+%_ptr_Private_v2float = OpTypePointer Private %v2float
+     %conv_S = OpFunction %S None %17
+        %val = OpFunctionParameter %S_std140
+         %20 = OpLabel
+         %21 = OpCompositeExtract %int %val 0
+         %22 = OpCompositeExtract %v2float %val 1
+         %23 = OpCompositeExtract %v2float %val 2
+         %24 = OpCompositeExtract %v2float %val 3
+         %25 = OpCompositeConstruct %mat3v2float %22 %23 %24
+         %26 = OpCompositeExtract %int %val 4
+         %27 = OpCompositeConstruct %S %21 %25 %26
+               OpReturnValue %27
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %28
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %31 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %16
+          %i = OpVariable %_ptr_Function_uint Function %36
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %49
+               OpBranch %37
+         %37 = OpLabel
+               OpLoopMerge %38 %39 None
+               OpBranch %40
+         %40 = OpLabel
+         %42 = OpLoad %uint %i
+         %43 = OpULessThan %bool %42 %uint_4
+         %41 = OpLogicalNot %bool %43
+               OpSelectionMerge %45 None
+               OpBranchConditional %41 %46 %45
+         %46 = OpLabel
+               OpBranch %38
+         %45 = OpLabel
+               OpStore %var_for_index %val_0
+         %50 = OpLoad %uint %i
+         %52 = OpAccessChain %_ptr_Function_S %arr %50
+         %54 = OpLoad %uint %i
+         %56 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %54
+         %57 = OpLoad %S_std140 %56
+         %53 = OpFunctionCall %S %conv_S %57
+               OpStore %52 %53
+               OpBranch %39
+         %39 = OpLabel
+         %58 = OpLoad %uint %i
+         %60 = OpIAdd %uint %58 %uint_1
+               OpStore %i %60
+               OpBranch %37
+         %38 = OpLabel
+         %61 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %61
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat3v2float None %62
+         %64 = OpLabel
+         %69 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %72 = OpAccessChain %_ptr_Uniform_v2float %69 %uint_1
+         %73 = OpLoad %v2float %72
+         %75 = OpAccessChain %_ptr_Uniform_v2float %69 %uint_2
+         %76 = OpLoad %v2float %75
+         %79 = OpAccessChain %_ptr_Uniform_v2float %69 %uint_3
+         %80 = OpLoad %v2float %79
+         %81 = OpCompositeConstruct %mat3v2float %73 %76 %80
+               OpReturnValue %81
+               OpFunctionEnd
+          %f = OpFunction %void None %82
+         %85 = OpLabel
+         %88 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+         %89 = OpLoad %_arr_S_std140_uint_4 %88
+         %86 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %89
+               OpStore %p %86
+         %92 = OpAccessChain %_ptr_Private_S %p %int_1
+         %94 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %95 = OpLoad %S_std140 %94
+         %93 = OpFunctionCall %S %conv_S %95
+               OpStore %92 %93
+         %98 = OpAccessChain %_ptr_Private_mat3v2float %p %int_3 %uint_1
+         %99 = OpFunctionCall %mat3v2float %load_u_inner_2_m
+               OpStore %98 %99
+        %102 = OpAccessChain %_ptr_Private_v2float %p %int_1 %uint_1 %100
+        %103 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %36 %uint_2
+        %104 = OpLoad %v2float %103
+        %105 = OpVectorShuffle %v2float %104 %104 1 0
+               OpStore %102 %105
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..3872d22
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_private.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+struct S {
+  before : i32,
+  m : mat3x2<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+var<private> p : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[2];
+  p[3].m = u[2].m;
+  p[1].m[0] = u[0].m[1].yx;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_storage.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_storage.wgsl
new file mode 100644
index 0000000..232fa23
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_storage.wgsl
@@ -0,0 +1,17 @@
+struct S {
+  before : i32,
+  m : mat3x2<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+@group(0) @binding(1) var<storage, read_write> s : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[2];
+    s[3].m = u[2].m;
+    s[1].m[0] = u[0].m[1].yx;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_storage.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..2869d03
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_storage.wgsl.expected.dxc.hlsl
@@ -0,0 +1,68 @@
+struct S {
+  int before;
+  float3x2 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_3(RWByteAddressBuffer buffer, uint offset, float3x2 value) {
+  buffer.Store2((offset + 0u), asuint(value[0u]));
+  buffer.Store2((offset + 8u), asuint(value[1u]));
+  buffer.Store2((offset + 16u), asuint(value[2u]));
+}
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, S value) {
+  buffer.Store((offset + 0u), asuint(value.before));
+  tint_symbol_3(buffer, (offset + 8u), value.m);
+  buffer.Store((offset + 64u), asuint(value.after));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, S value[4]) {
+  S array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 128u)), array[i]);
+    }
+  }
+}
+
+float3x2 tint_symbol_8(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
+  return float3x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)));
+}
+
+S tint_symbol_6(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_10 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_8(buffer, (offset + 8u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_10;
+}
+
+typedef S tint_symbol_5_ret[4];
+tint_symbol_5_ret tint_symbol_5(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_6(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_5(u, 0u));
+  tint_symbol_1(s, 128u, tint_symbol_6(u, 256u));
+  tint_symbol_3(s, 392u, tint_symbol_8(u, 264u));
+  s.Store2(136u, asuint(asfloat(u[1].xy).yx));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_storage.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..2869d03
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_storage.wgsl.expected.fxc.hlsl
@@ -0,0 +1,68 @@
+struct S {
+  int before;
+  float3x2 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_3(RWByteAddressBuffer buffer, uint offset, float3x2 value) {
+  buffer.Store2((offset + 0u), asuint(value[0u]));
+  buffer.Store2((offset + 8u), asuint(value[1u]));
+  buffer.Store2((offset + 16u), asuint(value[2u]));
+}
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, S value) {
+  buffer.Store((offset + 0u), asuint(value.before));
+  tint_symbol_3(buffer, (offset + 8u), value.m);
+  buffer.Store((offset + 64u), asuint(value.after));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, S value[4]) {
+  S array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 128u)), array[i]);
+    }
+  }
+}
+
+float3x2 tint_symbol_8(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
+  return float3x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)));
+}
+
+S tint_symbol_6(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_10 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_8(buffer, (offset + 8u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_10;
+}
+
+typedef S tint_symbol_5_ret[4];
+tint_symbol_5_ret tint_symbol_5(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_6(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_5(u, 0u));
+  tint_symbol_1(s, 128u, tint_symbol_6(u, 256u));
+  tint_symbol_3(s, 392u, tint_symbol_8(u, 264u));
+  s.Store2(136u, asuint(asfloat(u[1].xy).yx));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..c09c8f9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_storage.wgsl.expected.glsl
@@ -0,0 +1,102 @@
+#version 310 es
+
+struct S {
+  int before;
+  uint pad;
+  mat3x2 m;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  int after;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+};
+
+struct S_std140 {
+  int before;
+  uint pad;
+  vec2 m_0;
+  vec2 m_1;
+  vec2 m_2;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  int after;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  S inner[4];
+} s;
+
+S conv_S(S_std140 val) {
+  return S(val.before, val.pad, mat3x2(val.m_0, val.m_1, val.m_2), val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.after, val.pad_9, val.pad_10, val.pad_11, val.pad_12, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21, val.pad_22, val.pad_23);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+mat3x2 load_u_inner_2_m() {
+  return mat3x2(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2);
+}
+
+void f() {
+  s.inner = conv_arr4_S(u.inner);
+  s.inner[1] = conv_S(u.inner[2u]);
+  s.inner[3].m = load_u_inner_2_m();
+  s.inner[1].m[0] = u.inner[0u].m_1.yx;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..8bdc778
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_storage.wgsl.expected.msl
@@ -0,0 +1,33 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0008 */ float3x2 m;
+  /* 0x0020 */ tint_array<int8_t, 32> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+kernel void f(device tint_array<S, 4>* tint_symbol [[buffer(1)]], const constant tint_array<S, 4>* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
+  (*(tint_symbol))[3].m = (*(tint_symbol_1))[2].m;
+  (*(tint_symbol))[1].m[0] = float2((*(tint_symbol_1))[0].m[1]).yx;
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_storage.wgsl.expected.spvasm
new file mode 100644
index 0000000..dca749f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_storage.wgsl.expected.spvasm
@@ -0,0 +1,182 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 109
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "m_2"
+               OpMemberName %S_std140 4 "after"
+               OpName %u "u"
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %s "s"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 8
+               OpMemberDecorate %S_std140 2 Offset 16
+               OpMemberDecorate %S_std140 3 Offset 24
+               OpMemberDecorate %S_std140 4 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 8
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 8
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+               OpDecorate %s DescriptorSet 0
+               OpDecorate %s Binding 1
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v2float = OpTypeVector %float 2
+   %S_std140 = OpTypeStruct %int %v2float %v2float %v2float %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+%mat3v2float = OpTypeMatrix %v2float 3
+          %S = OpTypeStruct %int %mat3v2float %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+    %u_block = OpTypeStruct %_arr_S_uint_4
+%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
+          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+         %17 = OpTypeFunction %S %S_std140
+         %28 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+         %34 = OpConstantNull %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %37 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %50 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %63 = OpTypeFunction %mat3v2float
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %83 = OpTypeFunction %void
+%_ptr_StorageBuffer__arr_S_uint_4 = OpTypePointer StorageBuffer %_arr_S_uint_4
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+      %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
+      %int_3 = OpConstant %int 3
+%_ptr_StorageBuffer_mat3v2float = OpTypePointer StorageBuffer %mat3v2float
+        %103 = OpConstantNull %int
+%_ptr_StorageBuffer_v2float = OpTypePointer StorageBuffer %v2float
+     %conv_S = OpFunction %S None %17
+        %val = OpFunctionParameter %S_std140
+         %20 = OpLabel
+         %21 = OpCompositeExtract %int %val 0
+         %22 = OpCompositeExtract %v2float %val 1
+         %23 = OpCompositeExtract %v2float %val 2
+         %24 = OpCompositeExtract %v2float %val 3
+         %25 = OpCompositeConstruct %mat3v2float %22 %23 %24
+         %26 = OpCompositeExtract %int %val 4
+         %27 = OpCompositeConstruct %S %21 %25 %26
+               OpReturnValue %27
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %28
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %31 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %34
+          %i = OpVariable %_ptr_Function_uint Function %37
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %50
+               OpBranch %38
+         %38 = OpLabel
+               OpLoopMerge %39 %40 None
+               OpBranch %41
+         %41 = OpLabel
+         %43 = OpLoad %uint %i
+         %44 = OpULessThan %bool %43 %uint_4
+         %42 = OpLogicalNot %bool %44
+               OpSelectionMerge %46 None
+               OpBranchConditional %42 %47 %46
+         %47 = OpLabel
+               OpBranch %39
+         %46 = OpLabel
+               OpStore %var_for_index %val_0
+         %51 = OpLoad %uint %i
+         %53 = OpAccessChain %_ptr_Function_S %arr %51
+         %55 = OpLoad %uint %i
+         %57 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %55
+         %58 = OpLoad %S_std140 %57
+         %54 = OpFunctionCall %S %conv_S %58
+               OpStore %53 %54
+               OpBranch %40
+         %40 = OpLabel
+         %59 = OpLoad %uint %i
+         %61 = OpIAdd %uint %59 %uint_1
+               OpStore %i %61
+               OpBranch %38
+         %39 = OpLabel
+         %62 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %62
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat3v2float None %63
+         %65 = OpLabel
+         %70 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %73 = OpAccessChain %_ptr_Uniform_v2float %70 %uint_1
+         %74 = OpLoad %v2float %73
+         %76 = OpAccessChain %_ptr_Uniform_v2float %70 %uint_2
+         %77 = OpLoad %v2float %76
+         %80 = OpAccessChain %_ptr_Uniform_v2float %70 %uint_3
+         %81 = OpLoad %v2float %80
+         %82 = OpCompositeConstruct %mat3v2float %74 %77 %81
+               OpReturnValue %82
+               OpFunctionEnd
+          %f = OpFunction %void None %83
+         %86 = OpLabel
+         %88 = OpAccessChain %_ptr_StorageBuffer__arr_S_uint_4 %s %uint_0
+         %91 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+         %92 = OpLoad %_arr_S_std140_uint_4 %91
+         %89 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %92
+               OpStore %88 %89
+         %95 = OpAccessChain %_ptr_StorageBuffer_S %s %uint_0 %int_1
+         %97 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %98 = OpLoad %S_std140 %97
+         %96 = OpFunctionCall %S %conv_S %98
+               OpStore %95 %96
+        %101 = OpAccessChain %_ptr_StorageBuffer_mat3v2float %s %uint_0 %int_3 %uint_1
+        %102 = OpFunctionCall %mat3v2float %load_u_inner_2_m
+               OpStore %101 %102
+        %105 = OpAccessChain %_ptr_StorageBuffer_v2float %s %uint_0 %int_1 %uint_1 %103
+        %106 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %37 %uint_2
+        %107 = OpLoad %v2float %106
+        %108 = OpVectorShuffle %v2float %107 %107 1 0
+               OpStore %105 %108
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..bda40b3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+struct S {
+  before : i32,
+  m : mat3x2<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@group(0) @binding(1) var<storage, read_write> s : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[2];
+  s[3].m = u[2].m;
+  s[1].m[0] = u[0].m[1].yx;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_workgroup.wgsl
new file mode 100644
index 0000000..a06722a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_workgroup.wgsl
@@ -0,0 +1,17 @@
+struct S {
+  before : i32,
+  m : mat3x2<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+var<workgroup> w : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[2];
+    w[3].m = u[2].m;
+    w[1].m[0] = u[0].m[1].yx;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_workgroup.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..35c2670
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_workgroup.wgsl.expected.dxc.hlsl
@@ -0,0 +1,63 @@
+struct S {
+  int before;
+  float3x2 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+groupshared S w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+float3x2 tint_symbol_5(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
+  return float3x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)));
+}
+
+S tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_8 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_5(buffer, (offset + 8u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_8;
+}
+
+typedef S tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      const S tint_symbol_7 = (S)0;
+      w[i] = tint_symbol_7;
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 256u);
+  w[3].m = tint_symbol_5(u, 264u);
+  w[1].m[0] = asfloat(u[1].xy).yx;
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_workgroup.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..35c2670
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_workgroup.wgsl.expected.fxc.hlsl
@@ -0,0 +1,63 @@
+struct S {
+  int before;
+  float3x2 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+groupshared S w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+float3x2 tint_symbol_5(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
+  return float3x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)));
+}
+
+S tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_8 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_5(buffer, (offset + 8u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_8;
+}
+
+typedef S tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      const S tint_symbol_7 = (S)0;
+      w[i] = tint_symbol_7;
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 256u);
+  w[3].m = tint_symbol_5(u, 264u);
+  w[1].m[0] = asfloat(u[1].xy).yx;
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..e5c3eb1
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,107 @@
+#version 310 es
+
+struct S {
+  int before;
+  uint pad;
+  mat3x2 m;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  int after;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+};
+
+struct S_std140 {
+  int before;
+  uint pad;
+  vec2 m_0;
+  vec2 m_1;
+  vec2 m_2;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  int after;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+shared S w[4];
+S conv_S(S_std140 val) {
+  return S(val.before, val.pad, mat3x2(val.m_0, val.m_1, val.m_2), val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.after, val.pad_9, val.pad_10, val.pad_11, val.pad_12, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21, val.pad_22, val.pad_23);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, mat3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+mat3x2 load_u_inner_2_m() {
+  return mat3x2(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2);
+}
+
+void f(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      uint i = idx;
+      S tint_symbol = S(0, 0u, mat3x2(vec2(0.0f), vec2(0.0f), vec2(0.0f)), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u);
+      w[i] = tint_symbol;
+    }
+  }
+  barrier();
+  w = conv_arr4_S(u.inner);
+  w[1] = conv_S(u.inner[2u]);
+  w[3].m = load_u_inner_2_m();
+  w[1].m[0] = u.inner[0u].m_1.yx;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..03a5ba8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,48 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0008 */ float3x2 m;
+  /* 0x0020 */ tint_array<int8_t, 32> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+struct tint_symbol_6 {
+  tint_array<S, 4> w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup tint_array<S, 4>* const tint_symbol_1, const constant tint_array<S, 4>* const tint_symbol_2) {
+  for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+    uint const i = idx;
+    S const tint_symbol = S{};
+    (*(tint_symbol_1))[i] = tint_symbol;
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol_1) = *(tint_symbol_2);
+  (*(tint_symbol_1))[1] = (*(tint_symbol_2))[2];
+  (*(tint_symbol_1))[3].m = (*(tint_symbol_2))[2].m;
+  (*(tint_symbol_1))[1].m[0] = float2((*(tint_symbol_2))[0].m[1]).yx;
+}
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol_5 [[buffer(0)]], threadgroup tint_symbol_6* tint_symbol_4 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup tint_array<S, 4>* const tint_symbol_3 = &((*(tint_symbol_4)).w);
+  f_inner(local_invocation_index, tint_symbol_3, tint_symbol_5);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_workgroup.wgsl.expected.spvasm
new file mode 100644
index 0000000..e5ef490
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_workgroup.wgsl.expected.spvasm
@@ -0,0 +1,216 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 131
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %local_invocation_index_1 "local_invocation_index_1"
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "m_2"
+               OpMemberName %S_std140 4 "after"
+               OpName %u "u"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %w "w"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f_inner "f_inner"
+               OpName %local_invocation_index "local_invocation_index"
+               OpName %idx "idx"
+               OpName %f "f"
+               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 8
+               OpMemberDecorate %S_std140 2 Offset 16
+               OpMemberDecorate %S_std140 3 Offset 24
+               OpMemberDecorate %S_std140 4 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 8
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 8
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v2float = OpTypeVector %float 2
+   %S_std140 = OpTypeStruct %int %v2float %v2float %v2float %int
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+%mat3v2float = OpTypeMatrix %v2float 3
+          %S = OpTypeStruct %int %mat3v2float %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+%_ptr_Workgroup__arr_S_uint_4 = OpTypePointer Workgroup %_arr_S_uint_4
+          %w = OpVariable %_ptr_Workgroup__arr_S_uint_4 Workgroup
+         %18 = OpTypeFunction %S %S_std140
+         %29 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+         %35 = OpConstantNull %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %38 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %51 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %64 = OpTypeFunction %mat3v2float
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %84 = OpTypeFunction %void %uint
+%_ptr_Workgroup_S = OpTypePointer Workgroup %S
+        %102 = OpConstantNull %S
+   %uint_264 = OpConstant %uint 264
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+      %int_1 = OpConstant %int 1
+      %int_3 = OpConstant %int 3
+%_ptr_Workgroup_mat3v2float = OpTypePointer Workgroup %mat3v2float
+        %120 = OpConstantNull %int
+%_ptr_Workgroup_v2float = OpTypePointer Workgroup %v2float
+        %126 = OpTypeFunction %void
+     %conv_S = OpFunction %S None %18
+        %val = OpFunctionParameter %S_std140
+         %21 = OpLabel
+         %22 = OpCompositeExtract %int %val 0
+         %23 = OpCompositeExtract %v2float %val 1
+         %24 = OpCompositeExtract %v2float %val 2
+         %25 = OpCompositeExtract %v2float %val 3
+         %26 = OpCompositeConstruct %mat3v2float %23 %24 %25
+         %27 = OpCompositeExtract %int %val 4
+         %28 = OpCompositeConstruct %S %22 %26 %27
+               OpReturnValue %28
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %29
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %32 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %35
+          %i = OpVariable %_ptr_Function_uint Function %38
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %51
+               OpBranch %39
+         %39 = OpLabel
+               OpLoopMerge %40 %41 None
+               OpBranch %42
+         %42 = OpLabel
+         %44 = OpLoad %uint %i
+         %45 = OpULessThan %bool %44 %uint_4
+         %43 = OpLogicalNot %bool %45
+               OpSelectionMerge %47 None
+               OpBranchConditional %43 %48 %47
+         %48 = OpLabel
+               OpBranch %40
+         %47 = OpLabel
+               OpStore %var_for_index %val_0
+         %52 = OpLoad %uint %i
+         %54 = OpAccessChain %_ptr_Function_S %arr %52
+         %56 = OpLoad %uint %i
+         %58 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %56
+         %59 = OpLoad %S_std140 %58
+         %55 = OpFunctionCall %S %conv_S %59
+               OpStore %54 %55
+               OpBranch %41
+         %41 = OpLabel
+         %60 = OpLoad %uint %i
+         %62 = OpIAdd %uint %60 %uint_1
+               OpStore %i %62
+               OpBranch %39
+         %40 = OpLabel
+         %63 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %63
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat3v2float None %64
+         %66 = OpLabel
+         %71 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %74 = OpAccessChain %_ptr_Uniform_v2float %71 %uint_1
+         %75 = OpLoad %v2float %74
+         %77 = OpAccessChain %_ptr_Uniform_v2float %71 %uint_2
+         %78 = OpLoad %v2float %77
+         %81 = OpAccessChain %_ptr_Uniform_v2float %71 %uint_3
+         %82 = OpLoad %v2float %81
+         %83 = OpCompositeConstruct %mat3v2float %75 %78 %82
+               OpReturnValue %83
+               OpFunctionEnd
+    %f_inner = OpFunction %void None %84
+%local_invocation_index = OpFunctionParameter %uint
+         %88 = OpLabel
+        %idx = OpVariable %_ptr_Function_uint Function %38
+               OpStore %idx %local_invocation_index
+               OpBranch %90
+         %90 = OpLabel
+               OpLoopMerge %91 %92 None
+               OpBranch %93
+         %93 = OpLabel
+         %95 = OpLoad %uint %idx
+         %96 = OpULessThan %bool %95 %uint_4
+         %94 = OpLogicalNot %bool %96
+               OpSelectionMerge %97 None
+               OpBranchConditional %94 %98 %97
+         %98 = OpLabel
+               OpBranch %91
+         %97 = OpLabel
+         %99 = OpLoad %uint %idx
+        %101 = OpAccessChain %_ptr_Workgroup_S %w %99
+               OpStore %101 %102
+               OpBranch %92
+         %92 = OpLabel
+        %103 = OpLoad %uint %idx
+        %104 = OpIAdd %uint %103 %uint_1
+               OpStore %idx %104
+               OpBranch %90
+         %91 = OpLabel
+               OpControlBarrier %uint_2 %uint_2 %uint_264
+        %109 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+        %110 = OpLoad %_arr_S_std140_uint_4 %109
+        %107 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %110
+               OpStore %w %107
+        %112 = OpAccessChain %_ptr_Workgroup_S %w %int_1
+        %114 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+        %115 = OpLoad %S_std140 %114
+        %113 = OpFunctionCall %S %conv_S %115
+               OpStore %112 %113
+        %118 = OpAccessChain %_ptr_Workgroup_mat3v2float %w %int_3 %uint_1
+        %119 = OpFunctionCall %mat3v2float %load_u_inner_2_m
+               OpStore %118 %119
+        %122 = OpAccessChain %_ptr_Workgroup_v2float %w %int_1 %uint_1 %120
+        %123 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %38 %uint_2
+        %124 = OpLoad %v2float %123
+        %125 = OpVectorShuffle %v2float %124 %124 1 0
+               OpStore %122 %125
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %126
+        %128 = OpLabel
+        %130 = OpLoad %uint %local_invocation_index_1
+        %129 = OpFunctionCall %void %f_inner %130
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..f44928d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x2_f32/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+struct S {
+  before : i32,
+  m : mat3x2<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+var<workgroup> w : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[2];
+  w[3].m = u[2].m;
+  w[1].m[0] = u[0].m[1].yx;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/dynamic_index_via_ptr.wgsl
new file mode 100644
index 0000000..b428216
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/dynamic_index_via_ptr.wgsl
@@ -0,0 +1,34 @@
+enable f16;
+
+struct Inner {
+  @size(64)
+  m : mat3x3<f16>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a           = &a;
+  let p_a_i         = &((*p_a)[i()]);
+  let p_a_i_a       = &((*p_a_i).a);
+  let p_a_i_a_i     = &((*p_a_i_a)[i()]);
+  let p_a_i_a_i_m   = &((*p_a_i_a_i).m);
+  let p_a_i_a_i_m_i = &((*p_a_i_a_i_m)[i()]);
+
+
+  let l_a             : array<Outer, 4> =  *p_a;
+  let l_a_i           : Outer           =  *p_a_i;
+  let l_a_i_a         : array<Inner, 4> =  *p_a_i_a;
+  let l_a_i_a_i       : Inner           =  *p_a_i_a_i;
+  let l_a_i_a_i_m     : mat3x3<f16>     =  *p_a_i_a_i_m;
+  let l_a_i_a_i_m_i   : vec3<f16>       =  *p_a_i_a_i_m_i;
+  let l_a_i_a_i_m_i_i : f16             = (*p_a_i_a_i_m_i)[i()];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..ef9e0c4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,93 @@
+struct Inner {
+  matrix<float16_t, 3, 3> m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 3, 3> tint_symbol_8(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  return matrix<float16_t, 3, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]));
+}
+
+Inner tint_symbol_7(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_11 = {tint_symbol_8(buffer, (offset + 0u))};
+  return tint_symbol_11;
+}
+
+typedef Inner tint_symbol_6_ret[4];
+tint_symbol_6_ret tint_symbol_6(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_7(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_5(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_12 = {tint_symbol_6(buffer, (offset + 0u))};
+  return tint_symbol_12;
+}
+
+typedef Outer tint_symbol_4_ret[4];
+tint_symbol_4_ret tint_symbol_4(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
+      arr_1[i_2] = tint_symbol_5(buffer, (offset + (i_2 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_a_i_save = i();
+  const int p_a_i_a_i_m_i_save = i();
+  const Outer l_a[4] = tint_symbol_4(a, 0u);
+  const Outer l_a_i = tint_symbol_5(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a[4] = tint_symbol_6(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a_i = tint_symbol_7(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const matrix<float16_t, 3, 3> l_a_i_a_i_m = tint_symbol_8(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const uint scalar_offset_3 = ((((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))) + (8u * uint(p_a_i_a_i_m_i_save)))) / 4;
+  uint4 ubo_load_7 = a[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  const vector<float16_t, 3> l_a_i_a_i_m_i = vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]);
+  const int tint_symbol = p_a_i_save;
+  const int tint_symbol_1 = p_a_i_a_i_save;
+  const int tint_symbol_2 = p_a_i_a_i_m_i_save;
+  const int tint_symbol_3 = i();
+  const uint scalar_offset_bytes = (((((256u * uint(tint_symbol)) + (64u * uint(tint_symbol_1))) + (8u * uint(tint_symbol_2))) + (2u * uint(tint_symbol_3))));
+  const uint scalar_offset_index = scalar_offset_bytes / 4;
+  const float16_t l_a_i_a_i_m_i_i = float16_t(f16tof32(((a[scalar_offset_index / 4][scalar_offset_index % 4] >> (scalar_offset_bytes % 4 == 0 ? 0 : 16)) & 0xFFFF)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..6a4d6e3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,98 @@
+SKIP: FAILED
+
+struct Inner {
+  matrix<float16_t, 3, 3> m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 3, 3> tint_symbol_8(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  return matrix<float16_t, 3, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]));
+}
+
+Inner tint_symbol_7(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_11 = {tint_symbol_8(buffer, (offset + 0u))};
+  return tint_symbol_11;
+}
+
+typedef Inner tint_symbol_6_ret[4];
+tint_symbol_6_ret tint_symbol_6(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_7(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_5(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_12 = {tint_symbol_6(buffer, (offset + 0u))};
+  return tint_symbol_12;
+}
+
+typedef Outer tint_symbol_4_ret[4];
+tint_symbol_4_ret tint_symbol_4(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
+      arr_1[i_2] = tint_symbol_5(buffer, (offset + (i_2 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_a_i_save = i();
+  const int p_a_i_a_i_m_i_save = i();
+  const Outer l_a[4] = tint_symbol_4(a, 0u);
+  const Outer l_a_i = tint_symbol_5(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a[4] = tint_symbol_6(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a_i = tint_symbol_7(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const matrix<float16_t, 3, 3> l_a_i_a_i_m = tint_symbol_8(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const uint scalar_offset_3 = ((((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))) + (8u * uint(p_a_i_a_i_m_i_save)))) / 4;
+  uint4 ubo_load_7 = a[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  const vector<float16_t, 3> l_a_i_a_i_m_i = vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]);
+  const int tint_symbol = p_a_i_save;
+  const int tint_symbol_1 = p_a_i_a_i_save;
+  const int tint_symbol_2 = p_a_i_a_i_m_i_save;
+  const int tint_symbol_3 = i();
+  const uint scalar_offset_bytes = (((((256u * uint(tint_symbol)) + (64u * uint(tint_symbol_1))) + (8u * uint(tint_symbol_2))) + (2u * uint(tint_symbol_3))));
+  const uint scalar_offset_index = scalar_offset_bytes / 4;
+  const float16_t l_a_i_a_i_m_i_i = float16_t(f16tof32(((a[scalar_offset_index / 4][scalar_offset_index % 4] >> (scalar_offset_bytes % 4 == 0 ? 0 : 16)) & 0xFFFF)));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001CC9AE84850(2,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/dynamic_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..25724b8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,152 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct Inner {
+  f16mat3 m;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+};
+
+struct Inner_std140 {
+  f16vec3 m_0;
+  f16vec3 m_1;
+  f16vec3 m_2;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+};
+
+struct Outer {
+  Inner a[4];
+};
+
+struct Outer_std140 {
+  Inner_std140 a[4];
+};
+
+layout(binding = 0, std140) uniform a_block_std140_ubo {
+  Outer_std140 inner[4];
+} a;
+
+int counter = 0;
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+Inner conv_Inner(Inner_std140 val) {
+  return Inner(f16mat3(val.m_0, val.m_1, val.m_2), val.pad, val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9);
+}
+
+Inner[4] conv_arr4_Inner(Inner_std140 val[4]) {
+  Inner arr[4] = Inner[4](Inner(f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_Inner(val[i]);
+    }
+  }
+  return arr;
+}
+
+Outer conv_Outer(Outer_std140 val) {
+  return Outer(conv_arr4_Inner(val.a));
+}
+
+Outer[4] conv_arr4_Outer(Outer_std140 val[4]) {
+  Outer arr[4] = Outer[4](Outer(Inner[4](Inner(f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_Outer(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat3 load_a_inner_p0_a_p1_m(uint p0, uint p1) {
+  uint s_save = p0;
+  uint s_save_1 = p1;
+  return f16mat3(a.inner[s_save].a[s_save_1].m_0, a.inner[s_save].a[s_save_1].m_1, a.inner[s_save].a[s_save_1].m_2);
+}
+
+f16vec3 load_a_inner_p0_a_p1_m_p2(uint p0, uint p1, uint p2) {
+  switch(p2) {
+    case 0u: {
+      return a.inner[p0].a[p1].m_0;
+      break;
+    }
+    case 1u: {
+      return a.inner[p0].a[p1].m_1;
+      break;
+    }
+    case 2u: {
+      return a.inner[p0].a[p1].m_2;
+      break;
+    }
+    default: {
+      return f16vec3(0.0hf);
+      break;
+    }
+  }
+}
+
+float16_t load_a_inner_p0_a_p1_m_p2_p3(uint p0, uint p1, uint p2, uint p3) {
+  switch(p2) {
+    case 0u: {
+      return a.inner[p0].a[p1].m_0[p3];
+      break;
+    }
+    case 1u: {
+      return a.inner[p0].a[p1].m_1[p3];
+      break;
+    }
+    case 2u: {
+      return a.inner[p0].a[p1].m_2[p3];
+      break;
+    }
+    default: {
+      return 0.0hf;
+      break;
+    }
+  }
+}
+
+void f() {
+  Outer p_a[4] = conv_arr4_Outer(a.inner);
+  int tint_symbol = i();
+  Outer p_a_i = conv_Outer(a.inner[tint_symbol]);
+  Inner p_a_i_a[4] = conv_arr4_Inner(a.inner[tint_symbol].a);
+  int tint_symbol_1 = i();
+  Inner p_a_i_a_i = conv_Inner(a.inner[tint_symbol].a[tint_symbol_1]);
+  f16mat3 p_a_i_a_i_m = load_a_inner_p0_a_p1_m(uint(tint_symbol), uint(tint_symbol_1));
+  int tint_symbol_2 = i();
+  f16vec3 p_a_i_a_i_m_i = load_a_inner_p0_a_p1_m_p2(uint(tint_symbol), uint(tint_symbol_1), uint(tint_symbol_2));
+  Outer l_a[4] = conv_arr4_Outer(a.inner);
+  Outer l_a_i = conv_Outer(a.inner[tint_symbol]);
+  Inner l_a_i_a[4] = conv_arr4_Inner(a.inner[tint_symbol].a);
+  Inner l_a_i_a_i = conv_Inner(a.inner[tint_symbol].a[tint_symbol_1]);
+  f16mat3 l_a_i_a_i_m = load_a_inner_p0_a_p1_m(uint(tint_symbol), uint(tint_symbol_1));
+  f16vec3 l_a_i_a_i_m_i = load_a_inner_p0_a_p1_m_p2(uint(tint_symbol), uint(tint_symbol_1), uint(tint_symbol_2));
+  int tint_symbol_3 = i();
+  float16_t l_a_i_a_i_m_i_i = load_a_inner_p0_a_p1_m_p2_p3(uint(tint_symbol), uint(tint_symbol_1), uint(tint_symbol_2), uint(tint_symbol_3));
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/dynamic_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..5fbd9f0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/dynamic_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,49 @@
+#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 Inner {
+  /* 0x0000 */ half3x3 m;
+  /* 0x0018 */ tint_array<int8_t, 40> tint_pad;
+};
+
+struct Outer {
+  /* 0x0000 */ tint_array<Inner, 4> a;
+};
+
+int i() {
+  thread int tint_symbol_4 = 0;
+  tint_symbol_4 = as_type<int>((as_type<uint>(tint_symbol_4) + as_type<uint>(1)));
+  return tint_symbol_4;
+}
+
+kernel void f(const constant tint_array<Outer, 4>* tint_symbol_5 [[buffer(0)]]) {
+  int const tint_symbol = i();
+  int const p_a_i_save = tint_symbol;
+  int const tint_symbol_1 = i();
+  int const p_a_i_a_i_save = tint_symbol_1;
+  int const tint_symbol_2 = i();
+  int const p_a_i_a_i_m_i_save = tint_symbol_2;
+  tint_array<Outer, 4> const l_a = *(tint_symbol_5);
+  Outer const l_a_i = (*(tint_symbol_5))[p_a_i_save];
+  tint_array<Inner, 4> const l_a_i_a = (*(tint_symbol_5))[p_a_i_save].a;
+  Inner const l_a_i_a_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save];
+  half3x3 const l_a_i_a_i_m = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m;
+  half3 const l_a_i_a_i_m_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save];
+  int const tint_symbol_3 = i();
+  half const l_a_i_a_i_m_i_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save][tint_symbol_3];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..c6e47d1
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,324 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 204
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block_std140 "a_block_std140"
+               OpMemberName %a_block_std140 0 "inner"
+               OpName %Outer_std140 "Outer_std140"
+               OpMemberName %Outer_std140 0 "a"
+               OpName %Inner_std140 "Inner_std140"
+               OpMemberName %Inner_std140 0 "m_0"
+               OpMemberName %Inner_std140 1 "m_1"
+               OpMemberName %Inner_std140 2 "m_2"
+               OpName %a "a"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %Inner "Inner"
+               OpMemberName %Inner 0 "m"
+               OpName %conv_Inner "conv_Inner"
+               OpName %val "val"
+               OpName %conv_arr4_Inner "conv_arr4_Inner"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i_0 "i"
+               OpName %var_for_index_1 "var_for_index_1"
+               OpName %Outer "Outer"
+               OpMemberName %Outer 0 "a"
+               OpName %conv_Outer "conv_Outer"
+               OpName %val_1 "val"
+               OpName %conv_arr4_Outer "conv_arr4_Outer"
+               OpName %val_2 "val"
+               OpName %arr_0 "arr"
+               OpName %i_1 "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_a_inner_p0_a_p1_m "load_a_inner_p0_a_p1_m"
+               OpName %p0 "p0"
+               OpName %p1 "p1"
+               OpName %load_a_inner_p0_a_p1_m_p2 "load_a_inner_p0_a_p1_m_p2"
+               OpName %p0_0 "p0"
+               OpName %p1_0 "p1"
+               OpName %p2 "p2"
+               OpName %load_a_inner_p0_a_p1_m_p2_p3 "load_a_inner_p0_a_p1_m_p2_p3"
+               OpName %p0_1 "p0"
+               OpName %p1_1 "p1"
+               OpName %p2_0 "p2"
+               OpName %p3 "p3"
+               OpName %f "f"
+               OpDecorate %a_block_std140 Block
+               OpMemberDecorate %a_block_std140 0 Offset 0
+               OpMemberDecorate %Outer_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 1 Offset 8
+               OpMemberDecorate %Inner_std140 2 Offset 16
+               OpDecorate %_arr_Inner_std140_uint_4 ArrayStride 64
+               OpDecorate %_arr_Outer_std140_uint_4 ArrayStride 256
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+               OpMemberDecorate %Inner 0 Offset 0
+               OpMemberDecorate %Inner 0 ColMajor
+               OpMemberDecorate %Inner 0 MatrixStride 8
+               OpDecorate %_arr_Inner_uint_4 ArrayStride 64
+               OpMemberDecorate %Outer 0 Offset 0
+               OpDecorate %_arr_Outer_uint_4 ArrayStride 256
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+%Inner_std140 = OpTypeStruct %v3half %v3half %v3half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_Inner_std140_uint_4 = OpTypeArray %Inner_std140 %uint_4
+%Outer_std140 = OpTypeStruct %_arr_Inner_std140_uint_4
+%_arr_Outer_std140_uint_4 = OpTypeArray %Outer_std140 %uint_4
+%a_block_std140 = OpTypeStruct %_arr_Outer_std140_uint_4
+%_ptr_Uniform_a_block_std140 = OpTypePointer Uniform %a_block_std140
+          %a = OpVariable %_ptr_Uniform_a_block_std140 Uniform
+        %int = OpTypeInt 32 1
+         %13 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %13
+         %16 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+ %mat3v3half = OpTypeMatrix %v3half 3
+      %Inner = OpTypeStruct %mat3v3half
+         %23 = OpTypeFunction %Inner %Inner_std140
+%_arr_Inner_uint_4 = OpTypeArray %Inner %uint_4
+         %34 = OpTypeFunction %_arr_Inner_uint_4 %_arr_Inner_std140_uint_4
+%_ptr_Function__arr_Inner_uint_4 = OpTypePointer Function %_arr_Inner_uint_4
+         %41 = OpConstantNull %_arr_Inner_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %44 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_Inner_std140_uint_4 = OpTypePointer Function %_arr_Inner_std140_uint_4
+         %57 = OpConstantNull %_arr_Inner_std140_uint_4
+%_ptr_Function_Inner = OpTypePointer Function %Inner
+%_ptr_Function_Inner_std140 = OpTypePointer Function %Inner_std140
+     %uint_1 = OpConstant %uint 1
+      %Outer = OpTypeStruct %_arr_Inner_uint_4
+         %70 = OpTypeFunction %Outer %Outer_std140
+%_arr_Outer_uint_4 = OpTypeArray %Outer %uint_4
+         %78 = OpTypeFunction %_arr_Outer_uint_4 %_arr_Outer_std140_uint_4
+%_ptr_Function__arr_Outer_uint_4 = OpTypePointer Function %_arr_Outer_uint_4
+         %85 = OpConstantNull %_arr_Outer_uint_4
+%_ptr_Function__arr_Outer_std140_uint_4 = OpTypePointer Function %_arr_Outer_std140_uint_4
+         %98 = OpConstantNull %_arr_Outer_std140_uint_4
+%_ptr_Function_Outer = OpTypePointer Function %Outer
+%_ptr_Function_Outer_std140 = OpTypePointer Function %Outer_std140
+        %110 = OpTypeFunction %mat3v3half %uint %uint
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_Inner_std140 = OpTypePointer Uniform %Inner_std140
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+     %uint_2 = OpConstant %uint 2
+        %131 = OpTypeFunction %v3half %uint %uint %uint
+        %148 = OpConstantNull %v3half
+        %149 = OpTypeFunction %half %uint %uint %uint %uint
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+        %168 = OpConstantNull %half
+       %void = OpTypeVoid
+        %169 = OpTypeFunction %void
+%_ptr_Uniform__arr_Outer_std140_uint_4 = OpTypePointer Uniform %_arr_Outer_std140_uint_4
+%_ptr_Uniform_Outer_std140 = OpTypePointer Uniform %Outer_std140
+%_ptr_Uniform__arr_Inner_std140_uint_4 = OpTypePointer Uniform %_arr_Inner_std140_uint_4
+          %i = OpFunction %int None %16
+         %18 = OpLabel
+         %19 = OpLoad %int %counter
+         %21 = OpIAdd %int %19 %int_1
+               OpStore %counter %21
+         %22 = OpLoad %int %counter
+               OpReturnValue %22
+               OpFunctionEnd
+ %conv_Inner = OpFunction %Inner None %23
+        %val = OpFunctionParameter %Inner_std140
+         %28 = OpLabel
+         %29 = OpCompositeExtract %v3half %val 0
+         %30 = OpCompositeExtract %v3half %val 1
+         %31 = OpCompositeExtract %v3half %val 2
+         %32 = OpCompositeConstruct %mat3v3half %29 %30 %31
+         %33 = OpCompositeConstruct %Inner %32
+               OpReturnValue %33
+               OpFunctionEnd
+%conv_arr4_Inner = OpFunction %_arr_Inner_uint_4 None %34
+      %val_0 = OpFunctionParameter %_arr_Inner_std140_uint_4
+         %38 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_Inner_uint_4 Function %41
+        %i_0 = OpVariable %_ptr_Function_uint Function %44
+%var_for_index_1 = OpVariable %_ptr_Function__arr_Inner_std140_uint_4 Function %57
+               OpBranch %45
+         %45 = OpLabel
+               OpLoopMerge %46 %47 None
+               OpBranch %48
+         %48 = OpLabel
+         %50 = OpLoad %uint %i_0
+         %51 = OpULessThan %bool %50 %uint_4
+         %49 = OpLogicalNot %bool %51
+               OpSelectionMerge %53 None
+               OpBranchConditional %49 %54 %53
+         %54 = OpLabel
+               OpBranch %46
+         %53 = OpLabel
+               OpStore %var_for_index_1 %val_0
+         %58 = OpLoad %uint %i_0
+         %60 = OpAccessChain %_ptr_Function_Inner %arr %58
+         %62 = OpLoad %uint %i_0
+         %64 = OpAccessChain %_ptr_Function_Inner_std140 %var_for_index_1 %62
+         %65 = OpLoad %Inner_std140 %64
+         %61 = OpFunctionCall %Inner %conv_Inner %65
+               OpStore %60 %61
+               OpBranch %47
+         %47 = OpLabel
+         %66 = OpLoad %uint %i_0
+         %68 = OpIAdd %uint %66 %uint_1
+               OpStore %i_0 %68
+               OpBranch %45
+         %46 = OpLabel
+         %69 = OpLoad %_arr_Inner_uint_4 %arr
+               OpReturnValue %69
+               OpFunctionEnd
+ %conv_Outer = OpFunction %Outer None %70
+      %val_1 = OpFunctionParameter %Outer_std140
+         %74 = OpLabel
+         %76 = OpCompositeExtract %_arr_Inner_std140_uint_4 %val_1 0
+         %75 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %76
+         %77 = OpCompositeConstruct %Outer %75
+               OpReturnValue %77
+               OpFunctionEnd
+%conv_arr4_Outer = OpFunction %_arr_Outer_uint_4 None %78
+      %val_2 = OpFunctionParameter %_arr_Outer_std140_uint_4
+         %82 = OpLabel
+      %arr_0 = OpVariable %_ptr_Function__arr_Outer_uint_4 Function %85
+        %i_1 = OpVariable %_ptr_Function_uint Function %44
+%var_for_index = OpVariable %_ptr_Function__arr_Outer_std140_uint_4 Function %98
+               OpBranch %87
+         %87 = OpLabel
+               OpLoopMerge %88 %89 None
+               OpBranch %90
+         %90 = OpLabel
+         %92 = OpLoad %uint %i_1
+         %93 = OpULessThan %bool %92 %uint_4
+         %91 = OpLogicalNot %bool %93
+               OpSelectionMerge %94 None
+               OpBranchConditional %91 %95 %94
+         %95 = OpLabel
+               OpBranch %88
+         %94 = OpLabel
+               OpStore %var_for_index %val_2
+         %99 = OpLoad %uint %i_1
+        %101 = OpAccessChain %_ptr_Function_Outer %arr_0 %99
+        %103 = OpLoad %uint %i_1
+        %105 = OpAccessChain %_ptr_Function_Outer_std140 %var_for_index %103
+        %106 = OpLoad %Outer_std140 %105
+        %102 = OpFunctionCall %Outer %conv_Outer %106
+               OpStore %101 %102
+               OpBranch %89
+         %89 = OpLabel
+        %107 = OpLoad %uint %i_1
+        %108 = OpIAdd %uint %107 %uint_1
+               OpStore %i_1 %108
+               OpBranch %87
+         %88 = OpLabel
+        %109 = OpLoad %_arr_Outer_uint_4 %arr_0
+               OpReturnValue %109
+               OpFunctionEnd
+%load_a_inner_p0_a_p1_m = OpFunction %mat3v3half None %110
+         %p0 = OpFunctionParameter %uint
+         %p1 = OpFunctionParameter %uint
+        %114 = OpLabel
+        %118 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %p0 %uint_0 %p1
+        %121 = OpAccessChain %_ptr_Uniform_v3half %118 %uint_0
+        %122 = OpLoad %v3half %121
+        %124 = OpAccessChain %_ptr_Uniform_v3half %118 %uint_1
+        %125 = OpLoad %v3half %124
+        %128 = OpAccessChain %_ptr_Uniform_v3half %118 %uint_2
+        %129 = OpLoad %v3half %128
+        %130 = OpCompositeConstruct %mat3v3half %122 %125 %129
+               OpReturnValue %130
+               OpFunctionEnd
+%load_a_inner_p0_a_p1_m_p2 = OpFunction %v3half None %131
+       %p0_0 = OpFunctionParameter %uint
+       %p1_0 = OpFunctionParameter %uint
+         %p2 = OpFunctionParameter %uint
+        %136 = OpLabel
+               OpSelectionMerge %137 None
+               OpSwitch %p2 %138 0 %139 1 %140 2 %141
+        %139 = OpLabel
+        %142 = OpAccessChain %_ptr_Uniform_v3half %a %uint_0 %p0_0 %uint_0 %p1_0 %uint_0
+        %143 = OpLoad %v3half %142
+               OpReturnValue %143
+        %140 = OpLabel
+        %144 = OpAccessChain %_ptr_Uniform_v3half %a %uint_0 %p0_0 %uint_0 %p1_0 %uint_1
+        %145 = OpLoad %v3half %144
+               OpReturnValue %145
+        %141 = OpLabel
+        %146 = OpAccessChain %_ptr_Uniform_v3half %a %uint_0 %p0_0 %uint_0 %p1_0 %uint_2
+        %147 = OpLoad %v3half %146
+               OpReturnValue %147
+        %138 = OpLabel
+               OpReturnValue %148
+        %137 = OpLabel
+               OpReturnValue %148
+               OpFunctionEnd
+%load_a_inner_p0_a_p1_m_p2_p3 = OpFunction %half None %149
+       %p0_1 = OpFunctionParameter %uint
+       %p1_1 = OpFunctionParameter %uint
+       %p2_0 = OpFunctionParameter %uint
+         %p3 = OpFunctionParameter %uint
+        %155 = OpLabel
+               OpSelectionMerge %156 None
+               OpSwitch %p2_0 %157 0 %158 1 %159 2 %160
+        %158 = OpLabel
+        %162 = OpAccessChain %_ptr_Uniform_half %a %uint_0 %p0_1 %uint_0 %p1_1 %uint_0 %p3
+        %163 = OpLoad %half %162
+               OpReturnValue %163
+        %159 = OpLabel
+        %164 = OpAccessChain %_ptr_Uniform_half %a %uint_0 %p0_1 %uint_0 %p1_1 %uint_1 %p3
+        %165 = OpLoad %half %164
+               OpReturnValue %165
+        %160 = OpLabel
+        %166 = OpAccessChain %_ptr_Uniform_half %a %uint_0 %p0_1 %uint_0 %p1_1 %uint_2 %p3
+        %167 = OpLoad %half %166
+               OpReturnValue %167
+        %157 = OpLabel
+               OpReturnValue %168
+        %156 = OpLabel
+               OpReturnValue %168
+               OpFunctionEnd
+          %f = OpFunction %void None %169
+        %172 = OpLabel
+        %173 = OpFunctionCall %int %i
+        %174 = OpFunctionCall %int %i
+        %175 = OpFunctionCall %int %i
+        %178 = OpAccessChain %_ptr_Uniform__arr_Outer_std140_uint_4 %a %uint_0
+        %179 = OpLoad %_arr_Outer_std140_uint_4 %178
+        %176 = OpFunctionCall %_arr_Outer_uint_4 %conv_arr4_Outer %179
+        %182 = OpAccessChain %_ptr_Uniform_Outer_std140 %a %uint_0 %173
+        %183 = OpLoad %Outer_std140 %182
+        %180 = OpFunctionCall %Outer %conv_Outer %183
+        %186 = OpAccessChain %_ptr_Uniform__arr_Inner_std140_uint_4 %a %uint_0 %173 %uint_0
+        %187 = OpLoad %_arr_Inner_std140_uint_4 %186
+        %184 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %187
+        %189 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %173 %uint_0 %174
+        %190 = OpLoad %Inner_std140 %189
+        %188 = OpFunctionCall %Inner %conv_Inner %190
+        %192 = OpBitcast %uint %173
+        %193 = OpBitcast %uint %174
+        %191 = OpFunctionCall %mat3v3half %load_a_inner_p0_a_p1_m %192 %193
+        %195 = OpBitcast %uint %173
+        %196 = OpBitcast %uint %174
+        %197 = OpBitcast %uint %175
+        %194 = OpFunctionCall %v3half %load_a_inner_p0_a_p1_m_p2 %195 %196 %197
+        %198 = OpFunctionCall %int %i
+        %200 = OpBitcast %uint %173
+        %201 = OpBitcast %uint %174
+        %202 = OpBitcast %uint %175
+        %203 = OpBitcast %uint %198
+        %199 = OpFunctionCall %half %load_a_inner_p0_a_p1_m_p2_p3 %200 %201 %202 %203
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..07b0c80
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,36 @@
+enable f16;
+
+struct Inner {
+  @size(64)
+  m : mat3x3<f16>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_i = &((*(p_a))[i()]);
+  let p_a_i_a = &((*(p_a_i)).a);
+  let p_a_i_a_i = &((*(p_a_i_a))[i()]);
+  let p_a_i_a_i_m = &((*(p_a_i_a_i)).m);
+  let p_a_i_a_i_m_i = &((*(p_a_i_a_i_m))[i()]);
+  let l_a : array<Outer, 4> = *(p_a);
+  let l_a_i : Outer = *(p_a_i);
+  let l_a_i_a : array<Inner, 4> = *(p_a_i_a);
+  let l_a_i_a_i : Inner = *(p_a_i_a_i);
+  let l_a_i_a_i_m : mat3x3<f16> = *(p_a_i_a_i_m);
+  let l_a_i_a_i_m_i : vec3<f16> = *(p_a_i_a_i_m_i);
+  let l_a_i_a_i_m_i_i : f16 = (*(p_a_i_a_i_m_i))[i()];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/static_index_via_ptr.wgsl
new file mode 100644
index 0000000..84e1840
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/static_index_via_ptr.wgsl
@@ -0,0 +1,31 @@
+enable f16;
+
+struct Inner {
+  @size(64)
+  m : mat3x3<f16>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &a;
+  let p_a_3 = &((*p_a)[3]);
+  let p_a_3_a = &((*p_a_3).a);
+  let p_a_3_a_2 = &((*p_a_3_a)[2]);
+  let p_a_3_a_2_m = &((*p_a_3_a_2).m);
+  let p_a_3_a_2_m_1 = &((*p_a_3_a_2_m)[1]);
+
+
+  let l_a             : array<Outer, 4> = *p_a;
+  let l_a_3           : Outer           = *p_a_3;
+  let l_a_3_a         : array<Inner, 4> = *p_a_3_a;
+  let l_a_3_a_2       : Inner           = *p_a_3_a_2;
+  let l_a_3_a_2_m     : mat3x3<f16>     = *p_a_3_a_2_m;
+  let l_a_3_a_2_m_1   : vec3<f16>       = *p_a_3_a_2_m_1;
+  let l_a_3_a_2_m_1_0 : f16             = (*p_a_3_a_2_m_1)[0];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..ed02e03
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,76 @@
+struct Inner {
+  matrix<float16_t, 3, 3> m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+
+matrix<float16_t, 3, 3> tint_symbol_4(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  return matrix<float16_t, 3, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]));
+}
+
+Inner tint_symbol_3(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_7 = {tint_symbol_4(buffer, (offset + 0u))};
+  return tint_symbol_7;
+}
+
+typedef Inner tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_3(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_1(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_8 = {tint_symbol_2(buffer, (offset + 0u))};
+  return tint_symbol_8;
+}
+
+typedef Outer tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr_1[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const Outer l_a[4] = tint_symbol(a, 0u);
+  const Outer l_a_3 = tint_symbol_1(a, 768u);
+  const Inner l_a_3_a[4] = tint_symbol_2(a, 768u);
+  const Inner l_a_3_a_2 = tint_symbol_3(a, 896u);
+  const matrix<float16_t, 3, 3> l_a_3_a_2_m = tint_symbol_4(a, 896u);
+  uint2 ubo_load_6 = a[56].zw;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  const vector<float16_t, 3> l_a_3_a_2_m_1 = vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]);
+  const float16_t l_a_3_a_2_m_1_0 = float16_t(f16tof32(((a[56].z) & 0xFFFF)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..6e52af4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,81 @@
+SKIP: FAILED
+
+struct Inner {
+  matrix<float16_t, 3, 3> m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+
+matrix<float16_t, 3, 3> tint_symbol_4(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  return matrix<float16_t, 3, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]));
+}
+
+Inner tint_symbol_3(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_7 = {tint_symbol_4(buffer, (offset + 0u))};
+  return tint_symbol_7;
+}
+
+typedef Inner tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_3(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_1(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_8 = {tint_symbol_2(buffer, (offset + 0u))};
+  return tint_symbol_8;
+}
+
+typedef Outer tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr_1[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const Outer l_a[4] = tint_symbol(a, 0u);
+  const Outer l_a_3 = tint_symbol_1(a, 768u);
+  const Inner l_a_3_a[4] = tint_symbol_2(a, 768u);
+  const Inner l_a_3_a_2 = tint_symbol_3(a, 896u);
+  const matrix<float16_t, 3, 3> l_a_3_a_2_m = tint_symbol_4(a, 896u);
+  uint2 ubo_load_6 = a[56].zw;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  const vector<float16_t, 3> l_a_3_a_2_m_1 = vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]);
+  const float16_t l_a_3_a_2_m_1_0 = float16_t(f16tof32(((a[56].z) & 0xFFFF)));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000021CC01A0970(2,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/static_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..17bbfac
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/static_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,98 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct Inner {
+  f16mat3 m;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+};
+
+struct Inner_std140 {
+  f16vec3 m_0;
+  f16vec3 m_1;
+  f16vec3 m_2;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+};
+
+struct Outer {
+  Inner a[4];
+};
+
+struct Outer_std140 {
+  Inner_std140 a[4];
+};
+
+layout(binding = 0, std140) uniform a_block_std140_ubo {
+  Outer_std140 inner[4];
+} a;
+
+Inner conv_Inner(Inner_std140 val) {
+  return Inner(f16mat3(val.m_0, val.m_1, val.m_2), val.pad, val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9);
+}
+
+Inner[4] conv_arr4_Inner(Inner_std140 val[4]) {
+  Inner arr[4] = Inner[4](Inner(f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_Inner(val[i]);
+    }
+  }
+  return arr;
+}
+
+Outer conv_Outer(Outer_std140 val) {
+  return Outer(conv_arr4_Inner(val.a));
+}
+
+Outer[4] conv_arr4_Outer(Outer_std140 val[4]) {
+  Outer arr[4] = Outer[4](Outer(Inner[4](Inner(f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_Outer(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat3 load_a_inner_3_a_2_m() {
+  return f16mat3(a.inner[3u].a[2u].m_0, a.inner[3u].a[2u].m_1, a.inner[3u].a[2u].m_2);
+}
+
+void f() {
+  Outer p_a[4] = conv_arr4_Outer(a.inner);
+  Outer p_a_3 = conv_Outer(a.inner[3u]);
+  Inner p_a_3_a[4] = conv_arr4_Inner(a.inner[3u].a);
+  Inner p_a_3_a_2 = conv_Inner(a.inner[3u].a[2u]);
+  f16mat3 p_a_3_a_2_m = load_a_inner_3_a_2_m();
+  f16vec3 p_a_3_a_2_m_1 = a.inner[3u].a[2u].m_1;
+  Outer l_a[4] = conv_arr4_Outer(a.inner);
+  Outer l_a_3 = conv_Outer(a.inner[3u]);
+  Inner l_a_3_a[4] = conv_arr4_Inner(a.inner[3u].a);
+  Inner l_a_3_a_2 = conv_Inner(a.inner[3u].a[2u]);
+  f16mat3 l_a_3_a_2_m = load_a_inner_3_a_2_m();
+  f16vec3 l_a_3_a_2_m_1 = a.inner[3u].a[2u].m_1;
+  float16_t l_a_3_a_2_m_1_0 = a.inner[3u].a[2u].m_1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/static_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..b7594a9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/static_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,36 @@
+#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 Inner {
+  /* 0x0000 */ half3x3 m;
+  /* 0x0018 */ tint_array<int8_t, 40> tint_pad;
+};
+
+struct Outer {
+  /* 0x0000 */ tint_array<Inner, 4> a;
+};
+
+kernel void f(const constant tint_array<Outer, 4>* tint_symbol [[buffer(0)]]) {
+  tint_array<Outer, 4> const l_a = *(tint_symbol);
+  Outer const l_a_3 = (*(tint_symbol))[3];
+  tint_array<Inner, 4> const l_a_3_a = (*(tint_symbol))[3].a;
+  Inner const l_a_3_a_2 = (*(tint_symbol))[3].a[2];
+  half3x3 const l_a_3_a_2_m = (*(tint_symbol))[3].a[2].m;
+  half3 const l_a_3_a_2_m_1 = (*(tint_symbol))[3].a[2].m[1];
+  half const l_a_3_a_2_m_1_0 = (*(tint_symbol))[3].a[2].m[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/static_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..a51fd59
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/static_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,232 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 144
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block_std140 "a_block_std140"
+               OpMemberName %a_block_std140 0 "inner"
+               OpName %Outer_std140 "Outer_std140"
+               OpMemberName %Outer_std140 0 "a"
+               OpName %Inner_std140 "Inner_std140"
+               OpMemberName %Inner_std140 0 "m_0"
+               OpMemberName %Inner_std140 1 "m_1"
+               OpMemberName %Inner_std140 2 "m_2"
+               OpName %a "a"
+               OpName %Inner "Inner"
+               OpMemberName %Inner 0 "m"
+               OpName %conv_Inner "conv_Inner"
+               OpName %val "val"
+               OpName %conv_arr4_Inner "conv_arr4_Inner"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index_1 "var_for_index_1"
+               OpName %Outer "Outer"
+               OpMemberName %Outer 0 "a"
+               OpName %conv_Outer "conv_Outer"
+               OpName %val_1 "val"
+               OpName %conv_arr4_Outer "conv_arr4_Outer"
+               OpName %val_2 "val"
+               OpName %arr_0 "arr"
+               OpName %i_0 "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_a_inner_3_a_2_m "load_a_inner_3_a_2_m"
+               OpName %f "f"
+               OpDecorate %a_block_std140 Block
+               OpMemberDecorate %a_block_std140 0 Offset 0
+               OpMemberDecorate %Outer_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 1 Offset 8
+               OpMemberDecorate %Inner_std140 2 Offset 16
+               OpDecorate %_arr_Inner_std140_uint_4 ArrayStride 64
+               OpDecorate %_arr_Outer_std140_uint_4 ArrayStride 256
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+               OpMemberDecorate %Inner 0 Offset 0
+               OpMemberDecorate %Inner 0 ColMajor
+               OpMemberDecorate %Inner 0 MatrixStride 8
+               OpDecorate %_arr_Inner_uint_4 ArrayStride 64
+               OpMemberDecorate %Outer 0 Offset 0
+               OpDecorate %_arr_Outer_uint_4 ArrayStride 256
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+%Inner_std140 = OpTypeStruct %v3half %v3half %v3half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_Inner_std140_uint_4 = OpTypeArray %Inner_std140 %uint_4
+%Outer_std140 = OpTypeStruct %_arr_Inner_std140_uint_4
+%_arr_Outer_std140_uint_4 = OpTypeArray %Outer_std140 %uint_4
+%a_block_std140 = OpTypeStruct %_arr_Outer_std140_uint_4
+%_ptr_Uniform_a_block_std140 = OpTypePointer Uniform %a_block_std140
+          %a = OpVariable %_ptr_Uniform_a_block_std140 Uniform
+ %mat3v3half = OpTypeMatrix %v3half 3
+      %Inner = OpTypeStruct %mat3v3half
+         %12 = OpTypeFunction %Inner %Inner_std140
+%_arr_Inner_uint_4 = OpTypeArray %Inner %uint_4
+         %23 = OpTypeFunction %_arr_Inner_uint_4 %_arr_Inner_std140_uint_4
+%_ptr_Function__arr_Inner_uint_4 = OpTypePointer Function %_arr_Inner_uint_4
+         %30 = OpConstantNull %_arr_Inner_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %33 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_Inner_std140_uint_4 = OpTypePointer Function %_arr_Inner_std140_uint_4
+         %46 = OpConstantNull %_arr_Inner_std140_uint_4
+%_ptr_Function_Inner = OpTypePointer Function %Inner
+%_ptr_Function_Inner_std140 = OpTypePointer Function %Inner_std140
+     %uint_1 = OpConstant %uint 1
+      %Outer = OpTypeStruct %_arr_Inner_uint_4
+         %59 = OpTypeFunction %Outer %Outer_std140
+%_arr_Outer_uint_4 = OpTypeArray %Outer %uint_4
+         %67 = OpTypeFunction %_arr_Outer_uint_4 %_arr_Outer_std140_uint_4
+%_ptr_Function__arr_Outer_uint_4 = OpTypePointer Function %_arr_Outer_uint_4
+         %74 = OpConstantNull %_arr_Outer_uint_4
+%_ptr_Function__arr_Outer_std140_uint_4 = OpTypePointer Function %_arr_Outer_std140_uint_4
+         %87 = OpConstantNull %_arr_Outer_std140_uint_4
+%_ptr_Function_Outer = OpTypePointer Function %Outer
+%_ptr_Function_Outer_std140 = OpTypePointer Function %Outer_std140
+         %99 = OpTypeFunction %mat3v3half
+     %uint_0 = OpConstant %uint 0
+     %uint_3 = OpConstant %uint 3
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_Inner_std140 = OpTypePointer Uniform %Inner_std140
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+       %void = OpTypeVoid
+        %119 = OpTypeFunction %void
+%_ptr_Uniform__arr_Outer_std140_uint_4 = OpTypePointer Uniform %_arr_Outer_std140_uint_4
+%_ptr_Uniform_Outer_std140 = OpTypePointer Uniform %Outer_std140
+%_ptr_Uniform__arr_Inner_std140_uint_4 = OpTypePointer Uniform %_arr_Inner_std140_uint_4
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+ %conv_Inner = OpFunction %Inner None %12
+        %val = OpFunctionParameter %Inner_std140
+         %17 = OpLabel
+         %18 = OpCompositeExtract %v3half %val 0
+         %19 = OpCompositeExtract %v3half %val 1
+         %20 = OpCompositeExtract %v3half %val 2
+         %21 = OpCompositeConstruct %mat3v3half %18 %19 %20
+         %22 = OpCompositeConstruct %Inner %21
+               OpReturnValue %22
+               OpFunctionEnd
+%conv_arr4_Inner = OpFunction %_arr_Inner_uint_4 None %23
+      %val_0 = OpFunctionParameter %_arr_Inner_std140_uint_4
+         %27 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_Inner_uint_4 Function %30
+          %i = OpVariable %_ptr_Function_uint Function %33
+%var_for_index_1 = OpVariable %_ptr_Function__arr_Inner_std140_uint_4 Function %46
+               OpBranch %34
+         %34 = OpLabel
+               OpLoopMerge %35 %36 None
+               OpBranch %37
+         %37 = OpLabel
+         %39 = OpLoad %uint %i
+         %40 = OpULessThan %bool %39 %uint_4
+         %38 = OpLogicalNot %bool %40
+               OpSelectionMerge %42 None
+               OpBranchConditional %38 %43 %42
+         %43 = OpLabel
+               OpBranch %35
+         %42 = OpLabel
+               OpStore %var_for_index_1 %val_0
+         %47 = OpLoad %uint %i
+         %49 = OpAccessChain %_ptr_Function_Inner %arr %47
+         %51 = OpLoad %uint %i
+         %53 = OpAccessChain %_ptr_Function_Inner_std140 %var_for_index_1 %51
+         %54 = OpLoad %Inner_std140 %53
+         %50 = OpFunctionCall %Inner %conv_Inner %54
+               OpStore %49 %50
+               OpBranch %36
+         %36 = OpLabel
+         %55 = OpLoad %uint %i
+         %57 = OpIAdd %uint %55 %uint_1
+               OpStore %i %57
+               OpBranch %34
+         %35 = OpLabel
+         %58 = OpLoad %_arr_Inner_uint_4 %arr
+               OpReturnValue %58
+               OpFunctionEnd
+ %conv_Outer = OpFunction %Outer None %59
+      %val_1 = OpFunctionParameter %Outer_std140
+         %63 = OpLabel
+         %65 = OpCompositeExtract %_arr_Inner_std140_uint_4 %val_1 0
+         %64 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %65
+         %66 = OpCompositeConstruct %Outer %64
+               OpReturnValue %66
+               OpFunctionEnd
+%conv_arr4_Outer = OpFunction %_arr_Outer_uint_4 None %67
+      %val_2 = OpFunctionParameter %_arr_Outer_std140_uint_4
+         %71 = OpLabel
+      %arr_0 = OpVariable %_ptr_Function__arr_Outer_uint_4 Function %74
+        %i_0 = OpVariable %_ptr_Function_uint Function %33
+%var_for_index = OpVariable %_ptr_Function__arr_Outer_std140_uint_4 Function %87
+               OpBranch %76
+         %76 = OpLabel
+               OpLoopMerge %77 %78 None
+               OpBranch %79
+         %79 = OpLabel
+         %81 = OpLoad %uint %i_0
+         %82 = OpULessThan %bool %81 %uint_4
+         %80 = OpLogicalNot %bool %82
+               OpSelectionMerge %83 None
+               OpBranchConditional %80 %84 %83
+         %84 = OpLabel
+               OpBranch %77
+         %83 = OpLabel
+               OpStore %var_for_index %val_2
+         %88 = OpLoad %uint %i_0
+         %90 = OpAccessChain %_ptr_Function_Outer %arr_0 %88
+         %92 = OpLoad %uint %i_0
+         %94 = OpAccessChain %_ptr_Function_Outer_std140 %var_for_index %92
+         %95 = OpLoad %Outer_std140 %94
+         %91 = OpFunctionCall %Outer %conv_Outer %95
+               OpStore %90 %91
+               OpBranch %78
+         %78 = OpLabel
+         %96 = OpLoad %uint %i_0
+         %97 = OpIAdd %uint %96 %uint_1
+               OpStore %i_0 %97
+               OpBranch %76
+         %77 = OpLabel
+         %98 = OpLoad %_arr_Outer_uint_4 %arr_0
+               OpReturnValue %98
+               OpFunctionEnd
+%load_a_inner_3_a_2_m = OpFunction %mat3v3half None %99
+        %101 = OpLabel
+        %107 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %uint_3 %uint_0 %uint_2
+        %110 = OpAccessChain %_ptr_Uniform_v3half %107 %uint_0
+        %111 = OpLoad %v3half %110
+        %113 = OpAccessChain %_ptr_Uniform_v3half %107 %uint_1
+        %114 = OpLoad %v3half %113
+        %116 = OpAccessChain %_ptr_Uniform_v3half %107 %uint_2
+        %117 = OpLoad %v3half %116
+        %118 = OpCompositeConstruct %mat3v3half %111 %114 %117
+               OpReturnValue %118
+               OpFunctionEnd
+          %f = OpFunction %void None %119
+        %122 = OpLabel
+        %125 = OpAccessChain %_ptr_Uniform__arr_Outer_std140_uint_4 %a %uint_0
+        %126 = OpLoad %_arr_Outer_std140_uint_4 %125
+        %123 = OpFunctionCall %_arr_Outer_uint_4 %conv_arr4_Outer %126
+        %129 = OpAccessChain %_ptr_Uniform_Outer_std140 %a %uint_0 %uint_3
+        %130 = OpLoad %Outer_std140 %129
+        %127 = OpFunctionCall %Outer %conv_Outer %130
+        %133 = OpAccessChain %_ptr_Uniform__arr_Inner_std140_uint_4 %a %uint_0 %uint_3 %uint_0
+        %134 = OpLoad %_arr_Inner_std140_uint_4 %133
+        %131 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %134
+        %136 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %uint_3 %uint_0 %uint_2
+        %137 = OpLoad %Inner_std140 %136
+        %135 = OpFunctionCall %Inner %conv_Inner %137
+        %138 = OpFunctionCall %mat3v3half %load_a_inner_3_a_2_m
+        %139 = OpAccessChain %_ptr_Uniform_v3half %a %uint_0 %uint_3 %uint_0 %uint_2 %uint_1
+        %140 = OpLoad %v3half %139
+        %142 = OpAccessChain %_ptr_Uniform_half %a %uint_0 %uint_3 %uint_0 %uint_2 %uint_1 %33
+        %143 = OpLoad %half %142
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/static_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..e7b4e1e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/static_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,29 @@
+enable f16;
+
+struct Inner {
+  @size(64)
+  m : mat3x3<f16>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_3 = &((*(p_a))[3]);
+  let p_a_3_a = &((*(p_a_3)).a);
+  let p_a_3_a_2 = &((*(p_a_3_a))[2]);
+  let p_a_3_a_2_m = &((*(p_a_3_a_2)).m);
+  let p_a_3_a_2_m_1 = &((*(p_a_3_a_2_m))[1]);
+  let l_a : array<Outer, 4> = *(p_a);
+  let l_a_3 : Outer = *(p_a_3);
+  let l_a_3_a : array<Inner, 4> = *(p_a_3_a);
+  let l_a_3_a_2 : Inner = *(p_a_3_a_2);
+  let l_a_3_a_2_m : mat3x3<f16> = *(p_a_3_a_2_m);
+  let l_a_3_a_2_m_1 : vec3<f16> = *(p_a_3_a_2_m_1);
+  let l_a_3_a_2_m_1_0 : f16 = (*(p_a_3_a_2_m_1))[0];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_builtin.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_builtin.wgsl
new file mode 100644
index 0000000..a8f6d50
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_builtin.wgsl
@@ -0,0 +1,17 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat3x3<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    let t = transpose(u[2].m);
+    let l = length(u[0].m[1].zxy);
+    let a = abs(u[0].m[1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_builtin.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..f79425f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_builtin.wgsl.expected.dxc.hlsl
@@ -0,0 +1,36 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+matrix<float16_t, 3, 3> tint_symbol(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  return matrix<float16_t, 3, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 3, 3> t = transpose(tint_symbol(u, 264u));
+  uint2 ubo_load_6 = u[1].xy;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  const float16_t l = length(vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]).zxy);
+  uint2 ubo_load_7 = u[1].xy;
+  vector<float16_t, 2> ubo_load_7_xz = vector<float16_t, 2>(f16tof32(ubo_load_7 & 0xFFFF));
+  float16_t ubo_load_7_y = f16tof32(ubo_load_7[0] >> 16);
+  const float16_t a = abs(vector<float16_t, 3>(ubo_load_7_xz[0], ubo_load_7_y, ubo_load_7_xz[1]).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_builtin.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..bb722e2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_builtin.wgsl.expected.fxc.hlsl
@@ -0,0 +1,41 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+matrix<float16_t, 3, 3> tint_symbol(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  return matrix<float16_t, 3, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 3, 3> t = transpose(tint_symbol(u, 264u));
+  uint2 ubo_load_6 = u[1].xy;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  const float16_t l = length(vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]).zxy);
+  uint2 ubo_load_7 = u[1].xy;
+  vector<float16_t, 2> ubo_load_7_xz = vector<float16_t, 2>(f16tof32(ubo_load_7 & 0xFFFF));
+  float16_t ubo_load_7_y = f16tof32(ubo_load_7[0] >> 16);
+  const float16_t a = abs(vector<float16_t, 3>(ubo_load_7_xz[0], ubo_load_7_y, ubo_load_7_xz[1]).zxy.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001BFA9E0F690(5,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_builtin.wgsl.expected.glsl
new file mode 100644
index 0000000..fdc2b36
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_builtin.wgsl.expected.glsl
@@ -0,0 +1,84 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct S {
+  int before;
+  uint pad;
+  f16mat3 m;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  int after;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+};
+
+struct S_std140 {
+  int before;
+  uint pad;
+  f16vec3 m_0;
+  f16vec3 m_1;
+  f16vec3 m_2;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  int after;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+f16mat3 load_u_inner_2_m() {
+  return f16mat3(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2);
+}
+
+void f() {
+  f16mat3 t = transpose(load_u_inner_2_m());
+  float16_t l = length(u.inner[0u].m_1.zxy);
+  float16_t a = abs(u.inner[0u].m_1.zxy[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_builtin.wgsl.expected.msl
new file mode 100644
index 0000000..350c296
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_builtin.wgsl.expected.msl
@@ -0,0 +1,32 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0008 */ half3x3 m;
+  /* 0x0020 */ tint_array<int8_t, 32> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol [[buffer(0)]]) {
+  half3x3 const t = transpose((*(tint_symbol))[2].m);
+  half const l = length(half3((*(tint_symbol))[0].m[1]).zxy);
+  half const a = fabs(half3((*(tint_symbol))[0].m[1]).zxy[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_builtin.wgsl.expected.spvasm
new file mode 100644
index 0000000..30a0ddd
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_builtin.wgsl.expected.spvasm
@@ -0,0 +1,84 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 50
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+         %40 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "m_2"
+               OpMemberName %S_std140 4 "after"
+               OpName %u "u"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 8
+               OpMemberDecorate %S_std140 2 Offset 16
+               OpMemberDecorate %S_std140 3 Offset 24
+               OpMemberDecorate %S_std140 4 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+   %S_std140 = OpTypeStruct %int %v3half %v3half %v3half %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat3v3half = OpTypeMatrix %v3half 3
+         %11 = OpTypeFunction %mat3v3half
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+     %uint_1 = OpConstant %uint 1
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %33 = OpTypeFunction %void
+         %41 = OpConstantNull %uint
+%load_u_inner_2_m = OpFunction %mat3v3half None %11
+         %14 = OpLabel
+         %19 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %23 = OpAccessChain %_ptr_Uniform_v3half %19 %uint_1
+         %24 = OpLoad %v3half %23
+         %26 = OpAccessChain %_ptr_Uniform_v3half %19 %uint_2
+         %27 = OpLoad %v3half %26
+         %30 = OpAccessChain %_ptr_Uniform_v3half %19 %uint_3
+         %31 = OpLoad %v3half %30
+         %32 = OpCompositeConstruct %mat3v3half %24 %27 %31
+               OpReturnValue %32
+               OpFunctionEnd
+          %f = OpFunction %void None %33
+         %36 = OpLabel
+         %38 = OpFunctionCall %mat3v3half %load_u_inner_2_m
+         %37 = OpTranspose %mat3v3half %38
+         %42 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0 %41 %uint_2
+         %43 = OpLoad %v3half %42
+         %44 = OpVectorShuffle %v3half %43 %43 2 0 1
+         %39 = OpExtInst %half %40 Length %44
+         %46 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0 %41 %uint_2
+         %47 = OpLoad %v3half %46
+         %48 = OpVectorShuffle %v3half %47 %47 2 0 1
+         %49 = OpCompositeExtract %half %48 0
+         %45 = OpExtInst %half %40 FAbs %49
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_builtin.wgsl.expected.wgsl
new file mode 100644
index 0000000..58666b8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_builtin.wgsl.expected.wgsl
@@ -0,0 +1,17 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat3x3<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let t = transpose(u[2].m);
+  let l = length(u[0].m[1].zxy);
+  let a = abs(u[0].m[1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_fn.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_fn.wgsl
new file mode 100644
index 0000000..01fffdd
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_fn.wgsl
@@ -0,0 +1,25 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat3x3<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+fn a(a : array<S, 4>) {}
+fn b(s : S) {}
+fn c(m : mat3x3<f16>) {}
+fn d(v : vec3<f16>) {}
+fn e(f : f16) {}
+
+@compute @workgroup_size(1)
+fn f() {
+    a(u);
+    b(u[2]);
+    c(u[2].m);
+    d(u[0].m[1].zxy);
+    e(u[0].m[1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_fn.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..08bbf31
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_fn.wgsl.expected.dxc.hlsl
@@ -0,0 +1,77 @@
+struct S {
+  int before;
+  matrix<float16_t, 3, 3> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(matrix<float16_t, 3, 3> m) {
+}
+
+void d(vector<float16_t, 3> v) {
+}
+
+void e(float16_t f_1) {
+}
+
+matrix<float16_t, 3, 3> tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  return matrix<float16_t, 3, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 256u));
+  c(tint_symbol_3(u, 264u));
+  uint2 ubo_load_6 = u[1].xy;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  d(vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]).zxy);
+  uint2 ubo_load_7 = u[1].xy;
+  vector<float16_t, 2> ubo_load_7_xz = vector<float16_t, 2>(f16tof32(ubo_load_7 & 0xFFFF));
+  float16_t ubo_load_7_y = f16tof32(ubo_load_7[0] >> 16);
+  e(vector<float16_t, 3>(ubo_load_7_xz[0], ubo_load_7_y, ubo_load_7_xz[1]).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_fn.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..f1deae3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_fn.wgsl.expected.fxc.hlsl
@@ -0,0 +1,82 @@
+SKIP: FAILED
+
+struct S {
+  int before;
+  matrix<float16_t, 3, 3> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(matrix<float16_t, 3, 3> m) {
+}
+
+void d(vector<float16_t, 3> v) {
+}
+
+void e(float16_t f_1) {
+}
+
+matrix<float16_t, 3, 3> tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  return matrix<float16_t, 3, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 256u));
+  c(tint_symbol_3(u, 264u));
+  uint2 ubo_load_6 = u[1].xy;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  d(vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]).zxy);
+  uint2 ubo_load_7 = u[1].xy;
+  vector<float16_t, 2> ubo_load_7_xz = vector<float16_t, 2>(f16tof32(ubo_load_7 & 0xFFFF));
+  float16_t ubo_load_7_y = f16tof32(ubo_load_7[0] >> 16);
+  e(vector<float16_t, 3>(ubo_load_7_xz[0], ubo_load_7_y, ubo_load_7_xz[1]).zxy.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001A1CC720100(3,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_fn.wgsl.expected.glsl
new file mode 100644
index 0000000..263e4168
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_fn.wgsl.expected.glsl
@@ -0,0 +1,115 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct S {
+  int before;
+  uint pad;
+  f16mat3 m;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  int after;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+};
+
+struct S_std140 {
+  int before;
+  uint pad;
+  f16vec3 m_0;
+  f16vec3 m_1;
+  f16vec3 m_2;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  int after;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(f16mat3 m) {
+}
+
+void d(f16vec3 v) {
+}
+
+void e(float16_t f_1) {
+}
+
+S conv_S(S_std140 val) {
+  return S(val.before, val.pad, f16mat3(val.m_0, val.m_1, val.m_2), val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.after, val.pad_9, val.pad_10, val.pad_11, val.pad_12, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21, val.pad_22, val.pad_23);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, 0u, f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat3 load_u_inner_2_m() {
+  return f16mat3(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2);
+}
+
+void f() {
+  a(conv_arr4_S(u.inner));
+  b(conv_S(u.inner[2u]));
+  c(load_u_inner_2_m());
+  d(u.inner[0u].m_1.zxy);
+  e(u.inner[0u].m_1.zxy[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_fn.wgsl.expected.msl
new file mode 100644
index 0000000..89e6084
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_fn.wgsl.expected.msl
@@ -0,0 +1,49 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0008 */ half3x3 m;
+  /* 0x0020 */ tint_array<int8_t, 32> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+void a(tint_array<S, 4> a_1) {
+}
+
+void b(S s) {
+}
+
+void c(half3x3 m) {
+}
+
+void d(half3 v) {
+}
+
+void e(half f_1) {
+}
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol [[buffer(0)]]) {
+  a(*(tint_symbol));
+  b((*(tint_symbol))[2]);
+  c((*(tint_symbol))[2].m);
+  d(half3((*(tint_symbol))[0].m[1]).zxy);
+  e(half3((*(tint_symbol))[0].m[1]).zxy[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_fn.wgsl.expected.spvasm
new file mode 100644
index 0000000..4bd94cd
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_fn.wgsl.expected.spvasm
@@ -0,0 +1,210 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 124
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "m_2"
+               OpMemberName %S_std140 4 "after"
+               OpName %u "u"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %a "a"
+               OpName %a_1 "a_1"
+               OpName %b "b"
+               OpName %s "s"
+               OpName %c "c"
+               OpName %m "m"
+               OpName %d "d"
+               OpName %v "v"
+               OpName %e "e"
+               OpName %f_1 "f_1"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 8
+               OpMemberDecorate %S_std140 2 Offset 16
+               OpMemberDecorate %S_std140 3 Offset 24
+               OpMemberDecorate %S_std140 4 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 8
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 8
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+   %S_std140 = OpTypeStruct %int %v3half %v3half %v3half %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+       %void = OpTypeVoid
+ %mat3v3half = OpTypeMatrix %v3half 3
+          %S = OpTypeStruct %int %mat3v3half %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+         %11 = OpTypeFunction %void %_arr_S_uint_4
+         %19 = OpTypeFunction %void %S
+         %23 = OpTypeFunction %void %mat3v3half
+         %27 = OpTypeFunction %void %v3half
+         %31 = OpTypeFunction %void %half
+         %35 = OpTypeFunction %S %S_std140
+         %46 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+         %52 = OpConstantNull %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %55 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %68 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %81 = OpTypeFunction %mat3v3half
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+     %uint_3 = OpConstant %uint 3
+        %101 = OpTypeFunction %void
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+          %a = OpFunction %void None %11
+        %a_1 = OpFunctionParameter %_arr_S_uint_4
+         %18 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %b = OpFunction %void None %19
+          %s = OpFunctionParameter %S
+         %22 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %c = OpFunction %void None %23
+          %m = OpFunctionParameter %mat3v3half
+         %26 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %d = OpFunction %void None %27
+          %v = OpFunctionParameter %v3half
+         %30 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %e = OpFunction %void None %31
+        %f_1 = OpFunctionParameter %half
+         %34 = OpLabel
+               OpReturn
+               OpFunctionEnd
+     %conv_S = OpFunction %S None %35
+        %val = OpFunctionParameter %S_std140
+         %38 = OpLabel
+         %39 = OpCompositeExtract %int %val 0
+         %40 = OpCompositeExtract %v3half %val 1
+         %41 = OpCompositeExtract %v3half %val 2
+         %42 = OpCompositeExtract %v3half %val 3
+         %43 = OpCompositeConstruct %mat3v3half %40 %41 %42
+         %44 = OpCompositeExtract %int %val 4
+         %45 = OpCompositeConstruct %S %39 %43 %44
+               OpReturnValue %45
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %46
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %49 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %52
+          %i = OpVariable %_ptr_Function_uint Function %55
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %68
+               OpBranch %56
+         %56 = OpLabel
+               OpLoopMerge %57 %58 None
+               OpBranch %59
+         %59 = OpLabel
+         %61 = OpLoad %uint %i
+         %62 = OpULessThan %bool %61 %uint_4
+         %60 = OpLogicalNot %bool %62
+               OpSelectionMerge %64 None
+               OpBranchConditional %60 %65 %64
+         %65 = OpLabel
+               OpBranch %57
+         %64 = OpLabel
+               OpStore %var_for_index %val_0
+         %69 = OpLoad %uint %i
+         %71 = OpAccessChain %_ptr_Function_S %arr %69
+         %73 = OpLoad %uint %i
+         %75 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %73
+         %76 = OpLoad %S_std140 %75
+         %72 = OpFunctionCall %S %conv_S %76
+               OpStore %71 %72
+               OpBranch %58
+         %58 = OpLabel
+         %77 = OpLoad %uint %i
+         %79 = OpIAdd %uint %77 %uint_1
+               OpStore %i %79
+               OpBranch %56
+         %57 = OpLabel
+         %80 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %80
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat3v3half None %81
+         %83 = OpLabel
+         %88 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %91 = OpAccessChain %_ptr_Uniform_v3half %88 %uint_1
+         %92 = OpLoad %v3half %91
+         %94 = OpAccessChain %_ptr_Uniform_v3half %88 %uint_2
+         %95 = OpLoad %v3half %94
+         %98 = OpAccessChain %_ptr_Uniform_v3half %88 %uint_3
+         %99 = OpLoad %v3half %98
+        %100 = OpCompositeConstruct %mat3v3half %92 %95 %99
+               OpReturnValue %100
+               OpFunctionEnd
+          %f = OpFunction %void None %101
+        %103 = OpLabel
+        %107 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+        %108 = OpLoad %_arr_S_std140_uint_4 %107
+        %105 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %108
+        %104 = OpFunctionCall %void %a %105
+        %111 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+        %112 = OpLoad %S_std140 %111
+        %110 = OpFunctionCall %S %conv_S %112
+        %109 = OpFunctionCall %void %b %110
+        %114 = OpFunctionCall %mat3v3half %load_u_inner_2_m
+        %113 = OpFunctionCall %void %c %114
+        %116 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0 %55 %uint_2
+        %117 = OpLoad %v3half %116
+        %118 = OpVectorShuffle %v3half %117 %117 2 0 1
+        %115 = OpFunctionCall %void %d %118
+        %120 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0 %55 %uint_2
+        %121 = OpLoad %v3half %120
+        %122 = OpVectorShuffle %v3half %121 %121 2 0 1
+        %123 = OpCompositeExtract %half %122 0
+        %119 = OpFunctionCall %void %e %123
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_fn.wgsl.expected.wgsl
new file mode 100644
index 0000000..786a6ba
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_fn.wgsl.expected.wgsl
@@ -0,0 +1,34 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat3x3<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+fn a(a : array<S, 4>) {
+}
+
+fn b(s : S) {
+}
+
+fn c(m : mat3x3<f16>) {
+}
+
+fn d(v : vec3<f16>) {
+}
+
+fn e(f : f16) {
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  a(u);
+  b(u[2]);
+  c(u[2].m);
+  d(u[0].m[1].zxy);
+  e(u[0].m[1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_private.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_private.wgsl
new file mode 100644
index 0000000..ab176ca
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_private.wgsl
@@ -0,0 +1,19 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat3x3<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+var<private> p : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[2];
+    p[3].m = u[2].m;
+    p[1].m[0] = u[0].m[1].zxy;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_private.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..dffe336
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_private.wgsl.expected.dxc.hlsl
@@ -0,0 +1,59 @@
+struct S {
+  int before;
+  matrix<float16_t, 3, 3> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+static S p[4] = (S[4])0;
+
+matrix<float16_t, 3, 3> tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  return matrix<float16_t, 3, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 256u);
+  p[3].m = tint_symbol_3(u, 264u);
+  uint2 ubo_load_6 = u[1].xy;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  p[1].m[0] = vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]).zxy;
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_private.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..7c9105a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_private.wgsl.expected.fxc.hlsl
@@ -0,0 +1,64 @@
+SKIP: FAILED
+
+struct S {
+  int before;
+  matrix<float16_t, 3, 3> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+static S p[4] = (S[4])0;
+
+matrix<float16_t, 3, 3> tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  return matrix<float16_t, 3, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 256u);
+  p[3].m = tint_symbol_3(u, 264u);
+  uint2 ubo_load_6 = u[1].xy;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  p[1].m[0] = vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]).zxy;
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000025A3E276990(3,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..35c7f1a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_private.wgsl.expected.glsl
@@ -0,0 +1,100 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct S {
+  int before;
+  uint pad;
+  f16mat3 m;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  int after;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+};
+
+struct S_std140 {
+  int before;
+  uint pad;
+  f16vec3 m_0;
+  f16vec3 m_1;
+  f16vec3 m_2;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  int after;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+S p[4] = S[4](S(0, 0u, f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+S conv_S(S_std140 val) {
+  return S(val.before, val.pad, f16mat3(val.m_0, val.m_1, val.m_2), val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.after, val.pad_9, val.pad_10, val.pad_11, val.pad_12, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21, val.pad_22, val.pad_23);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, 0u, f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat3 load_u_inner_2_m() {
+  return f16mat3(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2);
+}
+
+void f() {
+  p = conv_arr4_S(u.inner);
+  p[1] = conv_S(u.inner[2u]);
+  p[3].m = load_u_inner_2_m();
+  p[1].m[0] = u.inner[0u].m_1.zxy;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..ff2ae9b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_private.wgsl.expected.msl
@@ -0,0 +1,34 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0008 */ half3x3 m;
+  /* 0x0020 */ tint_array<int8_t, 32> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol_1 [[buffer(0)]]) {
+  thread tint_array<S, 4> tint_symbol = {};
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[2];
+  tint_symbol[3].m = (*(tint_symbol_1))[2].m;
+  tint_symbol[1].m[0] = half3((*(tint_symbol_1))[0].m[1]).zxy;
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_private.wgsl.expected.spvasm
new file mode 100644
index 0000000..26873c8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_private.wgsl.expected.spvasm
@@ -0,0 +1,177 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 106
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "m_2"
+               OpMemberName %S_std140 4 "after"
+               OpName %u "u"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %p "p"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 8
+               OpMemberDecorate %S_std140 2 Offset 16
+               OpMemberDecorate %S_std140 3 Offset 24
+               OpMemberDecorate %S_std140 4 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 8
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 8
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+   %S_std140 = OpTypeStruct %int %v3half %v3half %v3half %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat3v3half = OpTypeMatrix %v3half 3
+          %S = OpTypeStruct %int %mat3v3half %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+%_ptr_Private__arr_S_uint_4 = OpTypePointer Private %_arr_S_uint_4
+         %16 = OpConstantNull %_arr_S_uint_4
+          %p = OpVariable %_ptr_Private__arr_S_uint_4 Private %16
+         %17 = OpTypeFunction %S %S_std140
+         %28 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %36 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %49 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %62 = OpTypeFunction %mat3v3half
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %82 = OpTypeFunction %void
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+      %int_1 = OpConstant %int 1
+%_ptr_Private_S = OpTypePointer Private %S
+      %int_3 = OpConstant %int 3
+%_ptr_Private_mat3v3half = OpTypePointer Private %mat3v3half
+        %100 = OpConstantNull %int
+%_ptr_Private_v3half = OpTypePointer Private %v3half
+     %conv_S = OpFunction %S None %17
+        %val = OpFunctionParameter %S_std140
+         %20 = OpLabel
+         %21 = OpCompositeExtract %int %val 0
+         %22 = OpCompositeExtract %v3half %val 1
+         %23 = OpCompositeExtract %v3half %val 2
+         %24 = OpCompositeExtract %v3half %val 3
+         %25 = OpCompositeConstruct %mat3v3half %22 %23 %24
+         %26 = OpCompositeExtract %int %val 4
+         %27 = OpCompositeConstruct %S %21 %25 %26
+               OpReturnValue %27
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %28
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %31 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %16
+          %i = OpVariable %_ptr_Function_uint Function %36
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %49
+               OpBranch %37
+         %37 = OpLabel
+               OpLoopMerge %38 %39 None
+               OpBranch %40
+         %40 = OpLabel
+         %42 = OpLoad %uint %i
+         %43 = OpULessThan %bool %42 %uint_4
+         %41 = OpLogicalNot %bool %43
+               OpSelectionMerge %45 None
+               OpBranchConditional %41 %46 %45
+         %46 = OpLabel
+               OpBranch %38
+         %45 = OpLabel
+               OpStore %var_for_index %val_0
+         %50 = OpLoad %uint %i
+         %52 = OpAccessChain %_ptr_Function_S %arr %50
+         %54 = OpLoad %uint %i
+         %56 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %54
+         %57 = OpLoad %S_std140 %56
+         %53 = OpFunctionCall %S %conv_S %57
+               OpStore %52 %53
+               OpBranch %39
+         %39 = OpLabel
+         %58 = OpLoad %uint %i
+         %60 = OpIAdd %uint %58 %uint_1
+               OpStore %i %60
+               OpBranch %37
+         %38 = OpLabel
+         %61 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %61
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat3v3half None %62
+         %64 = OpLabel
+         %69 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %72 = OpAccessChain %_ptr_Uniform_v3half %69 %uint_1
+         %73 = OpLoad %v3half %72
+         %75 = OpAccessChain %_ptr_Uniform_v3half %69 %uint_2
+         %76 = OpLoad %v3half %75
+         %79 = OpAccessChain %_ptr_Uniform_v3half %69 %uint_3
+         %80 = OpLoad %v3half %79
+         %81 = OpCompositeConstruct %mat3v3half %73 %76 %80
+               OpReturnValue %81
+               OpFunctionEnd
+          %f = OpFunction %void None %82
+         %85 = OpLabel
+         %88 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+         %89 = OpLoad %_arr_S_std140_uint_4 %88
+         %86 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %89
+               OpStore %p %86
+         %92 = OpAccessChain %_ptr_Private_S %p %int_1
+         %94 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %95 = OpLoad %S_std140 %94
+         %93 = OpFunctionCall %S %conv_S %95
+               OpStore %92 %93
+         %98 = OpAccessChain %_ptr_Private_mat3v3half %p %int_3 %uint_1
+         %99 = OpFunctionCall %mat3v3half %load_u_inner_2_m
+               OpStore %98 %99
+        %102 = OpAccessChain %_ptr_Private_v3half %p %int_1 %uint_1 %100
+        %103 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0 %36 %uint_2
+        %104 = OpLoad %v3half %103
+        %105 = OpVectorShuffle %v3half %104 %104 2 0 1
+               OpStore %102 %105
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..d6f4bf6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_private.wgsl.expected.wgsl
@@ -0,0 +1,20 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat3x3<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+var<private> p : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[2];
+  p[3].m = u[2].m;
+  p[1].m[0] = u[0].m[1].zxy;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_storage.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_storage.wgsl
new file mode 100644
index 0000000..290b0f1
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_storage.wgsl
@@ -0,0 +1,19 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat3x3<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+@group(0) @binding(1) var<storage, read_write> s : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[2];
+    s[3].m = u[2].m;
+    s[1].m[0] = u[0].m[1].zxy;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_storage.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..403b78d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_storage.wgsl.expected.dxc.hlsl
@@ -0,0 +1,80 @@
+struct S {
+  int before;
+  matrix<float16_t, 3, 3> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_3(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 3, 3> value) {
+  buffer.Store<vector<float16_t, 3> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 8u), value[1u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 16u), value[2u]);
+}
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, S value) {
+  buffer.Store((offset + 0u), asuint(value.before));
+  tint_symbol_3(buffer, (offset + 8u), value.m);
+  buffer.Store((offset + 64u), asuint(value.after));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, S value[4]) {
+  S array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 128u)), array[i]);
+    }
+  }
+}
+
+matrix<float16_t, 3, 3> tint_symbol_8(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  return matrix<float16_t, 3, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]));
+}
+
+S tint_symbol_6(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_10 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_8(buffer, (offset + 8u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_10;
+}
+
+typedef S tint_symbol_5_ret[4];
+tint_symbol_5_ret tint_symbol_5(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_6(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_5(u, 0u));
+  tint_symbol_1(s, 128u, tint_symbol_6(u, 256u));
+  tint_symbol_3(s, 392u, tint_symbol_8(u, 264u));
+  uint2 ubo_load_6 = u[1].xy;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  s.Store<vector<float16_t, 3> >(136u, vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]).zxy);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_storage.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..c89fc84
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_storage.wgsl.expected.fxc.hlsl
@@ -0,0 +1,85 @@
+SKIP: FAILED
+
+struct S {
+  int before;
+  matrix<float16_t, 3, 3> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_3(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 3, 3> value) {
+  buffer.Store<vector<float16_t, 3> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 8u), value[1u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 16u), value[2u]);
+}
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, S value) {
+  buffer.Store((offset + 0u), asuint(value.before));
+  tint_symbol_3(buffer, (offset + 8u), value.m);
+  buffer.Store((offset + 64u), asuint(value.after));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, S value[4]) {
+  S array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 128u)), array[i]);
+    }
+  }
+}
+
+matrix<float16_t, 3, 3> tint_symbol_8(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  return matrix<float16_t, 3, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]));
+}
+
+S tint_symbol_6(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_10 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_8(buffer, (offset + 8u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_10;
+}
+
+typedef S tint_symbol_5_ret[4];
+tint_symbol_5_ret tint_symbol_5(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_6(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_5(u, 0u));
+  tint_symbol_1(s, 128u, tint_symbol_6(u, 256u));
+  tint_symbol_3(s, 392u, tint_symbol_8(u, 264u));
+  uint2 ubo_load_6 = u[1].xy;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  s.Store<vector<float16_t, 3> >(136u, vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]).zxy);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001D5F9C4A510(3,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..dec449e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_storage.wgsl.expected.glsl
@@ -0,0 +1,103 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct S {
+  int before;
+  uint pad;
+  f16mat3 m;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  int after;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+};
+
+struct S_std140 {
+  int before;
+  uint pad;
+  f16vec3 m_0;
+  f16vec3 m_1;
+  f16vec3 m_2;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  int after;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  S inner[4];
+} s;
+
+S conv_S(S_std140 val) {
+  return S(val.before, val.pad, f16mat3(val.m_0, val.m_1, val.m_2), val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.after, val.pad_9, val.pad_10, val.pad_11, val.pad_12, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21, val.pad_22, val.pad_23);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, 0u, f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat3 load_u_inner_2_m() {
+  return f16mat3(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2);
+}
+
+void f() {
+  s.inner = conv_arr4_S(u.inner);
+  s.inner[1] = conv_S(u.inner[2u]);
+  s.inner[3].m = load_u_inner_2_m();
+  s.inner[1].m[0] = u.inner[0u].m_1.zxy;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..c1f26b0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_storage.wgsl.expected.msl
@@ -0,0 +1,33 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0008 */ half3x3 m;
+  /* 0x0020 */ tint_array<int8_t, 32> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+kernel void f(device tint_array<S, 4>* tint_symbol [[buffer(1)]], const constant tint_array<S, 4>* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
+  (*(tint_symbol))[3].m = (*(tint_symbol_1))[2].m;
+  (*(tint_symbol))[1].m[0] = half3((*(tint_symbol_1))[0].m[1]).zxy;
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_storage.wgsl.expected.spvasm
new file mode 100644
index 0000000..cdbee5f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_storage.wgsl.expected.spvasm
@@ -0,0 +1,186 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 109
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "m_2"
+               OpMemberName %S_std140 4 "after"
+               OpName %u "u"
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %s "s"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 8
+               OpMemberDecorate %S_std140 2 Offset 16
+               OpMemberDecorate %S_std140 3 Offset 24
+               OpMemberDecorate %S_std140 4 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 8
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 8
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+               OpDecorate %s DescriptorSet 0
+               OpDecorate %s Binding 1
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+   %S_std140 = OpTypeStruct %int %v3half %v3half %v3half %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat3v3half = OpTypeMatrix %v3half 3
+          %S = OpTypeStruct %int %mat3v3half %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+    %u_block = OpTypeStruct %_arr_S_uint_4
+%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
+          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+         %17 = OpTypeFunction %S %S_std140
+         %28 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+         %34 = OpConstantNull %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %37 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %50 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %63 = OpTypeFunction %mat3v3half
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %83 = OpTypeFunction %void
+%_ptr_StorageBuffer__arr_S_uint_4 = OpTypePointer StorageBuffer %_arr_S_uint_4
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+      %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
+      %int_3 = OpConstant %int 3
+%_ptr_StorageBuffer_mat3v3half = OpTypePointer StorageBuffer %mat3v3half
+        %103 = OpConstantNull %int
+%_ptr_StorageBuffer_v3half = OpTypePointer StorageBuffer %v3half
+     %conv_S = OpFunction %S None %17
+        %val = OpFunctionParameter %S_std140
+         %20 = OpLabel
+         %21 = OpCompositeExtract %int %val 0
+         %22 = OpCompositeExtract %v3half %val 1
+         %23 = OpCompositeExtract %v3half %val 2
+         %24 = OpCompositeExtract %v3half %val 3
+         %25 = OpCompositeConstruct %mat3v3half %22 %23 %24
+         %26 = OpCompositeExtract %int %val 4
+         %27 = OpCompositeConstruct %S %21 %25 %26
+               OpReturnValue %27
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %28
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %31 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %34
+          %i = OpVariable %_ptr_Function_uint Function %37
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %50
+               OpBranch %38
+         %38 = OpLabel
+               OpLoopMerge %39 %40 None
+               OpBranch %41
+         %41 = OpLabel
+         %43 = OpLoad %uint %i
+         %44 = OpULessThan %bool %43 %uint_4
+         %42 = OpLogicalNot %bool %44
+               OpSelectionMerge %46 None
+               OpBranchConditional %42 %47 %46
+         %47 = OpLabel
+               OpBranch %39
+         %46 = OpLabel
+               OpStore %var_for_index %val_0
+         %51 = OpLoad %uint %i
+         %53 = OpAccessChain %_ptr_Function_S %arr %51
+         %55 = OpLoad %uint %i
+         %57 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %55
+         %58 = OpLoad %S_std140 %57
+         %54 = OpFunctionCall %S %conv_S %58
+               OpStore %53 %54
+               OpBranch %40
+         %40 = OpLabel
+         %59 = OpLoad %uint %i
+         %61 = OpIAdd %uint %59 %uint_1
+               OpStore %i %61
+               OpBranch %38
+         %39 = OpLabel
+         %62 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %62
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat3v3half None %63
+         %65 = OpLabel
+         %70 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %73 = OpAccessChain %_ptr_Uniform_v3half %70 %uint_1
+         %74 = OpLoad %v3half %73
+         %76 = OpAccessChain %_ptr_Uniform_v3half %70 %uint_2
+         %77 = OpLoad %v3half %76
+         %80 = OpAccessChain %_ptr_Uniform_v3half %70 %uint_3
+         %81 = OpLoad %v3half %80
+         %82 = OpCompositeConstruct %mat3v3half %74 %77 %81
+               OpReturnValue %82
+               OpFunctionEnd
+          %f = OpFunction %void None %83
+         %86 = OpLabel
+         %88 = OpAccessChain %_ptr_StorageBuffer__arr_S_uint_4 %s %uint_0
+         %91 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+         %92 = OpLoad %_arr_S_std140_uint_4 %91
+         %89 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %92
+               OpStore %88 %89
+         %95 = OpAccessChain %_ptr_StorageBuffer_S %s %uint_0 %int_1
+         %97 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %98 = OpLoad %S_std140 %97
+         %96 = OpFunctionCall %S %conv_S %98
+               OpStore %95 %96
+        %101 = OpAccessChain %_ptr_StorageBuffer_mat3v3half %s %uint_0 %int_3 %uint_1
+        %102 = OpFunctionCall %mat3v3half %load_u_inner_2_m
+               OpStore %101 %102
+        %105 = OpAccessChain %_ptr_StorageBuffer_v3half %s %uint_0 %int_1 %uint_1 %103
+        %106 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0 %37 %uint_2
+        %107 = OpLoad %v3half %106
+        %108 = OpVectorShuffle %v3half %107 %107 2 0 1
+               OpStore %105 %108
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..6a5bf6f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,20 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat3x3<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@group(0) @binding(1) var<storage, read_write> s : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[2];
+  s[3].m = u[2].m;
+  s[1].m[0] = u[0].m[1].zxy;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_workgroup.wgsl
new file mode 100644
index 0000000..c8835b5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_workgroup.wgsl
@@ -0,0 +1,19 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat3x3<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+var<workgroup> w : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[2];
+    w[3].m = u[2].m;
+    w[1].m[0] = u[0].m[1].zxy;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_workgroup.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..10d0d09
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_workgroup.wgsl.expected.dxc.hlsl
@@ -0,0 +1,75 @@
+struct S {
+  int before;
+  matrix<float16_t, 3, 3> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+groupshared S w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 3, 3> tint_symbol_5(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  return matrix<float16_t, 3, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]));
+}
+
+S tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_8 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_5(buffer, (offset + 8u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_8;
+}
+
+typedef S tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      const S tint_symbol_7 = (S)0;
+      w[i] = tint_symbol_7;
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 256u);
+  w[3].m = tint_symbol_5(u, 264u);
+  uint2 ubo_load_6 = u[1].xy;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  w[1].m[0] = vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]).zxy;
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_workgroup.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..b205f67
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_workgroup.wgsl.expected.fxc.hlsl
@@ -0,0 +1,80 @@
+SKIP: FAILED
+
+struct S {
+  int before;
+  matrix<float16_t, 3, 3> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+groupshared S w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 3, 3> tint_symbol_5(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  return matrix<float16_t, 3, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]));
+}
+
+S tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_8 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_5(buffer, (offset + 8u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_8;
+}
+
+typedef S tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      const S tint_symbol_7 = (S)0;
+      w[i] = tint_symbol_7;
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 256u);
+  w[3].m = tint_symbol_5(u, 264u);
+  uint2 ubo_load_6 = u[1].xy;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  w[1].m[0] = vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]).zxy;
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000021282D17B60(3,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..9a55a19
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,108 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct S {
+  int before;
+  uint pad;
+  f16mat3 m;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  int after;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+};
+
+struct S_std140 {
+  int before;
+  uint pad;
+  f16vec3 m_0;
+  f16vec3 m_1;
+  f16vec3 m_2;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  int after;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+shared S w[4];
+S conv_S(S_std140 val) {
+  return S(val.before, val.pad, f16mat3(val.m_0, val.m_1, val.m_2), val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.after, val.pad_9, val.pad_10, val.pad_11, val.pad_12, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21, val.pad_22, val.pad_23);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, 0u, f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat3 load_u_inner_2_m() {
+  return f16mat3(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2);
+}
+
+void f(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      uint i = idx;
+      S tint_symbol = S(0, 0u, f16mat3(f16vec3(0.0hf), f16vec3(0.0hf), f16vec3(0.0hf)), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u);
+      w[i] = tint_symbol;
+    }
+  }
+  barrier();
+  w = conv_arr4_S(u.inner);
+  w[1] = conv_S(u.inner[2u]);
+  w[3].m = load_u_inner_2_m();
+  w[1].m[0] = u.inner[0u].m_1.zxy;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..0e181df
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,48 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0008 */ half3x3 m;
+  /* 0x0020 */ tint_array<int8_t, 32> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+struct tint_symbol_6 {
+  tint_array<S, 4> w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup tint_array<S, 4>* const tint_symbol_1, const constant tint_array<S, 4>* const tint_symbol_2) {
+  for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+    uint const i = idx;
+    S const tint_symbol = S{};
+    (*(tint_symbol_1))[i] = tint_symbol;
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol_1) = *(tint_symbol_2);
+  (*(tint_symbol_1))[1] = (*(tint_symbol_2))[2];
+  (*(tint_symbol_1))[3].m = (*(tint_symbol_2))[2].m;
+  (*(tint_symbol_1))[1].m[0] = half3((*(tint_symbol_2))[0].m[1]).zxy;
+}
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol_5 [[buffer(0)]], threadgroup tint_symbol_6* tint_symbol_4 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup tint_array<S, 4>* const tint_symbol_3 = &((*(tint_symbol_4)).w);
+  f_inner(local_invocation_index, tint_symbol_3, tint_symbol_5);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_workgroup.wgsl.expected.spvasm
new file mode 100644
index 0000000..002fd8b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_workgroup.wgsl.expected.spvasm
@@ -0,0 +1,220 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 131
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %local_invocation_index_1 "local_invocation_index_1"
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "m_2"
+               OpMemberName %S_std140 4 "after"
+               OpName %u "u"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %w "w"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f_inner "f_inner"
+               OpName %local_invocation_index "local_invocation_index"
+               OpName %idx "idx"
+               OpName %f "f"
+               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 8
+               OpMemberDecorate %S_std140 2 Offset 16
+               OpMemberDecorate %S_std140 3 Offset 24
+               OpMemberDecorate %S_std140 4 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 8
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 8
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+   %S_std140 = OpTypeStruct %int %v3half %v3half %v3half %int
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat3v3half = OpTypeMatrix %v3half 3
+          %S = OpTypeStruct %int %mat3v3half %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+%_ptr_Workgroup__arr_S_uint_4 = OpTypePointer Workgroup %_arr_S_uint_4
+          %w = OpVariable %_ptr_Workgroup__arr_S_uint_4 Workgroup
+         %18 = OpTypeFunction %S %S_std140
+         %29 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+         %35 = OpConstantNull %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %38 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %51 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %64 = OpTypeFunction %mat3v3half
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %84 = OpTypeFunction %void %uint
+%_ptr_Workgroup_S = OpTypePointer Workgroup %S
+        %102 = OpConstantNull %S
+   %uint_264 = OpConstant %uint 264
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+      %int_1 = OpConstant %int 1
+      %int_3 = OpConstant %int 3
+%_ptr_Workgroup_mat3v3half = OpTypePointer Workgroup %mat3v3half
+        %120 = OpConstantNull %int
+%_ptr_Workgroup_v3half = OpTypePointer Workgroup %v3half
+        %126 = OpTypeFunction %void
+     %conv_S = OpFunction %S None %18
+        %val = OpFunctionParameter %S_std140
+         %21 = OpLabel
+         %22 = OpCompositeExtract %int %val 0
+         %23 = OpCompositeExtract %v3half %val 1
+         %24 = OpCompositeExtract %v3half %val 2
+         %25 = OpCompositeExtract %v3half %val 3
+         %26 = OpCompositeConstruct %mat3v3half %23 %24 %25
+         %27 = OpCompositeExtract %int %val 4
+         %28 = OpCompositeConstruct %S %22 %26 %27
+               OpReturnValue %28
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %29
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %32 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %35
+          %i = OpVariable %_ptr_Function_uint Function %38
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %51
+               OpBranch %39
+         %39 = OpLabel
+               OpLoopMerge %40 %41 None
+               OpBranch %42
+         %42 = OpLabel
+         %44 = OpLoad %uint %i
+         %45 = OpULessThan %bool %44 %uint_4
+         %43 = OpLogicalNot %bool %45
+               OpSelectionMerge %47 None
+               OpBranchConditional %43 %48 %47
+         %48 = OpLabel
+               OpBranch %40
+         %47 = OpLabel
+               OpStore %var_for_index %val_0
+         %52 = OpLoad %uint %i
+         %54 = OpAccessChain %_ptr_Function_S %arr %52
+         %56 = OpLoad %uint %i
+         %58 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %56
+         %59 = OpLoad %S_std140 %58
+         %55 = OpFunctionCall %S %conv_S %59
+               OpStore %54 %55
+               OpBranch %41
+         %41 = OpLabel
+         %60 = OpLoad %uint %i
+         %62 = OpIAdd %uint %60 %uint_1
+               OpStore %i %62
+               OpBranch %39
+         %40 = OpLabel
+         %63 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %63
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat3v3half None %64
+         %66 = OpLabel
+         %71 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %74 = OpAccessChain %_ptr_Uniform_v3half %71 %uint_1
+         %75 = OpLoad %v3half %74
+         %77 = OpAccessChain %_ptr_Uniform_v3half %71 %uint_2
+         %78 = OpLoad %v3half %77
+         %81 = OpAccessChain %_ptr_Uniform_v3half %71 %uint_3
+         %82 = OpLoad %v3half %81
+         %83 = OpCompositeConstruct %mat3v3half %75 %78 %82
+               OpReturnValue %83
+               OpFunctionEnd
+    %f_inner = OpFunction %void None %84
+%local_invocation_index = OpFunctionParameter %uint
+         %88 = OpLabel
+        %idx = OpVariable %_ptr_Function_uint Function %38
+               OpStore %idx %local_invocation_index
+               OpBranch %90
+         %90 = OpLabel
+               OpLoopMerge %91 %92 None
+               OpBranch %93
+         %93 = OpLabel
+         %95 = OpLoad %uint %idx
+         %96 = OpULessThan %bool %95 %uint_4
+         %94 = OpLogicalNot %bool %96
+               OpSelectionMerge %97 None
+               OpBranchConditional %94 %98 %97
+         %98 = OpLabel
+               OpBranch %91
+         %97 = OpLabel
+         %99 = OpLoad %uint %idx
+        %101 = OpAccessChain %_ptr_Workgroup_S %w %99
+               OpStore %101 %102
+               OpBranch %92
+         %92 = OpLabel
+        %103 = OpLoad %uint %idx
+        %104 = OpIAdd %uint %103 %uint_1
+               OpStore %idx %104
+               OpBranch %90
+         %91 = OpLabel
+               OpControlBarrier %uint_2 %uint_2 %uint_264
+        %109 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+        %110 = OpLoad %_arr_S_std140_uint_4 %109
+        %107 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %110
+               OpStore %w %107
+        %112 = OpAccessChain %_ptr_Workgroup_S %w %int_1
+        %114 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+        %115 = OpLoad %S_std140 %114
+        %113 = OpFunctionCall %S %conv_S %115
+               OpStore %112 %113
+        %118 = OpAccessChain %_ptr_Workgroup_mat3v3half %w %int_3 %uint_1
+        %119 = OpFunctionCall %mat3v3half %load_u_inner_2_m
+               OpStore %118 %119
+        %122 = OpAccessChain %_ptr_Workgroup_v3half %w %int_1 %uint_1 %120
+        %123 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0 %38 %uint_2
+        %124 = OpLoad %v3half %123
+        %125 = OpVectorShuffle %v3half %124 %124 2 0 1
+               OpStore %122 %125
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %126
+        %128 = OpLabel
+        %130 = OpLoad %uint %local_invocation_index_1
+        %129 = OpFunctionCall %void %f_inner %130
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..32a68e8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f16/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,20 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat3x3<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+var<workgroup> w : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[2];
+  w[3].m = u[2].m;
+  w[1].m[0] = u[0].m[1].zxy;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/dynamic_index_via_ptr.wgsl
new file mode 100644
index 0000000..ed316bc
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/dynamic_index_via_ptr.wgsl
@@ -0,0 +1,32 @@
+struct Inner {
+  @size(64)
+  m : mat3x3<f32>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a           = &a;
+  let p_a_i         = &((*p_a)[i()]);
+  let p_a_i_a       = &((*p_a_i).a);
+  let p_a_i_a_i     = &((*p_a_i_a)[i()]);
+  let p_a_i_a_i_m   = &((*p_a_i_a_i).m);
+  let p_a_i_a_i_m_i = &((*p_a_i_a_i_m)[i()]);
+
+
+  let l_a             : array<Outer, 4> =  *p_a;
+  let l_a_i           : Outer           =  *p_a_i;
+  let l_a_i_a         : array<Inner, 4> =  *p_a_i_a;
+  let l_a_i_a_i       : Inner           =  *p_a_i_a_i;
+  let l_a_i_a_i_m     : mat3x3<f32>     =  *p_a_i_a_i_m;
+  let l_a_i_a_i_m_i   : vec3<f32>       =  *p_a_i_a_i_m_i;
+  let l_a_i_a_i_m_i_i : f32             = (*p_a_i_a_i_m_i)[i()];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..debcd3f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,76 @@
+struct Inner {
+  float3x3 m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float3x3 tint_symbol_8(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+}
+
+Inner tint_symbol_7(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_11 = {tint_symbol_8(buffer, (offset + 0u))};
+  return tint_symbol_11;
+}
+
+typedef Inner tint_symbol_6_ret[4];
+tint_symbol_6_ret tint_symbol_6(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_7(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_5(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_12 = {tint_symbol_6(buffer, (offset + 0u))};
+  return tint_symbol_12;
+}
+
+typedef Outer tint_symbol_4_ret[4];
+tint_symbol_4_ret tint_symbol_4(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
+      arr_1[i_2] = tint_symbol_5(buffer, (offset + (i_2 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_a_i_save = i();
+  const int p_a_i_a_i_m_i_save = i();
+  const Outer l_a[4] = tint_symbol_4(a, 0u);
+  const Outer l_a_i = tint_symbol_5(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a[4] = tint_symbol_6(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a_i = tint_symbol_7(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const float3x3 l_a_i_a_i_m = tint_symbol_8(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const uint scalar_offset_3 = ((((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))) + (16u * uint(p_a_i_a_i_m_i_save)))) / 4;
+  const float3 l_a_i_a_i_m_i = asfloat(a[scalar_offset_3 / 4].xyz);
+  const int tint_symbol = p_a_i_save;
+  const int tint_symbol_1 = p_a_i_a_i_save;
+  const int tint_symbol_2 = p_a_i_a_i_m_i_save;
+  const int tint_symbol_3 = i();
+  const uint scalar_offset_4 = (((((256u * uint(tint_symbol)) + (64u * uint(tint_symbol_1))) + (16u * uint(tint_symbol_2))) + (4u * uint(tint_symbol_3)))) / 4;
+  const float l_a_i_a_i_m_i_i = asfloat(a[scalar_offset_4 / 4][scalar_offset_4 % 4]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..debcd3f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,76 @@
+struct Inner {
+  float3x3 m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float3x3 tint_symbol_8(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+}
+
+Inner tint_symbol_7(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_11 = {tint_symbol_8(buffer, (offset + 0u))};
+  return tint_symbol_11;
+}
+
+typedef Inner tint_symbol_6_ret[4];
+tint_symbol_6_ret tint_symbol_6(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_7(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_5(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_12 = {tint_symbol_6(buffer, (offset + 0u))};
+  return tint_symbol_12;
+}
+
+typedef Outer tint_symbol_4_ret[4];
+tint_symbol_4_ret tint_symbol_4(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
+      arr_1[i_2] = tint_symbol_5(buffer, (offset + (i_2 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_a_i_save = i();
+  const int p_a_i_a_i_m_i_save = i();
+  const Outer l_a[4] = tint_symbol_4(a, 0u);
+  const Outer l_a_i = tint_symbol_5(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a[4] = tint_symbol_6(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a_i = tint_symbol_7(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const float3x3 l_a_i_a_i_m = tint_symbol_8(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const uint scalar_offset_3 = ((((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))) + (16u * uint(p_a_i_a_i_m_i_save)))) / 4;
+  const float3 l_a_i_a_i_m_i = asfloat(a[scalar_offset_3 / 4].xyz);
+  const int tint_symbol = p_a_i_save;
+  const int tint_symbol_1 = p_a_i_a_i_save;
+  const int tint_symbol_2 = p_a_i_a_i_m_i_save;
+  const int tint_symbol_3 = i();
+  const uint scalar_offset_4 = (((((256u * uint(tint_symbol)) + (64u * uint(tint_symbol_1))) + (16u * uint(tint_symbol_2))) + (4u * uint(tint_symbol_3)))) / 4;
+  const float l_a_i_a_i_m_i_i = asfloat(a[scalar_offset_4 / 4][scalar_offset_4 % 4]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..1d273da
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,46 @@
+#version 310 es
+
+struct Inner {
+  mat3 m;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+};
+
+struct Outer {
+  Inner a[4];
+};
+
+layout(binding = 0, std140) uniform a_block_ubo {
+  Outer inner[4];
+} a;
+
+int counter = 0;
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+void f() {
+  int tint_symbol = i();
+  int p_a_i_save = tint_symbol;
+  int tint_symbol_1 = i();
+  int p_a_i_a_i_save = tint_symbol_1;
+  int tint_symbol_2 = i();
+  int p_a_i_a_i_m_i_save = tint_symbol_2;
+  Outer l_a[4] = a.inner;
+  Outer l_a_i = a.inner[p_a_i_save];
+  Inner l_a_i_a[4] = a.inner[p_a_i_save].a;
+  Inner l_a_i_a_i = a.inner[p_a_i_save].a[p_a_i_a_i_save];
+  mat3 l_a_i_a_i_m = a.inner[p_a_i_save].a[p_a_i_a_i_save].m;
+  vec3 l_a_i_a_i_m_i = a.inner[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save];
+  int tint_symbol_3 = i();
+  float l_a_i_a_i_m_i_i = a.inner[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save][tint_symbol_3];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..ec3d690
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,49 @@
+#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 Inner {
+  /* 0x0000 */ float3x3 m;
+  /* 0x0030 */ tint_array<int8_t, 16> tint_pad;
+};
+
+struct Outer {
+  /* 0x0000 */ tint_array<Inner, 4> a;
+};
+
+int i() {
+  thread int tint_symbol_4 = 0;
+  tint_symbol_4 = as_type<int>((as_type<uint>(tint_symbol_4) + as_type<uint>(1)));
+  return tint_symbol_4;
+}
+
+kernel void f(const constant tint_array<Outer, 4>* tint_symbol_5 [[buffer(0)]]) {
+  int const tint_symbol = i();
+  int const p_a_i_save = tint_symbol;
+  int const tint_symbol_1 = i();
+  int const p_a_i_a_i_save = tint_symbol_1;
+  int const tint_symbol_2 = i();
+  int const p_a_i_a_i_m_i_save = tint_symbol_2;
+  tint_array<Outer, 4> const l_a = *(tint_symbol_5);
+  Outer const l_a_i = (*(tint_symbol_5))[p_a_i_save];
+  tint_array<Inner, 4> const l_a_i_a = (*(tint_symbol_5))[p_a_i_save].a;
+  Inner const l_a_i_a_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save];
+  float3x3 const l_a_i_a_i_m = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m;
+  float3 const l_a_i_a_i_m_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save];
+  int const tint_symbol_3 = i();
+  float const l_a_i_a_i_m_i_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save][tint_symbol_3];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..3c32545
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,88 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 54
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block "a_block"
+               OpMemberName %a_block 0 "inner"
+               OpName %Outer "Outer"
+               OpMemberName %Outer 0 "a"
+               OpName %Inner "Inner"
+               OpMemberName %Inner 0 "m"
+               OpName %a "a"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %f "f"
+               OpDecorate %a_block Block
+               OpMemberDecorate %a_block 0 Offset 0
+               OpMemberDecorate %Outer 0 Offset 0
+               OpMemberDecorate %Inner 0 Offset 0
+               OpMemberDecorate %Inner 0 ColMajor
+               OpMemberDecorate %Inner 0 MatrixStride 16
+               OpDecorate %_arr_Inner_uint_4 ArrayStride 64
+               OpDecorate %_arr_Outer_uint_4 ArrayStride 256
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+      %Inner = OpTypeStruct %mat3v3float
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_Inner_uint_4 = OpTypeArray %Inner %uint_4
+      %Outer = OpTypeStruct %_arr_Inner_uint_4
+%_arr_Outer_uint_4 = OpTypeArray %Outer %uint_4
+    %a_block = OpTypeStruct %_arr_Outer_uint_4
+%_ptr_Uniform_a_block = OpTypePointer Uniform %a_block
+          %a = OpVariable %_ptr_Uniform_a_block Uniform
+        %int = OpTypeInt 32 1
+         %14 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %14
+         %17 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+       %void = OpTypeVoid
+         %24 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_Outer_uint_4 = OpTypePointer Uniform %_arr_Outer_uint_4
+%_ptr_Uniform_Outer = OpTypePointer Uniform %Outer
+%_ptr_Uniform__arr_Inner_uint_4 = OpTypePointer Uniform %_arr_Inner_uint_4
+%_ptr_Uniform_Inner = OpTypePointer Uniform %Inner
+%_ptr_Uniform_mat3v3float = OpTypePointer Uniform %mat3v3float
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+          %i = OpFunction %int None %17
+         %19 = OpLabel
+         %20 = OpLoad %int %counter
+         %22 = OpIAdd %int %20 %int_1
+               OpStore %counter %22
+         %23 = OpLoad %int %counter
+               OpReturnValue %23
+               OpFunctionEnd
+          %f = OpFunction %void None %24
+         %27 = OpLabel
+         %28 = OpFunctionCall %int %i
+         %29 = OpFunctionCall %int %i
+         %30 = OpFunctionCall %int %i
+         %33 = OpAccessChain %_ptr_Uniform__arr_Outer_uint_4 %a %uint_0
+         %34 = OpLoad %_arr_Outer_uint_4 %33
+         %36 = OpAccessChain %_ptr_Uniform_Outer %a %uint_0 %28
+         %37 = OpLoad %Outer %36
+         %39 = OpAccessChain %_ptr_Uniform__arr_Inner_uint_4 %a %uint_0 %28 %uint_0
+         %40 = OpLoad %_arr_Inner_uint_4 %39
+         %42 = OpAccessChain %_ptr_Uniform_Inner %a %uint_0 %28 %uint_0 %29
+         %43 = OpLoad %Inner %42
+         %45 = OpAccessChain %_ptr_Uniform_mat3v3float %a %uint_0 %28 %uint_0 %29 %uint_0
+         %46 = OpLoad %mat3v3float %45
+         %48 = OpAccessChain %_ptr_Uniform_v3float %a %uint_0 %28 %uint_0 %29 %uint_0 %30
+         %49 = OpLoad %v3float %48
+         %50 = OpFunctionCall %int %i
+         %52 = OpAccessChain %_ptr_Uniform_float %a %uint_0 %28 %uint_0 %29 %uint_0 %30 %50
+         %53 = OpLoad %float %52
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..028d0c2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,34 @@
+struct Inner {
+  @size(64)
+  m : mat3x3<f32>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_i = &((*(p_a))[i()]);
+  let p_a_i_a = &((*(p_a_i)).a);
+  let p_a_i_a_i = &((*(p_a_i_a))[i()]);
+  let p_a_i_a_i_m = &((*(p_a_i_a_i)).m);
+  let p_a_i_a_i_m_i = &((*(p_a_i_a_i_m))[i()]);
+  let l_a : array<Outer, 4> = *(p_a);
+  let l_a_i : Outer = *(p_a_i);
+  let l_a_i_a : array<Inner, 4> = *(p_a_i_a);
+  let l_a_i_a_i : Inner = *(p_a_i_a_i);
+  let l_a_i_a_i_m : mat3x3<f32> = *(p_a_i_a_i_m);
+  let l_a_i_a_i_m_i : vec3<f32> = *(p_a_i_a_i_m_i);
+  let l_a_i_a_i_m_i_i : f32 = (*(p_a_i_a_i_m_i))[i()];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/static_index_via_ptr.wgsl
new file mode 100644
index 0000000..bd25e46
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/static_index_via_ptr.wgsl
@@ -0,0 +1,29 @@
+struct Inner {
+  @size(64)
+  m : mat3x3<f32>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &a;
+  let p_a_3 = &((*p_a)[3]);
+  let p_a_3_a = &((*p_a_3).a);
+  let p_a_3_a_2 = &((*p_a_3_a)[2]);
+  let p_a_3_a_2_m = &((*p_a_3_a_2).m);
+  let p_a_3_a_2_m_1 = &((*p_a_3_a_2_m)[1]);
+
+
+  let l_a             : array<Outer, 4> = *p_a;
+  let l_a_3           : Outer           = *p_a_3;
+  let l_a_3_a         : array<Inner, 4> = *p_a_3_a;
+  let l_a_3_a_2       : Inner           = *p_a_3_a_2;
+  let l_a_3_a_2_m     : mat3x3<f32>     = *p_a_3_a_2_m;
+  let l_a_3_a_2_m_1   : vec3<f32>       = *p_a_3_a_2_m_1;
+  let l_a_3_a_2_m_1_0 : f32             = (*p_a_3_a_2_m_1)[0];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..13f6480
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,61 @@
+struct Inner {
+  float3x3 m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+
+float3x3 tint_symbol_4(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+}
+
+Inner tint_symbol_3(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_7 = {tint_symbol_4(buffer, (offset + 0u))};
+  return tint_symbol_7;
+}
+
+typedef Inner tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_3(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_1(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_8 = {tint_symbol_2(buffer, (offset + 0u))};
+  return tint_symbol_8;
+}
+
+typedef Outer tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr_1[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const Outer l_a[4] = tint_symbol(a, 0u);
+  const Outer l_a_3 = tint_symbol_1(a, 768u);
+  const Inner l_a_3_a[4] = tint_symbol_2(a, 768u);
+  const Inner l_a_3_a_2 = tint_symbol_3(a, 896u);
+  const float3x3 l_a_3_a_2_m = tint_symbol_4(a, 896u);
+  const float3 l_a_3_a_2_m_1 = asfloat(a[57].xyz);
+  const float l_a_3_a_2_m_1_0 = asfloat(a[57].x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..13f6480
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,61 @@
+struct Inner {
+  float3x3 m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+
+float3x3 tint_symbol_4(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+}
+
+Inner tint_symbol_3(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_7 = {tint_symbol_4(buffer, (offset + 0u))};
+  return tint_symbol_7;
+}
+
+typedef Inner tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_3(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_1(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_8 = {tint_symbol_2(buffer, (offset + 0u))};
+  return tint_symbol_8;
+}
+
+typedef Outer tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr_1[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const Outer l_a[4] = tint_symbol(a, 0u);
+  const Outer l_a_3 = tint_symbol_1(a, 768u);
+  const Inner l_a_3_a[4] = tint_symbol_2(a, 768u);
+  const Inner l_a_3_a_2 = tint_symbol_3(a, 896u);
+  const float3x3 l_a_3_a_2_m = tint_symbol_4(a, 896u);
+  const float3 l_a_3_a_2_m_1 = asfloat(a[57].xyz);
+  const float l_a_3_a_2_m_1_0 = asfloat(a[57].x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/static_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..ff47341
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/static_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,33 @@
+#version 310 es
+
+struct Inner {
+  mat3 m;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+};
+
+struct Outer {
+  Inner a[4];
+};
+
+layout(binding = 0, std140) uniform a_block_ubo {
+  Outer inner[4];
+} a;
+
+void f() {
+  Outer l_a[4] = a.inner;
+  Outer l_a_3 = a.inner[3];
+  Inner l_a_3_a[4] = a.inner[3].a;
+  Inner l_a_3_a_2 = a.inner[3].a[2];
+  mat3 l_a_3_a_2_m = a.inner[3].a[2].m;
+  vec3 l_a_3_a_2_m_1 = a.inner[3].a[2].m[1];
+  float l_a_3_a_2_m_1_0 = a.inner[3].a[2].m[1][0];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/static_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..4092ef5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/static_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,36 @@
+#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 Inner {
+  /* 0x0000 */ float3x3 m;
+  /* 0x0030 */ tint_array<int8_t, 16> tint_pad;
+};
+
+struct Outer {
+  /* 0x0000 */ tint_array<Inner, 4> a;
+};
+
+kernel void f(const constant tint_array<Outer, 4>* tint_symbol [[buffer(0)]]) {
+  tint_array<Outer, 4> const l_a = *(tint_symbol);
+  Outer const l_a_3 = (*(tint_symbol))[3];
+  tint_array<Inner, 4> const l_a_3_a = (*(tint_symbol))[3].a;
+  Inner const l_a_3_a_2 = (*(tint_symbol))[3].a[2];
+  float3x3 const l_a_3_a_2_m = (*(tint_symbol))[3].a[2].m;
+  float3 const l_a_3_a_2_m_1 = (*(tint_symbol))[3].a[2].m[1];
+  float const l_a_3_a_2_m_1_0 = (*(tint_symbol))[3].a[2].m[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/static_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..0eeec1b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/static_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,73 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 44
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block "a_block"
+               OpMemberName %a_block 0 "inner"
+               OpName %Outer "Outer"
+               OpMemberName %Outer 0 "a"
+               OpName %Inner "Inner"
+               OpMemberName %Inner 0 "m"
+               OpName %a "a"
+               OpName %f "f"
+               OpDecorate %a_block Block
+               OpMemberDecorate %a_block 0 Offset 0
+               OpMemberDecorate %Outer 0 Offset 0
+               OpMemberDecorate %Inner 0 Offset 0
+               OpMemberDecorate %Inner 0 ColMajor
+               OpMemberDecorate %Inner 0 MatrixStride 16
+               OpDecorate %_arr_Inner_uint_4 ArrayStride 64
+               OpDecorate %_arr_Outer_uint_4 ArrayStride 256
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+      %Inner = OpTypeStruct %mat3v3float
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_Inner_uint_4 = OpTypeArray %Inner %uint_4
+      %Outer = OpTypeStruct %_arr_Inner_uint_4
+%_arr_Outer_uint_4 = OpTypeArray %Outer %uint_4
+    %a_block = OpTypeStruct %_arr_Outer_uint_4
+%_ptr_Uniform_a_block = OpTypePointer Uniform %a_block
+          %a = OpVariable %_ptr_Uniform_a_block Uniform
+       %void = OpTypeVoid
+         %13 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_Outer_uint_4 = OpTypePointer Uniform %_arr_Outer_uint_4
+        %int = OpTypeInt 32 1
+      %int_3 = OpConstant %int 3
+%_ptr_Uniform_Outer = OpTypePointer Uniform %Outer
+%_ptr_Uniform__arr_Inner_uint_4 = OpTypePointer Uniform %_arr_Inner_uint_4
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_Inner = OpTypePointer Uniform %Inner
+%_ptr_Uniform_mat3v3float = OpTypePointer Uniform %mat3v3float
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+         %40 = OpConstantNull %int
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+          %f = OpFunction %void None %13
+         %16 = OpLabel
+         %19 = OpAccessChain %_ptr_Uniform__arr_Outer_uint_4 %a %uint_0
+         %20 = OpLoad %_arr_Outer_uint_4 %19
+         %24 = OpAccessChain %_ptr_Uniform_Outer %a %uint_0 %int_3
+         %25 = OpLoad %Outer %24
+         %27 = OpAccessChain %_ptr_Uniform__arr_Inner_uint_4 %a %uint_0 %int_3 %uint_0
+         %28 = OpLoad %_arr_Inner_uint_4 %27
+         %31 = OpAccessChain %_ptr_Uniform_Inner %a %uint_0 %int_3 %uint_0 %int_2
+         %32 = OpLoad %Inner %31
+         %34 = OpAccessChain %_ptr_Uniform_mat3v3float %a %uint_0 %int_3 %uint_0 %int_2 %uint_0
+         %35 = OpLoad %mat3v3float %34
+         %38 = OpAccessChain %_ptr_Uniform_v3float %a %uint_0 %int_3 %uint_0 %int_2 %uint_0 %int_1
+         %39 = OpLoad %v3float %38
+         %42 = OpAccessChain %_ptr_Uniform_float %a %uint_0 %int_3 %uint_0 %int_2 %uint_0 %int_1 %40
+         %43 = OpLoad %float %42
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/static_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..ae7fbe5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/static_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,27 @@
+struct Inner {
+  @size(64)
+  m : mat3x3<f32>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_3 = &((*(p_a))[3]);
+  let p_a_3_a = &((*(p_a_3)).a);
+  let p_a_3_a_2 = &((*(p_a_3_a))[2]);
+  let p_a_3_a_2_m = &((*(p_a_3_a_2)).m);
+  let p_a_3_a_2_m_1 = &((*(p_a_3_a_2_m))[1]);
+  let l_a : array<Outer, 4> = *(p_a);
+  let l_a_3 : Outer = *(p_a_3);
+  let l_a_3_a : array<Inner, 4> = *(p_a_3_a);
+  let l_a_3_a_2 : Inner = *(p_a_3_a_2);
+  let l_a_3_a_2_m : mat3x3<f32> = *(p_a_3_a_2_m);
+  let l_a_3_a_2_m_1 : vec3<f32> = *(p_a_3_a_2_m_1);
+  let l_a_3_a_2_m_1_0 : f32 = (*(p_a_3_a_2_m_1))[0];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_builtin.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_builtin.wgsl
new file mode 100644
index 0000000..12d9206
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_builtin.wgsl
@@ -0,0 +1,15 @@
+struct S {
+  before : i32,
+  m : mat3x3<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    let t = transpose(u[2].m);
+    let l = length(u[0].m[1].zxy);
+    let a = abs(u[0].m[1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_builtin.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..55e12dd
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_builtin.wgsl.expected.dxc.hlsl
@@ -0,0 +1,18 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+float3x3 tint_symbol(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float3x3 t = transpose(tint_symbol(u, 272u));
+  const float l = length(asfloat(u[2].xyz).zxy);
+  const float a = abs(asfloat(u[2].xyz).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_builtin.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..55e12dd
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_builtin.wgsl.expected.fxc.hlsl
@@ -0,0 +1,18 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+float3x3 tint_symbol(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float3x3 t = transpose(tint_symbol(u, 272u));
+  const float l = length(asfloat(u[2].xyz).zxy);
+  const float a = abs(asfloat(u[2].xyz).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_builtin.wgsl.expected.glsl
new file mode 100644
index 0000000..573743d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_builtin.wgsl.expected.glsl
@@ -0,0 +1,41 @@
+#version 310 es
+
+struct S {
+  int before;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  mat3 m;
+  int after;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+};
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  S inner[4];
+} u;
+
+void f() {
+  mat3 t = transpose(u.inner[2].m);
+  float l = length(u.inner[0].m[1].zxy);
+  float a = abs(u.inner[0].m[1].zxy.x);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_builtin.wgsl.expected.msl
new file mode 100644
index 0000000..08a4ad4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_builtin.wgsl.expected.msl
@@ -0,0 +1,31 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 12> tint_pad;
+  /* 0x0010 */ float3x3 m;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_1;
+};
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol [[buffer(0)]]) {
+  float3x3 const t = transpose((*(tint_symbol))[2].m);
+  float const l = length(float3((*(tint_symbol))[0].m[1]).zxy);
+  float const a = fabs(float3((*(tint_symbol))[0].m[1]).zxy[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_builtin.wgsl.expected.spvasm
new file mode 100644
index 0000000..d52bc20
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_builtin.wgsl.expected.spvasm
@@ -0,0 +1,65 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 36
+; Schema: 0
+               OpCapability Shader
+         %24 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %u "u"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 16
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 16
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+          %S = OpTypeStruct %int %mat3v3float %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+    %u_block = OpTypeStruct %_arr_S_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+         %12 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+      %int_2 = OpConstant %int 2
+     %uint_1 = OpConstant %uint 1
+%_ptr_Uniform_mat3v3float = OpTypePointer Uniform %mat3v3float
+         %25 = OpConstantNull %int
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+          %f = OpFunction %void None %12
+         %15 = OpLabel
+         %21 = OpAccessChain %_ptr_Uniform_mat3v3float %u %uint_0 %int_2 %uint_1
+         %22 = OpLoad %mat3v3float %21
+         %16 = OpTranspose %mat3v3float %22
+         %28 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %25 %uint_1 %int_1
+         %29 = OpLoad %v3float %28
+         %30 = OpVectorShuffle %v3float %29 %29 2 0 1
+         %23 = OpExtInst %float %24 Length %30
+         %32 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %25 %uint_1 %int_1
+         %33 = OpLoad %v3float %32
+         %34 = OpVectorShuffle %v3float %33 %33 2 0 1
+         %35 = OpCompositeExtract %float %34 0
+         %31 = OpExtInst %float %24 FAbs %35
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_builtin.wgsl.expected.wgsl
new file mode 100644
index 0000000..7ef5711
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_builtin.wgsl.expected.wgsl
@@ -0,0 +1,15 @@
+struct S {
+  before : i32,
+  m : mat3x3<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let t = transpose(u[2].m);
+  let l = length(u[0].m[1].zxy);
+  let a = abs(u[0].m[1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_fn.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_fn.wgsl
new file mode 100644
index 0000000..902ca19
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_fn.wgsl
@@ -0,0 +1,23 @@
+struct S {
+  before : i32,
+  m : mat3x3<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+fn a(a : array<S, 4>) {}
+fn b(s : S) {}
+fn c(m : mat3x3<f32>) {}
+fn d(v : vec3<f32>) {}
+fn e(f : f32) {}
+
+@compute @workgroup_size(1)
+fn f() {
+    a(u);
+    b(u[2]);
+    c(u[2].m);
+    d(u[0].m[1].zxy);
+    e(u[0].m[1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_fn.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..112cec2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_fn.wgsl.expected.dxc.hlsl
@@ -0,0 +1,59 @@
+struct S {
+  int before;
+  float3x3 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(float3x3 m) {
+}
+
+void d(float3 v) {
+}
+
+void e(float f_1) {
+}
+
+float3x3 tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_3(buffer, (offset + 16u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 256u));
+  c(tint_symbol_3(u, 272u));
+  d(asfloat(u[2].xyz).zxy);
+  e(asfloat(u[2].xyz).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_fn.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..112cec2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_fn.wgsl.expected.fxc.hlsl
@@ -0,0 +1,59 @@
+struct S {
+  int before;
+  float3x3 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(float3x3 m) {
+}
+
+void d(float3 v) {
+}
+
+void e(float f_1) {
+}
+
+float3x3 tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_3(buffer, (offset + 16u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 256u));
+  c(tint_symbol_3(u, 272u));
+  d(asfloat(u[2].xyz).zxy);
+  e(asfloat(u[2].xyz).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_fn.wgsl.expected.glsl
new file mode 100644
index 0000000..8697e87
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_fn.wgsl.expected.glsl
@@ -0,0 +1,58 @@
+#version 310 es
+
+struct S {
+  int before;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  mat3 m;
+  int after;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+};
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  S inner[4];
+} u;
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(mat3 m) {
+}
+
+void d(vec3 v) {
+}
+
+void e(float f_1) {
+}
+
+void f() {
+  a(u.inner);
+  b(u.inner[2]);
+  c(u.inner[2].m);
+  d(u.inner[0].m[1].zxy);
+  e(u.inner[0].m[1].zxy.x);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_fn.wgsl.expected.msl
new file mode 100644
index 0000000..bd1b6bd
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_fn.wgsl.expected.msl
@@ -0,0 +1,48 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 12> tint_pad;
+  /* 0x0010 */ float3x3 m;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_1;
+};
+
+void a(tint_array<S, 4> a_1) {
+}
+
+void b(S s) {
+}
+
+void c(float3x3 m) {
+}
+
+void d(float3 v) {
+}
+
+void e(float f_1) {
+}
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol [[buffer(0)]]) {
+  a(*(tint_symbol));
+  b((*(tint_symbol))[2]);
+  c((*(tint_symbol))[2].m);
+  d(float3((*(tint_symbol))[0].m[1]).zxy);
+  e(float3((*(tint_symbol))[0].m[1]).zxy[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_fn.wgsl.expected.spvasm
new file mode 100644
index 0000000..2438c29
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_fn.wgsl.expected.spvasm
@@ -0,0 +1,112 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 63
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %u "u"
+               OpName %a "a"
+               OpName %a_1 "a_1"
+               OpName %b "b"
+               OpName %s "s"
+               OpName %c "c"
+               OpName %m "m"
+               OpName %d "d"
+               OpName %v "v"
+               OpName %e "e"
+               OpName %f_1 "f_1"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 16
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 16
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+          %S = OpTypeStruct %int %mat3v3float %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+    %u_block = OpTypeStruct %_arr_S_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+         %12 = OpTypeFunction %void %_arr_S_uint_4
+         %17 = OpTypeFunction %void %S
+         %21 = OpTypeFunction %void %mat3v3float
+         %25 = OpTypeFunction %void %v3float
+         %29 = OpTypeFunction %void %float
+         %33 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_S_uint_4 = OpTypePointer Uniform %_arr_S_uint_4
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_S = OpTypePointer Uniform %S
+     %uint_1 = OpConstant %uint 1
+%_ptr_Uniform_mat3v3float = OpTypePointer Uniform %mat3v3float
+         %52 = OpConstantNull %int
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+          %a = OpFunction %void None %12
+        %a_1 = OpFunctionParameter %_arr_S_uint_4
+         %16 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %b = OpFunction %void None %17
+          %s = OpFunctionParameter %S
+         %20 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %c = OpFunction %void None %21
+          %m = OpFunctionParameter %mat3v3float
+         %24 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %d = OpFunction %void None %25
+          %v = OpFunctionParameter %v3float
+         %28 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %e = OpFunction %void None %29
+        %f_1 = OpFunctionParameter %float
+         %32 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %33
+         %35 = OpLabel
+         %39 = OpAccessChain %_ptr_Uniform__arr_S_uint_4 %u %uint_0
+         %40 = OpLoad %_arr_S_uint_4 %39
+         %36 = OpFunctionCall %void %a %40
+         %44 = OpAccessChain %_ptr_Uniform_S %u %uint_0 %int_2
+         %45 = OpLoad %S %44
+         %41 = OpFunctionCall %void %b %45
+         %49 = OpAccessChain %_ptr_Uniform_mat3v3float %u %uint_0 %int_2 %uint_1
+         %50 = OpLoad %mat3v3float %49
+         %46 = OpFunctionCall %void %c %50
+         %55 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %52 %uint_1 %int_1
+         %56 = OpLoad %v3float %55
+         %57 = OpVectorShuffle %v3float %56 %56 2 0 1
+         %51 = OpFunctionCall %void %d %57
+         %59 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %52 %uint_1 %int_1
+         %60 = OpLoad %v3float %59
+         %61 = OpVectorShuffle %v3float %60 %60 2 0 1
+         %62 = OpCompositeExtract %float %61 0
+         %58 = OpFunctionCall %void %e %62
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_fn.wgsl.expected.wgsl
new file mode 100644
index 0000000..e323489
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_fn.wgsl.expected.wgsl
@@ -0,0 +1,32 @@
+struct S {
+  before : i32,
+  m : mat3x3<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+fn a(a : array<S, 4>) {
+}
+
+fn b(s : S) {
+}
+
+fn c(m : mat3x3<f32>) {
+}
+
+fn d(v : vec3<f32>) {
+}
+
+fn e(f : f32) {
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  a(u);
+  b(u[2]);
+  c(u[2].m);
+  d(u[0].m[1].zxy);
+  e(u[0].m[1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_private.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_private.wgsl
new file mode 100644
index 0000000..32735dd
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_private.wgsl
@@ -0,0 +1,17 @@
+struct S {
+  before : i32,
+  m : mat3x3<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+var<private> p : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[2];
+    p[3].m = u[2].m;
+    p[1].m[0] = u[0].m[1].zxy;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_private.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..1645513
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_private.wgsl.expected.dxc.hlsl
@@ -0,0 +1,44 @@
+struct S {
+  int before;
+  float3x3 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+static S p[4] = (S[4])0;
+
+float3x3 tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_3(buffer, (offset + 16u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 256u);
+  p[3].m = tint_symbol_3(u, 272u);
+  p[1].m[0] = asfloat(u[2].xyz).zxy;
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_private.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..1645513
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_private.wgsl.expected.fxc.hlsl
@@ -0,0 +1,44 @@
+struct S {
+  int before;
+  float3x3 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+static S p[4] = (S[4])0;
+
+float3x3 tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_3(buffer, (offset + 16u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 256u);
+  p[3].m = tint_symbol_3(u, 272u);
+  p[1].m[0] = asfloat(u[2].xyz).zxy;
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..d8b2808
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_private.wgsl.expected.glsl
@@ -0,0 +1,43 @@
+#version 310 es
+
+struct S {
+  int before;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  mat3 m;
+  int after;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+};
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  S inner[4];
+} u;
+
+S p[4] = S[4](S(0, 0u, 0u, 0u, mat3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, 0u, 0u, mat3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, 0u, 0u, mat3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, 0u, 0u, mat3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+void f() {
+  p = u.inner;
+  p[1] = u.inner[2];
+  p[3].m = u.inner[2].m;
+  p[1].m[0] = u.inner[0].m[1].zxy;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..7e169af
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_private.wgsl.expected.msl
@@ -0,0 +1,33 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 12> tint_pad;
+  /* 0x0010 */ float3x3 m;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_1;
+};
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol_1 [[buffer(0)]]) {
+  thread tint_array<S, 4> tint_symbol = {};
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[2];
+  tint_symbol[3].m = (*(tint_symbol_1))[2].m;
+  tint_symbol[1].m[0] = float3((*(tint_symbol_1))[0].m[1]).zxy;
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_private.wgsl.expected.spvasm
new file mode 100644
index 0000000..7950fc0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_private.wgsl.expected.spvasm
@@ -0,0 +1,78 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 44
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %u "u"
+               OpName %p "p"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 16
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 16
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+          %S = OpTypeStruct %int %mat3v3float %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+    %u_block = OpTypeStruct %_arr_S_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_Private__arr_S_uint_4 = OpTypePointer Private %_arr_S_uint_4
+         %14 = OpConstantNull %_arr_S_uint_4
+          %p = OpVariable %_ptr_Private__arr_S_uint_4 Private %14
+       %void = OpTypeVoid
+         %15 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_S_uint_4 = OpTypePointer Uniform %_arr_S_uint_4
+      %int_1 = OpConstant %int 1
+%_ptr_Private_S = OpTypePointer Private %S
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_S = OpTypePointer Uniform %S
+      %int_3 = OpConstant %int 3
+     %uint_1 = OpConstant %uint 1
+%_ptr_Private_mat3v3float = OpTypePointer Private %mat3v3float
+%_ptr_Uniform_mat3v3float = OpTypePointer Uniform %mat3v3float
+         %37 = OpConstantNull %int
+%_ptr_Private_v3float = OpTypePointer Private %v3float
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+          %f = OpFunction %void None %15
+         %18 = OpLabel
+         %21 = OpAccessChain %_ptr_Uniform__arr_S_uint_4 %u %uint_0
+         %22 = OpLoad %_arr_S_uint_4 %21
+               OpStore %p %22
+         %25 = OpAccessChain %_ptr_Private_S %p %int_1
+         %28 = OpAccessChain %_ptr_Uniform_S %u %uint_0 %int_2
+         %29 = OpLoad %S %28
+               OpStore %25 %29
+         %33 = OpAccessChain %_ptr_Private_mat3v3float %p %int_3 %uint_1
+         %35 = OpAccessChain %_ptr_Uniform_mat3v3float %u %uint_0 %int_2 %uint_1
+         %36 = OpLoad %mat3v3float %35
+               OpStore %33 %36
+         %39 = OpAccessChain %_ptr_Private_v3float %p %int_1 %uint_1 %37
+         %41 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %37 %uint_1 %int_1
+         %42 = OpLoad %v3float %41
+         %43 = OpVectorShuffle %v3float %42 %42 2 0 1
+               OpStore %39 %43
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..0783f5a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_private.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+struct S {
+  before : i32,
+  m : mat3x3<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+var<private> p : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[2];
+  p[3].m = u[2].m;
+  p[1].m[0] = u[0].m[1].zxy;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_storage.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_storage.wgsl
new file mode 100644
index 0000000..35b7c90
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_storage.wgsl
@@ -0,0 +1,17 @@
+struct S {
+  before : i32,
+  m : mat3x3<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+@group(0) @binding(1) var<storage, read_write> s : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[2];
+    s[3].m = u[2].m;
+    s[1].m[0] = u[0].m[1].zxy;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_storage.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..51fb0e8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_storage.wgsl.expected.dxc.hlsl
@@ -0,0 +1,65 @@
+struct S {
+  int before;
+  float3x3 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_3(RWByteAddressBuffer buffer, uint offset, float3x3 value) {
+  buffer.Store3((offset + 0u), asuint(value[0u]));
+  buffer.Store3((offset + 16u), asuint(value[1u]));
+  buffer.Store3((offset + 32u), asuint(value[2u]));
+}
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, S value) {
+  buffer.Store((offset + 0u), asuint(value.before));
+  tint_symbol_3(buffer, (offset + 16u), value.m);
+  buffer.Store((offset + 64u), asuint(value.after));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, S value[4]) {
+  S array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 128u)), array[i]);
+    }
+  }
+}
+
+float3x3 tint_symbol_8(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+}
+
+S tint_symbol_6(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_10 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_8(buffer, (offset + 16u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_10;
+}
+
+typedef S tint_symbol_5_ret[4];
+tint_symbol_5_ret tint_symbol_5(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_6(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_5(u, 0u));
+  tint_symbol_1(s, 128u, tint_symbol_6(u, 256u));
+  tint_symbol_3(s, 400u, tint_symbol_8(u, 272u));
+  s.Store3(144u, asuint(asfloat(u[2].xyz).zxy));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_storage.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..51fb0e8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_storage.wgsl.expected.fxc.hlsl
@@ -0,0 +1,65 @@
+struct S {
+  int before;
+  float3x3 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_3(RWByteAddressBuffer buffer, uint offset, float3x3 value) {
+  buffer.Store3((offset + 0u), asuint(value[0u]));
+  buffer.Store3((offset + 16u), asuint(value[1u]));
+  buffer.Store3((offset + 32u), asuint(value[2u]));
+}
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, S value) {
+  buffer.Store((offset + 0u), asuint(value.before));
+  tint_symbol_3(buffer, (offset + 16u), value.m);
+  buffer.Store((offset + 64u), asuint(value.after));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, S value[4]) {
+  S array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 128u)), array[i]);
+    }
+  }
+}
+
+float3x3 tint_symbol_8(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+}
+
+S tint_symbol_6(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_10 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_8(buffer, (offset + 16u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_10;
+}
+
+typedef S tint_symbol_5_ret[4];
+tint_symbol_5_ret tint_symbol_5(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_6(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_5(u, 0u));
+  tint_symbol_1(s, 128u, tint_symbol_6(u, 256u));
+  tint_symbol_3(s, 400u, tint_symbol_8(u, 272u));
+  s.Store3(144u, asuint(asfloat(u[2].xyz).zxy));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..5f1ebf0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_storage.wgsl.expected.glsl
@@ -0,0 +1,46 @@
+#version 310 es
+
+struct S {
+  int before;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  mat3 m;
+  int after;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+};
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  S inner[4];
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  S inner[4];
+} s;
+
+void f() {
+  s.inner = u.inner;
+  s.inner[1] = u.inner[2];
+  s.inner[3].m = u.inner[2].m;
+  s.inner[1].m[0] = u.inner[0].m[1].zxy;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..6ffd304
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_storage.wgsl.expected.msl
@@ -0,0 +1,32 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 12> tint_pad;
+  /* 0x0010 */ float3x3 m;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_1;
+};
+
+kernel void f(device tint_array<S, 4>* tint_symbol [[buffer(1)]], const constant tint_array<S, 4>* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
+  (*(tint_symbol))[3].m = (*(tint_symbol_1))[2].m;
+  (*(tint_symbol))[1].m[0] = float3((*(tint_symbol_1))[0].m[1]).zxy;
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_storage.wgsl.expected.spvasm
new file mode 100644
index 0000000..a1b2958
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_storage.wgsl.expected.spvasm
@@ -0,0 +1,81 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 45
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %u "u"
+               OpName %s "s"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 16
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 16
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %s DescriptorSet 0
+               OpDecorate %s Binding 1
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+          %S = OpTypeStruct %int %mat3v3float %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+    %u_block = OpTypeStruct %_arr_S_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
+          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+       %void = OpTypeVoid
+         %14 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer__arr_S_uint_4 = OpTypePointer StorageBuffer %_arr_S_uint_4
+%_ptr_Uniform__arr_S_uint_4 = OpTypePointer Uniform %_arr_S_uint_4
+      %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_S = OpTypePointer Uniform %S
+      %int_3 = OpConstant %int 3
+     %uint_1 = OpConstant %uint 1
+%_ptr_StorageBuffer_mat3v3float = OpTypePointer StorageBuffer %mat3v3float
+%_ptr_Uniform_mat3v3float = OpTypePointer Uniform %mat3v3float
+         %38 = OpConstantNull %int
+%_ptr_StorageBuffer_v3float = OpTypePointer StorageBuffer %v3float
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+          %f = OpFunction %void None %14
+         %17 = OpLabel
+         %20 = OpAccessChain %_ptr_StorageBuffer__arr_S_uint_4 %s %uint_0
+         %22 = OpAccessChain %_ptr_Uniform__arr_S_uint_4 %u %uint_0
+         %23 = OpLoad %_arr_S_uint_4 %22
+               OpStore %20 %23
+         %26 = OpAccessChain %_ptr_StorageBuffer_S %s %uint_0 %int_1
+         %29 = OpAccessChain %_ptr_Uniform_S %u %uint_0 %int_2
+         %30 = OpLoad %S %29
+               OpStore %26 %30
+         %34 = OpAccessChain %_ptr_StorageBuffer_mat3v3float %s %uint_0 %int_3 %uint_1
+         %36 = OpAccessChain %_ptr_Uniform_mat3v3float %u %uint_0 %int_2 %uint_1
+         %37 = OpLoad %mat3v3float %36
+               OpStore %34 %37
+         %40 = OpAccessChain %_ptr_StorageBuffer_v3float %s %uint_0 %int_1 %uint_1 %38
+         %42 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %38 %uint_1 %int_1
+         %43 = OpLoad %v3float %42
+         %44 = OpVectorShuffle %v3float %43 %43 2 0 1
+               OpStore %40 %44
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..843821b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+struct S {
+  before : i32,
+  m : mat3x3<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@group(0) @binding(1) var<storage, read_write> s : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[2];
+  s[3].m = u[2].m;
+  s[1].m[0] = u[0].m[1].zxy;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_workgroup.wgsl
new file mode 100644
index 0000000..49368e1
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_workgroup.wgsl
@@ -0,0 +1,17 @@
+struct S {
+  before : i32,
+  m : mat3x3<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+var<workgroup> w : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[2];
+    w[3].m = u[2].m;
+    w[1].m[0] = u[0].m[1].zxy;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_workgroup.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..e50deb1
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_workgroup.wgsl.expected.dxc.hlsl
@@ -0,0 +1,60 @@
+struct S {
+  int before;
+  float3x3 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+groupshared S w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+float3x3 tint_symbol_5(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+}
+
+S tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_8 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_5(buffer, (offset + 16u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_8;
+}
+
+typedef S tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      const S tint_symbol_7 = (S)0;
+      w[i] = tint_symbol_7;
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 256u);
+  w[3].m = tint_symbol_5(u, 272u);
+  w[1].m[0] = asfloat(u[2].xyz).zxy;
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_workgroup.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..e50deb1
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_workgroup.wgsl.expected.fxc.hlsl
@@ -0,0 +1,60 @@
+struct S {
+  int before;
+  float3x3 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+groupshared S w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+float3x3 tint_symbol_5(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+}
+
+S tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_8 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_5(buffer, (offset + 16u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_8;
+}
+
+typedef S tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      const S tint_symbol_7 = (S)0;
+      w[i] = tint_symbol_7;
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 256u);
+  w[3].m = tint_symbol_5(u, 272u);
+  w[1].m[0] = asfloat(u[2].xyz).zxy;
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..c1a89c6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,51 @@
+#version 310 es
+
+struct S {
+  int before;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  mat3 m;
+  int after;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+};
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  S inner[4];
+} u;
+
+shared S w[4];
+void f(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      uint i = idx;
+      S tint_symbol = S(0, 0u, 0u, 0u, mat3(vec3(0.0f), vec3(0.0f), vec3(0.0f)), 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u);
+      w[i] = tint_symbol;
+    }
+  }
+  barrier();
+  w = u.inner;
+  w[1] = u.inner[2];
+  w[3].m = u.inner[2].m;
+  w[1].m[0] = u.inner[0].m[1].zxy;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..1fddc70
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,47 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 12> tint_pad;
+  /* 0x0010 */ float3x3 m;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_1;
+};
+
+struct tint_symbol_6 {
+  tint_array<S, 4> w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup tint_array<S, 4>* const tint_symbol_1, const constant tint_array<S, 4>* const tint_symbol_2) {
+  for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+    uint const i = idx;
+    S const tint_symbol = S{};
+    (*(tint_symbol_1))[i] = tint_symbol;
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol_1) = *(tint_symbol_2);
+  (*(tint_symbol_1))[1] = (*(tint_symbol_2))[2];
+  (*(tint_symbol_1))[3].m = (*(tint_symbol_2))[2].m;
+  (*(tint_symbol_1))[1].m[0] = float3((*(tint_symbol_2))[0].m[1]).zxy;
+}
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol_5 [[buffer(0)]], threadgroup tint_symbol_6* tint_symbol_4 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup tint_array<S, 4>* const tint_symbol_3 = &((*(tint_symbol_4)).w);
+  f_inner(local_invocation_index, tint_symbol_3, tint_symbol_5);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_workgroup.wgsl.expected.spvasm
new file mode 100644
index 0000000..7922ffb
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_workgroup.wgsl.expected.spvasm
@@ -0,0 +1,124 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 72
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %local_invocation_index_1 "local_invocation_index_1"
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %u "u"
+               OpName %w "w"
+               OpName %f_inner "f_inner"
+               OpName %local_invocation_index "local_invocation_index"
+               OpName %idx "idx"
+               OpName %f "f"
+               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 16
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 16
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+          %S = OpTypeStruct %int %mat3v3float %int
+     %uint_4 = OpConstant %uint 4
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+    %u_block = OpTypeStruct %_arr_S_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_Workgroup__arr_S_uint_4 = OpTypePointer Workgroup %_arr_S_uint_4
+          %w = OpVariable %_ptr_Workgroup__arr_S_uint_4 Workgroup
+       %void = OpTypeVoid
+         %16 = OpTypeFunction %void %uint
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %23 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Workgroup_S = OpTypePointer Workgroup %S
+         %37 = OpConstantNull %S
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+   %uint_264 = OpConstant %uint 264
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_S_uint_4 = OpTypePointer Uniform %_arr_S_uint_4
+      %int_1 = OpConstant %int 1
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_S = OpTypePointer Uniform %S
+      %int_3 = OpConstant %int 3
+%_ptr_Workgroup_mat3v3float = OpTypePointer Workgroup %mat3v3float
+%_ptr_Uniform_mat3v3float = OpTypePointer Uniform %mat3v3float
+         %60 = OpConstantNull %int
+%_ptr_Workgroup_v3float = OpTypePointer Workgroup %v3float
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+         %67 = OpTypeFunction %void
+    %f_inner = OpFunction %void None %16
+%local_invocation_index = OpFunctionParameter %uint
+         %20 = OpLabel
+        %idx = OpVariable %_ptr_Function_uint Function %23
+               OpStore %idx %local_invocation_index
+               OpBranch %24
+         %24 = OpLabel
+               OpLoopMerge %25 %26 None
+               OpBranch %27
+         %27 = OpLabel
+         %29 = OpLoad %uint %idx
+         %30 = OpULessThan %bool %29 %uint_4
+         %28 = OpLogicalNot %bool %30
+               OpSelectionMerge %32 None
+               OpBranchConditional %28 %33 %32
+         %33 = OpLabel
+               OpBranch %25
+         %32 = OpLabel
+         %34 = OpLoad %uint %idx
+         %36 = OpAccessChain %_ptr_Workgroup_S %w %34
+               OpStore %36 %37
+               OpBranch %26
+         %26 = OpLabel
+         %38 = OpLoad %uint %idx
+         %40 = OpIAdd %uint %38 %uint_1
+               OpStore %idx %40
+               OpBranch %24
+         %25 = OpLabel
+               OpControlBarrier %uint_2 %uint_2 %uint_264
+         %46 = OpAccessChain %_ptr_Uniform__arr_S_uint_4 %u %uint_0
+         %47 = OpLoad %_arr_S_uint_4 %46
+               OpStore %w %47
+         %49 = OpAccessChain %_ptr_Workgroup_S %w %int_1
+         %52 = OpAccessChain %_ptr_Uniform_S %u %uint_0 %int_2
+         %53 = OpLoad %S %52
+               OpStore %49 %53
+         %56 = OpAccessChain %_ptr_Workgroup_mat3v3float %w %int_3 %uint_1
+         %58 = OpAccessChain %_ptr_Uniform_mat3v3float %u %uint_0 %int_2 %uint_1
+         %59 = OpLoad %mat3v3float %58
+               OpStore %56 %59
+         %62 = OpAccessChain %_ptr_Workgroup_v3float %w %int_1 %uint_1 %60
+         %64 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %60 %uint_1 %int_1
+         %65 = OpLoad %v3float %64
+         %66 = OpVectorShuffle %v3float %65 %65 2 0 1
+               OpStore %62 %66
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %67
+         %69 = OpLabel
+         %71 = OpLoad %uint %local_invocation_index_1
+         %70 = OpFunctionCall %void %f_inner %71
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..1488b07
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x3_f32/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+struct S {
+  before : i32,
+  m : mat3x3<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+var<workgroup> w : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[2];
+  w[3].m = u[2].m;
+  w[1].m[0] = u[0].m[1].zxy;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/dynamic_index_via_ptr.wgsl
new file mode 100644
index 0000000..353b7ab
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/dynamic_index_via_ptr.wgsl
@@ -0,0 +1,34 @@
+enable f16;
+
+struct Inner {
+  @size(64)
+  m : mat3x4<f16>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a           = &a;
+  let p_a_i         = &((*p_a)[i()]);
+  let p_a_i_a       = &((*p_a_i).a);
+  let p_a_i_a_i     = &((*p_a_i_a)[i()]);
+  let p_a_i_a_i_m   = &((*p_a_i_a_i).m);
+  let p_a_i_a_i_m_i = &((*p_a_i_a_i_m)[i()]);
+
+
+  let l_a             : array<Outer, 4> =  *p_a;
+  let l_a_i           : Outer           =  *p_a_i;
+  let l_a_i_a         : array<Inner, 4> =  *p_a_i_a;
+  let l_a_i_a_i       : Inner           =  *p_a_i_a_i;
+  let l_a_i_a_i_m     : mat3x4<f16>     =  *p_a_i_a_i_m;
+  let l_a_i_a_i_m_i   : vec4<f16>       =  *p_a_i_a_i_m_i;
+  let l_a_i_a_i_m_i_i : f16             = (*p_a_i_a_i_m_i)[i()];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..7487aeb
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,93 @@
+struct Inner {
+  matrix<float16_t, 3, 4> m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 3, 4> tint_symbol_8(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  return matrix<float16_t, 3, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]));
+}
+
+Inner tint_symbol_7(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_11 = {tint_symbol_8(buffer, (offset + 0u))};
+  return tint_symbol_11;
+}
+
+typedef Inner tint_symbol_6_ret[4];
+tint_symbol_6_ret tint_symbol_6(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_7(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_5(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_12 = {tint_symbol_6(buffer, (offset + 0u))};
+  return tint_symbol_12;
+}
+
+typedef Outer tint_symbol_4_ret[4];
+tint_symbol_4_ret tint_symbol_4(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
+      arr_1[i_2] = tint_symbol_5(buffer, (offset + (i_2 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_a_i_save = i();
+  const int p_a_i_a_i_m_i_save = i();
+  const Outer l_a[4] = tint_symbol_4(a, 0u);
+  const Outer l_a_i = tint_symbol_5(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a[4] = tint_symbol_6(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a_i = tint_symbol_7(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const matrix<float16_t, 3, 4> l_a_i_a_i_m = tint_symbol_8(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const uint scalar_offset_3 = ((((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))) + (8u * uint(p_a_i_a_i_m_i_save)))) / 4;
+  uint4 ubo_load_7 = a[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  const vector<float16_t, 4> l_a_i_a_i_m_i = vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]);
+  const int tint_symbol = p_a_i_save;
+  const int tint_symbol_1 = p_a_i_a_i_save;
+  const int tint_symbol_2 = p_a_i_a_i_m_i_save;
+  const int tint_symbol_3 = i();
+  const uint scalar_offset_bytes = (((((256u * uint(tint_symbol)) + (64u * uint(tint_symbol_1))) + (8u * uint(tint_symbol_2))) + (2u * uint(tint_symbol_3))));
+  const uint scalar_offset_index = scalar_offset_bytes / 4;
+  const float16_t l_a_i_a_i_m_i_i = float16_t(f16tof32(((a[scalar_offset_index / 4][scalar_offset_index % 4] >> (scalar_offset_bytes % 4 == 0 ? 0 : 16)) & 0xFFFF)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..cf6d6ac
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,98 @@
+SKIP: FAILED
+
+struct Inner {
+  matrix<float16_t, 3, 4> m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 3, 4> tint_symbol_8(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  return matrix<float16_t, 3, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]));
+}
+
+Inner tint_symbol_7(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_11 = {tint_symbol_8(buffer, (offset + 0u))};
+  return tint_symbol_11;
+}
+
+typedef Inner tint_symbol_6_ret[4];
+tint_symbol_6_ret tint_symbol_6(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_7(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_5(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_12 = {tint_symbol_6(buffer, (offset + 0u))};
+  return tint_symbol_12;
+}
+
+typedef Outer tint_symbol_4_ret[4];
+tint_symbol_4_ret tint_symbol_4(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
+      arr_1[i_2] = tint_symbol_5(buffer, (offset + (i_2 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_a_i_save = i();
+  const int p_a_i_a_i_m_i_save = i();
+  const Outer l_a[4] = tint_symbol_4(a, 0u);
+  const Outer l_a_i = tint_symbol_5(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a[4] = tint_symbol_6(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a_i = tint_symbol_7(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const matrix<float16_t, 3, 4> l_a_i_a_i_m = tint_symbol_8(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const uint scalar_offset_3 = ((((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))) + (8u * uint(p_a_i_a_i_m_i_save)))) / 4;
+  uint4 ubo_load_7 = a[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  const vector<float16_t, 4> l_a_i_a_i_m_i = vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]);
+  const int tint_symbol = p_a_i_save;
+  const int tint_symbol_1 = p_a_i_a_i_save;
+  const int tint_symbol_2 = p_a_i_a_i_m_i_save;
+  const int tint_symbol_3 = i();
+  const uint scalar_offset_bytes = (((((256u * uint(tint_symbol)) + (64u * uint(tint_symbol_1))) + (8u * uint(tint_symbol_2))) + (2u * uint(tint_symbol_3))));
+  const uint scalar_offset_index = scalar_offset_bytes / 4;
+  const float16_t l_a_i_a_i_m_i_i = float16_t(f16tof32(((a[scalar_offset_index / 4][scalar_offset_index % 4] >> (scalar_offset_bytes % 4 == 0 ? 0 : 16)) & 0xFFFF)));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001C15A92C5C0(2,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/dynamic_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..5b0a6bc
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,152 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct Inner {
+  f16mat3x4 m;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+};
+
+struct Inner_std140 {
+  f16vec4 m_0;
+  f16vec4 m_1;
+  f16vec4 m_2;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+};
+
+struct Outer {
+  Inner a[4];
+};
+
+struct Outer_std140 {
+  Inner_std140 a[4];
+};
+
+layout(binding = 0, std140) uniform a_block_std140_ubo {
+  Outer_std140 inner[4];
+} a;
+
+int counter = 0;
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+Inner conv_Inner(Inner_std140 val) {
+  return Inner(f16mat3x4(val.m_0, val.m_1, val.m_2), val.pad, val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9);
+}
+
+Inner[4] conv_arr4_Inner(Inner_std140 val[4]) {
+  Inner arr[4] = Inner[4](Inner(f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_Inner(val[i]);
+    }
+  }
+  return arr;
+}
+
+Outer conv_Outer(Outer_std140 val) {
+  return Outer(conv_arr4_Inner(val.a));
+}
+
+Outer[4] conv_arr4_Outer(Outer_std140 val[4]) {
+  Outer arr[4] = Outer[4](Outer(Inner[4](Inner(f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_Outer(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat3x4 load_a_inner_p0_a_p1_m(uint p0, uint p1) {
+  uint s_save = p0;
+  uint s_save_1 = p1;
+  return f16mat3x4(a.inner[s_save].a[s_save_1].m_0, a.inner[s_save].a[s_save_1].m_1, a.inner[s_save].a[s_save_1].m_2);
+}
+
+f16vec4 load_a_inner_p0_a_p1_m_p2(uint p0, uint p1, uint p2) {
+  switch(p2) {
+    case 0u: {
+      return a.inner[p0].a[p1].m_0;
+      break;
+    }
+    case 1u: {
+      return a.inner[p0].a[p1].m_1;
+      break;
+    }
+    case 2u: {
+      return a.inner[p0].a[p1].m_2;
+      break;
+    }
+    default: {
+      return f16vec4(0.0hf);
+      break;
+    }
+  }
+}
+
+float16_t load_a_inner_p0_a_p1_m_p2_p3(uint p0, uint p1, uint p2, uint p3) {
+  switch(p2) {
+    case 0u: {
+      return a.inner[p0].a[p1].m_0[p3];
+      break;
+    }
+    case 1u: {
+      return a.inner[p0].a[p1].m_1[p3];
+      break;
+    }
+    case 2u: {
+      return a.inner[p0].a[p1].m_2[p3];
+      break;
+    }
+    default: {
+      return 0.0hf;
+      break;
+    }
+  }
+}
+
+void f() {
+  Outer p_a[4] = conv_arr4_Outer(a.inner);
+  int tint_symbol = i();
+  Outer p_a_i = conv_Outer(a.inner[tint_symbol]);
+  Inner p_a_i_a[4] = conv_arr4_Inner(a.inner[tint_symbol].a);
+  int tint_symbol_1 = i();
+  Inner p_a_i_a_i = conv_Inner(a.inner[tint_symbol].a[tint_symbol_1]);
+  f16mat3x4 p_a_i_a_i_m = load_a_inner_p0_a_p1_m(uint(tint_symbol), uint(tint_symbol_1));
+  int tint_symbol_2 = i();
+  f16vec4 p_a_i_a_i_m_i = load_a_inner_p0_a_p1_m_p2(uint(tint_symbol), uint(tint_symbol_1), uint(tint_symbol_2));
+  Outer l_a[4] = conv_arr4_Outer(a.inner);
+  Outer l_a_i = conv_Outer(a.inner[tint_symbol]);
+  Inner l_a_i_a[4] = conv_arr4_Inner(a.inner[tint_symbol].a);
+  Inner l_a_i_a_i = conv_Inner(a.inner[tint_symbol].a[tint_symbol_1]);
+  f16mat3x4 l_a_i_a_i_m = load_a_inner_p0_a_p1_m(uint(tint_symbol), uint(tint_symbol_1));
+  f16vec4 l_a_i_a_i_m_i = load_a_inner_p0_a_p1_m_p2(uint(tint_symbol), uint(tint_symbol_1), uint(tint_symbol_2));
+  int tint_symbol_3 = i();
+  float16_t l_a_i_a_i_m_i_i = load_a_inner_p0_a_p1_m_p2_p3(uint(tint_symbol), uint(tint_symbol_1), uint(tint_symbol_2), uint(tint_symbol_3));
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/dynamic_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..eed6f51
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/dynamic_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,49 @@
+#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 Inner {
+  /* 0x0000 */ half3x4 m;
+  /* 0x0018 */ tint_array<int8_t, 40> tint_pad;
+};
+
+struct Outer {
+  /* 0x0000 */ tint_array<Inner, 4> a;
+};
+
+int i() {
+  thread int tint_symbol_4 = 0;
+  tint_symbol_4 = as_type<int>((as_type<uint>(tint_symbol_4) + as_type<uint>(1)));
+  return tint_symbol_4;
+}
+
+kernel void f(const constant tint_array<Outer, 4>* tint_symbol_5 [[buffer(0)]]) {
+  int const tint_symbol = i();
+  int const p_a_i_save = tint_symbol;
+  int const tint_symbol_1 = i();
+  int const p_a_i_a_i_save = tint_symbol_1;
+  int const tint_symbol_2 = i();
+  int const p_a_i_a_i_m_i_save = tint_symbol_2;
+  tint_array<Outer, 4> const l_a = *(tint_symbol_5);
+  Outer const l_a_i = (*(tint_symbol_5))[p_a_i_save];
+  tint_array<Inner, 4> const l_a_i_a = (*(tint_symbol_5))[p_a_i_save].a;
+  Inner const l_a_i_a_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save];
+  half3x4 const l_a_i_a_i_m = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m;
+  half4 const l_a_i_a_i_m_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save];
+  int const tint_symbol_3 = i();
+  half const l_a_i_a_i_m_i_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save][tint_symbol_3];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..4f50ed0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,324 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 204
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block_std140 "a_block_std140"
+               OpMemberName %a_block_std140 0 "inner"
+               OpName %Outer_std140 "Outer_std140"
+               OpMemberName %Outer_std140 0 "a"
+               OpName %Inner_std140 "Inner_std140"
+               OpMemberName %Inner_std140 0 "m_0"
+               OpMemberName %Inner_std140 1 "m_1"
+               OpMemberName %Inner_std140 2 "m_2"
+               OpName %a "a"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %Inner "Inner"
+               OpMemberName %Inner 0 "m"
+               OpName %conv_Inner "conv_Inner"
+               OpName %val "val"
+               OpName %conv_arr4_Inner "conv_arr4_Inner"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i_0 "i"
+               OpName %var_for_index_1 "var_for_index_1"
+               OpName %Outer "Outer"
+               OpMemberName %Outer 0 "a"
+               OpName %conv_Outer "conv_Outer"
+               OpName %val_1 "val"
+               OpName %conv_arr4_Outer "conv_arr4_Outer"
+               OpName %val_2 "val"
+               OpName %arr_0 "arr"
+               OpName %i_1 "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_a_inner_p0_a_p1_m "load_a_inner_p0_a_p1_m"
+               OpName %p0 "p0"
+               OpName %p1 "p1"
+               OpName %load_a_inner_p0_a_p1_m_p2 "load_a_inner_p0_a_p1_m_p2"
+               OpName %p0_0 "p0"
+               OpName %p1_0 "p1"
+               OpName %p2 "p2"
+               OpName %load_a_inner_p0_a_p1_m_p2_p3 "load_a_inner_p0_a_p1_m_p2_p3"
+               OpName %p0_1 "p0"
+               OpName %p1_1 "p1"
+               OpName %p2_0 "p2"
+               OpName %p3 "p3"
+               OpName %f "f"
+               OpDecorate %a_block_std140 Block
+               OpMemberDecorate %a_block_std140 0 Offset 0
+               OpMemberDecorate %Outer_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 1 Offset 8
+               OpMemberDecorate %Inner_std140 2 Offset 16
+               OpDecorate %_arr_Inner_std140_uint_4 ArrayStride 64
+               OpDecorate %_arr_Outer_std140_uint_4 ArrayStride 256
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+               OpMemberDecorate %Inner 0 Offset 0
+               OpMemberDecorate %Inner 0 ColMajor
+               OpMemberDecorate %Inner 0 MatrixStride 8
+               OpDecorate %_arr_Inner_uint_4 ArrayStride 64
+               OpMemberDecorate %Outer 0 Offset 0
+               OpDecorate %_arr_Outer_uint_4 ArrayStride 256
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+%Inner_std140 = OpTypeStruct %v4half %v4half %v4half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_Inner_std140_uint_4 = OpTypeArray %Inner_std140 %uint_4
+%Outer_std140 = OpTypeStruct %_arr_Inner_std140_uint_4
+%_arr_Outer_std140_uint_4 = OpTypeArray %Outer_std140 %uint_4
+%a_block_std140 = OpTypeStruct %_arr_Outer_std140_uint_4
+%_ptr_Uniform_a_block_std140 = OpTypePointer Uniform %a_block_std140
+          %a = OpVariable %_ptr_Uniform_a_block_std140 Uniform
+        %int = OpTypeInt 32 1
+         %13 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %13
+         %16 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+ %mat3v4half = OpTypeMatrix %v4half 3
+      %Inner = OpTypeStruct %mat3v4half
+         %23 = OpTypeFunction %Inner %Inner_std140
+%_arr_Inner_uint_4 = OpTypeArray %Inner %uint_4
+         %34 = OpTypeFunction %_arr_Inner_uint_4 %_arr_Inner_std140_uint_4
+%_ptr_Function__arr_Inner_uint_4 = OpTypePointer Function %_arr_Inner_uint_4
+         %41 = OpConstantNull %_arr_Inner_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %44 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_Inner_std140_uint_4 = OpTypePointer Function %_arr_Inner_std140_uint_4
+         %57 = OpConstantNull %_arr_Inner_std140_uint_4
+%_ptr_Function_Inner = OpTypePointer Function %Inner
+%_ptr_Function_Inner_std140 = OpTypePointer Function %Inner_std140
+     %uint_1 = OpConstant %uint 1
+      %Outer = OpTypeStruct %_arr_Inner_uint_4
+         %70 = OpTypeFunction %Outer %Outer_std140
+%_arr_Outer_uint_4 = OpTypeArray %Outer %uint_4
+         %78 = OpTypeFunction %_arr_Outer_uint_4 %_arr_Outer_std140_uint_4
+%_ptr_Function__arr_Outer_uint_4 = OpTypePointer Function %_arr_Outer_uint_4
+         %85 = OpConstantNull %_arr_Outer_uint_4
+%_ptr_Function__arr_Outer_std140_uint_4 = OpTypePointer Function %_arr_Outer_std140_uint_4
+         %98 = OpConstantNull %_arr_Outer_std140_uint_4
+%_ptr_Function_Outer = OpTypePointer Function %Outer
+%_ptr_Function_Outer_std140 = OpTypePointer Function %Outer_std140
+        %110 = OpTypeFunction %mat3v4half %uint %uint
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_Inner_std140 = OpTypePointer Uniform %Inner_std140
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+     %uint_2 = OpConstant %uint 2
+        %131 = OpTypeFunction %v4half %uint %uint %uint
+        %148 = OpConstantNull %v4half
+        %149 = OpTypeFunction %half %uint %uint %uint %uint
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+        %168 = OpConstantNull %half
+       %void = OpTypeVoid
+        %169 = OpTypeFunction %void
+%_ptr_Uniform__arr_Outer_std140_uint_4 = OpTypePointer Uniform %_arr_Outer_std140_uint_4
+%_ptr_Uniform_Outer_std140 = OpTypePointer Uniform %Outer_std140
+%_ptr_Uniform__arr_Inner_std140_uint_4 = OpTypePointer Uniform %_arr_Inner_std140_uint_4
+          %i = OpFunction %int None %16
+         %18 = OpLabel
+         %19 = OpLoad %int %counter
+         %21 = OpIAdd %int %19 %int_1
+               OpStore %counter %21
+         %22 = OpLoad %int %counter
+               OpReturnValue %22
+               OpFunctionEnd
+ %conv_Inner = OpFunction %Inner None %23
+        %val = OpFunctionParameter %Inner_std140
+         %28 = OpLabel
+         %29 = OpCompositeExtract %v4half %val 0
+         %30 = OpCompositeExtract %v4half %val 1
+         %31 = OpCompositeExtract %v4half %val 2
+         %32 = OpCompositeConstruct %mat3v4half %29 %30 %31
+         %33 = OpCompositeConstruct %Inner %32
+               OpReturnValue %33
+               OpFunctionEnd
+%conv_arr4_Inner = OpFunction %_arr_Inner_uint_4 None %34
+      %val_0 = OpFunctionParameter %_arr_Inner_std140_uint_4
+         %38 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_Inner_uint_4 Function %41
+        %i_0 = OpVariable %_ptr_Function_uint Function %44
+%var_for_index_1 = OpVariable %_ptr_Function__arr_Inner_std140_uint_4 Function %57
+               OpBranch %45
+         %45 = OpLabel
+               OpLoopMerge %46 %47 None
+               OpBranch %48
+         %48 = OpLabel
+         %50 = OpLoad %uint %i_0
+         %51 = OpULessThan %bool %50 %uint_4
+         %49 = OpLogicalNot %bool %51
+               OpSelectionMerge %53 None
+               OpBranchConditional %49 %54 %53
+         %54 = OpLabel
+               OpBranch %46
+         %53 = OpLabel
+               OpStore %var_for_index_1 %val_0
+         %58 = OpLoad %uint %i_0
+         %60 = OpAccessChain %_ptr_Function_Inner %arr %58
+         %62 = OpLoad %uint %i_0
+         %64 = OpAccessChain %_ptr_Function_Inner_std140 %var_for_index_1 %62
+         %65 = OpLoad %Inner_std140 %64
+         %61 = OpFunctionCall %Inner %conv_Inner %65
+               OpStore %60 %61
+               OpBranch %47
+         %47 = OpLabel
+         %66 = OpLoad %uint %i_0
+         %68 = OpIAdd %uint %66 %uint_1
+               OpStore %i_0 %68
+               OpBranch %45
+         %46 = OpLabel
+         %69 = OpLoad %_arr_Inner_uint_4 %arr
+               OpReturnValue %69
+               OpFunctionEnd
+ %conv_Outer = OpFunction %Outer None %70
+      %val_1 = OpFunctionParameter %Outer_std140
+         %74 = OpLabel
+         %76 = OpCompositeExtract %_arr_Inner_std140_uint_4 %val_1 0
+         %75 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %76
+         %77 = OpCompositeConstruct %Outer %75
+               OpReturnValue %77
+               OpFunctionEnd
+%conv_arr4_Outer = OpFunction %_arr_Outer_uint_4 None %78
+      %val_2 = OpFunctionParameter %_arr_Outer_std140_uint_4
+         %82 = OpLabel
+      %arr_0 = OpVariable %_ptr_Function__arr_Outer_uint_4 Function %85
+        %i_1 = OpVariable %_ptr_Function_uint Function %44
+%var_for_index = OpVariable %_ptr_Function__arr_Outer_std140_uint_4 Function %98
+               OpBranch %87
+         %87 = OpLabel
+               OpLoopMerge %88 %89 None
+               OpBranch %90
+         %90 = OpLabel
+         %92 = OpLoad %uint %i_1
+         %93 = OpULessThan %bool %92 %uint_4
+         %91 = OpLogicalNot %bool %93
+               OpSelectionMerge %94 None
+               OpBranchConditional %91 %95 %94
+         %95 = OpLabel
+               OpBranch %88
+         %94 = OpLabel
+               OpStore %var_for_index %val_2
+         %99 = OpLoad %uint %i_1
+        %101 = OpAccessChain %_ptr_Function_Outer %arr_0 %99
+        %103 = OpLoad %uint %i_1
+        %105 = OpAccessChain %_ptr_Function_Outer_std140 %var_for_index %103
+        %106 = OpLoad %Outer_std140 %105
+        %102 = OpFunctionCall %Outer %conv_Outer %106
+               OpStore %101 %102
+               OpBranch %89
+         %89 = OpLabel
+        %107 = OpLoad %uint %i_1
+        %108 = OpIAdd %uint %107 %uint_1
+               OpStore %i_1 %108
+               OpBranch %87
+         %88 = OpLabel
+        %109 = OpLoad %_arr_Outer_uint_4 %arr_0
+               OpReturnValue %109
+               OpFunctionEnd
+%load_a_inner_p0_a_p1_m = OpFunction %mat3v4half None %110
+         %p0 = OpFunctionParameter %uint
+         %p1 = OpFunctionParameter %uint
+        %114 = OpLabel
+        %118 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %p0 %uint_0 %p1
+        %121 = OpAccessChain %_ptr_Uniform_v4half %118 %uint_0
+        %122 = OpLoad %v4half %121
+        %124 = OpAccessChain %_ptr_Uniform_v4half %118 %uint_1
+        %125 = OpLoad %v4half %124
+        %128 = OpAccessChain %_ptr_Uniform_v4half %118 %uint_2
+        %129 = OpLoad %v4half %128
+        %130 = OpCompositeConstruct %mat3v4half %122 %125 %129
+               OpReturnValue %130
+               OpFunctionEnd
+%load_a_inner_p0_a_p1_m_p2 = OpFunction %v4half None %131
+       %p0_0 = OpFunctionParameter %uint
+       %p1_0 = OpFunctionParameter %uint
+         %p2 = OpFunctionParameter %uint
+        %136 = OpLabel
+               OpSelectionMerge %137 None
+               OpSwitch %p2 %138 0 %139 1 %140 2 %141
+        %139 = OpLabel
+        %142 = OpAccessChain %_ptr_Uniform_v4half %a %uint_0 %p0_0 %uint_0 %p1_0 %uint_0
+        %143 = OpLoad %v4half %142
+               OpReturnValue %143
+        %140 = OpLabel
+        %144 = OpAccessChain %_ptr_Uniform_v4half %a %uint_0 %p0_0 %uint_0 %p1_0 %uint_1
+        %145 = OpLoad %v4half %144
+               OpReturnValue %145
+        %141 = OpLabel
+        %146 = OpAccessChain %_ptr_Uniform_v4half %a %uint_0 %p0_0 %uint_0 %p1_0 %uint_2
+        %147 = OpLoad %v4half %146
+               OpReturnValue %147
+        %138 = OpLabel
+               OpReturnValue %148
+        %137 = OpLabel
+               OpReturnValue %148
+               OpFunctionEnd
+%load_a_inner_p0_a_p1_m_p2_p3 = OpFunction %half None %149
+       %p0_1 = OpFunctionParameter %uint
+       %p1_1 = OpFunctionParameter %uint
+       %p2_0 = OpFunctionParameter %uint
+         %p3 = OpFunctionParameter %uint
+        %155 = OpLabel
+               OpSelectionMerge %156 None
+               OpSwitch %p2_0 %157 0 %158 1 %159 2 %160
+        %158 = OpLabel
+        %162 = OpAccessChain %_ptr_Uniform_half %a %uint_0 %p0_1 %uint_0 %p1_1 %uint_0 %p3
+        %163 = OpLoad %half %162
+               OpReturnValue %163
+        %159 = OpLabel
+        %164 = OpAccessChain %_ptr_Uniform_half %a %uint_0 %p0_1 %uint_0 %p1_1 %uint_1 %p3
+        %165 = OpLoad %half %164
+               OpReturnValue %165
+        %160 = OpLabel
+        %166 = OpAccessChain %_ptr_Uniform_half %a %uint_0 %p0_1 %uint_0 %p1_1 %uint_2 %p3
+        %167 = OpLoad %half %166
+               OpReturnValue %167
+        %157 = OpLabel
+               OpReturnValue %168
+        %156 = OpLabel
+               OpReturnValue %168
+               OpFunctionEnd
+          %f = OpFunction %void None %169
+        %172 = OpLabel
+        %173 = OpFunctionCall %int %i
+        %174 = OpFunctionCall %int %i
+        %175 = OpFunctionCall %int %i
+        %178 = OpAccessChain %_ptr_Uniform__arr_Outer_std140_uint_4 %a %uint_0
+        %179 = OpLoad %_arr_Outer_std140_uint_4 %178
+        %176 = OpFunctionCall %_arr_Outer_uint_4 %conv_arr4_Outer %179
+        %182 = OpAccessChain %_ptr_Uniform_Outer_std140 %a %uint_0 %173
+        %183 = OpLoad %Outer_std140 %182
+        %180 = OpFunctionCall %Outer %conv_Outer %183
+        %186 = OpAccessChain %_ptr_Uniform__arr_Inner_std140_uint_4 %a %uint_0 %173 %uint_0
+        %187 = OpLoad %_arr_Inner_std140_uint_4 %186
+        %184 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %187
+        %189 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %173 %uint_0 %174
+        %190 = OpLoad %Inner_std140 %189
+        %188 = OpFunctionCall %Inner %conv_Inner %190
+        %192 = OpBitcast %uint %173
+        %193 = OpBitcast %uint %174
+        %191 = OpFunctionCall %mat3v4half %load_a_inner_p0_a_p1_m %192 %193
+        %195 = OpBitcast %uint %173
+        %196 = OpBitcast %uint %174
+        %197 = OpBitcast %uint %175
+        %194 = OpFunctionCall %v4half %load_a_inner_p0_a_p1_m_p2 %195 %196 %197
+        %198 = OpFunctionCall %int %i
+        %200 = OpBitcast %uint %173
+        %201 = OpBitcast %uint %174
+        %202 = OpBitcast %uint %175
+        %203 = OpBitcast %uint %198
+        %199 = OpFunctionCall %half %load_a_inner_p0_a_p1_m_p2_p3 %200 %201 %202 %203
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..f439e90
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,36 @@
+enable f16;
+
+struct Inner {
+  @size(64)
+  m : mat3x4<f16>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_i = &((*(p_a))[i()]);
+  let p_a_i_a = &((*(p_a_i)).a);
+  let p_a_i_a_i = &((*(p_a_i_a))[i()]);
+  let p_a_i_a_i_m = &((*(p_a_i_a_i)).m);
+  let p_a_i_a_i_m_i = &((*(p_a_i_a_i_m))[i()]);
+  let l_a : array<Outer, 4> = *(p_a);
+  let l_a_i : Outer = *(p_a_i);
+  let l_a_i_a : array<Inner, 4> = *(p_a_i_a);
+  let l_a_i_a_i : Inner = *(p_a_i_a_i);
+  let l_a_i_a_i_m : mat3x4<f16> = *(p_a_i_a_i_m);
+  let l_a_i_a_i_m_i : vec4<f16> = *(p_a_i_a_i_m_i);
+  let l_a_i_a_i_m_i_i : f16 = (*(p_a_i_a_i_m_i))[i()];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/static_index_via_ptr.wgsl
new file mode 100644
index 0000000..bb5b51e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/static_index_via_ptr.wgsl
@@ -0,0 +1,31 @@
+enable f16;
+
+struct Inner {
+  @size(64)
+  m : mat3x4<f16>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &a;
+  let p_a_3 = &((*p_a)[3]);
+  let p_a_3_a = &((*p_a_3).a);
+  let p_a_3_a_2 = &((*p_a_3_a)[2]);
+  let p_a_3_a_2_m = &((*p_a_3_a_2).m);
+  let p_a_3_a_2_m_1 = &((*p_a_3_a_2_m)[1]);
+
+
+  let l_a             : array<Outer, 4> = *p_a;
+  let l_a_3           : Outer           = *p_a_3;
+  let l_a_3_a         : array<Inner, 4> = *p_a_3_a;
+  let l_a_3_a_2       : Inner           = *p_a_3_a_2;
+  let l_a_3_a_2_m     : mat3x4<f16>     = *p_a_3_a_2_m;
+  let l_a_3_a_2_m_1   : vec4<f16>       = *p_a_3_a_2_m_1;
+  let l_a_3_a_2_m_1_0 : f16             = (*p_a_3_a_2_m_1)[0];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..356bff3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,76 @@
+struct Inner {
+  matrix<float16_t, 3, 4> m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+
+matrix<float16_t, 3, 4> tint_symbol_4(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  return matrix<float16_t, 3, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]));
+}
+
+Inner tint_symbol_3(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_7 = {tint_symbol_4(buffer, (offset + 0u))};
+  return tint_symbol_7;
+}
+
+typedef Inner tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_3(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_1(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_8 = {tint_symbol_2(buffer, (offset + 0u))};
+  return tint_symbol_8;
+}
+
+typedef Outer tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr_1[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const Outer l_a[4] = tint_symbol(a, 0u);
+  const Outer l_a_3 = tint_symbol_1(a, 768u);
+  const Inner l_a_3_a[4] = tint_symbol_2(a, 768u);
+  const Inner l_a_3_a_2 = tint_symbol_3(a, 896u);
+  const matrix<float16_t, 3, 4> l_a_3_a_2_m = tint_symbol_4(a, 896u);
+  uint2 ubo_load_6 = a[56].zw;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  const vector<float16_t, 4> l_a_3_a_2_m_1 = vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]);
+  const float16_t l_a_3_a_2_m_1_0 = float16_t(f16tof32(((a[56].z) & 0xFFFF)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..681fb5e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,81 @@
+SKIP: FAILED
+
+struct Inner {
+  matrix<float16_t, 3, 4> m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+
+matrix<float16_t, 3, 4> tint_symbol_4(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  return matrix<float16_t, 3, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]));
+}
+
+Inner tint_symbol_3(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_7 = {tint_symbol_4(buffer, (offset + 0u))};
+  return tint_symbol_7;
+}
+
+typedef Inner tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_3(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_1(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_8 = {tint_symbol_2(buffer, (offset + 0u))};
+  return tint_symbol_8;
+}
+
+typedef Outer tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr_1[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const Outer l_a[4] = tint_symbol(a, 0u);
+  const Outer l_a_3 = tint_symbol_1(a, 768u);
+  const Inner l_a_3_a[4] = tint_symbol_2(a, 768u);
+  const Inner l_a_3_a_2 = tint_symbol_3(a, 896u);
+  const matrix<float16_t, 3, 4> l_a_3_a_2_m = tint_symbol_4(a, 896u);
+  uint2 ubo_load_6 = a[56].zw;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  const vector<float16_t, 4> l_a_3_a_2_m_1 = vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]);
+  const float16_t l_a_3_a_2_m_1_0 = float16_t(f16tof32(((a[56].z) & 0xFFFF)));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000002CC6184FF70(2,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/static_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..185039b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/static_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,98 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct Inner {
+  f16mat3x4 m;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+};
+
+struct Inner_std140 {
+  f16vec4 m_0;
+  f16vec4 m_1;
+  f16vec4 m_2;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+};
+
+struct Outer {
+  Inner a[4];
+};
+
+struct Outer_std140 {
+  Inner_std140 a[4];
+};
+
+layout(binding = 0, std140) uniform a_block_std140_ubo {
+  Outer_std140 inner[4];
+} a;
+
+Inner conv_Inner(Inner_std140 val) {
+  return Inner(f16mat3x4(val.m_0, val.m_1, val.m_2), val.pad, val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9);
+}
+
+Inner[4] conv_arr4_Inner(Inner_std140 val[4]) {
+  Inner arr[4] = Inner[4](Inner(f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_Inner(val[i]);
+    }
+  }
+  return arr;
+}
+
+Outer conv_Outer(Outer_std140 val) {
+  return Outer(conv_arr4_Inner(val.a));
+}
+
+Outer[4] conv_arr4_Outer(Outer_std140 val[4]) {
+  Outer arr[4] = Outer[4](Outer(Inner[4](Inner(f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_Outer(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat3x4 load_a_inner_3_a_2_m() {
+  return f16mat3x4(a.inner[3u].a[2u].m_0, a.inner[3u].a[2u].m_1, a.inner[3u].a[2u].m_2);
+}
+
+void f() {
+  Outer p_a[4] = conv_arr4_Outer(a.inner);
+  Outer p_a_3 = conv_Outer(a.inner[3u]);
+  Inner p_a_3_a[4] = conv_arr4_Inner(a.inner[3u].a);
+  Inner p_a_3_a_2 = conv_Inner(a.inner[3u].a[2u]);
+  f16mat3x4 p_a_3_a_2_m = load_a_inner_3_a_2_m();
+  f16vec4 p_a_3_a_2_m_1 = a.inner[3u].a[2u].m_1;
+  Outer l_a[4] = conv_arr4_Outer(a.inner);
+  Outer l_a_3 = conv_Outer(a.inner[3u]);
+  Inner l_a_3_a[4] = conv_arr4_Inner(a.inner[3u].a);
+  Inner l_a_3_a_2 = conv_Inner(a.inner[3u].a[2u]);
+  f16mat3x4 l_a_3_a_2_m = load_a_inner_3_a_2_m();
+  f16vec4 l_a_3_a_2_m_1 = a.inner[3u].a[2u].m_1;
+  float16_t l_a_3_a_2_m_1_0 = a.inner[3u].a[2u].m_1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/static_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..7d2bfd1
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/static_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,36 @@
+#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 Inner {
+  /* 0x0000 */ half3x4 m;
+  /* 0x0018 */ tint_array<int8_t, 40> tint_pad;
+};
+
+struct Outer {
+  /* 0x0000 */ tint_array<Inner, 4> a;
+};
+
+kernel void f(const constant tint_array<Outer, 4>* tint_symbol [[buffer(0)]]) {
+  tint_array<Outer, 4> const l_a = *(tint_symbol);
+  Outer const l_a_3 = (*(tint_symbol))[3];
+  tint_array<Inner, 4> const l_a_3_a = (*(tint_symbol))[3].a;
+  Inner const l_a_3_a_2 = (*(tint_symbol))[3].a[2];
+  half3x4 const l_a_3_a_2_m = (*(tint_symbol))[3].a[2].m;
+  half4 const l_a_3_a_2_m_1 = (*(tint_symbol))[3].a[2].m[1];
+  half const l_a_3_a_2_m_1_0 = (*(tint_symbol))[3].a[2].m[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/static_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..dce6859
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/static_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,232 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 144
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block_std140 "a_block_std140"
+               OpMemberName %a_block_std140 0 "inner"
+               OpName %Outer_std140 "Outer_std140"
+               OpMemberName %Outer_std140 0 "a"
+               OpName %Inner_std140 "Inner_std140"
+               OpMemberName %Inner_std140 0 "m_0"
+               OpMemberName %Inner_std140 1 "m_1"
+               OpMemberName %Inner_std140 2 "m_2"
+               OpName %a "a"
+               OpName %Inner "Inner"
+               OpMemberName %Inner 0 "m"
+               OpName %conv_Inner "conv_Inner"
+               OpName %val "val"
+               OpName %conv_arr4_Inner "conv_arr4_Inner"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index_1 "var_for_index_1"
+               OpName %Outer "Outer"
+               OpMemberName %Outer 0 "a"
+               OpName %conv_Outer "conv_Outer"
+               OpName %val_1 "val"
+               OpName %conv_arr4_Outer "conv_arr4_Outer"
+               OpName %val_2 "val"
+               OpName %arr_0 "arr"
+               OpName %i_0 "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_a_inner_3_a_2_m "load_a_inner_3_a_2_m"
+               OpName %f "f"
+               OpDecorate %a_block_std140 Block
+               OpMemberDecorate %a_block_std140 0 Offset 0
+               OpMemberDecorate %Outer_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 1 Offset 8
+               OpMemberDecorate %Inner_std140 2 Offset 16
+               OpDecorate %_arr_Inner_std140_uint_4 ArrayStride 64
+               OpDecorate %_arr_Outer_std140_uint_4 ArrayStride 256
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+               OpMemberDecorate %Inner 0 Offset 0
+               OpMemberDecorate %Inner 0 ColMajor
+               OpMemberDecorate %Inner 0 MatrixStride 8
+               OpDecorate %_arr_Inner_uint_4 ArrayStride 64
+               OpMemberDecorate %Outer 0 Offset 0
+               OpDecorate %_arr_Outer_uint_4 ArrayStride 256
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+%Inner_std140 = OpTypeStruct %v4half %v4half %v4half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_Inner_std140_uint_4 = OpTypeArray %Inner_std140 %uint_4
+%Outer_std140 = OpTypeStruct %_arr_Inner_std140_uint_4
+%_arr_Outer_std140_uint_4 = OpTypeArray %Outer_std140 %uint_4
+%a_block_std140 = OpTypeStruct %_arr_Outer_std140_uint_4
+%_ptr_Uniform_a_block_std140 = OpTypePointer Uniform %a_block_std140
+          %a = OpVariable %_ptr_Uniform_a_block_std140 Uniform
+ %mat3v4half = OpTypeMatrix %v4half 3
+      %Inner = OpTypeStruct %mat3v4half
+         %12 = OpTypeFunction %Inner %Inner_std140
+%_arr_Inner_uint_4 = OpTypeArray %Inner %uint_4
+         %23 = OpTypeFunction %_arr_Inner_uint_4 %_arr_Inner_std140_uint_4
+%_ptr_Function__arr_Inner_uint_4 = OpTypePointer Function %_arr_Inner_uint_4
+         %30 = OpConstantNull %_arr_Inner_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %33 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_Inner_std140_uint_4 = OpTypePointer Function %_arr_Inner_std140_uint_4
+         %46 = OpConstantNull %_arr_Inner_std140_uint_4
+%_ptr_Function_Inner = OpTypePointer Function %Inner
+%_ptr_Function_Inner_std140 = OpTypePointer Function %Inner_std140
+     %uint_1 = OpConstant %uint 1
+      %Outer = OpTypeStruct %_arr_Inner_uint_4
+         %59 = OpTypeFunction %Outer %Outer_std140
+%_arr_Outer_uint_4 = OpTypeArray %Outer %uint_4
+         %67 = OpTypeFunction %_arr_Outer_uint_4 %_arr_Outer_std140_uint_4
+%_ptr_Function__arr_Outer_uint_4 = OpTypePointer Function %_arr_Outer_uint_4
+         %74 = OpConstantNull %_arr_Outer_uint_4
+%_ptr_Function__arr_Outer_std140_uint_4 = OpTypePointer Function %_arr_Outer_std140_uint_4
+         %87 = OpConstantNull %_arr_Outer_std140_uint_4
+%_ptr_Function_Outer = OpTypePointer Function %Outer
+%_ptr_Function_Outer_std140 = OpTypePointer Function %Outer_std140
+         %99 = OpTypeFunction %mat3v4half
+     %uint_0 = OpConstant %uint 0
+     %uint_3 = OpConstant %uint 3
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_Inner_std140 = OpTypePointer Uniform %Inner_std140
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+       %void = OpTypeVoid
+        %119 = OpTypeFunction %void
+%_ptr_Uniform__arr_Outer_std140_uint_4 = OpTypePointer Uniform %_arr_Outer_std140_uint_4
+%_ptr_Uniform_Outer_std140 = OpTypePointer Uniform %Outer_std140
+%_ptr_Uniform__arr_Inner_std140_uint_4 = OpTypePointer Uniform %_arr_Inner_std140_uint_4
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+ %conv_Inner = OpFunction %Inner None %12
+        %val = OpFunctionParameter %Inner_std140
+         %17 = OpLabel
+         %18 = OpCompositeExtract %v4half %val 0
+         %19 = OpCompositeExtract %v4half %val 1
+         %20 = OpCompositeExtract %v4half %val 2
+         %21 = OpCompositeConstruct %mat3v4half %18 %19 %20
+         %22 = OpCompositeConstruct %Inner %21
+               OpReturnValue %22
+               OpFunctionEnd
+%conv_arr4_Inner = OpFunction %_arr_Inner_uint_4 None %23
+      %val_0 = OpFunctionParameter %_arr_Inner_std140_uint_4
+         %27 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_Inner_uint_4 Function %30
+          %i = OpVariable %_ptr_Function_uint Function %33
+%var_for_index_1 = OpVariable %_ptr_Function__arr_Inner_std140_uint_4 Function %46
+               OpBranch %34
+         %34 = OpLabel
+               OpLoopMerge %35 %36 None
+               OpBranch %37
+         %37 = OpLabel
+         %39 = OpLoad %uint %i
+         %40 = OpULessThan %bool %39 %uint_4
+         %38 = OpLogicalNot %bool %40
+               OpSelectionMerge %42 None
+               OpBranchConditional %38 %43 %42
+         %43 = OpLabel
+               OpBranch %35
+         %42 = OpLabel
+               OpStore %var_for_index_1 %val_0
+         %47 = OpLoad %uint %i
+         %49 = OpAccessChain %_ptr_Function_Inner %arr %47
+         %51 = OpLoad %uint %i
+         %53 = OpAccessChain %_ptr_Function_Inner_std140 %var_for_index_1 %51
+         %54 = OpLoad %Inner_std140 %53
+         %50 = OpFunctionCall %Inner %conv_Inner %54
+               OpStore %49 %50
+               OpBranch %36
+         %36 = OpLabel
+         %55 = OpLoad %uint %i
+         %57 = OpIAdd %uint %55 %uint_1
+               OpStore %i %57
+               OpBranch %34
+         %35 = OpLabel
+         %58 = OpLoad %_arr_Inner_uint_4 %arr
+               OpReturnValue %58
+               OpFunctionEnd
+ %conv_Outer = OpFunction %Outer None %59
+      %val_1 = OpFunctionParameter %Outer_std140
+         %63 = OpLabel
+         %65 = OpCompositeExtract %_arr_Inner_std140_uint_4 %val_1 0
+         %64 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %65
+         %66 = OpCompositeConstruct %Outer %64
+               OpReturnValue %66
+               OpFunctionEnd
+%conv_arr4_Outer = OpFunction %_arr_Outer_uint_4 None %67
+      %val_2 = OpFunctionParameter %_arr_Outer_std140_uint_4
+         %71 = OpLabel
+      %arr_0 = OpVariable %_ptr_Function__arr_Outer_uint_4 Function %74
+        %i_0 = OpVariable %_ptr_Function_uint Function %33
+%var_for_index = OpVariable %_ptr_Function__arr_Outer_std140_uint_4 Function %87
+               OpBranch %76
+         %76 = OpLabel
+               OpLoopMerge %77 %78 None
+               OpBranch %79
+         %79 = OpLabel
+         %81 = OpLoad %uint %i_0
+         %82 = OpULessThan %bool %81 %uint_4
+         %80 = OpLogicalNot %bool %82
+               OpSelectionMerge %83 None
+               OpBranchConditional %80 %84 %83
+         %84 = OpLabel
+               OpBranch %77
+         %83 = OpLabel
+               OpStore %var_for_index %val_2
+         %88 = OpLoad %uint %i_0
+         %90 = OpAccessChain %_ptr_Function_Outer %arr_0 %88
+         %92 = OpLoad %uint %i_0
+         %94 = OpAccessChain %_ptr_Function_Outer_std140 %var_for_index %92
+         %95 = OpLoad %Outer_std140 %94
+         %91 = OpFunctionCall %Outer %conv_Outer %95
+               OpStore %90 %91
+               OpBranch %78
+         %78 = OpLabel
+         %96 = OpLoad %uint %i_0
+         %97 = OpIAdd %uint %96 %uint_1
+               OpStore %i_0 %97
+               OpBranch %76
+         %77 = OpLabel
+         %98 = OpLoad %_arr_Outer_uint_4 %arr_0
+               OpReturnValue %98
+               OpFunctionEnd
+%load_a_inner_3_a_2_m = OpFunction %mat3v4half None %99
+        %101 = OpLabel
+        %107 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %uint_3 %uint_0 %uint_2
+        %110 = OpAccessChain %_ptr_Uniform_v4half %107 %uint_0
+        %111 = OpLoad %v4half %110
+        %113 = OpAccessChain %_ptr_Uniform_v4half %107 %uint_1
+        %114 = OpLoad %v4half %113
+        %116 = OpAccessChain %_ptr_Uniform_v4half %107 %uint_2
+        %117 = OpLoad %v4half %116
+        %118 = OpCompositeConstruct %mat3v4half %111 %114 %117
+               OpReturnValue %118
+               OpFunctionEnd
+          %f = OpFunction %void None %119
+        %122 = OpLabel
+        %125 = OpAccessChain %_ptr_Uniform__arr_Outer_std140_uint_4 %a %uint_0
+        %126 = OpLoad %_arr_Outer_std140_uint_4 %125
+        %123 = OpFunctionCall %_arr_Outer_uint_4 %conv_arr4_Outer %126
+        %129 = OpAccessChain %_ptr_Uniform_Outer_std140 %a %uint_0 %uint_3
+        %130 = OpLoad %Outer_std140 %129
+        %127 = OpFunctionCall %Outer %conv_Outer %130
+        %133 = OpAccessChain %_ptr_Uniform__arr_Inner_std140_uint_4 %a %uint_0 %uint_3 %uint_0
+        %134 = OpLoad %_arr_Inner_std140_uint_4 %133
+        %131 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %134
+        %136 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %uint_3 %uint_0 %uint_2
+        %137 = OpLoad %Inner_std140 %136
+        %135 = OpFunctionCall %Inner %conv_Inner %137
+        %138 = OpFunctionCall %mat3v4half %load_a_inner_3_a_2_m
+        %139 = OpAccessChain %_ptr_Uniform_v4half %a %uint_0 %uint_3 %uint_0 %uint_2 %uint_1
+        %140 = OpLoad %v4half %139
+        %142 = OpAccessChain %_ptr_Uniform_half %a %uint_0 %uint_3 %uint_0 %uint_2 %uint_1 %33
+        %143 = OpLoad %half %142
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/static_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..f22e235
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/static_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,29 @@
+enable f16;
+
+struct Inner {
+  @size(64)
+  m : mat3x4<f16>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_3 = &((*(p_a))[3]);
+  let p_a_3_a = &((*(p_a_3)).a);
+  let p_a_3_a_2 = &((*(p_a_3_a))[2]);
+  let p_a_3_a_2_m = &((*(p_a_3_a_2)).m);
+  let p_a_3_a_2_m_1 = &((*(p_a_3_a_2_m))[1]);
+  let l_a : array<Outer, 4> = *(p_a);
+  let l_a_3 : Outer = *(p_a_3);
+  let l_a_3_a : array<Inner, 4> = *(p_a_3_a);
+  let l_a_3_a_2 : Inner = *(p_a_3_a_2);
+  let l_a_3_a_2_m : mat3x4<f16> = *(p_a_3_a_2_m);
+  let l_a_3_a_2_m_1 : vec4<f16> = *(p_a_3_a_2_m_1);
+  let l_a_3_a_2_m_1_0 : f16 = (*(p_a_3_a_2_m_1))[0];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_builtin.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_builtin.wgsl
new file mode 100644
index 0000000..8888b64
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_builtin.wgsl
@@ -0,0 +1,17 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat3x4<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    let t = transpose(u[2].m);
+    let l = length(u[0].m[1].ywxz);
+    let a = abs(u[0].m[1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_builtin.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..b0b62a9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_builtin.wgsl.expected.dxc.hlsl
@@ -0,0 +1,36 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+matrix<float16_t, 3, 4> tint_symbol(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  return matrix<float16_t, 3, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 4, 3> t = transpose(tint_symbol(u, 264u));
+  uint2 ubo_load_6 = u[1].xy;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  const float16_t l = length(vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]).ywxz);
+  uint2 ubo_load_7 = u[1].xy;
+  vector<float16_t, 2> ubo_load_7_xz = vector<float16_t, 2>(f16tof32(ubo_load_7 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_7_yw = vector<float16_t, 2>(f16tof32(ubo_load_7 >> 16));
+  const float16_t a = abs(vector<float16_t, 4>(ubo_load_7_xz[0], ubo_load_7_yw[0], ubo_load_7_xz[1], ubo_load_7_yw[1]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_builtin.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..2568b7a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_builtin.wgsl.expected.fxc.hlsl
@@ -0,0 +1,41 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+matrix<float16_t, 3, 4> tint_symbol(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  return matrix<float16_t, 3, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 4, 3> t = transpose(tint_symbol(u, 264u));
+  uint2 ubo_load_6 = u[1].xy;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  const float16_t l = length(vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]).ywxz);
+  uint2 ubo_load_7 = u[1].xy;
+  vector<float16_t, 2> ubo_load_7_xz = vector<float16_t, 2>(f16tof32(ubo_load_7 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_7_yw = vector<float16_t, 2>(f16tof32(ubo_load_7 >> 16));
+  const float16_t a = abs(vector<float16_t, 4>(ubo_load_7_xz[0], ubo_load_7_yw[0], ubo_load_7_xz[1], ubo_load_7_yw[1]).ywxz.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000002683960F9A0(5,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_builtin.wgsl.expected.glsl
new file mode 100644
index 0000000..afb0d15
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_builtin.wgsl.expected.glsl
@@ -0,0 +1,84 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct S {
+  int before;
+  uint pad;
+  f16mat3x4 m;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  int after;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+};
+
+struct S_std140 {
+  int before;
+  uint pad;
+  f16vec4 m_0;
+  f16vec4 m_1;
+  f16vec4 m_2;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  int after;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+f16mat3x4 load_u_inner_2_m() {
+  return f16mat3x4(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2);
+}
+
+void f() {
+  f16mat4x3 t = transpose(load_u_inner_2_m());
+  float16_t l = length(u.inner[0u].m_1.ywxz);
+  float16_t a = abs(u.inner[0u].m_1.ywxz[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_builtin.wgsl.expected.msl
new file mode 100644
index 0000000..0c0b9e8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_builtin.wgsl.expected.msl
@@ -0,0 +1,32 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0008 */ half3x4 m;
+  /* 0x0020 */ tint_array<int8_t, 32> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol [[buffer(0)]]) {
+  half4x3 const t = transpose((*(tint_symbol))[2].m);
+  half const l = length(half4((*(tint_symbol))[0].m[1]).ywxz);
+  half const a = fabs(half4((*(tint_symbol))[0].m[1]).ywxz[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_builtin.wgsl.expected.spvasm
new file mode 100644
index 0000000..1d01a7c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_builtin.wgsl.expected.spvasm
@@ -0,0 +1,86 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 52
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+         %42 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "m_2"
+               OpMemberName %S_std140 4 "after"
+               OpName %u "u"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 8
+               OpMemberDecorate %S_std140 2 Offset 16
+               OpMemberDecorate %S_std140 3 Offset 24
+               OpMemberDecorate %S_std140 4 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+   %S_std140 = OpTypeStruct %int %v4half %v4half %v4half %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat3v4half = OpTypeMatrix %v4half 3
+         %11 = OpTypeFunction %mat3v4half
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+     %uint_1 = OpConstant %uint 1
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %33 = OpTypeFunction %void
+     %v3half = OpTypeVector %half 3
+ %mat4v3half = OpTypeMatrix %v3half 4
+         %43 = OpConstantNull %uint
+%load_u_inner_2_m = OpFunction %mat3v4half None %11
+         %14 = OpLabel
+         %19 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %23 = OpAccessChain %_ptr_Uniform_v4half %19 %uint_1
+         %24 = OpLoad %v4half %23
+         %26 = OpAccessChain %_ptr_Uniform_v4half %19 %uint_2
+         %27 = OpLoad %v4half %26
+         %30 = OpAccessChain %_ptr_Uniform_v4half %19 %uint_3
+         %31 = OpLoad %v4half %30
+         %32 = OpCompositeConstruct %mat3v4half %24 %27 %31
+               OpReturnValue %32
+               OpFunctionEnd
+          %f = OpFunction %void None %33
+         %36 = OpLabel
+         %40 = OpFunctionCall %mat3v4half %load_u_inner_2_m
+         %37 = OpTranspose %mat4v3half %40
+         %44 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0 %43 %uint_2
+         %45 = OpLoad %v4half %44
+         %46 = OpVectorShuffle %v4half %45 %45 1 3 0 2
+         %41 = OpExtInst %half %42 Length %46
+         %48 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0 %43 %uint_2
+         %49 = OpLoad %v4half %48
+         %50 = OpVectorShuffle %v4half %49 %49 1 3 0 2
+         %51 = OpCompositeExtract %half %50 0
+         %47 = OpExtInst %half %42 FAbs %51
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_builtin.wgsl.expected.wgsl
new file mode 100644
index 0000000..c598c75
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_builtin.wgsl.expected.wgsl
@@ -0,0 +1,17 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat3x4<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let t = transpose(u[2].m);
+  let l = length(u[0].m[1].ywxz);
+  let a = abs(u[0].m[1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_fn.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_fn.wgsl
new file mode 100644
index 0000000..3161686
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_fn.wgsl
@@ -0,0 +1,25 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat3x4<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+fn a(a : array<S, 4>) {}
+fn b(s : S) {}
+fn c(m : mat3x4<f16>) {}
+fn d(v : vec4<f16>) {}
+fn e(f : f16) {}
+
+@compute @workgroup_size(1)
+fn f() {
+    a(u);
+    b(u[2]);
+    c(u[2].m);
+    d(u[0].m[1].ywxz);
+    e(u[0].m[1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_fn.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..a190fc0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_fn.wgsl.expected.dxc.hlsl
@@ -0,0 +1,77 @@
+struct S {
+  int before;
+  matrix<float16_t, 3, 4> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(matrix<float16_t, 3, 4> m) {
+}
+
+void d(vector<float16_t, 4> v) {
+}
+
+void e(float16_t f_1) {
+}
+
+matrix<float16_t, 3, 4> tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  return matrix<float16_t, 3, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 256u));
+  c(tint_symbol_3(u, 264u));
+  uint2 ubo_load_6 = u[1].xy;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  d(vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]).ywxz);
+  uint2 ubo_load_7 = u[1].xy;
+  vector<float16_t, 2> ubo_load_7_xz = vector<float16_t, 2>(f16tof32(ubo_load_7 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_7_yw = vector<float16_t, 2>(f16tof32(ubo_load_7 >> 16));
+  e(vector<float16_t, 4>(ubo_load_7_xz[0], ubo_load_7_yw[0], ubo_load_7_xz[1], ubo_load_7_yw[1]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_fn.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..21d911e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_fn.wgsl.expected.fxc.hlsl
@@ -0,0 +1,82 @@
+SKIP: FAILED
+
+struct S {
+  int before;
+  matrix<float16_t, 3, 4> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(matrix<float16_t, 3, 4> m) {
+}
+
+void d(vector<float16_t, 4> v) {
+}
+
+void e(float16_t f_1) {
+}
+
+matrix<float16_t, 3, 4> tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  return matrix<float16_t, 3, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 256u));
+  c(tint_symbol_3(u, 264u));
+  uint2 ubo_load_6 = u[1].xy;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  d(vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]).ywxz);
+  uint2 ubo_load_7 = u[1].xy;
+  vector<float16_t, 2> ubo_load_7_xz = vector<float16_t, 2>(f16tof32(ubo_load_7 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_7_yw = vector<float16_t, 2>(f16tof32(ubo_load_7 >> 16));
+  e(vector<float16_t, 4>(ubo_load_7_xz[0], ubo_load_7_yw[0], ubo_load_7_xz[1], ubo_load_7_yw[1]).ywxz.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x00000278FC792580(3,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_fn.wgsl.expected.glsl
new file mode 100644
index 0000000..d66d7ae
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_fn.wgsl.expected.glsl
@@ -0,0 +1,115 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct S {
+  int before;
+  uint pad;
+  f16mat3x4 m;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  int after;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+};
+
+struct S_std140 {
+  int before;
+  uint pad;
+  f16vec4 m_0;
+  f16vec4 m_1;
+  f16vec4 m_2;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  int after;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(f16mat3x4 m) {
+}
+
+void d(f16vec4 v) {
+}
+
+void e(float16_t f_1) {
+}
+
+S conv_S(S_std140 val) {
+  return S(val.before, val.pad, f16mat3x4(val.m_0, val.m_1, val.m_2), val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.after, val.pad_9, val.pad_10, val.pad_11, val.pad_12, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21, val.pad_22, val.pad_23);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, 0u, f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat3x4 load_u_inner_2_m() {
+  return f16mat3x4(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2);
+}
+
+void f() {
+  a(conv_arr4_S(u.inner));
+  b(conv_S(u.inner[2u]));
+  c(load_u_inner_2_m());
+  d(u.inner[0u].m_1.ywxz);
+  e(u.inner[0u].m_1.ywxz[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_fn.wgsl.expected.msl
new file mode 100644
index 0000000..abf6c24
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_fn.wgsl.expected.msl
@@ -0,0 +1,49 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0008 */ half3x4 m;
+  /* 0x0020 */ tint_array<int8_t, 32> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+void a(tint_array<S, 4> a_1) {
+}
+
+void b(S s) {
+}
+
+void c(half3x4 m) {
+}
+
+void d(half4 v) {
+}
+
+void e(half f_1) {
+}
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol [[buffer(0)]]) {
+  a(*(tint_symbol));
+  b((*(tint_symbol))[2]);
+  c((*(tint_symbol))[2].m);
+  d(half4((*(tint_symbol))[0].m[1]).ywxz);
+  e(half4((*(tint_symbol))[0].m[1]).ywxz[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_fn.wgsl.expected.spvasm
new file mode 100644
index 0000000..296c26c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_fn.wgsl.expected.spvasm
@@ -0,0 +1,210 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 124
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "m_2"
+               OpMemberName %S_std140 4 "after"
+               OpName %u "u"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %a "a"
+               OpName %a_1 "a_1"
+               OpName %b "b"
+               OpName %s "s"
+               OpName %c "c"
+               OpName %m "m"
+               OpName %d "d"
+               OpName %v "v"
+               OpName %e "e"
+               OpName %f_1 "f_1"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 8
+               OpMemberDecorate %S_std140 2 Offset 16
+               OpMemberDecorate %S_std140 3 Offset 24
+               OpMemberDecorate %S_std140 4 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 8
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 8
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+   %S_std140 = OpTypeStruct %int %v4half %v4half %v4half %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+       %void = OpTypeVoid
+ %mat3v4half = OpTypeMatrix %v4half 3
+          %S = OpTypeStruct %int %mat3v4half %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+         %11 = OpTypeFunction %void %_arr_S_uint_4
+         %19 = OpTypeFunction %void %S
+         %23 = OpTypeFunction %void %mat3v4half
+         %27 = OpTypeFunction %void %v4half
+         %31 = OpTypeFunction %void %half
+         %35 = OpTypeFunction %S %S_std140
+         %46 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+         %52 = OpConstantNull %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %55 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %68 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %81 = OpTypeFunction %mat3v4half
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+     %uint_3 = OpConstant %uint 3
+        %101 = OpTypeFunction %void
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+          %a = OpFunction %void None %11
+        %a_1 = OpFunctionParameter %_arr_S_uint_4
+         %18 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %b = OpFunction %void None %19
+          %s = OpFunctionParameter %S
+         %22 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %c = OpFunction %void None %23
+          %m = OpFunctionParameter %mat3v4half
+         %26 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %d = OpFunction %void None %27
+          %v = OpFunctionParameter %v4half
+         %30 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %e = OpFunction %void None %31
+        %f_1 = OpFunctionParameter %half
+         %34 = OpLabel
+               OpReturn
+               OpFunctionEnd
+     %conv_S = OpFunction %S None %35
+        %val = OpFunctionParameter %S_std140
+         %38 = OpLabel
+         %39 = OpCompositeExtract %int %val 0
+         %40 = OpCompositeExtract %v4half %val 1
+         %41 = OpCompositeExtract %v4half %val 2
+         %42 = OpCompositeExtract %v4half %val 3
+         %43 = OpCompositeConstruct %mat3v4half %40 %41 %42
+         %44 = OpCompositeExtract %int %val 4
+         %45 = OpCompositeConstruct %S %39 %43 %44
+               OpReturnValue %45
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %46
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %49 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %52
+          %i = OpVariable %_ptr_Function_uint Function %55
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %68
+               OpBranch %56
+         %56 = OpLabel
+               OpLoopMerge %57 %58 None
+               OpBranch %59
+         %59 = OpLabel
+         %61 = OpLoad %uint %i
+         %62 = OpULessThan %bool %61 %uint_4
+         %60 = OpLogicalNot %bool %62
+               OpSelectionMerge %64 None
+               OpBranchConditional %60 %65 %64
+         %65 = OpLabel
+               OpBranch %57
+         %64 = OpLabel
+               OpStore %var_for_index %val_0
+         %69 = OpLoad %uint %i
+         %71 = OpAccessChain %_ptr_Function_S %arr %69
+         %73 = OpLoad %uint %i
+         %75 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %73
+         %76 = OpLoad %S_std140 %75
+         %72 = OpFunctionCall %S %conv_S %76
+               OpStore %71 %72
+               OpBranch %58
+         %58 = OpLabel
+         %77 = OpLoad %uint %i
+         %79 = OpIAdd %uint %77 %uint_1
+               OpStore %i %79
+               OpBranch %56
+         %57 = OpLabel
+         %80 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %80
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat3v4half None %81
+         %83 = OpLabel
+         %88 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %91 = OpAccessChain %_ptr_Uniform_v4half %88 %uint_1
+         %92 = OpLoad %v4half %91
+         %94 = OpAccessChain %_ptr_Uniform_v4half %88 %uint_2
+         %95 = OpLoad %v4half %94
+         %98 = OpAccessChain %_ptr_Uniform_v4half %88 %uint_3
+         %99 = OpLoad %v4half %98
+        %100 = OpCompositeConstruct %mat3v4half %92 %95 %99
+               OpReturnValue %100
+               OpFunctionEnd
+          %f = OpFunction %void None %101
+        %103 = OpLabel
+        %107 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+        %108 = OpLoad %_arr_S_std140_uint_4 %107
+        %105 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %108
+        %104 = OpFunctionCall %void %a %105
+        %111 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+        %112 = OpLoad %S_std140 %111
+        %110 = OpFunctionCall %S %conv_S %112
+        %109 = OpFunctionCall %void %b %110
+        %114 = OpFunctionCall %mat3v4half %load_u_inner_2_m
+        %113 = OpFunctionCall %void %c %114
+        %116 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0 %55 %uint_2
+        %117 = OpLoad %v4half %116
+        %118 = OpVectorShuffle %v4half %117 %117 1 3 0 2
+        %115 = OpFunctionCall %void %d %118
+        %120 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0 %55 %uint_2
+        %121 = OpLoad %v4half %120
+        %122 = OpVectorShuffle %v4half %121 %121 1 3 0 2
+        %123 = OpCompositeExtract %half %122 0
+        %119 = OpFunctionCall %void %e %123
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_fn.wgsl.expected.wgsl
new file mode 100644
index 0000000..431ed93
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_fn.wgsl.expected.wgsl
@@ -0,0 +1,34 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat3x4<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+fn a(a : array<S, 4>) {
+}
+
+fn b(s : S) {
+}
+
+fn c(m : mat3x4<f16>) {
+}
+
+fn d(v : vec4<f16>) {
+}
+
+fn e(f : f16) {
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  a(u);
+  b(u[2]);
+  c(u[2].m);
+  d(u[0].m[1].ywxz);
+  e(u[0].m[1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_private.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_private.wgsl
new file mode 100644
index 0000000..d857256
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_private.wgsl
@@ -0,0 +1,19 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat3x4<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+var<private> p : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[2];
+    p[3].m = u[2].m;
+    p[1].m[0] = u[0].m[1].ywxz;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_private.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..60c2c7a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_private.wgsl.expected.dxc.hlsl
@@ -0,0 +1,59 @@
+struct S {
+  int before;
+  matrix<float16_t, 3, 4> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+static S p[4] = (S[4])0;
+
+matrix<float16_t, 3, 4> tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  return matrix<float16_t, 3, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 256u);
+  p[3].m = tint_symbol_3(u, 264u);
+  uint2 ubo_load_6 = u[1].xy;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  p[1].m[0] = vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]).ywxz;
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_private.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..5da97a8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_private.wgsl.expected.fxc.hlsl
@@ -0,0 +1,64 @@
+SKIP: FAILED
+
+struct S {
+  int before;
+  matrix<float16_t, 3, 4> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+static S p[4] = (S[4])0;
+
+matrix<float16_t, 3, 4> tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  return matrix<float16_t, 3, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 256u);
+  p[3].m = tint_symbol_3(u, 264u);
+  uint2 ubo_load_6 = u[1].xy;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  p[1].m[0] = vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]).ywxz;
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000002605021E560(3,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..3d4a68d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_private.wgsl.expected.glsl
@@ -0,0 +1,100 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct S {
+  int before;
+  uint pad;
+  f16mat3x4 m;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  int after;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+};
+
+struct S_std140 {
+  int before;
+  uint pad;
+  f16vec4 m_0;
+  f16vec4 m_1;
+  f16vec4 m_2;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  int after;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+S p[4] = S[4](S(0, 0u, f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+S conv_S(S_std140 val) {
+  return S(val.before, val.pad, f16mat3x4(val.m_0, val.m_1, val.m_2), val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.after, val.pad_9, val.pad_10, val.pad_11, val.pad_12, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21, val.pad_22, val.pad_23);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, 0u, f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat3x4 load_u_inner_2_m() {
+  return f16mat3x4(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2);
+}
+
+void f() {
+  p = conv_arr4_S(u.inner);
+  p[1] = conv_S(u.inner[2u]);
+  p[3].m = load_u_inner_2_m();
+  p[1].m[0] = u.inner[0u].m_1.ywxz;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..23983c5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_private.wgsl.expected.msl
@@ -0,0 +1,34 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0008 */ half3x4 m;
+  /* 0x0020 */ tint_array<int8_t, 32> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol_1 [[buffer(0)]]) {
+  thread tint_array<S, 4> tint_symbol = {};
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[2];
+  tint_symbol[3].m = (*(tint_symbol_1))[2].m;
+  tint_symbol[1].m[0] = half4((*(tint_symbol_1))[0].m[1]).ywxz;
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_private.wgsl.expected.spvasm
new file mode 100644
index 0000000..dbb4838
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_private.wgsl.expected.spvasm
@@ -0,0 +1,177 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 106
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "m_2"
+               OpMemberName %S_std140 4 "after"
+               OpName %u "u"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %p "p"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 8
+               OpMemberDecorate %S_std140 2 Offset 16
+               OpMemberDecorate %S_std140 3 Offset 24
+               OpMemberDecorate %S_std140 4 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 8
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 8
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+   %S_std140 = OpTypeStruct %int %v4half %v4half %v4half %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat3v4half = OpTypeMatrix %v4half 3
+          %S = OpTypeStruct %int %mat3v4half %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+%_ptr_Private__arr_S_uint_4 = OpTypePointer Private %_arr_S_uint_4
+         %16 = OpConstantNull %_arr_S_uint_4
+          %p = OpVariable %_ptr_Private__arr_S_uint_4 Private %16
+         %17 = OpTypeFunction %S %S_std140
+         %28 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %36 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %49 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %62 = OpTypeFunction %mat3v4half
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %82 = OpTypeFunction %void
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+      %int_1 = OpConstant %int 1
+%_ptr_Private_S = OpTypePointer Private %S
+      %int_3 = OpConstant %int 3
+%_ptr_Private_mat3v4half = OpTypePointer Private %mat3v4half
+        %100 = OpConstantNull %int
+%_ptr_Private_v4half = OpTypePointer Private %v4half
+     %conv_S = OpFunction %S None %17
+        %val = OpFunctionParameter %S_std140
+         %20 = OpLabel
+         %21 = OpCompositeExtract %int %val 0
+         %22 = OpCompositeExtract %v4half %val 1
+         %23 = OpCompositeExtract %v4half %val 2
+         %24 = OpCompositeExtract %v4half %val 3
+         %25 = OpCompositeConstruct %mat3v4half %22 %23 %24
+         %26 = OpCompositeExtract %int %val 4
+         %27 = OpCompositeConstruct %S %21 %25 %26
+               OpReturnValue %27
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %28
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %31 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %16
+          %i = OpVariable %_ptr_Function_uint Function %36
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %49
+               OpBranch %37
+         %37 = OpLabel
+               OpLoopMerge %38 %39 None
+               OpBranch %40
+         %40 = OpLabel
+         %42 = OpLoad %uint %i
+         %43 = OpULessThan %bool %42 %uint_4
+         %41 = OpLogicalNot %bool %43
+               OpSelectionMerge %45 None
+               OpBranchConditional %41 %46 %45
+         %46 = OpLabel
+               OpBranch %38
+         %45 = OpLabel
+               OpStore %var_for_index %val_0
+         %50 = OpLoad %uint %i
+         %52 = OpAccessChain %_ptr_Function_S %arr %50
+         %54 = OpLoad %uint %i
+         %56 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %54
+         %57 = OpLoad %S_std140 %56
+         %53 = OpFunctionCall %S %conv_S %57
+               OpStore %52 %53
+               OpBranch %39
+         %39 = OpLabel
+         %58 = OpLoad %uint %i
+         %60 = OpIAdd %uint %58 %uint_1
+               OpStore %i %60
+               OpBranch %37
+         %38 = OpLabel
+         %61 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %61
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat3v4half None %62
+         %64 = OpLabel
+         %69 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %72 = OpAccessChain %_ptr_Uniform_v4half %69 %uint_1
+         %73 = OpLoad %v4half %72
+         %75 = OpAccessChain %_ptr_Uniform_v4half %69 %uint_2
+         %76 = OpLoad %v4half %75
+         %79 = OpAccessChain %_ptr_Uniform_v4half %69 %uint_3
+         %80 = OpLoad %v4half %79
+         %81 = OpCompositeConstruct %mat3v4half %73 %76 %80
+               OpReturnValue %81
+               OpFunctionEnd
+          %f = OpFunction %void None %82
+         %85 = OpLabel
+         %88 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+         %89 = OpLoad %_arr_S_std140_uint_4 %88
+         %86 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %89
+               OpStore %p %86
+         %92 = OpAccessChain %_ptr_Private_S %p %int_1
+         %94 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %95 = OpLoad %S_std140 %94
+         %93 = OpFunctionCall %S %conv_S %95
+               OpStore %92 %93
+         %98 = OpAccessChain %_ptr_Private_mat3v4half %p %int_3 %uint_1
+         %99 = OpFunctionCall %mat3v4half %load_u_inner_2_m
+               OpStore %98 %99
+        %102 = OpAccessChain %_ptr_Private_v4half %p %int_1 %uint_1 %100
+        %103 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0 %36 %uint_2
+        %104 = OpLoad %v4half %103
+        %105 = OpVectorShuffle %v4half %104 %104 1 3 0 2
+               OpStore %102 %105
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..e8ef5f7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_private.wgsl.expected.wgsl
@@ -0,0 +1,20 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat3x4<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+var<private> p : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[2];
+  p[3].m = u[2].m;
+  p[1].m[0] = u[0].m[1].ywxz;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_storage.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_storage.wgsl
new file mode 100644
index 0000000..ab3c08c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_storage.wgsl
@@ -0,0 +1,19 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat3x4<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+@group(0) @binding(1) var<storage, read_write> s : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[2];
+    s[3].m = u[2].m;
+    s[1].m[0] = u[0].m[1].ywxz;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_storage.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..c236690
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_storage.wgsl.expected.dxc.hlsl
@@ -0,0 +1,80 @@
+struct S {
+  int before;
+  matrix<float16_t, 3, 4> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_3(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 3, 4> value) {
+  buffer.Store<vector<float16_t, 4> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 8u), value[1u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 16u), value[2u]);
+}
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, S value) {
+  buffer.Store((offset + 0u), asuint(value.before));
+  tint_symbol_3(buffer, (offset + 8u), value.m);
+  buffer.Store((offset + 64u), asuint(value.after));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, S value[4]) {
+  S array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 128u)), array[i]);
+    }
+  }
+}
+
+matrix<float16_t, 3, 4> tint_symbol_8(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  return matrix<float16_t, 3, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]));
+}
+
+S tint_symbol_6(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_10 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_8(buffer, (offset + 8u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_10;
+}
+
+typedef S tint_symbol_5_ret[4];
+tint_symbol_5_ret tint_symbol_5(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_6(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_5(u, 0u));
+  tint_symbol_1(s, 128u, tint_symbol_6(u, 256u));
+  tint_symbol_3(s, 392u, tint_symbol_8(u, 264u));
+  uint2 ubo_load_6 = u[1].xy;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  s.Store<vector<float16_t, 4> >(136u, vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]).ywxz);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_storage.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..49f88f1
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_storage.wgsl.expected.fxc.hlsl
@@ -0,0 +1,85 @@
+SKIP: FAILED
+
+struct S {
+  int before;
+  matrix<float16_t, 3, 4> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_3(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 3, 4> value) {
+  buffer.Store<vector<float16_t, 4> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 8u), value[1u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 16u), value[2u]);
+}
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, S value) {
+  buffer.Store((offset + 0u), asuint(value.before));
+  tint_symbol_3(buffer, (offset + 8u), value.m);
+  buffer.Store((offset + 64u), asuint(value.after));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, S value[4]) {
+  S array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 128u)), array[i]);
+    }
+  }
+}
+
+matrix<float16_t, 3, 4> tint_symbol_8(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  return matrix<float16_t, 3, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]));
+}
+
+S tint_symbol_6(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_10 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_8(buffer, (offset + 8u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_10;
+}
+
+typedef S tint_symbol_5_ret[4];
+tint_symbol_5_ret tint_symbol_5(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_6(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_5(u, 0u));
+  tint_symbol_1(s, 128u, tint_symbol_6(u, 256u));
+  tint_symbol_3(s, 392u, tint_symbol_8(u, 264u));
+  uint2 ubo_load_6 = u[1].xy;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  s.Store<vector<float16_t, 4> >(136u, vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]).ywxz);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001FE54B10170(3,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..bd567f0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_storage.wgsl.expected.glsl
@@ -0,0 +1,103 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct S {
+  int before;
+  uint pad;
+  f16mat3x4 m;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  int after;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+};
+
+struct S_std140 {
+  int before;
+  uint pad;
+  f16vec4 m_0;
+  f16vec4 m_1;
+  f16vec4 m_2;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  int after;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  S inner[4];
+} s;
+
+S conv_S(S_std140 val) {
+  return S(val.before, val.pad, f16mat3x4(val.m_0, val.m_1, val.m_2), val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.after, val.pad_9, val.pad_10, val.pad_11, val.pad_12, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21, val.pad_22, val.pad_23);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, 0u, f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat3x4 load_u_inner_2_m() {
+  return f16mat3x4(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2);
+}
+
+void f() {
+  s.inner = conv_arr4_S(u.inner);
+  s.inner[1] = conv_S(u.inner[2u]);
+  s.inner[3].m = load_u_inner_2_m();
+  s.inner[1].m[0] = u.inner[0u].m_1.ywxz;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..519bfae
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_storage.wgsl.expected.msl
@@ -0,0 +1,33 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0008 */ half3x4 m;
+  /* 0x0020 */ tint_array<int8_t, 32> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+kernel void f(device tint_array<S, 4>* tint_symbol [[buffer(1)]], const constant tint_array<S, 4>* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
+  (*(tint_symbol))[3].m = (*(tint_symbol_1))[2].m;
+  (*(tint_symbol))[1].m[0] = half4((*(tint_symbol_1))[0].m[1]).ywxz;
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_storage.wgsl.expected.spvasm
new file mode 100644
index 0000000..7b96c19
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_storage.wgsl.expected.spvasm
@@ -0,0 +1,186 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 109
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "m_2"
+               OpMemberName %S_std140 4 "after"
+               OpName %u "u"
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %s "s"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 8
+               OpMemberDecorate %S_std140 2 Offset 16
+               OpMemberDecorate %S_std140 3 Offset 24
+               OpMemberDecorate %S_std140 4 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 8
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 8
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+               OpDecorate %s DescriptorSet 0
+               OpDecorate %s Binding 1
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+   %S_std140 = OpTypeStruct %int %v4half %v4half %v4half %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat3v4half = OpTypeMatrix %v4half 3
+          %S = OpTypeStruct %int %mat3v4half %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+    %u_block = OpTypeStruct %_arr_S_uint_4
+%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
+          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+         %17 = OpTypeFunction %S %S_std140
+         %28 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+         %34 = OpConstantNull %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %37 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %50 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %63 = OpTypeFunction %mat3v4half
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %83 = OpTypeFunction %void
+%_ptr_StorageBuffer__arr_S_uint_4 = OpTypePointer StorageBuffer %_arr_S_uint_4
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+      %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
+      %int_3 = OpConstant %int 3
+%_ptr_StorageBuffer_mat3v4half = OpTypePointer StorageBuffer %mat3v4half
+        %103 = OpConstantNull %int
+%_ptr_StorageBuffer_v4half = OpTypePointer StorageBuffer %v4half
+     %conv_S = OpFunction %S None %17
+        %val = OpFunctionParameter %S_std140
+         %20 = OpLabel
+         %21 = OpCompositeExtract %int %val 0
+         %22 = OpCompositeExtract %v4half %val 1
+         %23 = OpCompositeExtract %v4half %val 2
+         %24 = OpCompositeExtract %v4half %val 3
+         %25 = OpCompositeConstruct %mat3v4half %22 %23 %24
+         %26 = OpCompositeExtract %int %val 4
+         %27 = OpCompositeConstruct %S %21 %25 %26
+               OpReturnValue %27
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %28
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %31 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %34
+          %i = OpVariable %_ptr_Function_uint Function %37
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %50
+               OpBranch %38
+         %38 = OpLabel
+               OpLoopMerge %39 %40 None
+               OpBranch %41
+         %41 = OpLabel
+         %43 = OpLoad %uint %i
+         %44 = OpULessThan %bool %43 %uint_4
+         %42 = OpLogicalNot %bool %44
+               OpSelectionMerge %46 None
+               OpBranchConditional %42 %47 %46
+         %47 = OpLabel
+               OpBranch %39
+         %46 = OpLabel
+               OpStore %var_for_index %val_0
+         %51 = OpLoad %uint %i
+         %53 = OpAccessChain %_ptr_Function_S %arr %51
+         %55 = OpLoad %uint %i
+         %57 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %55
+         %58 = OpLoad %S_std140 %57
+         %54 = OpFunctionCall %S %conv_S %58
+               OpStore %53 %54
+               OpBranch %40
+         %40 = OpLabel
+         %59 = OpLoad %uint %i
+         %61 = OpIAdd %uint %59 %uint_1
+               OpStore %i %61
+               OpBranch %38
+         %39 = OpLabel
+         %62 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %62
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat3v4half None %63
+         %65 = OpLabel
+         %70 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %73 = OpAccessChain %_ptr_Uniform_v4half %70 %uint_1
+         %74 = OpLoad %v4half %73
+         %76 = OpAccessChain %_ptr_Uniform_v4half %70 %uint_2
+         %77 = OpLoad %v4half %76
+         %80 = OpAccessChain %_ptr_Uniform_v4half %70 %uint_3
+         %81 = OpLoad %v4half %80
+         %82 = OpCompositeConstruct %mat3v4half %74 %77 %81
+               OpReturnValue %82
+               OpFunctionEnd
+          %f = OpFunction %void None %83
+         %86 = OpLabel
+         %88 = OpAccessChain %_ptr_StorageBuffer__arr_S_uint_4 %s %uint_0
+         %91 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+         %92 = OpLoad %_arr_S_std140_uint_4 %91
+         %89 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %92
+               OpStore %88 %89
+         %95 = OpAccessChain %_ptr_StorageBuffer_S %s %uint_0 %int_1
+         %97 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %98 = OpLoad %S_std140 %97
+         %96 = OpFunctionCall %S %conv_S %98
+               OpStore %95 %96
+        %101 = OpAccessChain %_ptr_StorageBuffer_mat3v4half %s %uint_0 %int_3 %uint_1
+        %102 = OpFunctionCall %mat3v4half %load_u_inner_2_m
+               OpStore %101 %102
+        %105 = OpAccessChain %_ptr_StorageBuffer_v4half %s %uint_0 %int_1 %uint_1 %103
+        %106 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0 %37 %uint_2
+        %107 = OpLoad %v4half %106
+        %108 = OpVectorShuffle %v4half %107 %107 1 3 0 2
+               OpStore %105 %108
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..9e7bab0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,20 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat3x4<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@group(0) @binding(1) var<storage, read_write> s : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[2];
+  s[3].m = u[2].m;
+  s[1].m[0] = u[0].m[1].ywxz;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_workgroup.wgsl
new file mode 100644
index 0000000..94af8f4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_workgroup.wgsl
@@ -0,0 +1,19 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat3x4<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+var<workgroup> w : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[2];
+    w[3].m = u[2].m;
+    w[1].m[0] = u[0].m[1].ywxz;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_workgroup.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..e0f83f8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_workgroup.wgsl.expected.dxc.hlsl
@@ -0,0 +1,75 @@
+struct S {
+  int before;
+  matrix<float16_t, 3, 4> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+groupshared S w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 3, 4> tint_symbol_5(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  return matrix<float16_t, 3, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]));
+}
+
+S tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_8 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_5(buffer, (offset + 8u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_8;
+}
+
+typedef S tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      const S tint_symbol_7 = (S)0;
+      w[i] = tint_symbol_7;
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 256u);
+  w[3].m = tint_symbol_5(u, 264u);
+  uint2 ubo_load_6 = u[1].xy;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  w[1].m[0] = vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]).ywxz;
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_workgroup.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..fc24a1c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_workgroup.wgsl.expected.fxc.hlsl
@@ -0,0 +1,80 @@
+SKIP: FAILED
+
+struct S {
+  int before;
+  matrix<float16_t, 3, 4> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+groupshared S w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 3, 4> tint_symbol_5(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  return matrix<float16_t, 3, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]));
+}
+
+S tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_8 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_5(buffer, (offset + 8u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_8;
+}
+
+typedef S tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      const S tint_symbol_7 = (S)0;
+      w[i] = tint_symbol_7;
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 256u);
+  w[3].m = tint_symbol_5(u, 264u);
+  uint2 ubo_load_6 = u[1].xy;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  w[1].m[0] = vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]).ywxz;
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001FEBFD6AE90(3,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..2e03b1a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,108 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct S {
+  int before;
+  uint pad;
+  f16mat3x4 m;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  int after;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+};
+
+struct S_std140 {
+  int before;
+  uint pad;
+  f16vec4 m_0;
+  f16vec4 m_1;
+  f16vec4 m_2;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  int after;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+shared S w[4];
+S conv_S(S_std140 val) {
+  return S(val.before, val.pad, f16mat3x4(val.m_0, val.m_1, val.m_2), val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.after, val.pad_9, val.pad_10, val.pad_11, val.pad_12, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21, val.pad_22, val.pad_23);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, 0u, f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat3x4 load_u_inner_2_m() {
+  return f16mat3x4(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2);
+}
+
+void f(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      uint i = idx;
+      S tint_symbol = S(0, 0u, f16mat3x4(f16vec4(0.0hf), f16vec4(0.0hf), f16vec4(0.0hf)), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u);
+      w[i] = tint_symbol;
+    }
+  }
+  barrier();
+  w = conv_arr4_S(u.inner);
+  w[1] = conv_S(u.inner[2u]);
+  w[3].m = load_u_inner_2_m();
+  w[1].m[0] = u.inner[0u].m_1.ywxz;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..444e7ca
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,48 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0008 */ half3x4 m;
+  /* 0x0020 */ tint_array<int8_t, 32> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+struct tint_symbol_6 {
+  tint_array<S, 4> w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup tint_array<S, 4>* const tint_symbol_1, const constant tint_array<S, 4>* const tint_symbol_2) {
+  for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+    uint const i = idx;
+    S const tint_symbol = S{};
+    (*(tint_symbol_1))[i] = tint_symbol;
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol_1) = *(tint_symbol_2);
+  (*(tint_symbol_1))[1] = (*(tint_symbol_2))[2];
+  (*(tint_symbol_1))[3].m = (*(tint_symbol_2))[2].m;
+  (*(tint_symbol_1))[1].m[0] = half4((*(tint_symbol_2))[0].m[1]).ywxz;
+}
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol_5 [[buffer(0)]], threadgroup tint_symbol_6* tint_symbol_4 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup tint_array<S, 4>* const tint_symbol_3 = &((*(tint_symbol_4)).w);
+  f_inner(local_invocation_index, tint_symbol_3, tint_symbol_5);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_workgroup.wgsl.expected.spvasm
new file mode 100644
index 0000000..63eb276
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_workgroup.wgsl.expected.spvasm
@@ -0,0 +1,220 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 131
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %local_invocation_index_1 "local_invocation_index_1"
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "m_2"
+               OpMemberName %S_std140 4 "after"
+               OpName %u "u"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %w "w"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f_inner "f_inner"
+               OpName %local_invocation_index "local_invocation_index"
+               OpName %idx "idx"
+               OpName %f "f"
+               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 8
+               OpMemberDecorate %S_std140 2 Offset 16
+               OpMemberDecorate %S_std140 3 Offset 24
+               OpMemberDecorate %S_std140 4 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 8
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 8
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+   %S_std140 = OpTypeStruct %int %v4half %v4half %v4half %int
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat3v4half = OpTypeMatrix %v4half 3
+          %S = OpTypeStruct %int %mat3v4half %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+%_ptr_Workgroup__arr_S_uint_4 = OpTypePointer Workgroup %_arr_S_uint_4
+          %w = OpVariable %_ptr_Workgroup__arr_S_uint_4 Workgroup
+         %18 = OpTypeFunction %S %S_std140
+         %29 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+         %35 = OpConstantNull %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %38 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %51 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %64 = OpTypeFunction %mat3v4half
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %84 = OpTypeFunction %void %uint
+%_ptr_Workgroup_S = OpTypePointer Workgroup %S
+        %102 = OpConstantNull %S
+   %uint_264 = OpConstant %uint 264
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+      %int_1 = OpConstant %int 1
+      %int_3 = OpConstant %int 3
+%_ptr_Workgroup_mat3v4half = OpTypePointer Workgroup %mat3v4half
+        %120 = OpConstantNull %int
+%_ptr_Workgroup_v4half = OpTypePointer Workgroup %v4half
+        %126 = OpTypeFunction %void
+     %conv_S = OpFunction %S None %18
+        %val = OpFunctionParameter %S_std140
+         %21 = OpLabel
+         %22 = OpCompositeExtract %int %val 0
+         %23 = OpCompositeExtract %v4half %val 1
+         %24 = OpCompositeExtract %v4half %val 2
+         %25 = OpCompositeExtract %v4half %val 3
+         %26 = OpCompositeConstruct %mat3v4half %23 %24 %25
+         %27 = OpCompositeExtract %int %val 4
+         %28 = OpCompositeConstruct %S %22 %26 %27
+               OpReturnValue %28
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %29
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %32 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %35
+          %i = OpVariable %_ptr_Function_uint Function %38
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %51
+               OpBranch %39
+         %39 = OpLabel
+               OpLoopMerge %40 %41 None
+               OpBranch %42
+         %42 = OpLabel
+         %44 = OpLoad %uint %i
+         %45 = OpULessThan %bool %44 %uint_4
+         %43 = OpLogicalNot %bool %45
+               OpSelectionMerge %47 None
+               OpBranchConditional %43 %48 %47
+         %48 = OpLabel
+               OpBranch %40
+         %47 = OpLabel
+               OpStore %var_for_index %val_0
+         %52 = OpLoad %uint %i
+         %54 = OpAccessChain %_ptr_Function_S %arr %52
+         %56 = OpLoad %uint %i
+         %58 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %56
+         %59 = OpLoad %S_std140 %58
+         %55 = OpFunctionCall %S %conv_S %59
+               OpStore %54 %55
+               OpBranch %41
+         %41 = OpLabel
+         %60 = OpLoad %uint %i
+         %62 = OpIAdd %uint %60 %uint_1
+               OpStore %i %62
+               OpBranch %39
+         %40 = OpLabel
+         %63 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %63
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat3v4half None %64
+         %66 = OpLabel
+         %71 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %74 = OpAccessChain %_ptr_Uniform_v4half %71 %uint_1
+         %75 = OpLoad %v4half %74
+         %77 = OpAccessChain %_ptr_Uniform_v4half %71 %uint_2
+         %78 = OpLoad %v4half %77
+         %81 = OpAccessChain %_ptr_Uniform_v4half %71 %uint_3
+         %82 = OpLoad %v4half %81
+         %83 = OpCompositeConstruct %mat3v4half %75 %78 %82
+               OpReturnValue %83
+               OpFunctionEnd
+    %f_inner = OpFunction %void None %84
+%local_invocation_index = OpFunctionParameter %uint
+         %88 = OpLabel
+        %idx = OpVariable %_ptr_Function_uint Function %38
+               OpStore %idx %local_invocation_index
+               OpBranch %90
+         %90 = OpLabel
+               OpLoopMerge %91 %92 None
+               OpBranch %93
+         %93 = OpLabel
+         %95 = OpLoad %uint %idx
+         %96 = OpULessThan %bool %95 %uint_4
+         %94 = OpLogicalNot %bool %96
+               OpSelectionMerge %97 None
+               OpBranchConditional %94 %98 %97
+         %98 = OpLabel
+               OpBranch %91
+         %97 = OpLabel
+         %99 = OpLoad %uint %idx
+        %101 = OpAccessChain %_ptr_Workgroup_S %w %99
+               OpStore %101 %102
+               OpBranch %92
+         %92 = OpLabel
+        %103 = OpLoad %uint %idx
+        %104 = OpIAdd %uint %103 %uint_1
+               OpStore %idx %104
+               OpBranch %90
+         %91 = OpLabel
+               OpControlBarrier %uint_2 %uint_2 %uint_264
+        %109 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+        %110 = OpLoad %_arr_S_std140_uint_4 %109
+        %107 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %110
+               OpStore %w %107
+        %112 = OpAccessChain %_ptr_Workgroup_S %w %int_1
+        %114 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+        %115 = OpLoad %S_std140 %114
+        %113 = OpFunctionCall %S %conv_S %115
+               OpStore %112 %113
+        %118 = OpAccessChain %_ptr_Workgroup_mat3v4half %w %int_3 %uint_1
+        %119 = OpFunctionCall %mat3v4half %load_u_inner_2_m
+               OpStore %118 %119
+        %122 = OpAccessChain %_ptr_Workgroup_v4half %w %int_1 %uint_1 %120
+        %123 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0 %38 %uint_2
+        %124 = OpLoad %v4half %123
+        %125 = OpVectorShuffle %v4half %124 %124 1 3 0 2
+               OpStore %122 %125
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %126
+        %128 = OpLabel
+        %130 = OpLoad %uint %local_invocation_index_1
+        %129 = OpFunctionCall %void %f_inner %130
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..cecda57
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f16/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,20 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat3x4<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+var<workgroup> w : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[2];
+  w[3].m = u[2].m;
+  w[1].m[0] = u[0].m[1].ywxz;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/dynamic_index_via_ptr.wgsl
new file mode 100644
index 0000000..252c1e6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/dynamic_index_via_ptr.wgsl
@@ -0,0 +1,32 @@
+struct Inner {
+  @size(64)
+  m : mat3x4<f32>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a           = &a;
+  let p_a_i         = &((*p_a)[i()]);
+  let p_a_i_a       = &((*p_a_i).a);
+  let p_a_i_a_i     = &((*p_a_i_a)[i()]);
+  let p_a_i_a_i_m   = &((*p_a_i_a_i).m);
+  let p_a_i_a_i_m_i = &((*p_a_i_a_i_m)[i()]);
+
+
+  let l_a             : array<Outer, 4> =  *p_a;
+  let l_a_i           : Outer           =  *p_a_i;
+  let l_a_i_a         : array<Inner, 4> =  *p_a_i_a;
+  let l_a_i_a_i       : Inner           =  *p_a_i_a_i;
+  let l_a_i_a_i_m     : mat3x4<f32>     =  *p_a_i_a_i_m;
+  let l_a_i_a_i_m_i   : vec4<f32>       =  *p_a_i_a_i_m_i;
+  let l_a_i_a_i_m_i_i : f32             = (*p_a_i_a_i_m_i)[i()];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..2e5ba64
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,76 @@
+struct Inner {
+  float3x4 m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float3x4 tint_symbol_8(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+}
+
+Inner tint_symbol_7(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_11 = {tint_symbol_8(buffer, (offset + 0u))};
+  return tint_symbol_11;
+}
+
+typedef Inner tint_symbol_6_ret[4];
+tint_symbol_6_ret tint_symbol_6(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_7(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_5(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_12 = {tint_symbol_6(buffer, (offset + 0u))};
+  return tint_symbol_12;
+}
+
+typedef Outer tint_symbol_4_ret[4];
+tint_symbol_4_ret tint_symbol_4(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
+      arr_1[i_2] = tint_symbol_5(buffer, (offset + (i_2 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_a_i_save = i();
+  const int p_a_i_a_i_m_i_save = i();
+  const Outer l_a[4] = tint_symbol_4(a, 0u);
+  const Outer l_a_i = tint_symbol_5(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a[4] = tint_symbol_6(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a_i = tint_symbol_7(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const float3x4 l_a_i_a_i_m = tint_symbol_8(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const uint scalar_offset_3 = ((((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))) + (16u * uint(p_a_i_a_i_m_i_save)))) / 4;
+  const float4 l_a_i_a_i_m_i = asfloat(a[scalar_offset_3 / 4]);
+  const int tint_symbol = p_a_i_save;
+  const int tint_symbol_1 = p_a_i_a_i_save;
+  const int tint_symbol_2 = p_a_i_a_i_m_i_save;
+  const int tint_symbol_3 = i();
+  const uint scalar_offset_4 = (((((256u * uint(tint_symbol)) + (64u * uint(tint_symbol_1))) + (16u * uint(tint_symbol_2))) + (4u * uint(tint_symbol_3)))) / 4;
+  const float l_a_i_a_i_m_i_i = asfloat(a[scalar_offset_4 / 4][scalar_offset_4 % 4]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..2e5ba64
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,76 @@
+struct Inner {
+  float3x4 m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float3x4 tint_symbol_8(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+}
+
+Inner tint_symbol_7(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_11 = {tint_symbol_8(buffer, (offset + 0u))};
+  return tint_symbol_11;
+}
+
+typedef Inner tint_symbol_6_ret[4];
+tint_symbol_6_ret tint_symbol_6(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_7(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_5(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_12 = {tint_symbol_6(buffer, (offset + 0u))};
+  return tint_symbol_12;
+}
+
+typedef Outer tint_symbol_4_ret[4];
+tint_symbol_4_ret tint_symbol_4(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
+      arr_1[i_2] = tint_symbol_5(buffer, (offset + (i_2 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_a_i_save = i();
+  const int p_a_i_a_i_m_i_save = i();
+  const Outer l_a[4] = tint_symbol_4(a, 0u);
+  const Outer l_a_i = tint_symbol_5(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a[4] = tint_symbol_6(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a_i = tint_symbol_7(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const float3x4 l_a_i_a_i_m = tint_symbol_8(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const uint scalar_offset_3 = ((((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))) + (16u * uint(p_a_i_a_i_m_i_save)))) / 4;
+  const float4 l_a_i_a_i_m_i = asfloat(a[scalar_offset_3 / 4]);
+  const int tint_symbol = p_a_i_save;
+  const int tint_symbol_1 = p_a_i_a_i_save;
+  const int tint_symbol_2 = p_a_i_a_i_m_i_save;
+  const int tint_symbol_3 = i();
+  const uint scalar_offset_4 = (((((256u * uint(tint_symbol)) + (64u * uint(tint_symbol_1))) + (16u * uint(tint_symbol_2))) + (4u * uint(tint_symbol_3)))) / 4;
+  const float l_a_i_a_i_m_i_i = asfloat(a[scalar_offset_4 / 4][scalar_offset_4 % 4]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..1b6b32e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,46 @@
+#version 310 es
+
+struct Inner {
+  mat3x4 m;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+};
+
+struct Outer {
+  Inner a[4];
+};
+
+layout(binding = 0, std140) uniform a_block_ubo {
+  Outer inner[4];
+} a;
+
+int counter = 0;
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+void f() {
+  int tint_symbol = i();
+  int p_a_i_save = tint_symbol;
+  int tint_symbol_1 = i();
+  int p_a_i_a_i_save = tint_symbol_1;
+  int tint_symbol_2 = i();
+  int p_a_i_a_i_m_i_save = tint_symbol_2;
+  Outer l_a[4] = a.inner;
+  Outer l_a_i = a.inner[p_a_i_save];
+  Inner l_a_i_a[4] = a.inner[p_a_i_save].a;
+  Inner l_a_i_a_i = a.inner[p_a_i_save].a[p_a_i_a_i_save];
+  mat3x4 l_a_i_a_i_m = a.inner[p_a_i_save].a[p_a_i_a_i_save].m;
+  vec4 l_a_i_a_i_m_i = a.inner[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save];
+  int tint_symbol_3 = i();
+  float l_a_i_a_i_m_i_i = a.inner[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save][tint_symbol_3];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..c277984
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,49 @@
+#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 Inner {
+  /* 0x0000 */ float3x4 m;
+  /* 0x0030 */ tint_array<int8_t, 16> tint_pad;
+};
+
+struct Outer {
+  /* 0x0000 */ tint_array<Inner, 4> a;
+};
+
+int i() {
+  thread int tint_symbol_4 = 0;
+  tint_symbol_4 = as_type<int>((as_type<uint>(tint_symbol_4) + as_type<uint>(1)));
+  return tint_symbol_4;
+}
+
+kernel void f(const constant tint_array<Outer, 4>* tint_symbol_5 [[buffer(0)]]) {
+  int const tint_symbol = i();
+  int const p_a_i_save = tint_symbol;
+  int const tint_symbol_1 = i();
+  int const p_a_i_a_i_save = tint_symbol_1;
+  int const tint_symbol_2 = i();
+  int const p_a_i_a_i_m_i_save = tint_symbol_2;
+  tint_array<Outer, 4> const l_a = *(tint_symbol_5);
+  Outer const l_a_i = (*(tint_symbol_5))[p_a_i_save];
+  tint_array<Inner, 4> const l_a_i_a = (*(tint_symbol_5))[p_a_i_save].a;
+  Inner const l_a_i_a_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save];
+  float3x4 const l_a_i_a_i_m = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m;
+  float4 const l_a_i_a_i_m_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save];
+  int const tint_symbol_3 = i();
+  float const l_a_i_a_i_m_i_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save][tint_symbol_3];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..6342891
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,88 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 54
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block "a_block"
+               OpMemberName %a_block 0 "inner"
+               OpName %Outer "Outer"
+               OpMemberName %Outer 0 "a"
+               OpName %Inner "Inner"
+               OpMemberName %Inner 0 "m"
+               OpName %a "a"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %f "f"
+               OpDecorate %a_block Block
+               OpMemberDecorate %a_block 0 Offset 0
+               OpMemberDecorate %Outer 0 Offset 0
+               OpMemberDecorate %Inner 0 Offset 0
+               OpMemberDecorate %Inner 0 ColMajor
+               OpMemberDecorate %Inner 0 MatrixStride 16
+               OpDecorate %_arr_Inner_uint_4 ArrayStride 64
+               OpDecorate %_arr_Outer_uint_4 ArrayStride 256
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat3v4float = OpTypeMatrix %v4float 3
+      %Inner = OpTypeStruct %mat3v4float
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_Inner_uint_4 = OpTypeArray %Inner %uint_4
+      %Outer = OpTypeStruct %_arr_Inner_uint_4
+%_arr_Outer_uint_4 = OpTypeArray %Outer %uint_4
+    %a_block = OpTypeStruct %_arr_Outer_uint_4
+%_ptr_Uniform_a_block = OpTypePointer Uniform %a_block
+          %a = OpVariable %_ptr_Uniform_a_block Uniform
+        %int = OpTypeInt 32 1
+         %14 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %14
+         %17 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+       %void = OpTypeVoid
+         %24 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_Outer_uint_4 = OpTypePointer Uniform %_arr_Outer_uint_4
+%_ptr_Uniform_Outer = OpTypePointer Uniform %Outer
+%_ptr_Uniform__arr_Inner_uint_4 = OpTypePointer Uniform %_arr_Inner_uint_4
+%_ptr_Uniform_Inner = OpTypePointer Uniform %Inner
+%_ptr_Uniform_mat3v4float = OpTypePointer Uniform %mat3v4float
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+          %i = OpFunction %int None %17
+         %19 = OpLabel
+         %20 = OpLoad %int %counter
+         %22 = OpIAdd %int %20 %int_1
+               OpStore %counter %22
+         %23 = OpLoad %int %counter
+               OpReturnValue %23
+               OpFunctionEnd
+          %f = OpFunction %void None %24
+         %27 = OpLabel
+         %28 = OpFunctionCall %int %i
+         %29 = OpFunctionCall %int %i
+         %30 = OpFunctionCall %int %i
+         %33 = OpAccessChain %_ptr_Uniform__arr_Outer_uint_4 %a %uint_0
+         %34 = OpLoad %_arr_Outer_uint_4 %33
+         %36 = OpAccessChain %_ptr_Uniform_Outer %a %uint_0 %28
+         %37 = OpLoad %Outer %36
+         %39 = OpAccessChain %_ptr_Uniform__arr_Inner_uint_4 %a %uint_0 %28 %uint_0
+         %40 = OpLoad %_arr_Inner_uint_4 %39
+         %42 = OpAccessChain %_ptr_Uniform_Inner %a %uint_0 %28 %uint_0 %29
+         %43 = OpLoad %Inner %42
+         %45 = OpAccessChain %_ptr_Uniform_mat3v4float %a %uint_0 %28 %uint_0 %29 %uint_0
+         %46 = OpLoad %mat3v4float %45
+         %48 = OpAccessChain %_ptr_Uniform_v4float %a %uint_0 %28 %uint_0 %29 %uint_0 %30
+         %49 = OpLoad %v4float %48
+         %50 = OpFunctionCall %int %i
+         %52 = OpAccessChain %_ptr_Uniform_float %a %uint_0 %28 %uint_0 %29 %uint_0 %30 %50
+         %53 = OpLoad %float %52
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..73f5a5d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,34 @@
+struct Inner {
+  @size(64)
+  m : mat3x4<f32>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_i = &((*(p_a))[i()]);
+  let p_a_i_a = &((*(p_a_i)).a);
+  let p_a_i_a_i = &((*(p_a_i_a))[i()]);
+  let p_a_i_a_i_m = &((*(p_a_i_a_i)).m);
+  let p_a_i_a_i_m_i = &((*(p_a_i_a_i_m))[i()]);
+  let l_a : array<Outer, 4> = *(p_a);
+  let l_a_i : Outer = *(p_a_i);
+  let l_a_i_a : array<Inner, 4> = *(p_a_i_a);
+  let l_a_i_a_i : Inner = *(p_a_i_a_i);
+  let l_a_i_a_i_m : mat3x4<f32> = *(p_a_i_a_i_m);
+  let l_a_i_a_i_m_i : vec4<f32> = *(p_a_i_a_i_m_i);
+  let l_a_i_a_i_m_i_i : f32 = (*(p_a_i_a_i_m_i))[i()];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/static_index_via_ptr.wgsl
new file mode 100644
index 0000000..c378c04
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/static_index_via_ptr.wgsl
@@ -0,0 +1,29 @@
+struct Inner {
+  @size(64)
+  m : mat3x4<f32>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &a;
+  let p_a_3 = &((*p_a)[3]);
+  let p_a_3_a = &((*p_a_3).a);
+  let p_a_3_a_2 = &((*p_a_3_a)[2]);
+  let p_a_3_a_2_m = &((*p_a_3_a_2).m);
+  let p_a_3_a_2_m_1 = &((*p_a_3_a_2_m)[1]);
+
+
+  let l_a             : array<Outer, 4> = *p_a;
+  let l_a_3           : Outer           = *p_a_3;
+  let l_a_3_a         : array<Inner, 4> = *p_a_3_a;
+  let l_a_3_a_2       : Inner           = *p_a_3_a_2;
+  let l_a_3_a_2_m     : mat3x4<f32>     = *p_a_3_a_2_m;
+  let l_a_3_a_2_m_1   : vec4<f32>       = *p_a_3_a_2_m_1;
+  let l_a_3_a_2_m_1_0 : f32             = (*p_a_3_a_2_m_1)[0];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..26a9369
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,61 @@
+struct Inner {
+  float3x4 m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+
+float3x4 tint_symbol_4(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+}
+
+Inner tint_symbol_3(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_7 = {tint_symbol_4(buffer, (offset + 0u))};
+  return tint_symbol_7;
+}
+
+typedef Inner tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_3(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_1(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_8 = {tint_symbol_2(buffer, (offset + 0u))};
+  return tint_symbol_8;
+}
+
+typedef Outer tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr_1[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const Outer l_a[4] = tint_symbol(a, 0u);
+  const Outer l_a_3 = tint_symbol_1(a, 768u);
+  const Inner l_a_3_a[4] = tint_symbol_2(a, 768u);
+  const Inner l_a_3_a_2 = tint_symbol_3(a, 896u);
+  const float3x4 l_a_3_a_2_m = tint_symbol_4(a, 896u);
+  const float4 l_a_3_a_2_m_1 = asfloat(a[57]);
+  const float l_a_3_a_2_m_1_0 = asfloat(a[57].x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..26a9369
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,61 @@
+struct Inner {
+  float3x4 m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+
+float3x4 tint_symbol_4(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+}
+
+Inner tint_symbol_3(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_7 = {tint_symbol_4(buffer, (offset + 0u))};
+  return tint_symbol_7;
+}
+
+typedef Inner tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_3(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_1(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_8 = {tint_symbol_2(buffer, (offset + 0u))};
+  return tint_symbol_8;
+}
+
+typedef Outer tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr_1[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const Outer l_a[4] = tint_symbol(a, 0u);
+  const Outer l_a_3 = tint_symbol_1(a, 768u);
+  const Inner l_a_3_a[4] = tint_symbol_2(a, 768u);
+  const Inner l_a_3_a_2 = tint_symbol_3(a, 896u);
+  const float3x4 l_a_3_a_2_m = tint_symbol_4(a, 896u);
+  const float4 l_a_3_a_2_m_1 = asfloat(a[57]);
+  const float l_a_3_a_2_m_1_0 = asfloat(a[57].x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/static_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..e23c570
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/static_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,33 @@
+#version 310 es
+
+struct Inner {
+  mat3x4 m;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+};
+
+struct Outer {
+  Inner a[4];
+};
+
+layout(binding = 0, std140) uniform a_block_ubo {
+  Outer inner[4];
+} a;
+
+void f() {
+  Outer l_a[4] = a.inner;
+  Outer l_a_3 = a.inner[3];
+  Inner l_a_3_a[4] = a.inner[3].a;
+  Inner l_a_3_a_2 = a.inner[3].a[2];
+  mat3x4 l_a_3_a_2_m = a.inner[3].a[2].m;
+  vec4 l_a_3_a_2_m_1 = a.inner[3].a[2].m[1];
+  float l_a_3_a_2_m_1_0 = a.inner[3].a[2].m[1][0];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/static_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..f8ef4dc
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/static_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,36 @@
+#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 Inner {
+  /* 0x0000 */ float3x4 m;
+  /* 0x0030 */ tint_array<int8_t, 16> tint_pad;
+};
+
+struct Outer {
+  /* 0x0000 */ tint_array<Inner, 4> a;
+};
+
+kernel void f(const constant tint_array<Outer, 4>* tint_symbol [[buffer(0)]]) {
+  tint_array<Outer, 4> const l_a = *(tint_symbol);
+  Outer const l_a_3 = (*(tint_symbol))[3];
+  tint_array<Inner, 4> const l_a_3_a = (*(tint_symbol))[3].a;
+  Inner const l_a_3_a_2 = (*(tint_symbol))[3].a[2];
+  float3x4 const l_a_3_a_2_m = (*(tint_symbol))[3].a[2].m;
+  float4 const l_a_3_a_2_m_1 = (*(tint_symbol))[3].a[2].m[1];
+  float const l_a_3_a_2_m_1_0 = (*(tint_symbol))[3].a[2].m[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/static_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..39b3fdc
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/static_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,73 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 44
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block "a_block"
+               OpMemberName %a_block 0 "inner"
+               OpName %Outer "Outer"
+               OpMemberName %Outer 0 "a"
+               OpName %Inner "Inner"
+               OpMemberName %Inner 0 "m"
+               OpName %a "a"
+               OpName %f "f"
+               OpDecorate %a_block Block
+               OpMemberDecorate %a_block 0 Offset 0
+               OpMemberDecorate %Outer 0 Offset 0
+               OpMemberDecorate %Inner 0 Offset 0
+               OpMemberDecorate %Inner 0 ColMajor
+               OpMemberDecorate %Inner 0 MatrixStride 16
+               OpDecorate %_arr_Inner_uint_4 ArrayStride 64
+               OpDecorate %_arr_Outer_uint_4 ArrayStride 256
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat3v4float = OpTypeMatrix %v4float 3
+      %Inner = OpTypeStruct %mat3v4float
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_Inner_uint_4 = OpTypeArray %Inner %uint_4
+      %Outer = OpTypeStruct %_arr_Inner_uint_4
+%_arr_Outer_uint_4 = OpTypeArray %Outer %uint_4
+    %a_block = OpTypeStruct %_arr_Outer_uint_4
+%_ptr_Uniform_a_block = OpTypePointer Uniform %a_block
+          %a = OpVariable %_ptr_Uniform_a_block Uniform
+       %void = OpTypeVoid
+         %13 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_Outer_uint_4 = OpTypePointer Uniform %_arr_Outer_uint_4
+        %int = OpTypeInt 32 1
+      %int_3 = OpConstant %int 3
+%_ptr_Uniform_Outer = OpTypePointer Uniform %Outer
+%_ptr_Uniform__arr_Inner_uint_4 = OpTypePointer Uniform %_arr_Inner_uint_4
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_Inner = OpTypePointer Uniform %Inner
+%_ptr_Uniform_mat3v4float = OpTypePointer Uniform %mat3v4float
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+         %40 = OpConstantNull %int
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+          %f = OpFunction %void None %13
+         %16 = OpLabel
+         %19 = OpAccessChain %_ptr_Uniform__arr_Outer_uint_4 %a %uint_0
+         %20 = OpLoad %_arr_Outer_uint_4 %19
+         %24 = OpAccessChain %_ptr_Uniform_Outer %a %uint_0 %int_3
+         %25 = OpLoad %Outer %24
+         %27 = OpAccessChain %_ptr_Uniform__arr_Inner_uint_4 %a %uint_0 %int_3 %uint_0
+         %28 = OpLoad %_arr_Inner_uint_4 %27
+         %31 = OpAccessChain %_ptr_Uniform_Inner %a %uint_0 %int_3 %uint_0 %int_2
+         %32 = OpLoad %Inner %31
+         %34 = OpAccessChain %_ptr_Uniform_mat3v4float %a %uint_0 %int_3 %uint_0 %int_2 %uint_0
+         %35 = OpLoad %mat3v4float %34
+         %38 = OpAccessChain %_ptr_Uniform_v4float %a %uint_0 %int_3 %uint_0 %int_2 %uint_0 %int_1
+         %39 = OpLoad %v4float %38
+         %42 = OpAccessChain %_ptr_Uniform_float %a %uint_0 %int_3 %uint_0 %int_2 %uint_0 %int_1 %40
+         %43 = OpLoad %float %42
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/static_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..cb991e4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/static_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,27 @@
+struct Inner {
+  @size(64)
+  m : mat3x4<f32>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_3 = &((*(p_a))[3]);
+  let p_a_3_a = &((*(p_a_3)).a);
+  let p_a_3_a_2 = &((*(p_a_3_a))[2]);
+  let p_a_3_a_2_m = &((*(p_a_3_a_2)).m);
+  let p_a_3_a_2_m_1 = &((*(p_a_3_a_2_m))[1]);
+  let l_a : array<Outer, 4> = *(p_a);
+  let l_a_3 : Outer = *(p_a_3);
+  let l_a_3_a : array<Inner, 4> = *(p_a_3_a);
+  let l_a_3_a_2 : Inner = *(p_a_3_a_2);
+  let l_a_3_a_2_m : mat3x4<f32> = *(p_a_3_a_2_m);
+  let l_a_3_a_2_m_1 : vec4<f32> = *(p_a_3_a_2_m_1);
+  let l_a_3_a_2_m_1_0 : f32 = (*(p_a_3_a_2_m_1))[0];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_builtin.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_builtin.wgsl
new file mode 100644
index 0000000..0a98f13
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_builtin.wgsl
@@ -0,0 +1,15 @@
+struct S {
+  before : i32,
+  m : mat3x4<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    let t = transpose(u[2].m);
+    let l = length(u[0].m[1].ywxz);
+    let a = abs(u[0].m[1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_builtin.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..0826949
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_builtin.wgsl.expected.dxc.hlsl
@@ -0,0 +1,18 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+float3x4 tint_symbol(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float4x3 t = transpose(tint_symbol(u, 272u));
+  const float l = length(asfloat(u[2]).ywxz);
+  const float a = abs(asfloat(u[2]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_builtin.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..0826949
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_builtin.wgsl.expected.fxc.hlsl
@@ -0,0 +1,18 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+float3x4 tint_symbol(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float4x3 t = transpose(tint_symbol(u, 272u));
+  const float l = length(asfloat(u[2]).ywxz);
+  const float a = abs(asfloat(u[2]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_builtin.wgsl.expected.glsl
new file mode 100644
index 0000000..0e0b28f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_builtin.wgsl.expected.glsl
@@ -0,0 +1,41 @@
+#version 310 es
+
+struct S {
+  int before;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  mat3x4 m;
+  int after;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+};
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  S inner[4];
+} u;
+
+void f() {
+  mat4x3 t = transpose(u.inner[2].m);
+  float l = length(u.inner[0].m[1].ywxz);
+  float a = abs(u.inner[0].m[1].ywxz.x);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_builtin.wgsl.expected.msl
new file mode 100644
index 0000000..c93494d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_builtin.wgsl.expected.msl
@@ -0,0 +1,31 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 12> tint_pad;
+  /* 0x0010 */ float3x4 m;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_1;
+};
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol [[buffer(0)]]) {
+  float4x3 const t = transpose((*(tint_symbol))[2].m);
+  float const l = length(float4((*(tint_symbol))[0].m[1]).ywxz);
+  float const a = fabs(float4((*(tint_symbol))[0].m[1]).ywxz[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_builtin.wgsl.expected.spvasm
new file mode 100644
index 0000000..022664f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_builtin.wgsl.expected.spvasm
@@ -0,0 +1,67 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 38
+; Schema: 0
+               OpCapability Shader
+         %26 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %u "u"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 16
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 16
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat3v4float = OpTypeMatrix %v4float 3
+          %S = OpTypeStruct %int %mat3v4float %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+    %u_block = OpTypeStruct %_arr_S_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+         %12 = OpTypeFunction %void
+    %v3float = OpTypeVector %float 3
+%mat4v3float = OpTypeMatrix %v3float 4
+     %uint_0 = OpConstant %uint 0
+      %int_2 = OpConstant %int 2
+     %uint_1 = OpConstant %uint 1
+%_ptr_Uniform_mat3v4float = OpTypePointer Uniform %mat3v4float
+         %27 = OpConstantNull %int
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+          %f = OpFunction %void None %12
+         %15 = OpLabel
+         %23 = OpAccessChain %_ptr_Uniform_mat3v4float %u %uint_0 %int_2 %uint_1
+         %24 = OpLoad %mat3v4float %23
+         %16 = OpTranspose %mat4v3float %24
+         %30 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %27 %uint_1 %int_1
+         %31 = OpLoad %v4float %30
+         %32 = OpVectorShuffle %v4float %31 %31 1 3 0 2
+         %25 = OpExtInst %float %26 Length %32
+         %34 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %27 %uint_1 %int_1
+         %35 = OpLoad %v4float %34
+         %36 = OpVectorShuffle %v4float %35 %35 1 3 0 2
+         %37 = OpCompositeExtract %float %36 0
+         %33 = OpExtInst %float %26 FAbs %37
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_builtin.wgsl.expected.wgsl
new file mode 100644
index 0000000..8e60f77
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_builtin.wgsl.expected.wgsl
@@ -0,0 +1,15 @@
+struct S {
+  before : i32,
+  m : mat3x4<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let t = transpose(u[2].m);
+  let l = length(u[0].m[1].ywxz);
+  let a = abs(u[0].m[1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_fn.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_fn.wgsl
new file mode 100644
index 0000000..17458df
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_fn.wgsl
@@ -0,0 +1,23 @@
+struct S {
+  before : i32,
+  m : mat3x4<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+fn a(a : array<S, 4>) {}
+fn b(s : S) {}
+fn c(m : mat3x4<f32>) {}
+fn d(v : vec4<f32>) {}
+fn e(f : f32) {}
+
+@compute @workgroup_size(1)
+fn f() {
+    a(u);
+    b(u[2]);
+    c(u[2].m);
+    d(u[0].m[1].ywxz);
+    e(u[0].m[1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_fn.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..0bc1c2f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_fn.wgsl.expected.dxc.hlsl
@@ -0,0 +1,59 @@
+struct S {
+  int before;
+  float3x4 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(float3x4 m) {
+}
+
+void d(float4 v) {
+}
+
+void e(float f_1) {
+}
+
+float3x4 tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_3(buffer, (offset + 16u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 256u));
+  c(tint_symbol_3(u, 272u));
+  d(asfloat(u[2]).ywxz);
+  e(asfloat(u[2]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_fn.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..0bc1c2f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_fn.wgsl.expected.fxc.hlsl
@@ -0,0 +1,59 @@
+struct S {
+  int before;
+  float3x4 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(float3x4 m) {
+}
+
+void d(float4 v) {
+}
+
+void e(float f_1) {
+}
+
+float3x4 tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_3(buffer, (offset + 16u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 256u));
+  c(tint_symbol_3(u, 272u));
+  d(asfloat(u[2]).ywxz);
+  e(asfloat(u[2]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_fn.wgsl.expected.glsl
new file mode 100644
index 0000000..894d25f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_fn.wgsl.expected.glsl
@@ -0,0 +1,58 @@
+#version 310 es
+
+struct S {
+  int before;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  mat3x4 m;
+  int after;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+};
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  S inner[4];
+} u;
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(mat3x4 m) {
+}
+
+void d(vec4 v) {
+}
+
+void e(float f_1) {
+}
+
+void f() {
+  a(u.inner);
+  b(u.inner[2]);
+  c(u.inner[2].m);
+  d(u.inner[0].m[1].ywxz);
+  e(u.inner[0].m[1].ywxz.x);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_fn.wgsl.expected.msl
new file mode 100644
index 0000000..b2034ef
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_fn.wgsl.expected.msl
@@ -0,0 +1,48 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 12> tint_pad;
+  /* 0x0010 */ float3x4 m;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_1;
+};
+
+void a(tint_array<S, 4> a_1) {
+}
+
+void b(S s) {
+}
+
+void c(float3x4 m) {
+}
+
+void d(float4 v) {
+}
+
+void e(float f_1) {
+}
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol [[buffer(0)]]) {
+  a(*(tint_symbol));
+  b((*(tint_symbol))[2]);
+  c((*(tint_symbol))[2].m);
+  d(float4((*(tint_symbol))[0].m[1]).ywxz);
+  e(float4((*(tint_symbol))[0].m[1]).ywxz[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_fn.wgsl.expected.spvasm
new file mode 100644
index 0000000..2d03cb6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_fn.wgsl.expected.spvasm
@@ -0,0 +1,112 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 63
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %u "u"
+               OpName %a "a"
+               OpName %a_1 "a_1"
+               OpName %b "b"
+               OpName %s "s"
+               OpName %c "c"
+               OpName %m "m"
+               OpName %d "d"
+               OpName %v "v"
+               OpName %e "e"
+               OpName %f_1 "f_1"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 16
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 16
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat3v4float = OpTypeMatrix %v4float 3
+          %S = OpTypeStruct %int %mat3v4float %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+    %u_block = OpTypeStruct %_arr_S_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+         %12 = OpTypeFunction %void %_arr_S_uint_4
+         %17 = OpTypeFunction %void %S
+         %21 = OpTypeFunction %void %mat3v4float
+         %25 = OpTypeFunction %void %v4float
+         %29 = OpTypeFunction %void %float
+         %33 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_S_uint_4 = OpTypePointer Uniform %_arr_S_uint_4
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_S = OpTypePointer Uniform %S
+     %uint_1 = OpConstant %uint 1
+%_ptr_Uniform_mat3v4float = OpTypePointer Uniform %mat3v4float
+         %52 = OpConstantNull %int
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+          %a = OpFunction %void None %12
+        %a_1 = OpFunctionParameter %_arr_S_uint_4
+         %16 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %b = OpFunction %void None %17
+          %s = OpFunctionParameter %S
+         %20 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %c = OpFunction %void None %21
+          %m = OpFunctionParameter %mat3v4float
+         %24 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %d = OpFunction %void None %25
+          %v = OpFunctionParameter %v4float
+         %28 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %e = OpFunction %void None %29
+        %f_1 = OpFunctionParameter %float
+         %32 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %33
+         %35 = OpLabel
+         %39 = OpAccessChain %_ptr_Uniform__arr_S_uint_4 %u %uint_0
+         %40 = OpLoad %_arr_S_uint_4 %39
+         %36 = OpFunctionCall %void %a %40
+         %44 = OpAccessChain %_ptr_Uniform_S %u %uint_0 %int_2
+         %45 = OpLoad %S %44
+         %41 = OpFunctionCall %void %b %45
+         %49 = OpAccessChain %_ptr_Uniform_mat3v4float %u %uint_0 %int_2 %uint_1
+         %50 = OpLoad %mat3v4float %49
+         %46 = OpFunctionCall %void %c %50
+         %55 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %52 %uint_1 %int_1
+         %56 = OpLoad %v4float %55
+         %57 = OpVectorShuffle %v4float %56 %56 1 3 0 2
+         %51 = OpFunctionCall %void %d %57
+         %59 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %52 %uint_1 %int_1
+         %60 = OpLoad %v4float %59
+         %61 = OpVectorShuffle %v4float %60 %60 1 3 0 2
+         %62 = OpCompositeExtract %float %61 0
+         %58 = OpFunctionCall %void %e %62
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_fn.wgsl.expected.wgsl
new file mode 100644
index 0000000..9fa6069
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_fn.wgsl.expected.wgsl
@@ -0,0 +1,32 @@
+struct S {
+  before : i32,
+  m : mat3x4<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+fn a(a : array<S, 4>) {
+}
+
+fn b(s : S) {
+}
+
+fn c(m : mat3x4<f32>) {
+}
+
+fn d(v : vec4<f32>) {
+}
+
+fn e(f : f32) {
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  a(u);
+  b(u[2]);
+  c(u[2].m);
+  d(u[0].m[1].ywxz);
+  e(u[0].m[1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_private.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_private.wgsl
new file mode 100644
index 0000000..b3978f6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_private.wgsl
@@ -0,0 +1,17 @@
+struct S {
+  before : i32,
+  m : mat3x4<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+var<private> p : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[2];
+    p[3].m = u[2].m;
+    p[1].m[0] = u[0].m[1].ywxz;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_private.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..d7e58d4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_private.wgsl.expected.dxc.hlsl
@@ -0,0 +1,44 @@
+struct S {
+  int before;
+  float3x4 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+static S p[4] = (S[4])0;
+
+float3x4 tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_3(buffer, (offset + 16u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 256u);
+  p[3].m = tint_symbol_3(u, 272u);
+  p[1].m[0] = asfloat(u[2]).ywxz;
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_private.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..d7e58d4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_private.wgsl.expected.fxc.hlsl
@@ -0,0 +1,44 @@
+struct S {
+  int before;
+  float3x4 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+static S p[4] = (S[4])0;
+
+float3x4 tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_3(buffer, (offset + 16u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 256u);
+  p[3].m = tint_symbol_3(u, 272u);
+  p[1].m[0] = asfloat(u[2]).ywxz;
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..690aaca
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_private.wgsl.expected.glsl
@@ -0,0 +1,43 @@
+#version 310 es
+
+struct S {
+  int before;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  mat3x4 m;
+  int after;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+};
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  S inner[4];
+} u;
+
+S p[4] = S[4](S(0, 0u, 0u, 0u, mat3x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, 0u, 0u, mat3x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, 0u, 0u, mat3x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, 0u, 0u, mat3x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+void f() {
+  p = u.inner;
+  p[1] = u.inner[2];
+  p[3].m = u.inner[2].m;
+  p[1].m[0] = u.inner[0].m[1].ywxz;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..53a32ac
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_private.wgsl.expected.msl
@@ -0,0 +1,33 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 12> tint_pad;
+  /* 0x0010 */ float3x4 m;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_1;
+};
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol_1 [[buffer(0)]]) {
+  thread tint_array<S, 4> tint_symbol = {};
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[2];
+  tint_symbol[3].m = (*(tint_symbol_1))[2].m;
+  tint_symbol[1].m[0] = float4((*(tint_symbol_1))[0].m[1]).ywxz;
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_private.wgsl.expected.spvasm
new file mode 100644
index 0000000..d7ca594
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_private.wgsl.expected.spvasm
@@ -0,0 +1,78 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 44
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %u "u"
+               OpName %p "p"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 16
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 16
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat3v4float = OpTypeMatrix %v4float 3
+          %S = OpTypeStruct %int %mat3v4float %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+    %u_block = OpTypeStruct %_arr_S_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_Private__arr_S_uint_4 = OpTypePointer Private %_arr_S_uint_4
+         %14 = OpConstantNull %_arr_S_uint_4
+          %p = OpVariable %_ptr_Private__arr_S_uint_4 Private %14
+       %void = OpTypeVoid
+         %15 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_S_uint_4 = OpTypePointer Uniform %_arr_S_uint_4
+      %int_1 = OpConstant %int 1
+%_ptr_Private_S = OpTypePointer Private %S
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_S = OpTypePointer Uniform %S
+      %int_3 = OpConstant %int 3
+     %uint_1 = OpConstant %uint 1
+%_ptr_Private_mat3v4float = OpTypePointer Private %mat3v4float
+%_ptr_Uniform_mat3v4float = OpTypePointer Uniform %mat3v4float
+         %37 = OpConstantNull %int
+%_ptr_Private_v4float = OpTypePointer Private %v4float
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+          %f = OpFunction %void None %15
+         %18 = OpLabel
+         %21 = OpAccessChain %_ptr_Uniform__arr_S_uint_4 %u %uint_0
+         %22 = OpLoad %_arr_S_uint_4 %21
+               OpStore %p %22
+         %25 = OpAccessChain %_ptr_Private_S %p %int_1
+         %28 = OpAccessChain %_ptr_Uniform_S %u %uint_0 %int_2
+         %29 = OpLoad %S %28
+               OpStore %25 %29
+         %33 = OpAccessChain %_ptr_Private_mat3v4float %p %int_3 %uint_1
+         %35 = OpAccessChain %_ptr_Uniform_mat3v4float %u %uint_0 %int_2 %uint_1
+         %36 = OpLoad %mat3v4float %35
+               OpStore %33 %36
+         %39 = OpAccessChain %_ptr_Private_v4float %p %int_1 %uint_1 %37
+         %41 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %37 %uint_1 %int_1
+         %42 = OpLoad %v4float %41
+         %43 = OpVectorShuffle %v4float %42 %42 1 3 0 2
+               OpStore %39 %43
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..25650c9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_private.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+struct S {
+  before : i32,
+  m : mat3x4<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+var<private> p : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[2];
+  p[3].m = u[2].m;
+  p[1].m[0] = u[0].m[1].ywxz;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_storage.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_storage.wgsl
new file mode 100644
index 0000000..e45b0e0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_storage.wgsl
@@ -0,0 +1,17 @@
+struct S {
+  before : i32,
+  m : mat3x4<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+@group(0) @binding(1) var<storage, read_write> s : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[2];
+    s[3].m = u[2].m;
+    s[1].m[0] = u[0].m[1].ywxz;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_storage.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..629f8ff
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_storage.wgsl.expected.dxc.hlsl
@@ -0,0 +1,65 @@
+struct S {
+  int before;
+  float3x4 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_3(RWByteAddressBuffer buffer, uint offset, float3x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+  buffer.Store4((offset + 32u), asuint(value[2u]));
+}
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, S value) {
+  buffer.Store((offset + 0u), asuint(value.before));
+  tint_symbol_3(buffer, (offset + 16u), value.m);
+  buffer.Store((offset + 64u), asuint(value.after));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, S value[4]) {
+  S array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 128u)), array[i]);
+    }
+  }
+}
+
+float3x4 tint_symbol_8(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+}
+
+S tint_symbol_6(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_10 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_8(buffer, (offset + 16u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_10;
+}
+
+typedef S tint_symbol_5_ret[4];
+tint_symbol_5_ret tint_symbol_5(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_6(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_5(u, 0u));
+  tint_symbol_1(s, 128u, tint_symbol_6(u, 256u));
+  tint_symbol_3(s, 400u, tint_symbol_8(u, 272u));
+  s.Store4(144u, asuint(asfloat(u[2]).ywxz));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_storage.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..629f8ff
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_storage.wgsl.expected.fxc.hlsl
@@ -0,0 +1,65 @@
+struct S {
+  int before;
+  float3x4 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_3(RWByteAddressBuffer buffer, uint offset, float3x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+  buffer.Store4((offset + 32u), asuint(value[2u]));
+}
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, S value) {
+  buffer.Store((offset + 0u), asuint(value.before));
+  tint_symbol_3(buffer, (offset + 16u), value.m);
+  buffer.Store((offset + 64u), asuint(value.after));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, S value[4]) {
+  S array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 128u)), array[i]);
+    }
+  }
+}
+
+float3x4 tint_symbol_8(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+}
+
+S tint_symbol_6(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_10 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_8(buffer, (offset + 16u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_10;
+}
+
+typedef S tint_symbol_5_ret[4];
+tint_symbol_5_ret tint_symbol_5(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_6(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_5(u, 0u));
+  tint_symbol_1(s, 128u, tint_symbol_6(u, 256u));
+  tint_symbol_3(s, 400u, tint_symbol_8(u, 272u));
+  s.Store4(144u, asuint(asfloat(u[2]).ywxz));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..1460b32
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_storage.wgsl.expected.glsl
@@ -0,0 +1,46 @@
+#version 310 es
+
+struct S {
+  int before;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  mat3x4 m;
+  int after;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+};
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  S inner[4];
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  S inner[4];
+} s;
+
+void f() {
+  s.inner = u.inner;
+  s.inner[1] = u.inner[2];
+  s.inner[3].m = u.inner[2].m;
+  s.inner[1].m[0] = u.inner[0].m[1].ywxz;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..8eb259e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_storage.wgsl.expected.msl
@@ -0,0 +1,32 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 12> tint_pad;
+  /* 0x0010 */ float3x4 m;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_1;
+};
+
+kernel void f(device tint_array<S, 4>* tint_symbol [[buffer(1)]], const constant tint_array<S, 4>* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
+  (*(tint_symbol))[3].m = (*(tint_symbol_1))[2].m;
+  (*(tint_symbol))[1].m[0] = float4((*(tint_symbol_1))[0].m[1]).ywxz;
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_storage.wgsl.expected.spvasm
new file mode 100644
index 0000000..8073e21
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_storage.wgsl.expected.spvasm
@@ -0,0 +1,81 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 45
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %u "u"
+               OpName %s "s"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 16
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 16
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %s DescriptorSet 0
+               OpDecorate %s Binding 1
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat3v4float = OpTypeMatrix %v4float 3
+          %S = OpTypeStruct %int %mat3v4float %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+    %u_block = OpTypeStruct %_arr_S_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
+          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+       %void = OpTypeVoid
+         %14 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer__arr_S_uint_4 = OpTypePointer StorageBuffer %_arr_S_uint_4
+%_ptr_Uniform__arr_S_uint_4 = OpTypePointer Uniform %_arr_S_uint_4
+      %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_S = OpTypePointer Uniform %S
+      %int_3 = OpConstant %int 3
+     %uint_1 = OpConstant %uint 1
+%_ptr_StorageBuffer_mat3v4float = OpTypePointer StorageBuffer %mat3v4float
+%_ptr_Uniform_mat3v4float = OpTypePointer Uniform %mat3v4float
+         %38 = OpConstantNull %int
+%_ptr_StorageBuffer_v4float = OpTypePointer StorageBuffer %v4float
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+          %f = OpFunction %void None %14
+         %17 = OpLabel
+         %20 = OpAccessChain %_ptr_StorageBuffer__arr_S_uint_4 %s %uint_0
+         %22 = OpAccessChain %_ptr_Uniform__arr_S_uint_4 %u %uint_0
+         %23 = OpLoad %_arr_S_uint_4 %22
+               OpStore %20 %23
+         %26 = OpAccessChain %_ptr_StorageBuffer_S %s %uint_0 %int_1
+         %29 = OpAccessChain %_ptr_Uniform_S %u %uint_0 %int_2
+         %30 = OpLoad %S %29
+               OpStore %26 %30
+         %34 = OpAccessChain %_ptr_StorageBuffer_mat3v4float %s %uint_0 %int_3 %uint_1
+         %36 = OpAccessChain %_ptr_Uniform_mat3v4float %u %uint_0 %int_2 %uint_1
+         %37 = OpLoad %mat3v4float %36
+               OpStore %34 %37
+         %40 = OpAccessChain %_ptr_StorageBuffer_v4float %s %uint_0 %int_1 %uint_1 %38
+         %42 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %38 %uint_1 %int_1
+         %43 = OpLoad %v4float %42
+         %44 = OpVectorShuffle %v4float %43 %43 1 3 0 2
+               OpStore %40 %44
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..607b7e0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+struct S {
+  before : i32,
+  m : mat3x4<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@group(0) @binding(1) var<storage, read_write> s : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[2];
+  s[3].m = u[2].m;
+  s[1].m[0] = u[0].m[1].ywxz;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_workgroup.wgsl
new file mode 100644
index 0000000..32d7130
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_workgroup.wgsl
@@ -0,0 +1,17 @@
+struct S {
+  before : i32,
+  m : mat3x4<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+var<workgroup> w : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[2];
+    w[3].m = u[2].m;
+    w[1].m[0] = u[0].m[1].ywxz;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_workgroup.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..2188035
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_workgroup.wgsl.expected.dxc.hlsl
@@ -0,0 +1,60 @@
+struct S {
+  int before;
+  float3x4 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+groupshared S w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+float3x4 tint_symbol_5(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+}
+
+S tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_8 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_5(buffer, (offset + 16u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_8;
+}
+
+typedef S tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      const S tint_symbol_7 = (S)0;
+      w[i] = tint_symbol_7;
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 256u);
+  w[3].m = tint_symbol_5(u, 272u);
+  w[1].m[0] = asfloat(u[2]).ywxz;
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_workgroup.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..2188035
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_workgroup.wgsl.expected.fxc.hlsl
@@ -0,0 +1,60 @@
+struct S {
+  int before;
+  float3x4 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+groupshared S w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+float3x4 tint_symbol_5(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+}
+
+S tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_3 = ((offset + 0u)) / 4;
+  const uint scalar_offset_4 = ((offset + 64u)) / 4;
+  const S tint_symbol_8 = {asint(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), tint_symbol_5(buffer, (offset + 16u)), asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
+  return tint_symbol_8;
+}
+
+typedef S tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      const S tint_symbol_7 = (S)0;
+      w[i] = tint_symbol_7;
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 256u);
+  w[3].m = tint_symbol_5(u, 272u);
+  w[1].m[0] = asfloat(u[2]).ywxz;
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..c3d1ec4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,51 @@
+#version 310 es
+
+struct S {
+  int before;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  mat3x4 m;
+  int after;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+};
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  S inner[4];
+} u;
+
+shared S w[4];
+void f(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      uint i = idx;
+      S tint_symbol = S(0, 0u, 0u, 0u, mat3x4(vec4(0.0f), vec4(0.0f), vec4(0.0f)), 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u);
+      w[i] = tint_symbol;
+    }
+  }
+  barrier();
+  w = u.inner;
+  w[1] = u.inner[2];
+  w[3].m = u.inner[2].m;
+  w[1].m[0] = u.inner[0].m[1].ywxz;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..8fb8e97
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,47 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 12> tint_pad;
+  /* 0x0010 */ float3x4 m;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_1;
+};
+
+struct tint_symbol_6 {
+  tint_array<S, 4> w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup tint_array<S, 4>* const tint_symbol_1, const constant tint_array<S, 4>* const tint_symbol_2) {
+  for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+    uint const i = idx;
+    S const tint_symbol = S{};
+    (*(tint_symbol_1))[i] = tint_symbol;
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol_1) = *(tint_symbol_2);
+  (*(tint_symbol_1))[1] = (*(tint_symbol_2))[2];
+  (*(tint_symbol_1))[3].m = (*(tint_symbol_2))[2].m;
+  (*(tint_symbol_1))[1].m[0] = float4((*(tint_symbol_2))[0].m[1]).ywxz;
+}
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol_5 [[buffer(0)]], threadgroup tint_symbol_6* tint_symbol_4 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup tint_array<S, 4>* const tint_symbol_3 = &((*(tint_symbol_4)).w);
+  f_inner(local_invocation_index, tint_symbol_3, tint_symbol_5);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_workgroup.wgsl.expected.spvasm
new file mode 100644
index 0000000..91d76ce
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_workgroup.wgsl.expected.spvasm
@@ -0,0 +1,124 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 72
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %local_invocation_index_1 "local_invocation_index_1"
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %u "u"
+               OpName %w "w"
+               OpName %f_inner "f_inner"
+               OpName %local_invocation_index "local_invocation_index"
+               OpName %idx "idx"
+               OpName %f "f"
+               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 16
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 16
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat3v4float = OpTypeMatrix %v4float 3
+          %S = OpTypeStruct %int %mat3v4float %int
+     %uint_4 = OpConstant %uint 4
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+    %u_block = OpTypeStruct %_arr_S_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_Workgroup__arr_S_uint_4 = OpTypePointer Workgroup %_arr_S_uint_4
+          %w = OpVariable %_ptr_Workgroup__arr_S_uint_4 Workgroup
+       %void = OpTypeVoid
+         %16 = OpTypeFunction %void %uint
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %23 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Workgroup_S = OpTypePointer Workgroup %S
+         %37 = OpConstantNull %S
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+   %uint_264 = OpConstant %uint 264
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_S_uint_4 = OpTypePointer Uniform %_arr_S_uint_4
+      %int_1 = OpConstant %int 1
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_S = OpTypePointer Uniform %S
+      %int_3 = OpConstant %int 3
+%_ptr_Workgroup_mat3v4float = OpTypePointer Workgroup %mat3v4float
+%_ptr_Uniform_mat3v4float = OpTypePointer Uniform %mat3v4float
+         %60 = OpConstantNull %int
+%_ptr_Workgroup_v4float = OpTypePointer Workgroup %v4float
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+         %67 = OpTypeFunction %void
+    %f_inner = OpFunction %void None %16
+%local_invocation_index = OpFunctionParameter %uint
+         %20 = OpLabel
+        %idx = OpVariable %_ptr_Function_uint Function %23
+               OpStore %idx %local_invocation_index
+               OpBranch %24
+         %24 = OpLabel
+               OpLoopMerge %25 %26 None
+               OpBranch %27
+         %27 = OpLabel
+         %29 = OpLoad %uint %idx
+         %30 = OpULessThan %bool %29 %uint_4
+         %28 = OpLogicalNot %bool %30
+               OpSelectionMerge %32 None
+               OpBranchConditional %28 %33 %32
+         %33 = OpLabel
+               OpBranch %25
+         %32 = OpLabel
+         %34 = OpLoad %uint %idx
+         %36 = OpAccessChain %_ptr_Workgroup_S %w %34
+               OpStore %36 %37
+               OpBranch %26
+         %26 = OpLabel
+         %38 = OpLoad %uint %idx
+         %40 = OpIAdd %uint %38 %uint_1
+               OpStore %idx %40
+               OpBranch %24
+         %25 = OpLabel
+               OpControlBarrier %uint_2 %uint_2 %uint_264
+         %46 = OpAccessChain %_ptr_Uniform__arr_S_uint_4 %u %uint_0
+         %47 = OpLoad %_arr_S_uint_4 %46
+               OpStore %w %47
+         %49 = OpAccessChain %_ptr_Workgroup_S %w %int_1
+         %52 = OpAccessChain %_ptr_Uniform_S %u %uint_0 %int_2
+         %53 = OpLoad %S %52
+               OpStore %49 %53
+         %56 = OpAccessChain %_ptr_Workgroup_mat3v4float %w %int_3 %uint_1
+         %58 = OpAccessChain %_ptr_Uniform_mat3v4float %u %uint_0 %int_2 %uint_1
+         %59 = OpLoad %mat3v4float %58
+               OpStore %56 %59
+         %62 = OpAccessChain %_ptr_Workgroup_v4float %w %int_1 %uint_1 %60
+         %64 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %60 %uint_1 %int_1
+         %65 = OpLoad %v4float %64
+         %66 = OpVectorShuffle %v4float %65 %65 1 3 0 2
+               OpStore %62 %66
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %67
+         %69 = OpLabel
+         %71 = OpLoad %uint %local_invocation_index_1
+         %70 = OpFunctionCall %void %f_inner %71
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..e6817a3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat3x4_f32/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+struct S {
+  before : i32,
+  m : mat3x4<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+var<workgroup> w : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[2];
+  w[3].m = u[2].m;
+  w[1].m[0] = u[0].m[1].ywxz;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x2/dynamic_index_via_ptr.wgsl
deleted file mode 100644
index 512ab8c..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/dynamic_index_via_ptr.wgsl
+++ /dev/null
@@ -1,31 +0,0 @@
-struct Inner {
-  m : mat4x2<f32>,
-}
-
-struct Outer {
-  a : array<Inner, 4>,
-}
-
-@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
-
-var<private> counter = 0;
-fn i() -> i32 { counter++; return counter; }
-
-@compute @workgroup_size(1)
-fn f() {
-  let p_a           = &a;
-  let p_a_i         = &((*p_a)[i()]);
-  let p_a_i_a       = &((*p_a_i).a);
-  let p_a_i_a_i     = &((*p_a_i_a)[i()]);
-  let p_a_i_a_i_m   = &((*p_a_i_a_i).m);
-  let p_a_i_a_i_m_i = &((*p_a_i_a_i_m)[i()]);
-
-
-  let l_a             : array<Outer, 4> =  *p_a;
-  let l_a_i           : Outer           =  *p_a_i;
-  let l_a_i_a         : array<Inner, 4> =  *p_a_i_a;
-  let l_a_i_a_i       : Inner           =  *p_a_i_a_i;
-  let l_a_i_a_i_m     : mat4x2<f32>     =  *p_a_i_a_i_m;
-  let l_a_i_a_i_m_i   : vec2<f32>       =  *p_a_i_a_i_m_i;
-  let l_a_i_a_i_m_i_i : f32             = (*p_a_i_a_i_m_i)[i()];
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x2/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
deleted file mode 100644
index 8d635a9..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
+++ /dev/null
@@ -1,82 +0,0 @@
-struct Inner {
-  float4x2 m;
-};
-struct Outer {
-  Inner a[4];
-};
-
-cbuffer cbuffer_a : register(b0, space0) {
-  uint4 a[32];
-};
-static int counter = 0;
-
-int i() {
-  counter = (counter + 1);
-  return counter;
-}
-
-float4x2 tint_symbol_8(uint4 buffer[32], uint offset) {
-  const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset / 4];
-  const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
-  const uint scalar_offset_2 = ((offset + 16u)) / 4;
-  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
-  const uint scalar_offset_3 = ((offset + 24u)) / 4;
-  uint4 ubo_load_3 = buffer[scalar_offset_3 / 4];
-  return float4x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)), asfloat(((scalar_offset_3 & 2) ? ubo_load_3.zw : ubo_load_3.xy)));
-}
-
-Inner tint_symbol_7(uint4 buffer[32], uint offset) {
-  const Inner tint_symbol_11 = {tint_symbol_8(buffer, (offset + 0u))};
-  return tint_symbol_11;
-}
-
-typedef Inner tint_symbol_6_ret[4];
-tint_symbol_6_ret tint_symbol_6(uint4 buffer[32], uint offset) {
-  Inner arr[4] = (Inner[4])0;
-  {
-    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
-      arr[i_1] = tint_symbol_7(buffer, (offset + (i_1 * 32u)));
-    }
-  }
-  return arr;
-}
-
-Outer tint_symbol_5(uint4 buffer[32], uint offset) {
-  const Outer tint_symbol_12 = {tint_symbol_6(buffer, (offset + 0u))};
-  return tint_symbol_12;
-}
-
-typedef Outer tint_symbol_4_ret[4];
-tint_symbol_4_ret tint_symbol_4(uint4 buffer[32], uint offset) {
-  Outer arr_1[4] = (Outer[4])0;
-  {
-    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
-      arr_1[i_2] = tint_symbol_5(buffer, (offset + (i_2 * 128u)));
-    }
-  }
-  return arr_1;
-}
-
-[numthreads(1, 1, 1)]
-void f() {
-  const int p_a_i_save = i();
-  const int p_a_i_a_i_save = i();
-  const int p_a_i_a_i_m_i_save = i();
-  const Outer l_a[4] = tint_symbol_4(a, 0u);
-  const Outer l_a_i = tint_symbol_5(a, (128u * uint(p_a_i_save)));
-  const Inner l_a_i_a[4] = tint_symbol_6(a, (128u * uint(p_a_i_save)));
-  const Inner l_a_i_a_i = tint_symbol_7(a, ((128u * uint(p_a_i_save)) + (32u * uint(p_a_i_a_i_save))));
-  const float4x2 l_a_i_a_i_m = tint_symbol_8(a, ((128u * uint(p_a_i_save)) + (32u * uint(p_a_i_a_i_save))));
-  const uint scalar_offset_4 = ((((128u * uint(p_a_i_save)) + (32u * uint(p_a_i_a_i_save))) + (8u * uint(p_a_i_a_i_m_i_save)))) / 4;
-  uint4 ubo_load_4 = a[scalar_offset_4 / 4];
-  const float2 l_a_i_a_i_m_i = asfloat(((scalar_offset_4 & 2) ? ubo_load_4.zw : ubo_load_4.xy));
-  const int tint_symbol = p_a_i_save;
-  const int tint_symbol_1 = p_a_i_a_i_save;
-  const int tint_symbol_2 = p_a_i_a_i_m_i_save;
-  const int tint_symbol_3 = i();
-  const uint scalar_offset_5 = (((((128u * uint(tint_symbol)) + (32u * uint(tint_symbol_1))) + (8u * uint(tint_symbol_2))) + (4u * uint(tint_symbol_3)))) / 4;
-  const float l_a_i_a_i_m_i_i = asfloat(a[scalar_offset_5 / 4][scalar_offset_5 % 4]);
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x2/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
deleted file mode 100644
index 8d635a9..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
+++ /dev/null
@@ -1,82 +0,0 @@
-struct Inner {
-  float4x2 m;
-};
-struct Outer {
-  Inner a[4];
-};
-
-cbuffer cbuffer_a : register(b0, space0) {
-  uint4 a[32];
-};
-static int counter = 0;
-
-int i() {
-  counter = (counter + 1);
-  return counter;
-}
-
-float4x2 tint_symbol_8(uint4 buffer[32], uint offset) {
-  const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset / 4];
-  const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
-  const uint scalar_offset_2 = ((offset + 16u)) / 4;
-  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
-  const uint scalar_offset_3 = ((offset + 24u)) / 4;
-  uint4 ubo_load_3 = buffer[scalar_offset_3 / 4];
-  return float4x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)), asfloat(((scalar_offset_3 & 2) ? ubo_load_3.zw : ubo_load_3.xy)));
-}
-
-Inner tint_symbol_7(uint4 buffer[32], uint offset) {
-  const Inner tint_symbol_11 = {tint_symbol_8(buffer, (offset + 0u))};
-  return tint_symbol_11;
-}
-
-typedef Inner tint_symbol_6_ret[4];
-tint_symbol_6_ret tint_symbol_6(uint4 buffer[32], uint offset) {
-  Inner arr[4] = (Inner[4])0;
-  {
-    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
-      arr[i_1] = tint_symbol_7(buffer, (offset + (i_1 * 32u)));
-    }
-  }
-  return arr;
-}
-
-Outer tint_symbol_5(uint4 buffer[32], uint offset) {
-  const Outer tint_symbol_12 = {tint_symbol_6(buffer, (offset + 0u))};
-  return tint_symbol_12;
-}
-
-typedef Outer tint_symbol_4_ret[4];
-tint_symbol_4_ret tint_symbol_4(uint4 buffer[32], uint offset) {
-  Outer arr_1[4] = (Outer[4])0;
-  {
-    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
-      arr_1[i_2] = tint_symbol_5(buffer, (offset + (i_2 * 128u)));
-    }
-  }
-  return arr_1;
-}
-
-[numthreads(1, 1, 1)]
-void f() {
-  const int p_a_i_save = i();
-  const int p_a_i_a_i_save = i();
-  const int p_a_i_a_i_m_i_save = i();
-  const Outer l_a[4] = tint_symbol_4(a, 0u);
-  const Outer l_a_i = tint_symbol_5(a, (128u * uint(p_a_i_save)));
-  const Inner l_a_i_a[4] = tint_symbol_6(a, (128u * uint(p_a_i_save)));
-  const Inner l_a_i_a_i = tint_symbol_7(a, ((128u * uint(p_a_i_save)) + (32u * uint(p_a_i_a_i_save))));
-  const float4x2 l_a_i_a_i_m = tint_symbol_8(a, ((128u * uint(p_a_i_save)) + (32u * uint(p_a_i_a_i_save))));
-  const uint scalar_offset_4 = ((((128u * uint(p_a_i_save)) + (32u * uint(p_a_i_a_i_save))) + (8u * uint(p_a_i_a_i_m_i_save)))) / 4;
-  uint4 ubo_load_4 = a[scalar_offset_4 / 4];
-  const float2 l_a_i_a_i_m_i = asfloat(((scalar_offset_4 & 2) ? ubo_load_4.zw : ubo_load_4.xy));
-  const int tint_symbol = p_a_i_save;
-  const int tint_symbol_1 = p_a_i_a_i_save;
-  const int tint_symbol_2 = p_a_i_a_i_m_i_save;
-  const int tint_symbol_3 = i();
-  const uint scalar_offset_5 = (((((128u * uint(tint_symbol)) + (32u * uint(tint_symbol_1))) + (8u * uint(tint_symbol_2))) + (4u * uint(tint_symbol_3)))) / 4;
-  const float l_a_i_a_i_m_i_i = asfloat(a[scalar_offset_5 / 4][scalar_offset_5 % 4]);
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x2/dynamic_index_via_ptr.wgsl.expected.glsl
deleted file mode 100644
index 4bffcae..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/dynamic_index_via_ptr.wgsl.expected.glsl
+++ /dev/null
@@ -1,140 +0,0 @@
-#version 310 es
-
-struct Inner {
-  mat4x2 m;
-};
-
-struct Inner_std140 {
-  vec2 m_0;
-  vec2 m_1;
-  vec2 m_2;
-  vec2 m_3;
-};
-
-struct Outer {
-  Inner a[4];
-};
-
-struct Outer_std140 {
-  Inner_std140 a[4];
-};
-
-layout(binding = 0, std140) uniform a_block_std140_ubo {
-  Outer_std140 inner[4];
-} a;
-
-int counter = 0;
-int i() {
-  counter = (counter + 1);
-  return counter;
-}
-
-Inner conv_Inner(Inner_std140 val) {
-  return Inner(mat4x2(val.m_0, val.m_1, val.m_2, val.m_3));
-}
-
-Inner[4] conv_arr4_Inner(Inner_std140 val[4]) {
-  Inner arr[4] = Inner[4](Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)));
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      arr[i] = conv_Inner(val[i]);
-    }
-  }
-  return arr;
-}
-
-Outer conv_Outer(Outer_std140 val) {
-  return Outer(conv_arr4_Inner(val.a));
-}
-
-Outer[4] conv_arr4_Outer(Outer_std140 val[4]) {
-  Outer arr[4] = Outer[4](Outer(Inner[4](Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)))), Outer(Inner[4](Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)))), Outer(Inner[4](Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)))), Outer(Inner[4](Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)))));
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      arr[i] = conv_Outer(val[i]);
-    }
-  }
-  return arr;
-}
-
-mat4x2 load_a_inner_p0_a_p1_m(uint p0, uint p1) {
-  uint s_save = p0;
-  uint s_save_1 = p1;
-  return mat4x2(a.inner[s_save].a[s_save_1].m_0, a.inner[s_save].a[s_save_1].m_1, a.inner[s_save].a[s_save_1].m_2, a.inner[s_save].a[s_save_1].m_3);
-}
-
-vec2 load_a_inner_p0_a_p1_m_p2(uint p0, uint p1, uint p2) {
-  switch(p2) {
-    case 0u: {
-      return a.inner[p0].a[p1].m_0;
-      break;
-    }
-    case 1u: {
-      return a.inner[p0].a[p1].m_1;
-      break;
-    }
-    case 2u: {
-      return a.inner[p0].a[p1].m_2;
-      break;
-    }
-    case 3u: {
-      return a.inner[p0].a[p1].m_3;
-      break;
-    }
-    default: {
-      return vec2(0.0f);
-      break;
-    }
-  }
-}
-
-float load_a_inner_p0_a_p1_m_p2_p3(uint p0, uint p1, uint p2, uint p3) {
-  switch(p2) {
-    case 0u: {
-      return a.inner[p0].a[p1].m_0[p3];
-      break;
-    }
-    case 1u: {
-      return a.inner[p0].a[p1].m_1[p3];
-      break;
-    }
-    case 2u: {
-      return a.inner[p0].a[p1].m_2[p3];
-      break;
-    }
-    case 3u: {
-      return a.inner[p0].a[p1].m_3[p3];
-      break;
-    }
-    default: {
-      return 0.0f;
-      break;
-    }
-  }
-}
-
-void f() {
-  Outer p_a[4] = conv_arr4_Outer(a.inner);
-  int tint_symbol = i();
-  Outer p_a_i = conv_Outer(a.inner[tint_symbol]);
-  Inner p_a_i_a[4] = conv_arr4_Inner(a.inner[tint_symbol].a);
-  int tint_symbol_1 = i();
-  Inner p_a_i_a_i = conv_Inner(a.inner[tint_symbol].a[tint_symbol_1]);
-  mat4x2 p_a_i_a_i_m = load_a_inner_p0_a_p1_m(uint(tint_symbol), uint(tint_symbol_1));
-  int tint_symbol_2 = i();
-  vec2 p_a_i_a_i_m_i = load_a_inner_p0_a_p1_m_p2(uint(tint_symbol), uint(tint_symbol_1), uint(tint_symbol_2));
-  Outer l_a[4] = conv_arr4_Outer(a.inner);
-  Outer l_a_i = conv_Outer(a.inner[tint_symbol]);
-  Inner l_a_i_a[4] = conv_arr4_Inner(a.inner[tint_symbol].a);
-  Inner l_a_i_a_i = conv_Inner(a.inner[tint_symbol].a[tint_symbol_1]);
-  mat4x2 l_a_i_a_i_m = load_a_inner_p0_a_p1_m(uint(tint_symbol), uint(tint_symbol_1));
-  vec2 l_a_i_a_i_m_i = load_a_inner_p0_a_p1_m_p2(uint(tint_symbol), uint(tint_symbol_1), uint(tint_symbol_2));
-  int tint_symbol_3 = i();
-  float l_a_i_a_i_m_i_i = load_a_inner_p0_a_p1_m_p2_p3(uint(tint_symbol), uint(tint_symbol_1), uint(tint_symbol_2), uint(tint_symbol_3));
-}
-
-layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
-void main() {
-  f();
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x2/dynamic_index_via_ptr.wgsl.expected.msl
deleted file mode 100644
index 2f43afe..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/dynamic_index_via_ptr.wgsl.expected.msl
+++ /dev/null
@@ -1,48 +0,0 @@
-#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 Inner {
-  /* 0x0000 */ float4x2 m;
-};
-
-struct Outer {
-  /* 0x0000 */ tint_array<Inner, 4> a;
-};
-
-int i() {
-  thread int tint_symbol_4 = 0;
-  tint_symbol_4 = as_type<int>((as_type<uint>(tint_symbol_4) + as_type<uint>(1)));
-  return tint_symbol_4;
-}
-
-kernel void f(const constant tint_array<Outer, 4>* tint_symbol_5 [[buffer(0)]]) {
-  int const tint_symbol = i();
-  int const p_a_i_save = tint_symbol;
-  int const tint_symbol_1 = i();
-  int const p_a_i_a_i_save = tint_symbol_1;
-  int const tint_symbol_2 = i();
-  int const p_a_i_a_i_m_i_save = tint_symbol_2;
-  tint_array<Outer, 4> const l_a = *(tint_symbol_5);
-  Outer const l_a_i = (*(tint_symbol_5))[p_a_i_save];
-  tint_array<Inner, 4> const l_a_i_a = (*(tint_symbol_5))[p_a_i_save].a;
-  Inner const l_a_i_a_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save];
-  float4x2 const l_a_i_a_i_m = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m;
-  float2 const l_a_i_a_i_m_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save];
-  int const tint_symbol_3 = i();
-  float const l_a_i_a_i_m_i_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save][tint_symbol_3];
-  return;
-}
-
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x2/dynamic_index_via_ptr.wgsl.expected.spvasm
deleted file mode 100644
index 9a4f081..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/dynamic_index_via_ptr.wgsl.expected.spvasm
+++ /dev/null
@@ -1,334 +0,0 @@
-; SPIR-V
-; Version: 1.3
-; Generator: Google Tint Compiler; 0
-; Bound: 215
-; Schema: 0
-               OpCapability Shader
-               OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %f "f"
-               OpExecutionMode %f LocalSize 1 1 1
-               OpName %a_block_std140 "a_block_std140"
-               OpMemberName %a_block_std140 0 "inner"
-               OpName %Outer_std140 "Outer_std140"
-               OpMemberName %Outer_std140 0 "a"
-               OpName %Inner_std140 "Inner_std140"
-               OpMemberName %Inner_std140 0 "m_0"
-               OpMemberName %Inner_std140 1 "m_1"
-               OpMemberName %Inner_std140 2 "m_2"
-               OpMemberName %Inner_std140 3 "m_3"
-               OpName %a "a"
-               OpName %counter "counter"
-               OpName %i "i"
-               OpName %Inner "Inner"
-               OpMemberName %Inner 0 "m"
-               OpName %conv_Inner "conv_Inner"
-               OpName %val "val"
-               OpName %conv_arr4_Inner "conv_arr4_Inner"
-               OpName %val_0 "val"
-               OpName %arr "arr"
-               OpName %i_0 "i"
-               OpName %var_for_index_1 "var_for_index_1"
-               OpName %Outer "Outer"
-               OpMemberName %Outer 0 "a"
-               OpName %conv_Outer "conv_Outer"
-               OpName %val_1 "val"
-               OpName %conv_arr4_Outer "conv_arr4_Outer"
-               OpName %val_2 "val"
-               OpName %arr_0 "arr"
-               OpName %i_1 "i"
-               OpName %var_for_index "var_for_index"
-               OpName %load_a_inner_p0_a_p1_m "load_a_inner_p0_a_p1_m"
-               OpName %p0 "p0"
-               OpName %p1 "p1"
-               OpName %load_a_inner_p0_a_p1_m_p2 "load_a_inner_p0_a_p1_m_p2"
-               OpName %p0_0 "p0"
-               OpName %p1_0 "p1"
-               OpName %p2 "p2"
-               OpName %load_a_inner_p0_a_p1_m_p2_p3 "load_a_inner_p0_a_p1_m_p2_p3"
-               OpName %p0_1 "p0"
-               OpName %p1_1 "p1"
-               OpName %p2_0 "p2"
-               OpName %p3 "p3"
-               OpName %f "f"
-               OpDecorate %a_block_std140 Block
-               OpMemberDecorate %a_block_std140 0 Offset 0
-               OpMemberDecorate %Outer_std140 0 Offset 0
-               OpMemberDecorate %Inner_std140 0 Offset 0
-               OpMemberDecorate %Inner_std140 1 Offset 8
-               OpMemberDecorate %Inner_std140 2 Offset 16
-               OpMemberDecorate %Inner_std140 3 Offset 24
-               OpDecorate %_arr_Inner_std140_uint_4 ArrayStride 32
-               OpDecorate %_arr_Outer_std140_uint_4 ArrayStride 128
-               OpDecorate %a NonWritable
-               OpDecorate %a DescriptorSet 0
-               OpDecorate %a Binding 0
-               OpMemberDecorate %Inner 0 Offset 0
-               OpMemberDecorate %Inner 0 ColMajor
-               OpMemberDecorate %Inner 0 MatrixStride 8
-               OpDecorate %_arr_Inner_uint_4 ArrayStride 32
-               OpMemberDecorate %Outer 0 Offset 0
-               OpDecorate %_arr_Outer_uint_4 ArrayStride 128
-      %float = OpTypeFloat 32
-    %v2float = OpTypeVector %float 2
-%Inner_std140 = OpTypeStruct %v2float %v2float %v2float %v2float
-       %uint = OpTypeInt 32 0
-     %uint_4 = OpConstant %uint 4
-%_arr_Inner_std140_uint_4 = OpTypeArray %Inner_std140 %uint_4
-%Outer_std140 = OpTypeStruct %_arr_Inner_std140_uint_4
-%_arr_Outer_std140_uint_4 = OpTypeArray %Outer_std140 %uint_4
-%a_block_std140 = OpTypeStruct %_arr_Outer_std140_uint_4
-%_ptr_Uniform_a_block_std140 = OpTypePointer Uniform %a_block_std140
-          %a = OpVariable %_ptr_Uniform_a_block_std140 Uniform
-        %int = OpTypeInt 32 1
-         %13 = OpConstantNull %int
-%_ptr_Private_int = OpTypePointer Private %int
-    %counter = OpVariable %_ptr_Private_int Private %13
-         %16 = OpTypeFunction %int
-      %int_1 = OpConstant %int 1
-%mat4v2float = OpTypeMatrix %v2float 4
-      %Inner = OpTypeStruct %mat4v2float
-         %23 = OpTypeFunction %Inner %Inner_std140
-%_arr_Inner_uint_4 = OpTypeArray %Inner %uint_4
-         %35 = OpTypeFunction %_arr_Inner_uint_4 %_arr_Inner_std140_uint_4
-%_ptr_Function__arr_Inner_uint_4 = OpTypePointer Function %_arr_Inner_uint_4
-         %42 = OpConstantNull %_arr_Inner_uint_4
-%_ptr_Function_uint = OpTypePointer Function %uint
-         %45 = OpConstantNull %uint
-       %bool = OpTypeBool
-%_ptr_Function__arr_Inner_std140_uint_4 = OpTypePointer Function %_arr_Inner_std140_uint_4
-         %58 = OpConstantNull %_arr_Inner_std140_uint_4
-%_ptr_Function_Inner = OpTypePointer Function %Inner
-%_ptr_Function_Inner_std140 = OpTypePointer Function %Inner_std140
-     %uint_1 = OpConstant %uint 1
-      %Outer = OpTypeStruct %_arr_Inner_uint_4
-         %71 = OpTypeFunction %Outer %Outer_std140
-%_arr_Outer_uint_4 = OpTypeArray %Outer %uint_4
-         %79 = OpTypeFunction %_arr_Outer_uint_4 %_arr_Outer_std140_uint_4
-%_ptr_Function__arr_Outer_uint_4 = OpTypePointer Function %_arr_Outer_uint_4
-         %86 = OpConstantNull %_arr_Outer_uint_4
-%_ptr_Function__arr_Outer_std140_uint_4 = OpTypePointer Function %_arr_Outer_std140_uint_4
-         %99 = OpConstantNull %_arr_Outer_std140_uint_4
-%_ptr_Function_Outer = OpTypePointer Function %Outer
-%_ptr_Function_Outer_std140 = OpTypePointer Function %Outer_std140
-        %111 = OpTypeFunction %mat4v2float %uint %uint
-     %uint_0 = OpConstant %uint 0
-%_ptr_Uniform_Inner_std140 = OpTypePointer Uniform %Inner_std140
-%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
-     %uint_2 = OpConstant %uint 2
-     %uint_3 = OpConstant %uint 3
-        %136 = OpTypeFunction %v2float %uint %uint %uint
-        %156 = OpConstantNull %v2float
-        %157 = OpTypeFunction %float %uint %uint %uint %uint
-%_ptr_Uniform_float = OpTypePointer Uniform %float
-        %179 = OpConstantNull %float
-       %void = OpTypeVoid
-        %180 = OpTypeFunction %void
-%_ptr_Uniform__arr_Outer_std140_uint_4 = OpTypePointer Uniform %_arr_Outer_std140_uint_4
-%_ptr_Uniform_Outer_std140 = OpTypePointer Uniform %Outer_std140
-%_ptr_Uniform__arr_Inner_std140_uint_4 = OpTypePointer Uniform %_arr_Inner_std140_uint_4
-          %i = OpFunction %int None %16
-         %18 = OpLabel
-         %19 = OpLoad %int %counter
-         %21 = OpIAdd %int %19 %int_1
-               OpStore %counter %21
-         %22 = OpLoad %int %counter
-               OpReturnValue %22
-               OpFunctionEnd
- %conv_Inner = OpFunction %Inner None %23
-        %val = OpFunctionParameter %Inner_std140
-         %28 = OpLabel
-         %29 = OpCompositeExtract %v2float %val 0
-         %30 = OpCompositeExtract %v2float %val 1
-         %31 = OpCompositeExtract %v2float %val 2
-         %32 = OpCompositeExtract %v2float %val 3
-         %33 = OpCompositeConstruct %mat4v2float %29 %30 %31 %32
-         %34 = OpCompositeConstruct %Inner %33
-               OpReturnValue %34
-               OpFunctionEnd
-%conv_arr4_Inner = OpFunction %_arr_Inner_uint_4 None %35
-      %val_0 = OpFunctionParameter %_arr_Inner_std140_uint_4
-         %39 = OpLabel
-        %arr = OpVariable %_ptr_Function__arr_Inner_uint_4 Function %42
-        %i_0 = OpVariable %_ptr_Function_uint Function %45
-%var_for_index_1 = OpVariable %_ptr_Function__arr_Inner_std140_uint_4 Function %58
-               OpBranch %46
-         %46 = OpLabel
-               OpLoopMerge %47 %48 None
-               OpBranch %49
-         %49 = OpLabel
-         %51 = OpLoad %uint %i_0
-         %52 = OpULessThan %bool %51 %uint_4
-         %50 = OpLogicalNot %bool %52
-               OpSelectionMerge %54 None
-               OpBranchConditional %50 %55 %54
-         %55 = OpLabel
-               OpBranch %47
-         %54 = OpLabel
-               OpStore %var_for_index_1 %val_0
-         %59 = OpLoad %uint %i_0
-         %61 = OpAccessChain %_ptr_Function_Inner %arr %59
-         %63 = OpLoad %uint %i_0
-         %65 = OpAccessChain %_ptr_Function_Inner_std140 %var_for_index_1 %63
-         %66 = OpLoad %Inner_std140 %65
-         %62 = OpFunctionCall %Inner %conv_Inner %66
-               OpStore %61 %62
-               OpBranch %48
-         %48 = OpLabel
-         %67 = OpLoad %uint %i_0
-         %69 = OpIAdd %uint %67 %uint_1
-               OpStore %i_0 %69
-               OpBranch %46
-         %47 = OpLabel
-         %70 = OpLoad %_arr_Inner_uint_4 %arr
-               OpReturnValue %70
-               OpFunctionEnd
- %conv_Outer = OpFunction %Outer None %71
-      %val_1 = OpFunctionParameter %Outer_std140
-         %75 = OpLabel
-         %77 = OpCompositeExtract %_arr_Inner_std140_uint_4 %val_1 0
-         %76 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %77
-         %78 = OpCompositeConstruct %Outer %76
-               OpReturnValue %78
-               OpFunctionEnd
-%conv_arr4_Outer = OpFunction %_arr_Outer_uint_4 None %79
-      %val_2 = OpFunctionParameter %_arr_Outer_std140_uint_4
-         %83 = OpLabel
-      %arr_0 = OpVariable %_ptr_Function__arr_Outer_uint_4 Function %86
-        %i_1 = OpVariable %_ptr_Function_uint Function %45
-%var_for_index = OpVariable %_ptr_Function__arr_Outer_std140_uint_4 Function %99
-               OpBranch %88
-         %88 = OpLabel
-               OpLoopMerge %89 %90 None
-               OpBranch %91
-         %91 = OpLabel
-         %93 = OpLoad %uint %i_1
-         %94 = OpULessThan %bool %93 %uint_4
-         %92 = OpLogicalNot %bool %94
-               OpSelectionMerge %95 None
-               OpBranchConditional %92 %96 %95
-         %96 = OpLabel
-               OpBranch %89
-         %95 = OpLabel
-               OpStore %var_for_index %val_2
-        %100 = OpLoad %uint %i_1
-        %102 = OpAccessChain %_ptr_Function_Outer %arr_0 %100
-        %104 = OpLoad %uint %i_1
-        %106 = OpAccessChain %_ptr_Function_Outer_std140 %var_for_index %104
-        %107 = OpLoad %Outer_std140 %106
-        %103 = OpFunctionCall %Outer %conv_Outer %107
-               OpStore %102 %103
-               OpBranch %90
-         %90 = OpLabel
-        %108 = OpLoad %uint %i_1
-        %109 = OpIAdd %uint %108 %uint_1
-               OpStore %i_1 %109
-               OpBranch %88
-         %89 = OpLabel
-        %110 = OpLoad %_arr_Outer_uint_4 %arr_0
-               OpReturnValue %110
-               OpFunctionEnd
-%load_a_inner_p0_a_p1_m = OpFunction %mat4v2float None %111
-         %p0 = OpFunctionParameter %uint
-         %p1 = OpFunctionParameter %uint
-        %115 = OpLabel
-        %119 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %p0 %uint_0 %p1
-        %122 = OpAccessChain %_ptr_Uniform_v2float %119 %uint_0
-        %123 = OpLoad %v2float %122
-        %125 = OpAccessChain %_ptr_Uniform_v2float %119 %uint_1
-        %126 = OpLoad %v2float %125
-        %129 = OpAccessChain %_ptr_Uniform_v2float %119 %uint_2
-        %130 = OpLoad %v2float %129
-        %133 = OpAccessChain %_ptr_Uniform_v2float %119 %uint_3
-        %134 = OpLoad %v2float %133
-        %135 = OpCompositeConstruct %mat4v2float %123 %126 %130 %134
-               OpReturnValue %135
-               OpFunctionEnd
-%load_a_inner_p0_a_p1_m_p2 = OpFunction %v2float None %136
-       %p0_0 = OpFunctionParameter %uint
-       %p1_0 = OpFunctionParameter %uint
-         %p2 = OpFunctionParameter %uint
-        %141 = OpLabel
-               OpSelectionMerge %142 None
-               OpSwitch %p2 %143 0 %144 1 %145 2 %146 3 %147
-        %144 = OpLabel
-        %148 = OpAccessChain %_ptr_Uniform_v2float %a %uint_0 %p0_0 %uint_0 %p1_0 %uint_0
-        %149 = OpLoad %v2float %148
-               OpReturnValue %149
-        %145 = OpLabel
-        %150 = OpAccessChain %_ptr_Uniform_v2float %a %uint_0 %p0_0 %uint_0 %p1_0 %uint_1
-        %151 = OpLoad %v2float %150
-               OpReturnValue %151
-        %146 = OpLabel
-        %152 = OpAccessChain %_ptr_Uniform_v2float %a %uint_0 %p0_0 %uint_0 %p1_0 %uint_2
-        %153 = OpLoad %v2float %152
-               OpReturnValue %153
-        %147 = OpLabel
-        %154 = OpAccessChain %_ptr_Uniform_v2float %a %uint_0 %p0_0 %uint_0 %p1_0 %uint_3
-        %155 = OpLoad %v2float %154
-               OpReturnValue %155
-        %143 = OpLabel
-               OpReturnValue %156
-        %142 = OpLabel
-               OpReturnValue %156
-               OpFunctionEnd
-%load_a_inner_p0_a_p1_m_p2_p3 = OpFunction %float None %157
-       %p0_1 = OpFunctionParameter %uint
-       %p1_1 = OpFunctionParameter %uint
-       %p2_0 = OpFunctionParameter %uint
-         %p3 = OpFunctionParameter %uint
-        %163 = OpLabel
-               OpSelectionMerge %164 None
-               OpSwitch %p2_0 %165 0 %166 1 %167 2 %168 3 %169
-        %166 = OpLabel
-        %171 = OpAccessChain %_ptr_Uniform_float %a %uint_0 %p0_1 %uint_0 %p1_1 %uint_0 %p3
-        %172 = OpLoad %float %171
-               OpReturnValue %172
-        %167 = OpLabel
-        %173 = OpAccessChain %_ptr_Uniform_float %a %uint_0 %p0_1 %uint_0 %p1_1 %uint_1 %p3
-        %174 = OpLoad %float %173
-               OpReturnValue %174
-        %168 = OpLabel
-        %175 = OpAccessChain %_ptr_Uniform_float %a %uint_0 %p0_1 %uint_0 %p1_1 %uint_2 %p3
-        %176 = OpLoad %float %175
-               OpReturnValue %176
-        %169 = OpLabel
-        %177 = OpAccessChain %_ptr_Uniform_float %a %uint_0 %p0_1 %uint_0 %p1_1 %uint_3 %p3
-        %178 = OpLoad %float %177
-               OpReturnValue %178
-        %165 = OpLabel
-               OpReturnValue %179
-        %164 = OpLabel
-               OpReturnValue %179
-               OpFunctionEnd
-          %f = OpFunction %void None %180
-        %183 = OpLabel
-        %184 = OpFunctionCall %int %i
-        %185 = OpFunctionCall %int %i
-        %186 = OpFunctionCall %int %i
-        %189 = OpAccessChain %_ptr_Uniform__arr_Outer_std140_uint_4 %a %uint_0
-        %190 = OpLoad %_arr_Outer_std140_uint_4 %189
-        %187 = OpFunctionCall %_arr_Outer_uint_4 %conv_arr4_Outer %190
-        %193 = OpAccessChain %_ptr_Uniform_Outer_std140 %a %uint_0 %184
-        %194 = OpLoad %Outer_std140 %193
-        %191 = OpFunctionCall %Outer %conv_Outer %194
-        %197 = OpAccessChain %_ptr_Uniform__arr_Inner_std140_uint_4 %a %uint_0 %184 %uint_0
-        %198 = OpLoad %_arr_Inner_std140_uint_4 %197
-        %195 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %198
-        %200 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %184 %uint_0 %185
-        %201 = OpLoad %Inner_std140 %200
-        %199 = OpFunctionCall %Inner %conv_Inner %201
-        %203 = OpBitcast %uint %184
-        %204 = OpBitcast %uint %185
-        %202 = OpFunctionCall %mat4v2float %load_a_inner_p0_a_p1_m %203 %204
-        %206 = OpBitcast %uint %184
-        %207 = OpBitcast %uint %185
-        %208 = OpBitcast %uint %186
-        %205 = OpFunctionCall %v2float %load_a_inner_p0_a_p1_m_p2 %206 %207 %208
-        %209 = OpFunctionCall %int %i
-        %211 = OpBitcast %uint %184
-        %212 = OpBitcast %uint %185
-        %213 = OpBitcast %uint %186
-        %214 = OpBitcast %uint %209
-        %210 = OpFunctionCall %float %load_a_inner_p0_a_p1_m_p2_p3 %211 %212 %213 %214
-               OpReturn
-               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x2/dynamic_index_via_ptr.wgsl.expected.wgsl
deleted file mode 100644
index 7cc47fe..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/dynamic_index_via_ptr.wgsl.expected.wgsl
+++ /dev/null
@@ -1,33 +0,0 @@
-struct Inner {
-  m : mat4x2<f32>,
-}
-
-struct Outer {
-  a : array<Inner, 4>,
-}
-
-@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
-
-var<private> counter = 0;
-
-fn i() -> i32 {
-  counter++;
-  return counter;
-}
-
-@compute @workgroup_size(1)
-fn f() {
-  let p_a = &(a);
-  let p_a_i = &((*(p_a))[i()]);
-  let p_a_i_a = &((*(p_a_i)).a);
-  let p_a_i_a_i = &((*(p_a_i_a))[i()]);
-  let p_a_i_a_i_m = &((*(p_a_i_a_i)).m);
-  let p_a_i_a_i_m_i = &((*(p_a_i_a_i_m))[i()]);
-  let l_a : array<Outer, 4> = *(p_a);
-  let l_a_i : Outer = *(p_a_i);
-  let l_a_i_a : array<Inner, 4> = *(p_a_i_a);
-  let l_a_i_a_i : Inner = *(p_a_i_a_i);
-  let l_a_i_a_i_m : mat4x2<f32> = *(p_a_i_a_i_m);
-  let l_a_i_a_i_m_i : vec2<f32> = *(p_a_i_a_i_m_i);
-  let l_a_i_a_i_m_i_i : f32 = (*(p_a_i_a_i_m_i))[i()];
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x2/static_index_via_ptr.wgsl
deleted file mode 100644
index 582e8ac..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/static_index_via_ptr.wgsl
+++ /dev/null
@@ -1,28 +0,0 @@
-struct Inner {
-  m : mat4x2<f32>,
-}
-
-struct Outer {
-  a : array<Inner, 4>,
-}
-
-@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
-
-@compute @workgroup_size(1)
-fn f() {
-  let p_a = &a;
-  let p_a_3 = &((*p_a)[3]);
-  let p_a_3_a = &((*p_a_3).a);
-  let p_a_3_a_2 = &((*p_a_3_a)[2]);
-  let p_a_3_a_2_m = &((*p_a_3_a_2).m);
-  let p_a_3_a_2_m_1 = &((*p_a_3_a_2_m)[1]);
-
-
-  let l_a             : array<Outer, 4> = *p_a;
-  let l_a_3           : Outer           = *p_a_3;
-  let l_a_3_a         : array<Inner, 4> = *p_a_3_a;
-  let l_a_3_a_2       : Inner           = *p_a_3_a_2;
-  let l_a_3_a_2_m     : mat4x2<f32>     = *p_a_3_a_2_m;
-  let l_a_3_a_2_m_1   : vec2<f32>       = *p_a_3_a_2_m_1;
-  let l_a_3_a_2_m_1_0 : f32             = (*p_a_3_a_2_m_1)[0];
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x2/static_index_via_ptr.wgsl.expected.dxc.hlsl
deleted file mode 100644
index f499d7c..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/static_index_via_ptr.wgsl.expected.dxc.hlsl
+++ /dev/null
@@ -1,66 +0,0 @@
-struct Inner {
-  float4x2 m;
-};
-struct Outer {
-  Inner a[4];
-};
-
-cbuffer cbuffer_a : register(b0, space0) {
-  uint4 a[32];
-};
-
-float4x2 tint_symbol_4(uint4 buffer[32], uint offset) {
-  const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset / 4];
-  const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
-  const uint scalar_offset_2 = ((offset + 16u)) / 4;
-  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
-  const uint scalar_offset_3 = ((offset + 24u)) / 4;
-  uint4 ubo_load_3 = buffer[scalar_offset_3 / 4];
-  return float4x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)), asfloat(((scalar_offset_3 & 2) ? ubo_load_3.zw : ubo_load_3.xy)));
-}
-
-Inner tint_symbol_3(uint4 buffer[32], uint offset) {
-  const Inner tint_symbol_7 = {tint_symbol_4(buffer, (offset + 0u))};
-  return tint_symbol_7;
-}
-
-typedef Inner tint_symbol_2_ret[4];
-tint_symbol_2_ret tint_symbol_2(uint4 buffer[32], uint offset) {
-  Inner arr[4] = (Inner[4])0;
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      arr[i] = tint_symbol_3(buffer, (offset + (i * 32u)));
-    }
-  }
-  return arr;
-}
-
-Outer tint_symbol_1(uint4 buffer[32], uint offset) {
-  const Outer tint_symbol_8 = {tint_symbol_2(buffer, (offset + 0u))};
-  return tint_symbol_8;
-}
-
-typedef Outer tint_symbol_ret[4];
-tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
-  Outer arr_1[4] = (Outer[4])0;
-  {
-    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
-      arr_1[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 128u)));
-    }
-  }
-  return arr_1;
-}
-
-[numthreads(1, 1, 1)]
-void f() {
-  const Outer l_a[4] = tint_symbol(a, 0u);
-  const Outer l_a_3 = tint_symbol_1(a, 384u);
-  const Inner l_a_3_a[4] = tint_symbol_2(a, 384u);
-  const Inner l_a_3_a_2 = tint_symbol_3(a, 448u);
-  const float4x2 l_a_3_a_2_m = tint_symbol_4(a, 448u);
-  const float2 l_a_3_a_2_m_1 = asfloat(a[28].zw);
-  const float l_a_3_a_2_m_1_0 = asfloat(a[28].z);
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x2/static_index_via_ptr.wgsl.expected.fxc.hlsl
deleted file mode 100644
index f499d7c..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/static_index_via_ptr.wgsl.expected.fxc.hlsl
+++ /dev/null
@@ -1,66 +0,0 @@
-struct Inner {
-  float4x2 m;
-};
-struct Outer {
-  Inner a[4];
-};
-
-cbuffer cbuffer_a : register(b0, space0) {
-  uint4 a[32];
-};
-
-float4x2 tint_symbol_4(uint4 buffer[32], uint offset) {
-  const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset / 4];
-  const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
-  const uint scalar_offset_2 = ((offset + 16u)) / 4;
-  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
-  const uint scalar_offset_3 = ((offset + 24u)) / 4;
-  uint4 ubo_load_3 = buffer[scalar_offset_3 / 4];
-  return float4x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)), asfloat(((scalar_offset_3 & 2) ? ubo_load_3.zw : ubo_load_3.xy)));
-}
-
-Inner tint_symbol_3(uint4 buffer[32], uint offset) {
-  const Inner tint_symbol_7 = {tint_symbol_4(buffer, (offset + 0u))};
-  return tint_symbol_7;
-}
-
-typedef Inner tint_symbol_2_ret[4];
-tint_symbol_2_ret tint_symbol_2(uint4 buffer[32], uint offset) {
-  Inner arr[4] = (Inner[4])0;
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      arr[i] = tint_symbol_3(buffer, (offset + (i * 32u)));
-    }
-  }
-  return arr;
-}
-
-Outer tint_symbol_1(uint4 buffer[32], uint offset) {
-  const Outer tint_symbol_8 = {tint_symbol_2(buffer, (offset + 0u))};
-  return tint_symbol_8;
-}
-
-typedef Outer tint_symbol_ret[4];
-tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
-  Outer arr_1[4] = (Outer[4])0;
-  {
-    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
-      arr_1[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 128u)));
-    }
-  }
-  return arr_1;
-}
-
-[numthreads(1, 1, 1)]
-void f() {
-  const Outer l_a[4] = tint_symbol(a, 0u);
-  const Outer l_a_3 = tint_symbol_1(a, 384u);
-  const Inner l_a_3_a[4] = tint_symbol_2(a, 384u);
-  const Inner l_a_3_a_2 = tint_symbol_3(a, 448u);
-  const float4x2 l_a_3_a_2_m = tint_symbol_4(a, 448u);
-  const float2 l_a_3_a_2_m_1 = asfloat(a[28].zw);
-  const float l_a_3_a_2_m_1_0 = asfloat(a[28].z);
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x2/static_index_via_ptr.wgsl.expected.glsl
deleted file mode 100644
index 658fe9e..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/static_index_via_ptr.wgsl.expected.glsl
+++ /dev/null
@@ -1,78 +0,0 @@
-#version 310 es
-
-struct Inner {
-  mat4x2 m;
-};
-
-struct Inner_std140 {
-  vec2 m_0;
-  vec2 m_1;
-  vec2 m_2;
-  vec2 m_3;
-};
-
-struct Outer {
-  Inner a[4];
-};
-
-struct Outer_std140 {
-  Inner_std140 a[4];
-};
-
-layout(binding = 0, std140) uniform a_block_std140_ubo {
-  Outer_std140 inner[4];
-} a;
-
-Inner conv_Inner(Inner_std140 val) {
-  return Inner(mat4x2(val.m_0, val.m_1, val.m_2, val.m_3));
-}
-
-Inner[4] conv_arr4_Inner(Inner_std140 val[4]) {
-  Inner arr[4] = Inner[4](Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)));
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      arr[i] = conv_Inner(val[i]);
-    }
-  }
-  return arr;
-}
-
-Outer conv_Outer(Outer_std140 val) {
-  return Outer(conv_arr4_Inner(val.a));
-}
-
-Outer[4] conv_arr4_Outer(Outer_std140 val[4]) {
-  Outer arr[4] = Outer[4](Outer(Inner[4](Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)))), Outer(Inner[4](Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)))), Outer(Inner[4](Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)))), Outer(Inner[4](Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)))));
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      arr[i] = conv_Outer(val[i]);
-    }
-  }
-  return arr;
-}
-
-mat4x2 load_a_inner_3_a_2_m() {
-  return mat4x2(a.inner[3u].a[2u].m_0, a.inner[3u].a[2u].m_1, a.inner[3u].a[2u].m_2, a.inner[3u].a[2u].m_3);
-}
-
-void f() {
-  Outer p_a[4] = conv_arr4_Outer(a.inner);
-  Outer p_a_3 = conv_Outer(a.inner[3u]);
-  Inner p_a_3_a[4] = conv_arr4_Inner(a.inner[3u].a);
-  Inner p_a_3_a_2 = conv_Inner(a.inner[3u].a[2u]);
-  mat4x2 p_a_3_a_2_m = load_a_inner_3_a_2_m();
-  vec2 p_a_3_a_2_m_1 = a.inner[3u].a[2u].m_1;
-  Outer l_a[4] = conv_arr4_Outer(a.inner);
-  Outer l_a_3 = conv_Outer(a.inner[3u]);
-  Inner l_a_3_a[4] = conv_arr4_Inner(a.inner[3u].a);
-  Inner l_a_3_a_2 = conv_Inner(a.inner[3u].a[2u]);
-  mat4x2 l_a_3_a_2_m = load_a_inner_3_a_2_m();
-  vec2 l_a_3_a_2_m_1 = a.inner[3u].a[2u].m_1;
-  float l_a_3_a_2_m_1_0 = a.inner[3u].a[2u].m_1[0u];
-}
-
-layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
-void main() {
-  f();
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x2/static_index_via_ptr.wgsl.expected.msl
deleted file mode 100644
index 457e620..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/static_index_via_ptr.wgsl.expected.msl
+++ /dev/null
@@ -1,35 +0,0 @@
-#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 Inner {
-  /* 0x0000 */ float4x2 m;
-};
-
-struct Outer {
-  /* 0x0000 */ tint_array<Inner, 4> a;
-};
-
-kernel void f(const constant tint_array<Outer, 4>* tint_symbol [[buffer(0)]]) {
-  tint_array<Outer, 4> const l_a = *(tint_symbol);
-  Outer const l_a_3 = (*(tint_symbol))[3];
-  tint_array<Inner, 4> const l_a_3_a = (*(tint_symbol))[3].a;
-  Inner const l_a_3_a_2 = (*(tint_symbol))[3].a[2];
-  float4x2 const l_a_3_a_2_m = (*(tint_symbol))[3].a[2].m;
-  float2 const l_a_3_a_2_m_1 = (*(tint_symbol))[3].a[2].m[1];
-  float const l_a_3_a_2_m_1_0 = (*(tint_symbol))[3].a[2].m[1][0];
-  return;
-}
-
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x2/static_index_via_ptr.wgsl.expected.spvasm
deleted file mode 100644
index 730d12b..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/static_index_via_ptr.wgsl.expected.spvasm
+++ /dev/null
@@ -1,233 +0,0 @@
-; SPIR-V
-; Version: 1.3
-; Generator: Google Tint Compiler; 0
-; Bound: 148
-; Schema: 0
-               OpCapability Shader
-               OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %f "f"
-               OpExecutionMode %f LocalSize 1 1 1
-               OpName %a_block_std140 "a_block_std140"
-               OpMemberName %a_block_std140 0 "inner"
-               OpName %Outer_std140 "Outer_std140"
-               OpMemberName %Outer_std140 0 "a"
-               OpName %Inner_std140 "Inner_std140"
-               OpMemberName %Inner_std140 0 "m_0"
-               OpMemberName %Inner_std140 1 "m_1"
-               OpMemberName %Inner_std140 2 "m_2"
-               OpMemberName %Inner_std140 3 "m_3"
-               OpName %a "a"
-               OpName %Inner "Inner"
-               OpMemberName %Inner 0 "m"
-               OpName %conv_Inner "conv_Inner"
-               OpName %val "val"
-               OpName %conv_arr4_Inner "conv_arr4_Inner"
-               OpName %val_0 "val"
-               OpName %arr "arr"
-               OpName %i "i"
-               OpName %var_for_index_1 "var_for_index_1"
-               OpName %Outer "Outer"
-               OpMemberName %Outer 0 "a"
-               OpName %conv_Outer "conv_Outer"
-               OpName %val_1 "val"
-               OpName %conv_arr4_Outer "conv_arr4_Outer"
-               OpName %val_2 "val"
-               OpName %arr_0 "arr"
-               OpName %i_0 "i"
-               OpName %var_for_index "var_for_index"
-               OpName %load_a_inner_3_a_2_m "load_a_inner_3_a_2_m"
-               OpName %f "f"
-               OpDecorate %a_block_std140 Block
-               OpMemberDecorate %a_block_std140 0 Offset 0
-               OpMemberDecorate %Outer_std140 0 Offset 0
-               OpMemberDecorate %Inner_std140 0 Offset 0
-               OpMemberDecorate %Inner_std140 1 Offset 8
-               OpMemberDecorate %Inner_std140 2 Offset 16
-               OpMemberDecorate %Inner_std140 3 Offset 24
-               OpDecorate %_arr_Inner_std140_uint_4 ArrayStride 32
-               OpDecorate %_arr_Outer_std140_uint_4 ArrayStride 128
-               OpDecorate %a NonWritable
-               OpDecorate %a DescriptorSet 0
-               OpDecorate %a Binding 0
-               OpMemberDecorate %Inner 0 Offset 0
-               OpMemberDecorate %Inner 0 ColMajor
-               OpMemberDecorate %Inner 0 MatrixStride 8
-               OpDecorate %_arr_Inner_uint_4 ArrayStride 32
-               OpMemberDecorate %Outer 0 Offset 0
-               OpDecorate %_arr_Outer_uint_4 ArrayStride 128
-      %float = OpTypeFloat 32
-    %v2float = OpTypeVector %float 2
-%Inner_std140 = OpTypeStruct %v2float %v2float %v2float %v2float
-       %uint = OpTypeInt 32 0
-     %uint_4 = OpConstant %uint 4
-%_arr_Inner_std140_uint_4 = OpTypeArray %Inner_std140 %uint_4
-%Outer_std140 = OpTypeStruct %_arr_Inner_std140_uint_4
-%_arr_Outer_std140_uint_4 = OpTypeArray %Outer_std140 %uint_4
-%a_block_std140 = OpTypeStruct %_arr_Outer_std140_uint_4
-%_ptr_Uniform_a_block_std140 = OpTypePointer Uniform %a_block_std140
-          %a = OpVariable %_ptr_Uniform_a_block_std140 Uniform
-%mat4v2float = OpTypeMatrix %v2float 4
-      %Inner = OpTypeStruct %mat4v2float
-         %12 = OpTypeFunction %Inner %Inner_std140
-%_arr_Inner_uint_4 = OpTypeArray %Inner %uint_4
-         %24 = OpTypeFunction %_arr_Inner_uint_4 %_arr_Inner_std140_uint_4
-%_ptr_Function__arr_Inner_uint_4 = OpTypePointer Function %_arr_Inner_uint_4
-         %31 = OpConstantNull %_arr_Inner_uint_4
-%_ptr_Function_uint = OpTypePointer Function %uint
-         %34 = OpConstantNull %uint
-       %bool = OpTypeBool
-%_ptr_Function__arr_Inner_std140_uint_4 = OpTypePointer Function %_arr_Inner_std140_uint_4
-         %47 = OpConstantNull %_arr_Inner_std140_uint_4
-%_ptr_Function_Inner = OpTypePointer Function %Inner
-%_ptr_Function_Inner_std140 = OpTypePointer Function %Inner_std140
-     %uint_1 = OpConstant %uint 1
-      %Outer = OpTypeStruct %_arr_Inner_uint_4
-         %60 = OpTypeFunction %Outer %Outer_std140
-%_arr_Outer_uint_4 = OpTypeArray %Outer %uint_4
-         %68 = OpTypeFunction %_arr_Outer_uint_4 %_arr_Outer_std140_uint_4
-%_ptr_Function__arr_Outer_uint_4 = OpTypePointer Function %_arr_Outer_uint_4
-         %75 = OpConstantNull %_arr_Outer_uint_4
-%_ptr_Function__arr_Outer_std140_uint_4 = OpTypePointer Function %_arr_Outer_std140_uint_4
-         %88 = OpConstantNull %_arr_Outer_std140_uint_4
-%_ptr_Function_Outer = OpTypePointer Function %Outer
-%_ptr_Function_Outer_std140 = OpTypePointer Function %Outer_std140
-        %100 = OpTypeFunction %mat4v2float
-     %uint_0 = OpConstant %uint 0
-     %uint_3 = OpConstant %uint 3
-     %uint_2 = OpConstant %uint 2
-%_ptr_Uniform_Inner_std140 = OpTypePointer Uniform %Inner_std140
-%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
-       %void = OpTypeVoid
-        %123 = OpTypeFunction %void
-%_ptr_Uniform__arr_Outer_std140_uint_4 = OpTypePointer Uniform %_arr_Outer_std140_uint_4
-%_ptr_Uniform_Outer_std140 = OpTypePointer Uniform %Outer_std140
-%_ptr_Uniform__arr_Inner_std140_uint_4 = OpTypePointer Uniform %_arr_Inner_std140_uint_4
-%_ptr_Uniform_float = OpTypePointer Uniform %float
- %conv_Inner = OpFunction %Inner None %12
-        %val = OpFunctionParameter %Inner_std140
-         %17 = OpLabel
-         %18 = OpCompositeExtract %v2float %val 0
-         %19 = OpCompositeExtract %v2float %val 1
-         %20 = OpCompositeExtract %v2float %val 2
-         %21 = OpCompositeExtract %v2float %val 3
-         %22 = OpCompositeConstruct %mat4v2float %18 %19 %20 %21
-         %23 = OpCompositeConstruct %Inner %22
-               OpReturnValue %23
-               OpFunctionEnd
-%conv_arr4_Inner = OpFunction %_arr_Inner_uint_4 None %24
-      %val_0 = OpFunctionParameter %_arr_Inner_std140_uint_4
-         %28 = OpLabel
-        %arr = OpVariable %_ptr_Function__arr_Inner_uint_4 Function %31
-          %i = OpVariable %_ptr_Function_uint Function %34
-%var_for_index_1 = OpVariable %_ptr_Function__arr_Inner_std140_uint_4 Function %47
-               OpBranch %35
-         %35 = OpLabel
-               OpLoopMerge %36 %37 None
-               OpBranch %38
-         %38 = OpLabel
-         %40 = OpLoad %uint %i
-         %41 = OpULessThan %bool %40 %uint_4
-         %39 = OpLogicalNot %bool %41
-               OpSelectionMerge %43 None
-               OpBranchConditional %39 %44 %43
-         %44 = OpLabel
-               OpBranch %36
-         %43 = OpLabel
-               OpStore %var_for_index_1 %val_0
-         %48 = OpLoad %uint %i
-         %50 = OpAccessChain %_ptr_Function_Inner %arr %48
-         %52 = OpLoad %uint %i
-         %54 = OpAccessChain %_ptr_Function_Inner_std140 %var_for_index_1 %52
-         %55 = OpLoad %Inner_std140 %54
-         %51 = OpFunctionCall %Inner %conv_Inner %55
-               OpStore %50 %51
-               OpBranch %37
-         %37 = OpLabel
-         %56 = OpLoad %uint %i
-         %58 = OpIAdd %uint %56 %uint_1
-               OpStore %i %58
-               OpBranch %35
-         %36 = OpLabel
-         %59 = OpLoad %_arr_Inner_uint_4 %arr
-               OpReturnValue %59
-               OpFunctionEnd
- %conv_Outer = OpFunction %Outer None %60
-      %val_1 = OpFunctionParameter %Outer_std140
-         %64 = OpLabel
-         %66 = OpCompositeExtract %_arr_Inner_std140_uint_4 %val_1 0
-         %65 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %66
-         %67 = OpCompositeConstruct %Outer %65
-               OpReturnValue %67
-               OpFunctionEnd
-%conv_arr4_Outer = OpFunction %_arr_Outer_uint_4 None %68
-      %val_2 = OpFunctionParameter %_arr_Outer_std140_uint_4
-         %72 = OpLabel
-      %arr_0 = OpVariable %_ptr_Function__arr_Outer_uint_4 Function %75
-        %i_0 = OpVariable %_ptr_Function_uint Function %34
-%var_for_index = OpVariable %_ptr_Function__arr_Outer_std140_uint_4 Function %88
-               OpBranch %77
-         %77 = OpLabel
-               OpLoopMerge %78 %79 None
-               OpBranch %80
-         %80 = OpLabel
-         %82 = OpLoad %uint %i_0
-         %83 = OpULessThan %bool %82 %uint_4
-         %81 = OpLogicalNot %bool %83
-               OpSelectionMerge %84 None
-               OpBranchConditional %81 %85 %84
-         %85 = OpLabel
-               OpBranch %78
-         %84 = OpLabel
-               OpStore %var_for_index %val_2
-         %89 = OpLoad %uint %i_0
-         %91 = OpAccessChain %_ptr_Function_Outer %arr_0 %89
-         %93 = OpLoad %uint %i_0
-         %95 = OpAccessChain %_ptr_Function_Outer_std140 %var_for_index %93
-         %96 = OpLoad %Outer_std140 %95
-         %92 = OpFunctionCall %Outer %conv_Outer %96
-               OpStore %91 %92
-               OpBranch %79
-         %79 = OpLabel
-         %97 = OpLoad %uint %i_0
-         %98 = OpIAdd %uint %97 %uint_1
-               OpStore %i_0 %98
-               OpBranch %77
-         %78 = OpLabel
-         %99 = OpLoad %_arr_Outer_uint_4 %arr_0
-               OpReturnValue %99
-               OpFunctionEnd
-%load_a_inner_3_a_2_m = OpFunction %mat4v2float None %100
-        %102 = OpLabel
-        %108 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %uint_3 %uint_0 %uint_2
-        %111 = OpAccessChain %_ptr_Uniform_v2float %108 %uint_0
-        %112 = OpLoad %v2float %111
-        %114 = OpAccessChain %_ptr_Uniform_v2float %108 %uint_1
-        %115 = OpLoad %v2float %114
-        %117 = OpAccessChain %_ptr_Uniform_v2float %108 %uint_2
-        %118 = OpLoad %v2float %117
-        %120 = OpAccessChain %_ptr_Uniform_v2float %108 %uint_3
-        %121 = OpLoad %v2float %120
-        %122 = OpCompositeConstruct %mat4v2float %112 %115 %118 %121
-               OpReturnValue %122
-               OpFunctionEnd
-          %f = OpFunction %void None %123
-        %126 = OpLabel
-        %129 = OpAccessChain %_ptr_Uniform__arr_Outer_std140_uint_4 %a %uint_0
-        %130 = OpLoad %_arr_Outer_std140_uint_4 %129
-        %127 = OpFunctionCall %_arr_Outer_uint_4 %conv_arr4_Outer %130
-        %133 = OpAccessChain %_ptr_Uniform_Outer_std140 %a %uint_0 %uint_3
-        %134 = OpLoad %Outer_std140 %133
-        %131 = OpFunctionCall %Outer %conv_Outer %134
-        %137 = OpAccessChain %_ptr_Uniform__arr_Inner_std140_uint_4 %a %uint_0 %uint_3 %uint_0
-        %138 = OpLoad %_arr_Inner_std140_uint_4 %137
-        %135 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %138
-        %140 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %uint_3 %uint_0 %uint_2
-        %141 = OpLoad %Inner_std140 %140
-        %139 = OpFunctionCall %Inner %conv_Inner %141
-        %142 = OpFunctionCall %mat4v2float %load_a_inner_3_a_2_m
-        %143 = OpAccessChain %_ptr_Uniform_v2float %a %uint_0 %uint_3 %uint_0 %uint_2 %uint_1
-        %144 = OpLoad %v2float %143
-        %146 = OpAccessChain %_ptr_Uniform_float %a %uint_0 %uint_3 %uint_0 %uint_2 %uint_1 %34
-        %147 = OpLoad %float %146
-               OpReturn
-               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x2/static_index_via_ptr.wgsl.expected.wgsl
deleted file mode 100644
index 6347a0e..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/static_index_via_ptr.wgsl.expected.wgsl
+++ /dev/null
@@ -1,26 +0,0 @@
-struct Inner {
-  m : mat4x2<f32>,
-}
-
-struct Outer {
-  a : array<Inner, 4>,
-}
-
-@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
-
-@compute @workgroup_size(1)
-fn f() {
-  let p_a = &(a);
-  let p_a_3 = &((*(p_a))[3]);
-  let p_a_3_a = &((*(p_a_3)).a);
-  let p_a_3_a_2 = &((*(p_a_3_a))[2]);
-  let p_a_3_a_2_m = &((*(p_a_3_a_2)).m);
-  let p_a_3_a_2_m_1 = &((*(p_a_3_a_2_m))[1]);
-  let l_a : array<Outer, 4> = *(p_a);
-  let l_a_3 : Outer = *(p_a_3);
-  let l_a_3_a : array<Inner, 4> = *(p_a_3_a);
-  let l_a_3_a_2 : Inner = *(p_a_3_a_2);
-  let l_a_3_a_2_m : mat4x2<f32> = *(p_a_3_a_2_m);
-  let l_a_3_a_2_m_1 : vec2<f32> = *(p_a_3_a_2_m_1);
-  let l_a_3_a_2_m_1_0 : f32 = (*(p_a_3_a_2_m_1))[0];
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/to_builtin.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x2/to_builtin.wgsl
deleted file mode 100644
index 7aa8fa0..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/to_builtin.wgsl
+++ /dev/null
@@ -1,14 +0,0 @@
-struct S {
-  before : i32,
-  m : mat4x2<f32>,
-  after : i32,
-}
-
-@group(0) @binding(0) var<uniform> u : array<S, 4>;
-
-@compute @workgroup_size(1)
-fn f() {
-    let t = transpose(u[2].m);
-    let l = length(u[0].m[1].yx);
-    let a = abs(u[0].m[1].yx.x);
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x2/to_builtin.wgsl.expected.dxc.hlsl
deleted file mode 100644
index f1fc60e..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/to_builtin.wgsl.expected.dxc.hlsl
+++ /dev/null
@@ -1,23 +0,0 @@
-cbuffer cbuffer_u : register(b0, space0) {
-  uint4 u[12];
-};
-
-float4x2 tint_symbol(uint4 buffer[12], uint offset) {
-  const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset / 4];
-  const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
-  const uint scalar_offset_2 = ((offset + 16u)) / 4;
-  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
-  const uint scalar_offset_3 = ((offset + 24u)) / 4;
-  uint4 ubo_load_3 = buffer[scalar_offset_3 / 4];
-  return float4x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)), asfloat(((scalar_offset_3 & 2) ? ubo_load_3.zw : ubo_load_3.xy)));
-}
-
-[numthreads(1, 1, 1)]
-void f() {
-  const float2x4 t = transpose(tint_symbol(u, 104u));
-  const float l = length(asfloat(u[1].xy).yx);
-  const float a = abs(asfloat(u[1].xy).yx.x);
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x2/to_builtin.wgsl.expected.fxc.hlsl
deleted file mode 100644
index f1fc60e..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/to_builtin.wgsl.expected.fxc.hlsl
+++ /dev/null
@@ -1,23 +0,0 @@
-cbuffer cbuffer_u : register(b0, space0) {
-  uint4 u[12];
-};
-
-float4x2 tint_symbol(uint4 buffer[12], uint offset) {
-  const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset / 4];
-  const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
-  const uint scalar_offset_2 = ((offset + 16u)) / 4;
-  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
-  const uint scalar_offset_3 = ((offset + 24u)) / 4;
-  uint4 ubo_load_3 = buffer[scalar_offset_3 / 4];
-  return float4x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)), asfloat(((scalar_offset_3 & 2) ? ubo_load_3.zw : ubo_load_3.xy)));
-}
-
-[numthreads(1, 1, 1)]
-void f() {
-  const float2x4 t = transpose(tint_symbol(u, 104u));
-  const float l = length(asfloat(u[1].xy).yx);
-  const float a = abs(asfloat(u[1].xy).yx.x);
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x2/to_builtin.wgsl.expected.glsl
deleted file mode 100644
index b5bbb97..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/to_builtin.wgsl.expected.glsl
+++ /dev/null
@@ -1,40 +0,0 @@
-#version 310 es
-
-struct S {
-  int before;
-  uint pad;
-  mat4x2 m;
-  int after;
-  uint pad_1;
-};
-
-struct S_std140 {
-  int before;
-  uint pad;
-  vec2 m_0;
-  vec2 m_1;
-  vec2 m_2;
-  vec2 m_3;
-  int after;
-  uint pad_1;
-};
-
-layout(binding = 0, std140) uniform u_block_std140_ubo {
-  S_std140 inner[4];
-} u;
-
-mat4x2 load_u_inner_2_m() {
-  return mat4x2(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2, u.inner[2u].m_3);
-}
-
-void f() {
-  mat2x4 t = transpose(load_u_inner_2_m());
-  float l = length(u.inner[0u].m_1.yx);
-  float a = abs(u.inner[0u].m_1.yx[0u]);
-}
-
-layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
-void main() {
-  f();
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x2/to_builtin.wgsl.expected.msl
deleted file mode 100644
index d66b53e..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/to_builtin.wgsl.expected.msl
+++ /dev/null
@@ -1,31 +0,0 @@
-#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 S {
-  /* 0x0000 */ int before;
-  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
-  /* 0x0008 */ float4x2 m;
-  /* 0x0028 */ int after;
-  /* 0x002c */ tint_array<int8_t, 4> tint_pad_1;
-};
-
-kernel void f(const constant tint_array<S, 4>* tint_symbol [[buffer(0)]]) {
-  float2x4 const t = transpose((*(tint_symbol))[2].m);
-  float const l = length(float2((*(tint_symbol))[0].m[1]).yx);
-  float const a = fabs(float2((*(tint_symbol))[0].m[1]).yx[0]);
-  return;
-}
-
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x2/to_builtin.wgsl.expected.spvasm
deleted file mode 100644
index 831410f..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/to_builtin.wgsl.expected.spvasm
+++ /dev/null
@@ -1,86 +0,0 @@
-; SPIR-V
-; Version: 1.3
-; Generator: Google Tint Compiler; 0
-; Bound: 55
-; Schema: 0
-               OpCapability Shader
-         %45 = OpExtInstImport "GLSL.std.450"
-               OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %f "f"
-               OpExecutionMode %f LocalSize 1 1 1
-               OpName %u_block_std140 "u_block_std140"
-               OpMemberName %u_block_std140 0 "inner"
-               OpName %S_std140 "S_std140"
-               OpMemberName %S_std140 0 "before"
-               OpMemberName %S_std140 1 "m_0"
-               OpMemberName %S_std140 2 "m_1"
-               OpMemberName %S_std140 3 "m_2"
-               OpMemberName %S_std140 4 "m_3"
-               OpMemberName %S_std140 5 "after"
-               OpName %u "u"
-               OpName %load_u_inner_2_m "load_u_inner_2_m"
-               OpName %f "f"
-               OpDecorate %u_block_std140 Block
-               OpMemberDecorate %u_block_std140 0 Offset 0
-               OpMemberDecorate %S_std140 0 Offset 0
-               OpMemberDecorate %S_std140 1 Offset 8
-               OpMemberDecorate %S_std140 2 Offset 16
-               OpMemberDecorate %S_std140 3 Offset 24
-               OpMemberDecorate %S_std140 4 Offset 32
-               OpMemberDecorate %S_std140 5 Offset 40
-               OpDecorate %_arr_S_std140_uint_4 ArrayStride 48
-               OpDecorate %u NonWritable
-               OpDecorate %u DescriptorSet 0
-               OpDecorate %u Binding 0
-        %int = OpTypeInt 32 1
-      %float = OpTypeFloat 32
-    %v2float = OpTypeVector %float 2
-   %S_std140 = OpTypeStruct %int %v2float %v2float %v2float %v2float %int
-       %uint = OpTypeInt 32 0
-     %uint_4 = OpConstant %uint 4
-%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
-%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
-%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
-          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
-%mat4v2float = OpTypeMatrix %v2float 4
-         %11 = OpTypeFunction %mat4v2float
-     %uint_0 = OpConstant %uint 0
-     %uint_2 = OpConstant %uint 2
-%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
-     %uint_1 = OpConstant %uint 1
-%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
-     %uint_3 = OpConstant %uint 3
-       %void = OpTypeVoid
-         %36 = OpTypeFunction %void
-    %v4float = OpTypeVector %float 4
-%mat2v4float = OpTypeMatrix %v4float 2
-         %46 = OpConstantNull %uint
-%load_u_inner_2_m = OpFunction %mat4v2float None %11
-         %14 = OpLabel
-         %19 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
-         %23 = OpAccessChain %_ptr_Uniform_v2float %19 %uint_1
-         %24 = OpLoad %v2float %23
-         %26 = OpAccessChain %_ptr_Uniform_v2float %19 %uint_2
-         %27 = OpLoad %v2float %26
-         %30 = OpAccessChain %_ptr_Uniform_v2float %19 %uint_3
-         %31 = OpLoad %v2float %30
-         %33 = OpAccessChain %_ptr_Uniform_v2float %19 %uint_4
-         %34 = OpLoad %v2float %33
-         %35 = OpCompositeConstruct %mat4v2float %24 %27 %31 %34
-               OpReturnValue %35
-               OpFunctionEnd
-          %f = OpFunction %void None %36
-         %39 = OpLabel
-         %43 = OpFunctionCall %mat4v2float %load_u_inner_2_m
-         %40 = OpTranspose %mat2v4float %43
-         %47 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %46 %uint_2
-         %48 = OpLoad %v2float %47
-         %49 = OpVectorShuffle %v2float %48 %48 1 0
-         %44 = OpExtInst %float %45 Length %49
-         %51 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %46 %uint_2
-         %52 = OpLoad %v2float %51
-         %53 = OpVectorShuffle %v2float %52 %52 1 0
-         %54 = OpCompositeExtract %float %53 0
-         %50 = OpExtInst %float %45 FAbs %54
-               OpReturn
-               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x2/to_builtin.wgsl.expected.wgsl
deleted file mode 100644
index 59bf43d..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/to_builtin.wgsl.expected.wgsl
+++ /dev/null
@@ -1,14 +0,0 @@
-struct S {
-  before : i32,
-  m : mat4x2<f32>,
-  after : i32,
-}
-
-@group(0) @binding(0) var<uniform> u : array<S, 4>;
-
-@compute @workgroup_size(1)
-fn f() {
-  let t = transpose(u[2].m);
-  let l = length(u[0].m[1].yx);
-  let a = abs(u[0].m[1].yx.x);
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/to_fn.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x2/to_fn.wgsl
deleted file mode 100644
index 41ca70c..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/to_fn.wgsl
+++ /dev/null
@@ -1,22 +0,0 @@
-struct S {
-  before : i32,
-  m : mat4x2<f32>,
-  after : i32,
-}
-
-@group(0) @binding(0) var<uniform> u : array<S, 4>;
-
-fn a(a : array<S, 4>) {}
-fn b(s : S) {}
-fn c(m : mat4x2<f32>) {}
-fn d(v : vec2<f32>) {}
-fn e(f : f32) {}
-
-@compute @workgroup_size(1)
-fn f() {
-    a(u);
-    b(u[2]);
-    c(u[2].m);
-    d(u[0].m[1].yx);
-    e(u[0].m[1].yx.x);
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x2/to_fn.wgsl.expected.dxc.hlsl
deleted file mode 100644
index 20e3b99..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/to_fn.wgsl.expected.dxc.hlsl
+++ /dev/null
@@ -1,64 +0,0 @@
-struct S {
-  int before;
-  float4x2 m;
-  int after;
-};
-
-cbuffer cbuffer_u : register(b0, space0) {
-  uint4 u[12];
-};
-
-void a(S a_1[4]) {
-}
-
-void b(S s) {
-}
-
-void c(float4x2 m) {
-}
-
-void d(float2 v) {
-}
-
-void e(float f_1) {
-}
-
-float4x2 tint_symbol_3(uint4 buffer[12], uint offset) {
-  const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset / 4];
-  const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
-  const uint scalar_offset_2 = ((offset + 16u)) / 4;
-  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
-  const uint scalar_offset_3 = ((offset + 24u)) / 4;
-  uint4 ubo_load_3 = buffer[scalar_offset_3 / 4];
-  return float4x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)), asfloat(((scalar_offset_3 & 2) ? ubo_load_3.zw : ubo_load_3.xy)));
-}
-
-S tint_symbol_1(uint4 buffer[12], uint offset) {
-  const uint scalar_offset_4 = ((offset + 0u)) / 4;
-  const uint scalar_offset_5 = ((offset + 40u)) / 4;
-  const S tint_symbol_5 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
-  return tint_symbol_5;
-}
-
-typedef S tint_symbol_ret[4];
-tint_symbol_ret tint_symbol(uint4 buffer[12], uint offset) {
-  S arr[4] = (S[4])0;
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      arr[i] = tint_symbol_1(buffer, (offset + (i * 48u)));
-    }
-  }
-  return arr;
-}
-
-[numthreads(1, 1, 1)]
-void f() {
-  a(tint_symbol(u, 0u));
-  b(tint_symbol_1(u, 96u));
-  c(tint_symbol_3(u, 104u));
-  d(asfloat(u[1].xy).yx);
-  e(asfloat(u[1].xy).yx.x);
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x2/to_fn.wgsl.expected.fxc.hlsl
deleted file mode 100644
index 20e3b99..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/to_fn.wgsl.expected.fxc.hlsl
+++ /dev/null
@@ -1,64 +0,0 @@
-struct S {
-  int before;
-  float4x2 m;
-  int after;
-};
-
-cbuffer cbuffer_u : register(b0, space0) {
-  uint4 u[12];
-};
-
-void a(S a_1[4]) {
-}
-
-void b(S s) {
-}
-
-void c(float4x2 m) {
-}
-
-void d(float2 v) {
-}
-
-void e(float f_1) {
-}
-
-float4x2 tint_symbol_3(uint4 buffer[12], uint offset) {
-  const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset / 4];
-  const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
-  const uint scalar_offset_2 = ((offset + 16u)) / 4;
-  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
-  const uint scalar_offset_3 = ((offset + 24u)) / 4;
-  uint4 ubo_load_3 = buffer[scalar_offset_3 / 4];
-  return float4x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)), asfloat(((scalar_offset_3 & 2) ? ubo_load_3.zw : ubo_load_3.xy)));
-}
-
-S tint_symbol_1(uint4 buffer[12], uint offset) {
-  const uint scalar_offset_4 = ((offset + 0u)) / 4;
-  const uint scalar_offset_5 = ((offset + 40u)) / 4;
-  const S tint_symbol_5 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
-  return tint_symbol_5;
-}
-
-typedef S tint_symbol_ret[4];
-tint_symbol_ret tint_symbol(uint4 buffer[12], uint offset) {
-  S arr[4] = (S[4])0;
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      arr[i] = tint_symbol_1(buffer, (offset + (i * 48u)));
-    }
-  }
-  return arr;
-}
-
-[numthreads(1, 1, 1)]
-void f() {
-  a(tint_symbol(u, 0u));
-  b(tint_symbol_1(u, 96u));
-  c(tint_symbol_3(u, 104u));
-  d(asfloat(u[1].xy).yx);
-  e(asfloat(u[1].xy).yx.x);
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x2/to_fn.wgsl.expected.glsl
deleted file mode 100644
index 43a4f88..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/to_fn.wgsl.expected.glsl
+++ /dev/null
@@ -1,71 +0,0 @@
-#version 310 es
-
-struct S {
-  int before;
-  uint pad;
-  mat4x2 m;
-  int after;
-  uint pad_1;
-};
-
-struct S_std140 {
-  int before;
-  uint pad;
-  vec2 m_0;
-  vec2 m_1;
-  vec2 m_2;
-  vec2 m_3;
-  int after;
-  uint pad_1;
-};
-
-layout(binding = 0, std140) uniform u_block_std140_ubo {
-  S_std140 inner[4];
-} u;
-
-void a(S a_1[4]) {
-}
-
-void b(S s) {
-}
-
-void c(mat4x2 m) {
-}
-
-void d(vec2 v) {
-}
-
-void e(float f_1) {
-}
-
-S conv_S(S_std140 val) {
-  return S(val.before, val.pad, mat4x2(val.m_0, val.m_1, val.m_2, val.m_3), val.after, val.pad_1);
-}
-
-S[4] conv_arr4_S(S_std140 val[4]) {
-  S arr[4] = S[4](S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0, 0u));
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      arr[i] = conv_S(val[i]);
-    }
-  }
-  return arr;
-}
-
-mat4x2 load_u_inner_2_m() {
-  return mat4x2(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2, u.inner[2u].m_3);
-}
-
-void f() {
-  a(conv_arr4_S(u.inner));
-  b(conv_S(u.inner[2u]));
-  c(load_u_inner_2_m());
-  d(u.inner[0u].m_1.yx);
-  e(u.inner[0u].m_1.yx[0u]);
-}
-
-layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
-void main() {
-  f();
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x2/to_fn.wgsl.expected.msl
deleted file mode 100644
index 61f3150..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/to_fn.wgsl.expected.msl
+++ /dev/null
@@ -1,48 +0,0 @@
-#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 S {
-  /* 0x0000 */ int before;
-  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
-  /* 0x0008 */ float4x2 m;
-  /* 0x0028 */ int after;
-  /* 0x002c */ tint_array<int8_t, 4> tint_pad_1;
-};
-
-void a(tint_array<S, 4> a_1) {
-}
-
-void b(S s) {
-}
-
-void c(float4x2 m) {
-}
-
-void d(float2 v) {
-}
-
-void e(float f_1) {
-}
-
-kernel void f(const constant tint_array<S, 4>* tint_symbol [[buffer(0)]]) {
-  a(*(tint_symbol));
-  b((*(tint_symbol))[2]);
-  c((*(tint_symbol))[2].m);
-  d(float2((*(tint_symbol))[0].m[1]).yx);
-  e(float2((*(tint_symbol))[0].m[1]).yx[0]);
-  return;
-}
-
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x2/to_fn.wgsl.expected.spvasm
deleted file mode 100644
index 63abbf3..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/to_fn.wgsl.expected.spvasm
+++ /dev/null
@@ -1,211 +0,0 @@
-; SPIR-V
-; Version: 1.3
-; Generator: Google Tint Compiler; 0
-; Bound: 128
-; Schema: 0
-               OpCapability Shader
-               OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %f "f"
-               OpExecutionMode %f LocalSize 1 1 1
-               OpName %u_block_std140 "u_block_std140"
-               OpMemberName %u_block_std140 0 "inner"
-               OpName %S_std140 "S_std140"
-               OpMemberName %S_std140 0 "before"
-               OpMemberName %S_std140 1 "m_0"
-               OpMemberName %S_std140 2 "m_1"
-               OpMemberName %S_std140 3 "m_2"
-               OpMemberName %S_std140 4 "m_3"
-               OpMemberName %S_std140 5 "after"
-               OpName %u "u"
-               OpName %S "S"
-               OpMemberName %S 0 "before"
-               OpMemberName %S 1 "m"
-               OpMemberName %S 2 "after"
-               OpName %a "a"
-               OpName %a_1 "a_1"
-               OpName %b "b"
-               OpName %s "s"
-               OpName %c "c"
-               OpName %m "m"
-               OpName %d "d"
-               OpName %v "v"
-               OpName %e "e"
-               OpName %f_1 "f_1"
-               OpName %conv_S "conv_S"
-               OpName %val "val"
-               OpName %conv_arr4_S "conv_arr4_S"
-               OpName %val_0 "val"
-               OpName %arr "arr"
-               OpName %i "i"
-               OpName %var_for_index "var_for_index"
-               OpName %load_u_inner_2_m "load_u_inner_2_m"
-               OpName %f "f"
-               OpDecorate %u_block_std140 Block
-               OpMemberDecorate %u_block_std140 0 Offset 0
-               OpMemberDecorate %S_std140 0 Offset 0
-               OpMemberDecorate %S_std140 1 Offset 8
-               OpMemberDecorate %S_std140 2 Offset 16
-               OpMemberDecorate %S_std140 3 Offset 24
-               OpMemberDecorate %S_std140 4 Offset 32
-               OpMemberDecorate %S_std140 5 Offset 40
-               OpDecorate %_arr_S_std140_uint_4 ArrayStride 48
-               OpDecorate %u NonWritable
-               OpDecorate %u DescriptorSet 0
-               OpDecorate %u Binding 0
-               OpMemberDecorate %S 0 Offset 0
-               OpMemberDecorate %S 1 Offset 8
-               OpMemberDecorate %S 1 ColMajor
-               OpMemberDecorate %S 1 MatrixStride 8
-               OpMemberDecorate %S 2 Offset 40
-               OpDecorate %_arr_S_uint_4 ArrayStride 48
-        %int = OpTypeInt 32 1
-      %float = OpTypeFloat 32
-    %v2float = OpTypeVector %float 2
-   %S_std140 = OpTypeStruct %int %v2float %v2float %v2float %v2float %int
-       %uint = OpTypeInt 32 0
-     %uint_4 = OpConstant %uint 4
-%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
-%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
-%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
-          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
-       %void = OpTypeVoid
-%mat4v2float = OpTypeMatrix %v2float 4
-          %S = OpTypeStruct %int %mat4v2float %int
-%_arr_S_uint_4 = OpTypeArray %S %uint_4
-         %11 = OpTypeFunction %void %_arr_S_uint_4
-         %19 = OpTypeFunction %void %S
-         %23 = OpTypeFunction %void %mat4v2float
-         %27 = OpTypeFunction %void %v2float
-         %31 = OpTypeFunction %void %float
-         %35 = OpTypeFunction %S %S_std140
-         %47 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
-%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
-         %53 = OpConstantNull %_arr_S_uint_4
-%_ptr_Function_uint = OpTypePointer Function %uint
-         %56 = OpConstantNull %uint
-       %bool = OpTypeBool
-%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
-         %69 = OpConstantNull %_arr_S_std140_uint_4
-%_ptr_Function_S = OpTypePointer Function %S
-%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
-     %uint_1 = OpConstant %uint 1
-         %82 = OpTypeFunction %mat4v2float
-     %uint_0 = OpConstant %uint 0
-     %uint_2 = OpConstant %uint 2
-%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
-%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
-     %uint_3 = OpConstant %uint 3
-        %105 = OpTypeFunction %void
-%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
-          %a = OpFunction %void None %11
-        %a_1 = OpFunctionParameter %_arr_S_uint_4
-         %18 = OpLabel
-               OpReturn
-               OpFunctionEnd
-          %b = OpFunction %void None %19
-          %s = OpFunctionParameter %S
-         %22 = OpLabel
-               OpReturn
-               OpFunctionEnd
-          %c = OpFunction %void None %23
-          %m = OpFunctionParameter %mat4v2float
-         %26 = OpLabel
-               OpReturn
-               OpFunctionEnd
-          %d = OpFunction %void None %27
-          %v = OpFunctionParameter %v2float
-         %30 = OpLabel
-               OpReturn
-               OpFunctionEnd
-          %e = OpFunction %void None %31
-        %f_1 = OpFunctionParameter %float
-         %34 = OpLabel
-               OpReturn
-               OpFunctionEnd
-     %conv_S = OpFunction %S None %35
-        %val = OpFunctionParameter %S_std140
-         %38 = OpLabel
-         %39 = OpCompositeExtract %int %val 0
-         %40 = OpCompositeExtract %v2float %val 1
-         %41 = OpCompositeExtract %v2float %val 2
-         %42 = OpCompositeExtract %v2float %val 3
-         %43 = OpCompositeExtract %v2float %val 4
-         %44 = OpCompositeConstruct %mat4v2float %40 %41 %42 %43
-         %45 = OpCompositeExtract %int %val 5
-         %46 = OpCompositeConstruct %S %39 %44 %45
-               OpReturnValue %46
-               OpFunctionEnd
-%conv_arr4_S = OpFunction %_arr_S_uint_4 None %47
-      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
-         %50 = OpLabel
-        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %53
-          %i = OpVariable %_ptr_Function_uint Function %56
-%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %69
-               OpBranch %57
-         %57 = OpLabel
-               OpLoopMerge %58 %59 None
-               OpBranch %60
-         %60 = OpLabel
-         %62 = OpLoad %uint %i
-         %63 = OpULessThan %bool %62 %uint_4
-         %61 = OpLogicalNot %bool %63
-               OpSelectionMerge %65 None
-               OpBranchConditional %61 %66 %65
-         %66 = OpLabel
-               OpBranch %58
-         %65 = OpLabel
-               OpStore %var_for_index %val_0
-         %70 = OpLoad %uint %i
-         %72 = OpAccessChain %_ptr_Function_S %arr %70
-         %74 = OpLoad %uint %i
-         %76 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %74
-         %77 = OpLoad %S_std140 %76
-         %73 = OpFunctionCall %S %conv_S %77
-               OpStore %72 %73
-               OpBranch %59
-         %59 = OpLabel
-         %78 = OpLoad %uint %i
-         %80 = OpIAdd %uint %78 %uint_1
-               OpStore %i %80
-               OpBranch %57
-         %58 = OpLabel
-         %81 = OpLoad %_arr_S_uint_4 %arr
-               OpReturnValue %81
-               OpFunctionEnd
-%load_u_inner_2_m = OpFunction %mat4v2float None %82
-         %84 = OpLabel
-         %89 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
-         %92 = OpAccessChain %_ptr_Uniform_v2float %89 %uint_1
-         %93 = OpLoad %v2float %92
-         %95 = OpAccessChain %_ptr_Uniform_v2float %89 %uint_2
-         %96 = OpLoad %v2float %95
-         %99 = OpAccessChain %_ptr_Uniform_v2float %89 %uint_3
-        %100 = OpLoad %v2float %99
-        %102 = OpAccessChain %_ptr_Uniform_v2float %89 %uint_4
-        %103 = OpLoad %v2float %102
-        %104 = OpCompositeConstruct %mat4v2float %93 %96 %100 %103
-               OpReturnValue %104
-               OpFunctionEnd
-          %f = OpFunction %void None %105
-        %107 = OpLabel
-        %111 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
-        %112 = OpLoad %_arr_S_std140_uint_4 %111
-        %109 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %112
-        %108 = OpFunctionCall %void %a %109
-        %115 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
-        %116 = OpLoad %S_std140 %115
-        %114 = OpFunctionCall %S %conv_S %116
-        %113 = OpFunctionCall %void %b %114
-        %118 = OpFunctionCall %mat4v2float %load_u_inner_2_m
-        %117 = OpFunctionCall %void %c %118
-        %120 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %56 %uint_2
-        %121 = OpLoad %v2float %120
-        %122 = OpVectorShuffle %v2float %121 %121 1 0
-        %119 = OpFunctionCall %void %d %122
-        %124 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %56 %uint_2
-        %125 = OpLoad %v2float %124
-        %126 = OpVectorShuffle %v2float %125 %125 1 0
-        %127 = OpCompositeExtract %float %126 0
-        %123 = OpFunctionCall %void %e %127
-               OpReturn
-               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x2/to_fn.wgsl.expected.wgsl
deleted file mode 100644
index 29258cc..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/to_fn.wgsl.expected.wgsl
+++ /dev/null
@@ -1,31 +0,0 @@
-struct S {
-  before : i32,
-  m : mat4x2<f32>,
-  after : i32,
-}
-
-@group(0) @binding(0) var<uniform> u : array<S, 4>;
-
-fn a(a : array<S, 4>) {
-}
-
-fn b(s : S) {
-}
-
-fn c(m : mat4x2<f32>) {
-}
-
-fn d(v : vec2<f32>) {
-}
-
-fn e(f : f32) {
-}
-
-@compute @workgroup_size(1)
-fn f() {
-  a(u);
-  b(u[2]);
-  c(u[2].m);
-  d(u[0].m[1].yx);
-  e(u[0].m[1].yx.x);
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/to_private.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x2/to_private.wgsl
deleted file mode 100644
index 4d8b759..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/to_private.wgsl
+++ /dev/null
@@ -1,16 +0,0 @@
-struct S {
-  before : i32,
-  m : mat4x2<f32>,
-  after : i32,
-}
-
-@group(0) @binding(0) var<uniform> u : array<S, 4>;
-var<private> p : array<S, 4>;
-
-@compute @workgroup_size(1)
-fn f() {
-    p = u;
-    p[1] = u[2];
-    p[3].m = u[2].m;
-    p[1].m[0] = u[0].m[1].yx;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x2/to_private.wgsl.expected.dxc.hlsl
deleted file mode 100644
index 1483eb4..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/to_private.wgsl.expected.dxc.hlsl
+++ /dev/null
@@ -1,49 +0,0 @@
-struct S {
-  int before;
-  float4x2 m;
-  int after;
-};
-
-cbuffer cbuffer_u : register(b0, space0) {
-  uint4 u[12];
-};
-static S p[4] = (S[4])0;
-
-float4x2 tint_symbol_3(uint4 buffer[12], uint offset) {
-  const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset / 4];
-  const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
-  const uint scalar_offset_2 = ((offset + 16u)) / 4;
-  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
-  const uint scalar_offset_3 = ((offset + 24u)) / 4;
-  uint4 ubo_load_3 = buffer[scalar_offset_3 / 4];
-  return float4x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)), asfloat(((scalar_offset_3 & 2) ? ubo_load_3.zw : ubo_load_3.xy)));
-}
-
-S tint_symbol_1(uint4 buffer[12], uint offset) {
-  const uint scalar_offset_4 = ((offset + 0u)) / 4;
-  const uint scalar_offset_5 = ((offset + 40u)) / 4;
-  const S tint_symbol_5 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
-  return tint_symbol_5;
-}
-
-typedef S tint_symbol_ret[4];
-tint_symbol_ret tint_symbol(uint4 buffer[12], uint offset) {
-  S arr[4] = (S[4])0;
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      arr[i] = tint_symbol_1(buffer, (offset + (i * 48u)));
-    }
-  }
-  return arr;
-}
-
-[numthreads(1, 1, 1)]
-void f() {
-  p = tint_symbol(u, 0u);
-  p[1] = tint_symbol_1(u, 96u);
-  p[3].m = tint_symbol_3(u, 104u);
-  p[1].m[0] = asfloat(u[1].xy).yx;
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x2/to_private.wgsl.expected.fxc.hlsl
deleted file mode 100644
index 1483eb4..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/to_private.wgsl.expected.fxc.hlsl
+++ /dev/null
@@ -1,49 +0,0 @@
-struct S {
-  int before;
-  float4x2 m;
-  int after;
-};
-
-cbuffer cbuffer_u : register(b0, space0) {
-  uint4 u[12];
-};
-static S p[4] = (S[4])0;
-
-float4x2 tint_symbol_3(uint4 buffer[12], uint offset) {
-  const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset / 4];
-  const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
-  const uint scalar_offset_2 = ((offset + 16u)) / 4;
-  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
-  const uint scalar_offset_3 = ((offset + 24u)) / 4;
-  uint4 ubo_load_3 = buffer[scalar_offset_3 / 4];
-  return float4x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)), asfloat(((scalar_offset_3 & 2) ? ubo_load_3.zw : ubo_load_3.xy)));
-}
-
-S tint_symbol_1(uint4 buffer[12], uint offset) {
-  const uint scalar_offset_4 = ((offset + 0u)) / 4;
-  const uint scalar_offset_5 = ((offset + 40u)) / 4;
-  const S tint_symbol_5 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
-  return tint_symbol_5;
-}
-
-typedef S tint_symbol_ret[4];
-tint_symbol_ret tint_symbol(uint4 buffer[12], uint offset) {
-  S arr[4] = (S[4])0;
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      arr[i] = tint_symbol_1(buffer, (offset + (i * 48u)));
-    }
-  }
-  return arr;
-}
-
-[numthreads(1, 1, 1)]
-void f() {
-  p = tint_symbol(u, 0u);
-  p[1] = tint_symbol_1(u, 96u);
-  p[3].m = tint_symbol_3(u, 104u);
-  p[1].m[0] = asfloat(u[1].xy).yx;
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x2/to_private.wgsl.expected.glsl
deleted file mode 100644
index 1ff8aa4..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/to_private.wgsl.expected.glsl
+++ /dev/null
@@ -1,56 +0,0 @@
-#version 310 es
-
-struct S {
-  int before;
-  uint pad;
-  mat4x2 m;
-  int after;
-  uint pad_1;
-};
-
-struct S_std140 {
-  int before;
-  uint pad;
-  vec2 m_0;
-  vec2 m_1;
-  vec2 m_2;
-  vec2 m_3;
-  int after;
-  uint pad_1;
-};
-
-layout(binding = 0, std140) uniform u_block_std140_ubo {
-  S_std140 inner[4];
-} u;
-
-S p[4] = S[4](S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0, 0u));
-S conv_S(S_std140 val) {
-  return S(val.before, val.pad, mat4x2(val.m_0, val.m_1, val.m_2, val.m_3), val.after, val.pad_1);
-}
-
-S[4] conv_arr4_S(S_std140 val[4]) {
-  S arr[4] = S[4](S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0, 0u));
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      arr[i] = conv_S(val[i]);
-    }
-  }
-  return arr;
-}
-
-mat4x2 load_u_inner_2_m() {
-  return mat4x2(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2, u.inner[2u].m_3);
-}
-
-void f() {
-  p = conv_arr4_S(u.inner);
-  p[1] = conv_S(u.inner[2u]);
-  p[3].m = load_u_inner_2_m();
-  p[1].m[0] = u.inner[0u].m_1.yx;
-}
-
-layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
-void main() {
-  f();
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x2/to_private.wgsl.expected.msl
deleted file mode 100644
index c5f914c..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/to_private.wgsl.expected.msl
+++ /dev/null
@@ -1,33 +0,0 @@
-#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 S {
-  /* 0x0000 */ int before;
-  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
-  /* 0x0008 */ float4x2 m;
-  /* 0x0028 */ int after;
-  /* 0x002c */ tint_array<int8_t, 4> tint_pad_1;
-};
-
-kernel void f(const constant tint_array<S, 4>* tint_symbol_1 [[buffer(0)]]) {
-  thread tint_array<S, 4> tint_symbol = {};
-  tint_symbol = *(tint_symbol_1);
-  tint_symbol[1] = (*(tint_symbol_1))[2];
-  tint_symbol[3].m = (*(tint_symbol_1))[2].m;
-  tint_symbol[1].m[0] = float2((*(tint_symbol_1))[0].m[1]).yx;
-  return;
-}
-
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x2/to_private.wgsl.expected.spvasm
deleted file mode 100644
index e0ac972..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/to_private.wgsl.expected.spvasm
+++ /dev/null
@@ -1,178 +0,0 @@
-; SPIR-V
-; Version: 1.3
-; Generator: Google Tint Compiler; 0
-; Bound: 110
-; Schema: 0
-               OpCapability Shader
-               OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %f "f"
-               OpExecutionMode %f LocalSize 1 1 1
-               OpName %u_block_std140 "u_block_std140"
-               OpMemberName %u_block_std140 0 "inner"
-               OpName %S_std140 "S_std140"
-               OpMemberName %S_std140 0 "before"
-               OpMemberName %S_std140 1 "m_0"
-               OpMemberName %S_std140 2 "m_1"
-               OpMemberName %S_std140 3 "m_2"
-               OpMemberName %S_std140 4 "m_3"
-               OpMemberName %S_std140 5 "after"
-               OpName %u "u"
-               OpName %S "S"
-               OpMemberName %S 0 "before"
-               OpMemberName %S 1 "m"
-               OpMemberName %S 2 "after"
-               OpName %p "p"
-               OpName %conv_S "conv_S"
-               OpName %val "val"
-               OpName %conv_arr4_S "conv_arr4_S"
-               OpName %val_0 "val"
-               OpName %arr "arr"
-               OpName %i "i"
-               OpName %var_for_index "var_for_index"
-               OpName %load_u_inner_2_m "load_u_inner_2_m"
-               OpName %f "f"
-               OpDecorate %u_block_std140 Block
-               OpMemberDecorate %u_block_std140 0 Offset 0
-               OpMemberDecorate %S_std140 0 Offset 0
-               OpMemberDecorate %S_std140 1 Offset 8
-               OpMemberDecorate %S_std140 2 Offset 16
-               OpMemberDecorate %S_std140 3 Offset 24
-               OpMemberDecorate %S_std140 4 Offset 32
-               OpMemberDecorate %S_std140 5 Offset 40
-               OpDecorate %_arr_S_std140_uint_4 ArrayStride 48
-               OpDecorate %u NonWritable
-               OpDecorate %u DescriptorSet 0
-               OpDecorate %u Binding 0
-               OpMemberDecorate %S 0 Offset 0
-               OpMemberDecorate %S 1 Offset 8
-               OpMemberDecorate %S 1 ColMajor
-               OpMemberDecorate %S 1 MatrixStride 8
-               OpMemberDecorate %S 2 Offset 40
-               OpDecorate %_arr_S_uint_4 ArrayStride 48
-        %int = OpTypeInt 32 1
-      %float = OpTypeFloat 32
-    %v2float = OpTypeVector %float 2
-   %S_std140 = OpTypeStruct %int %v2float %v2float %v2float %v2float %int
-       %uint = OpTypeInt 32 0
-     %uint_4 = OpConstant %uint 4
-%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
-%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
-%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
-          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
-%mat4v2float = OpTypeMatrix %v2float 4
-          %S = OpTypeStruct %int %mat4v2float %int
-%_arr_S_uint_4 = OpTypeArray %S %uint_4
-%_ptr_Private__arr_S_uint_4 = OpTypePointer Private %_arr_S_uint_4
-         %16 = OpConstantNull %_arr_S_uint_4
-          %p = OpVariable %_ptr_Private__arr_S_uint_4 Private %16
-         %17 = OpTypeFunction %S %S_std140
-         %29 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
-%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
-%_ptr_Function_uint = OpTypePointer Function %uint
-         %37 = OpConstantNull %uint
-       %bool = OpTypeBool
-%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
-         %50 = OpConstantNull %_arr_S_std140_uint_4
-%_ptr_Function_S = OpTypePointer Function %S
-%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
-     %uint_1 = OpConstant %uint 1
-         %63 = OpTypeFunction %mat4v2float
-     %uint_0 = OpConstant %uint 0
-     %uint_2 = OpConstant %uint 2
-%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
-%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
-     %uint_3 = OpConstant %uint 3
-       %void = OpTypeVoid
-         %86 = OpTypeFunction %void
-%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
-      %int_1 = OpConstant %int 1
-%_ptr_Private_S = OpTypePointer Private %S
-      %int_3 = OpConstant %int 3
-%_ptr_Private_mat4v2float = OpTypePointer Private %mat4v2float
-        %104 = OpConstantNull %int
-%_ptr_Private_v2float = OpTypePointer Private %v2float
-     %conv_S = OpFunction %S None %17
-        %val = OpFunctionParameter %S_std140
-         %20 = OpLabel
-         %21 = OpCompositeExtract %int %val 0
-         %22 = OpCompositeExtract %v2float %val 1
-         %23 = OpCompositeExtract %v2float %val 2
-         %24 = OpCompositeExtract %v2float %val 3
-         %25 = OpCompositeExtract %v2float %val 4
-         %26 = OpCompositeConstruct %mat4v2float %22 %23 %24 %25
-         %27 = OpCompositeExtract %int %val 5
-         %28 = OpCompositeConstruct %S %21 %26 %27
-               OpReturnValue %28
-               OpFunctionEnd
-%conv_arr4_S = OpFunction %_arr_S_uint_4 None %29
-      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
-         %32 = OpLabel
-        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %16
-          %i = OpVariable %_ptr_Function_uint Function %37
-%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %50
-               OpBranch %38
-         %38 = OpLabel
-               OpLoopMerge %39 %40 None
-               OpBranch %41
-         %41 = OpLabel
-         %43 = OpLoad %uint %i
-         %44 = OpULessThan %bool %43 %uint_4
-         %42 = OpLogicalNot %bool %44
-               OpSelectionMerge %46 None
-               OpBranchConditional %42 %47 %46
-         %47 = OpLabel
-               OpBranch %39
-         %46 = OpLabel
-               OpStore %var_for_index %val_0
-         %51 = OpLoad %uint %i
-         %53 = OpAccessChain %_ptr_Function_S %arr %51
-         %55 = OpLoad %uint %i
-         %57 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %55
-         %58 = OpLoad %S_std140 %57
-         %54 = OpFunctionCall %S %conv_S %58
-               OpStore %53 %54
-               OpBranch %40
-         %40 = OpLabel
-         %59 = OpLoad %uint %i
-         %61 = OpIAdd %uint %59 %uint_1
-               OpStore %i %61
-               OpBranch %38
-         %39 = OpLabel
-         %62 = OpLoad %_arr_S_uint_4 %arr
-               OpReturnValue %62
-               OpFunctionEnd
-%load_u_inner_2_m = OpFunction %mat4v2float None %63
-         %65 = OpLabel
-         %70 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
-         %73 = OpAccessChain %_ptr_Uniform_v2float %70 %uint_1
-         %74 = OpLoad %v2float %73
-         %76 = OpAccessChain %_ptr_Uniform_v2float %70 %uint_2
-         %77 = OpLoad %v2float %76
-         %80 = OpAccessChain %_ptr_Uniform_v2float %70 %uint_3
-         %81 = OpLoad %v2float %80
-         %83 = OpAccessChain %_ptr_Uniform_v2float %70 %uint_4
-         %84 = OpLoad %v2float %83
-         %85 = OpCompositeConstruct %mat4v2float %74 %77 %81 %84
-               OpReturnValue %85
-               OpFunctionEnd
-          %f = OpFunction %void None %86
-         %89 = OpLabel
-         %92 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
-         %93 = OpLoad %_arr_S_std140_uint_4 %92
-         %90 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %93
-               OpStore %p %90
-         %96 = OpAccessChain %_ptr_Private_S %p %int_1
-         %98 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
-         %99 = OpLoad %S_std140 %98
-         %97 = OpFunctionCall %S %conv_S %99
-               OpStore %96 %97
-        %102 = OpAccessChain %_ptr_Private_mat4v2float %p %int_3 %uint_1
-        %103 = OpFunctionCall %mat4v2float %load_u_inner_2_m
-               OpStore %102 %103
-        %106 = OpAccessChain %_ptr_Private_v2float %p %int_1 %uint_1 %104
-        %107 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %37 %uint_2
-        %108 = OpLoad %v2float %107
-        %109 = OpVectorShuffle %v2float %108 %108 1 0
-               OpStore %106 %109
-               OpReturn
-               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x2/to_private.wgsl.expected.wgsl
deleted file mode 100644
index 32b45e1..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/to_private.wgsl.expected.wgsl
+++ /dev/null
@@ -1,17 +0,0 @@
-struct S {
-  before : i32,
-  m : mat4x2<f32>,
-  after : i32,
-}
-
-@group(0) @binding(0) var<uniform> u : array<S, 4>;
-
-var<private> p : array<S, 4>;
-
-@compute @workgroup_size(1)
-fn f() {
-  p = u;
-  p[1] = u[2];
-  p[3].m = u[2].m;
-  p[1].m[0] = u[0].m[1].yx;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/to_storage.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x2/to_storage.wgsl
deleted file mode 100644
index 692ff38..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/to_storage.wgsl
+++ /dev/null
@@ -1,16 +0,0 @@
-struct S {
-  before : i32,
-  m : mat4x2<f32>,
-  after : i32,
-}
-
-@group(0) @binding(0) var<uniform> u : array<S, 4>;
-@group(0) @binding(1) var<storage, read_write> s : array<S, 4>;
-
-@compute @workgroup_size(1)
-fn f() {
-    s = u;
-    s[1] = u[2];
-    s[3].m = u[2].m;
-    s[1].m[0] = u[0].m[1].yx;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x2/to_storage.wgsl.expected.dxc.hlsl
deleted file mode 100644
index 8fd3fb0..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/to_storage.wgsl.expected.dxc.hlsl
+++ /dev/null
@@ -1,71 +0,0 @@
-struct S {
-  int before;
-  float4x2 m;
-  int after;
-};
-
-cbuffer cbuffer_u : register(b0, space0) {
-  uint4 u[12];
-};
-RWByteAddressBuffer s : register(u1, space0);
-
-void tint_symbol_3(RWByteAddressBuffer buffer, uint offset, float4x2 value) {
-  buffer.Store2((offset + 0u), asuint(value[0u]));
-  buffer.Store2((offset + 8u), asuint(value[1u]));
-  buffer.Store2((offset + 16u), asuint(value[2u]));
-  buffer.Store2((offset + 24u), asuint(value[3u]));
-}
-
-void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, S value) {
-  buffer.Store((offset + 0u), asuint(value.before));
-  tint_symbol_3(buffer, (offset + 8u), value.m);
-  buffer.Store((offset + 40u), asuint(value.after));
-}
-
-void tint_symbol(RWByteAddressBuffer buffer, uint offset, S value[4]) {
-  S array[4] = value;
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      tint_symbol_1(buffer, (offset + (i * 48u)), array[i]);
-    }
-  }
-}
-
-float4x2 tint_symbol_8(uint4 buffer[12], uint offset) {
-  const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset / 4];
-  const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
-  const uint scalar_offset_2 = ((offset + 16u)) / 4;
-  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
-  const uint scalar_offset_3 = ((offset + 24u)) / 4;
-  uint4 ubo_load_3 = buffer[scalar_offset_3 / 4];
-  return float4x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)), asfloat(((scalar_offset_3 & 2) ? ubo_load_3.zw : ubo_load_3.xy)));
-}
-
-S tint_symbol_6(uint4 buffer[12], uint offset) {
-  const uint scalar_offset_4 = ((offset + 0u)) / 4;
-  const uint scalar_offset_5 = ((offset + 40u)) / 4;
-  const S tint_symbol_10 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_8(buffer, (offset + 8u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
-  return tint_symbol_10;
-}
-
-typedef S tint_symbol_5_ret[4];
-tint_symbol_5_ret tint_symbol_5(uint4 buffer[12], uint offset) {
-  S arr[4] = (S[4])0;
-  {
-    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
-      arr[i_1] = tint_symbol_6(buffer, (offset + (i_1 * 48u)));
-    }
-  }
-  return arr;
-}
-
-[numthreads(1, 1, 1)]
-void f() {
-  tint_symbol(s, 0u, tint_symbol_5(u, 0u));
-  tint_symbol_1(s, 48u, tint_symbol_6(u, 96u));
-  tint_symbol_3(s, 152u, tint_symbol_8(u, 104u));
-  s.Store2(56u, asuint(asfloat(u[1].xy).yx));
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x2/to_storage.wgsl.expected.fxc.hlsl
deleted file mode 100644
index 8fd3fb0..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/to_storage.wgsl.expected.fxc.hlsl
+++ /dev/null
@@ -1,71 +0,0 @@
-struct S {
-  int before;
-  float4x2 m;
-  int after;
-};
-
-cbuffer cbuffer_u : register(b0, space0) {
-  uint4 u[12];
-};
-RWByteAddressBuffer s : register(u1, space0);
-
-void tint_symbol_3(RWByteAddressBuffer buffer, uint offset, float4x2 value) {
-  buffer.Store2((offset + 0u), asuint(value[0u]));
-  buffer.Store2((offset + 8u), asuint(value[1u]));
-  buffer.Store2((offset + 16u), asuint(value[2u]));
-  buffer.Store2((offset + 24u), asuint(value[3u]));
-}
-
-void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, S value) {
-  buffer.Store((offset + 0u), asuint(value.before));
-  tint_symbol_3(buffer, (offset + 8u), value.m);
-  buffer.Store((offset + 40u), asuint(value.after));
-}
-
-void tint_symbol(RWByteAddressBuffer buffer, uint offset, S value[4]) {
-  S array[4] = value;
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      tint_symbol_1(buffer, (offset + (i * 48u)), array[i]);
-    }
-  }
-}
-
-float4x2 tint_symbol_8(uint4 buffer[12], uint offset) {
-  const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset / 4];
-  const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
-  const uint scalar_offset_2 = ((offset + 16u)) / 4;
-  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
-  const uint scalar_offset_3 = ((offset + 24u)) / 4;
-  uint4 ubo_load_3 = buffer[scalar_offset_3 / 4];
-  return float4x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)), asfloat(((scalar_offset_3 & 2) ? ubo_load_3.zw : ubo_load_3.xy)));
-}
-
-S tint_symbol_6(uint4 buffer[12], uint offset) {
-  const uint scalar_offset_4 = ((offset + 0u)) / 4;
-  const uint scalar_offset_5 = ((offset + 40u)) / 4;
-  const S tint_symbol_10 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_8(buffer, (offset + 8u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
-  return tint_symbol_10;
-}
-
-typedef S tint_symbol_5_ret[4];
-tint_symbol_5_ret tint_symbol_5(uint4 buffer[12], uint offset) {
-  S arr[4] = (S[4])0;
-  {
-    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
-      arr[i_1] = tint_symbol_6(buffer, (offset + (i_1 * 48u)));
-    }
-  }
-  return arr;
-}
-
-[numthreads(1, 1, 1)]
-void f() {
-  tint_symbol(s, 0u, tint_symbol_5(u, 0u));
-  tint_symbol_1(s, 48u, tint_symbol_6(u, 96u));
-  tint_symbol_3(s, 152u, tint_symbol_8(u, 104u));
-  s.Store2(56u, asuint(asfloat(u[1].xy).yx));
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x2/to_storage.wgsl.expected.glsl
deleted file mode 100644
index d9b6a9f..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/to_storage.wgsl.expected.glsl
+++ /dev/null
@@ -1,59 +0,0 @@
-#version 310 es
-
-struct S {
-  int before;
-  uint pad;
-  mat4x2 m;
-  int after;
-  uint pad_1;
-};
-
-struct S_std140 {
-  int before;
-  uint pad;
-  vec2 m_0;
-  vec2 m_1;
-  vec2 m_2;
-  vec2 m_3;
-  int after;
-  uint pad_1;
-};
-
-layout(binding = 0, std140) uniform u_block_std140_ubo {
-  S_std140 inner[4];
-} u;
-
-layout(binding = 1, std430) buffer u_block_ssbo {
-  S inner[4];
-} s;
-
-S conv_S(S_std140 val) {
-  return S(val.before, val.pad, mat4x2(val.m_0, val.m_1, val.m_2, val.m_3), val.after, val.pad_1);
-}
-
-S[4] conv_arr4_S(S_std140 val[4]) {
-  S arr[4] = S[4](S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0, 0u));
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      arr[i] = conv_S(val[i]);
-    }
-  }
-  return arr;
-}
-
-mat4x2 load_u_inner_2_m() {
-  return mat4x2(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2, u.inner[2u].m_3);
-}
-
-void f() {
-  s.inner = conv_arr4_S(u.inner);
-  s.inner[1] = conv_S(u.inner[2u]);
-  s.inner[3].m = load_u_inner_2_m();
-  s.inner[1].m[0] = u.inner[0u].m_1.yx;
-}
-
-layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
-void main() {
-  f();
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x2/to_storage.wgsl.expected.msl
deleted file mode 100644
index 9ef8ea3..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/to_storage.wgsl.expected.msl
+++ /dev/null
@@ -1,32 +0,0 @@
-#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 S {
-  /* 0x0000 */ int before;
-  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
-  /* 0x0008 */ float4x2 m;
-  /* 0x0028 */ int after;
-  /* 0x002c */ tint_array<int8_t, 4> tint_pad_1;
-};
-
-kernel void f(device tint_array<S, 4>* tint_symbol [[buffer(1)]], const constant tint_array<S, 4>* tint_symbol_1 [[buffer(0)]]) {
-  *(tint_symbol) = *(tint_symbol_1);
-  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
-  (*(tint_symbol))[3].m = (*(tint_symbol_1))[2].m;
-  (*(tint_symbol))[1].m[0] = float2((*(tint_symbol_1))[0].m[1]).yx;
-  return;
-}
-
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x2/to_storage.wgsl.expected.spvasm
deleted file mode 100644
index bcbfadc5..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/to_storage.wgsl.expected.spvasm
+++ /dev/null
@@ -1,187 +0,0 @@
-; SPIR-V
-; Version: 1.3
-; Generator: Google Tint Compiler; 0
-; Bound: 113
-; Schema: 0
-               OpCapability Shader
-               OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %f "f"
-               OpExecutionMode %f LocalSize 1 1 1
-               OpName %u_block_std140 "u_block_std140"
-               OpMemberName %u_block_std140 0 "inner"
-               OpName %S_std140 "S_std140"
-               OpMemberName %S_std140 0 "before"
-               OpMemberName %S_std140 1 "m_0"
-               OpMemberName %S_std140 2 "m_1"
-               OpMemberName %S_std140 3 "m_2"
-               OpMemberName %S_std140 4 "m_3"
-               OpMemberName %S_std140 5 "after"
-               OpName %u "u"
-               OpName %u_block "u_block"
-               OpMemberName %u_block 0 "inner"
-               OpName %S "S"
-               OpMemberName %S 0 "before"
-               OpMemberName %S 1 "m"
-               OpMemberName %S 2 "after"
-               OpName %s "s"
-               OpName %conv_S "conv_S"
-               OpName %val "val"
-               OpName %conv_arr4_S "conv_arr4_S"
-               OpName %val_0 "val"
-               OpName %arr "arr"
-               OpName %i "i"
-               OpName %var_for_index "var_for_index"
-               OpName %load_u_inner_2_m "load_u_inner_2_m"
-               OpName %f "f"
-               OpDecorate %u_block_std140 Block
-               OpMemberDecorate %u_block_std140 0 Offset 0
-               OpMemberDecorate %S_std140 0 Offset 0
-               OpMemberDecorate %S_std140 1 Offset 8
-               OpMemberDecorate %S_std140 2 Offset 16
-               OpMemberDecorate %S_std140 3 Offset 24
-               OpMemberDecorate %S_std140 4 Offset 32
-               OpMemberDecorate %S_std140 5 Offset 40
-               OpDecorate %_arr_S_std140_uint_4 ArrayStride 48
-               OpDecorate %u NonWritable
-               OpDecorate %u DescriptorSet 0
-               OpDecorate %u Binding 0
-               OpDecorate %u_block Block
-               OpMemberDecorate %u_block 0 Offset 0
-               OpMemberDecorate %S 0 Offset 0
-               OpMemberDecorate %S 1 Offset 8
-               OpMemberDecorate %S 1 ColMajor
-               OpMemberDecorate %S 1 MatrixStride 8
-               OpMemberDecorate %S 2 Offset 40
-               OpDecorate %_arr_S_uint_4 ArrayStride 48
-               OpDecorate %s DescriptorSet 0
-               OpDecorate %s Binding 1
-        %int = OpTypeInt 32 1
-      %float = OpTypeFloat 32
-    %v2float = OpTypeVector %float 2
-   %S_std140 = OpTypeStruct %int %v2float %v2float %v2float %v2float %int
-       %uint = OpTypeInt 32 0
-     %uint_4 = OpConstant %uint 4
-%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
-%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
-%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
-          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
-%mat4v2float = OpTypeMatrix %v2float 4
-          %S = OpTypeStruct %int %mat4v2float %int
-%_arr_S_uint_4 = OpTypeArray %S %uint_4
-    %u_block = OpTypeStruct %_arr_S_uint_4
-%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
-          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
-         %17 = OpTypeFunction %S %S_std140
-         %29 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
-%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
-         %35 = OpConstantNull %_arr_S_uint_4
-%_ptr_Function_uint = OpTypePointer Function %uint
-         %38 = OpConstantNull %uint
-       %bool = OpTypeBool
-%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
-         %51 = OpConstantNull %_arr_S_std140_uint_4
-%_ptr_Function_S = OpTypePointer Function %S
-%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
-     %uint_1 = OpConstant %uint 1
-         %64 = OpTypeFunction %mat4v2float
-     %uint_0 = OpConstant %uint 0
-     %uint_2 = OpConstant %uint 2
-%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
-%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
-     %uint_3 = OpConstant %uint 3
-       %void = OpTypeVoid
-         %87 = OpTypeFunction %void
-%_ptr_StorageBuffer__arr_S_uint_4 = OpTypePointer StorageBuffer %_arr_S_uint_4
-%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
-      %int_1 = OpConstant %int 1
-%_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
-      %int_3 = OpConstant %int 3
-%_ptr_StorageBuffer_mat4v2float = OpTypePointer StorageBuffer %mat4v2float
-        %107 = OpConstantNull %int
-%_ptr_StorageBuffer_v2float = OpTypePointer StorageBuffer %v2float
-     %conv_S = OpFunction %S None %17
-        %val = OpFunctionParameter %S_std140
-         %20 = OpLabel
-         %21 = OpCompositeExtract %int %val 0
-         %22 = OpCompositeExtract %v2float %val 1
-         %23 = OpCompositeExtract %v2float %val 2
-         %24 = OpCompositeExtract %v2float %val 3
-         %25 = OpCompositeExtract %v2float %val 4
-         %26 = OpCompositeConstruct %mat4v2float %22 %23 %24 %25
-         %27 = OpCompositeExtract %int %val 5
-         %28 = OpCompositeConstruct %S %21 %26 %27
-               OpReturnValue %28
-               OpFunctionEnd
-%conv_arr4_S = OpFunction %_arr_S_uint_4 None %29
-      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
-         %32 = OpLabel
-        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %35
-          %i = OpVariable %_ptr_Function_uint Function %38
-%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %51
-               OpBranch %39
-         %39 = OpLabel
-               OpLoopMerge %40 %41 None
-               OpBranch %42
-         %42 = OpLabel
-         %44 = OpLoad %uint %i
-         %45 = OpULessThan %bool %44 %uint_4
-         %43 = OpLogicalNot %bool %45
-               OpSelectionMerge %47 None
-               OpBranchConditional %43 %48 %47
-         %48 = OpLabel
-               OpBranch %40
-         %47 = OpLabel
-               OpStore %var_for_index %val_0
-         %52 = OpLoad %uint %i
-         %54 = OpAccessChain %_ptr_Function_S %arr %52
-         %56 = OpLoad %uint %i
-         %58 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %56
-         %59 = OpLoad %S_std140 %58
-         %55 = OpFunctionCall %S %conv_S %59
-               OpStore %54 %55
-               OpBranch %41
-         %41 = OpLabel
-         %60 = OpLoad %uint %i
-         %62 = OpIAdd %uint %60 %uint_1
-               OpStore %i %62
-               OpBranch %39
-         %40 = OpLabel
-         %63 = OpLoad %_arr_S_uint_4 %arr
-               OpReturnValue %63
-               OpFunctionEnd
-%load_u_inner_2_m = OpFunction %mat4v2float None %64
-         %66 = OpLabel
-         %71 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
-         %74 = OpAccessChain %_ptr_Uniform_v2float %71 %uint_1
-         %75 = OpLoad %v2float %74
-         %77 = OpAccessChain %_ptr_Uniform_v2float %71 %uint_2
-         %78 = OpLoad %v2float %77
-         %81 = OpAccessChain %_ptr_Uniform_v2float %71 %uint_3
-         %82 = OpLoad %v2float %81
-         %84 = OpAccessChain %_ptr_Uniform_v2float %71 %uint_4
-         %85 = OpLoad %v2float %84
-         %86 = OpCompositeConstruct %mat4v2float %75 %78 %82 %85
-               OpReturnValue %86
-               OpFunctionEnd
-          %f = OpFunction %void None %87
-         %90 = OpLabel
-         %92 = OpAccessChain %_ptr_StorageBuffer__arr_S_uint_4 %s %uint_0
-         %95 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
-         %96 = OpLoad %_arr_S_std140_uint_4 %95
-         %93 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %96
-               OpStore %92 %93
-         %99 = OpAccessChain %_ptr_StorageBuffer_S %s %uint_0 %int_1
-        %101 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
-        %102 = OpLoad %S_std140 %101
-        %100 = OpFunctionCall %S %conv_S %102
-               OpStore %99 %100
-        %105 = OpAccessChain %_ptr_StorageBuffer_mat4v2float %s %uint_0 %int_3 %uint_1
-        %106 = OpFunctionCall %mat4v2float %load_u_inner_2_m
-               OpStore %105 %106
-        %109 = OpAccessChain %_ptr_StorageBuffer_v2float %s %uint_0 %int_1 %uint_1 %107
-        %110 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %38 %uint_2
-        %111 = OpLoad %v2float %110
-        %112 = OpVectorShuffle %v2float %111 %111 1 0
-               OpStore %109 %112
-               OpReturn
-               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x2/to_storage.wgsl.expected.wgsl
deleted file mode 100644
index 2c43651..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/to_storage.wgsl.expected.wgsl
+++ /dev/null
@@ -1,17 +0,0 @@
-struct S {
-  before : i32,
-  m : mat4x2<f32>,
-  after : i32,
-}
-
-@group(0) @binding(0) var<uniform> u : array<S, 4>;
-
-@group(0) @binding(1) var<storage, read_write> s : array<S, 4>;
-
-@compute @workgroup_size(1)
-fn f() {
-  s = u;
-  s[1] = u[2];
-  s[3].m = u[2].m;
-  s[1].m[0] = u[0].m[1].yx;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x2/to_workgroup.wgsl
deleted file mode 100644
index 63c1a5b..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/to_workgroup.wgsl
+++ /dev/null
@@ -1,16 +0,0 @@
-struct S {
-  before : i32,
-  m : mat4x2<f32>,
-  after : i32,
-}
-
-@group(0) @binding(0) var<uniform> u : array<S, 4>;
-var<workgroup> w : array<S, 4>;
-
-@compute @workgroup_size(1)
-fn f() {
-    w = u;
-    w[1] = u[2];
-    w[3].m = u[2].m;
-    w[1].m[0] = u[0].m[1].yx;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x2/to_workgroup.wgsl.expected.dxc.hlsl
deleted file mode 100644
index e80f0d1..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/to_workgroup.wgsl.expected.dxc.hlsl
+++ /dev/null
@@ -1,65 +0,0 @@
-struct S {
-  int before;
-  float4x2 m;
-  int after;
-};
-
-cbuffer cbuffer_u : register(b0, space0) {
-  uint4 u[12];
-};
-groupshared S w[4];
-
-struct tint_symbol_1 {
-  uint local_invocation_index : SV_GroupIndex;
-};
-
-float4x2 tint_symbol_5(uint4 buffer[12], uint offset) {
-  const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset / 4];
-  const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
-  const uint scalar_offset_2 = ((offset + 16u)) / 4;
-  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
-  const uint scalar_offset_3 = ((offset + 24u)) / 4;
-  uint4 ubo_load_3 = buffer[scalar_offset_3 / 4];
-  return float4x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)), asfloat(((scalar_offset_3 & 2) ? ubo_load_3.zw : ubo_load_3.xy)));
-}
-
-S tint_symbol_3(uint4 buffer[12], uint offset) {
-  const uint scalar_offset_4 = ((offset + 0u)) / 4;
-  const uint scalar_offset_5 = ((offset + 40u)) / 4;
-  const S tint_symbol_8 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_5(buffer, (offset + 8u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
-  return tint_symbol_8;
-}
-
-typedef S tint_symbol_2_ret[4];
-tint_symbol_2_ret tint_symbol_2(uint4 buffer[12], uint offset) {
-  S arr[4] = (S[4])0;
-  {
-    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
-      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 48u)));
-    }
-  }
-  return arr;
-}
-
-void f_inner(uint local_invocation_index) {
-  {
-    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
-      const uint i = idx;
-      const S tint_symbol_7 = (S)0;
-      w[i] = tint_symbol_7;
-    }
-  }
-  GroupMemoryBarrierWithGroupSync();
-  w = tint_symbol_2(u, 0u);
-  w[1] = tint_symbol_3(u, 96u);
-  w[3].m = tint_symbol_5(u, 104u);
-  w[1].m[0] = asfloat(u[1].xy).yx;
-}
-
-[numthreads(1, 1, 1)]
-void f(tint_symbol_1 tint_symbol) {
-  f_inner(tint_symbol.local_invocation_index);
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x2/to_workgroup.wgsl.expected.fxc.hlsl
deleted file mode 100644
index e80f0d1..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/to_workgroup.wgsl.expected.fxc.hlsl
+++ /dev/null
@@ -1,65 +0,0 @@
-struct S {
-  int before;
-  float4x2 m;
-  int after;
-};
-
-cbuffer cbuffer_u : register(b0, space0) {
-  uint4 u[12];
-};
-groupshared S w[4];
-
-struct tint_symbol_1 {
-  uint local_invocation_index : SV_GroupIndex;
-};
-
-float4x2 tint_symbol_5(uint4 buffer[12], uint offset) {
-  const uint scalar_offset = ((offset + 0u)) / 4;
-  uint4 ubo_load = buffer[scalar_offset / 4];
-  const uint scalar_offset_1 = ((offset + 8u)) / 4;
-  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
-  const uint scalar_offset_2 = ((offset + 16u)) / 4;
-  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
-  const uint scalar_offset_3 = ((offset + 24u)) / 4;
-  uint4 ubo_load_3 = buffer[scalar_offset_3 / 4];
-  return float4x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)), asfloat(((scalar_offset_3 & 2) ? ubo_load_3.zw : ubo_load_3.xy)));
-}
-
-S tint_symbol_3(uint4 buffer[12], uint offset) {
-  const uint scalar_offset_4 = ((offset + 0u)) / 4;
-  const uint scalar_offset_5 = ((offset + 40u)) / 4;
-  const S tint_symbol_8 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_5(buffer, (offset + 8u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
-  return tint_symbol_8;
-}
-
-typedef S tint_symbol_2_ret[4];
-tint_symbol_2_ret tint_symbol_2(uint4 buffer[12], uint offset) {
-  S arr[4] = (S[4])0;
-  {
-    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
-      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 48u)));
-    }
-  }
-  return arr;
-}
-
-void f_inner(uint local_invocation_index) {
-  {
-    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
-      const uint i = idx;
-      const S tint_symbol_7 = (S)0;
-      w[i] = tint_symbol_7;
-    }
-  }
-  GroupMemoryBarrierWithGroupSync();
-  w = tint_symbol_2(u, 0u);
-  w[1] = tint_symbol_3(u, 96u);
-  w[3].m = tint_symbol_5(u, 104u);
-  w[1].m[0] = asfloat(u[1].xy).yx;
-}
-
-[numthreads(1, 1, 1)]
-void f(tint_symbol_1 tint_symbol) {
-  f_inner(tint_symbol.local_invocation_index);
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x2/to_workgroup.wgsl.expected.glsl
deleted file mode 100644
index 2e8a05f..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/to_workgroup.wgsl.expected.glsl
+++ /dev/null
@@ -1,64 +0,0 @@
-#version 310 es
-
-struct S {
-  int before;
-  uint pad;
-  mat4x2 m;
-  int after;
-  uint pad_1;
-};
-
-struct S_std140 {
-  int before;
-  uint pad;
-  vec2 m_0;
-  vec2 m_1;
-  vec2 m_2;
-  vec2 m_3;
-  int after;
-  uint pad_1;
-};
-
-layout(binding = 0, std140) uniform u_block_std140_ubo {
-  S_std140 inner[4];
-} u;
-
-shared S w[4];
-S conv_S(S_std140 val) {
-  return S(val.before, val.pad, mat4x2(val.m_0, val.m_1, val.m_2, val.m_3), val.after, val.pad_1);
-}
-
-S[4] conv_arr4_S(S_std140 val[4]) {
-  S arr[4] = S[4](S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0, 0u), S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0, 0u));
-  {
-    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
-      arr[i] = conv_S(val[i]);
-    }
-  }
-  return arr;
-}
-
-mat4x2 load_u_inner_2_m() {
-  return mat4x2(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2, u.inner[2u].m_3);
-}
-
-void f(uint local_invocation_index) {
-  {
-    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
-      uint i = idx;
-      S tint_symbol = S(0, 0u, mat4x2(vec2(0.0f), vec2(0.0f), vec2(0.0f), vec2(0.0f)), 0, 0u);
-      w[i] = tint_symbol;
-    }
-  }
-  barrier();
-  w = conv_arr4_S(u.inner);
-  w[1] = conv_S(u.inner[2u]);
-  w[3].m = load_u_inner_2_m();
-  w[1].m[0] = u.inner[0u].m_1.yx;
-}
-
-layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
-void main() {
-  f(gl_LocalInvocationIndex);
-  return;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x2/to_workgroup.wgsl.expected.msl
deleted file mode 100644
index 1ef4862..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/to_workgroup.wgsl.expected.msl
+++ /dev/null
@@ -1,47 +0,0 @@
-#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 S {
-  /* 0x0000 */ int before;
-  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
-  /* 0x0008 */ float4x2 m;
-  /* 0x0028 */ int after;
-  /* 0x002c */ tint_array<int8_t, 4> tint_pad_1;
-};
-
-struct tint_symbol_6 {
-  tint_array<S, 4> w;
-};
-
-void f_inner(uint local_invocation_index, threadgroup tint_array<S, 4>* const tint_symbol_1, const constant tint_array<S, 4>* const tint_symbol_2) {
-  for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
-    uint const i = idx;
-    S const tint_symbol = S{};
-    (*(tint_symbol_1))[i] = tint_symbol;
-  }
-  threadgroup_barrier(mem_flags::mem_threadgroup);
-  *(tint_symbol_1) = *(tint_symbol_2);
-  (*(tint_symbol_1))[1] = (*(tint_symbol_2))[2];
-  (*(tint_symbol_1))[3].m = (*(tint_symbol_2))[2].m;
-  (*(tint_symbol_1))[1].m[0] = float2((*(tint_symbol_2))[0].m[1]).yx;
-}
-
-kernel void f(const constant tint_array<S, 4>* tint_symbol_5 [[buffer(0)]], threadgroup tint_symbol_6* tint_symbol_4 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
-  threadgroup tint_array<S, 4>* const tint_symbol_3 = &((*(tint_symbol_4)).w);
-  f_inner(local_invocation_index, tint_symbol_3, tint_symbol_5);
-  return;
-}
-
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x2/to_workgroup.wgsl.expected.spvasm
deleted file mode 100644
index a690ffc..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/to_workgroup.wgsl.expected.spvasm
+++ /dev/null
@@ -1,221 +0,0 @@
-; SPIR-V
-; Version: 1.3
-; Generator: Google Tint Compiler; 0
-; Bound: 135
-; Schema: 0
-               OpCapability Shader
-               OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
-               OpExecutionMode %f LocalSize 1 1 1
-               OpName %local_invocation_index_1 "local_invocation_index_1"
-               OpName %u_block_std140 "u_block_std140"
-               OpMemberName %u_block_std140 0 "inner"
-               OpName %S_std140 "S_std140"
-               OpMemberName %S_std140 0 "before"
-               OpMemberName %S_std140 1 "m_0"
-               OpMemberName %S_std140 2 "m_1"
-               OpMemberName %S_std140 3 "m_2"
-               OpMemberName %S_std140 4 "m_3"
-               OpMemberName %S_std140 5 "after"
-               OpName %u "u"
-               OpName %S "S"
-               OpMemberName %S 0 "before"
-               OpMemberName %S 1 "m"
-               OpMemberName %S 2 "after"
-               OpName %w "w"
-               OpName %conv_S "conv_S"
-               OpName %val "val"
-               OpName %conv_arr4_S "conv_arr4_S"
-               OpName %val_0 "val"
-               OpName %arr "arr"
-               OpName %i "i"
-               OpName %var_for_index "var_for_index"
-               OpName %load_u_inner_2_m "load_u_inner_2_m"
-               OpName %f_inner "f_inner"
-               OpName %local_invocation_index "local_invocation_index"
-               OpName %idx "idx"
-               OpName %f "f"
-               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
-               OpDecorate %u_block_std140 Block
-               OpMemberDecorate %u_block_std140 0 Offset 0
-               OpMemberDecorate %S_std140 0 Offset 0
-               OpMemberDecorate %S_std140 1 Offset 8
-               OpMemberDecorate %S_std140 2 Offset 16
-               OpMemberDecorate %S_std140 3 Offset 24
-               OpMemberDecorate %S_std140 4 Offset 32
-               OpMemberDecorate %S_std140 5 Offset 40
-               OpDecorate %_arr_S_std140_uint_4 ArrayStride 48
-               OpDecorate %u NonWritable
-               OpDecorate %u DescriptorSet 0
-               OpDecorate %u Binding 0
-               OpMemberDecorate %S 0 Offset 0
-               OpMemberDecorate %S 1 Offset 8
-               OpMemberDecorate %S 1 ColMajor
-               OpMemberDecorate %S 1 MatrixStride 8
-               OpMemberDecorate %S 2 Offset 40
-               OpDecorate %_arr_S_uint_4 ArrayStride 48
-       %uint = OpTypeInt 32 0
-%_ptr_Input_uint = OpTypePointer Input %uint
-%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
-        %int = OpTypeInt 32 1
-      %float = OpTypeFloat 32
-    %v2float = OpTypeVector %float 2
-   %S_std140 = OpTypeStruct %int %v2float %v2float %v2float %v2float %int
-     %uint_4 = OpConstant %uint 4
-%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
-%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
-%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
-          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
-%mat4v2float = OpTypeMatrix %v2float 4
-          %S = OpTypeStruct %int %mat4v2float %int
-%_arr_S_uint_4 = OpTypeArray %S %uint_4
-%_ptr_Workgroup__arr_S_uint_4 = OpTypePointer Workgroup %_arr_S_uint_4
-          %w = OpVariable %_ptr_Workgroup__arr_S_uint_4 Workgroup
-         %18 = OpTypeFunction %S %S_std140
-         %30 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
-%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
-         %36 = OpConstantNull %_arr_S_uint_4
-%_ptr_Function_uint = OpTypePointer Function %uint
-         %39 = OpConstantNull %uint
-       %bool = OpTypeBool
-%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
-         %52 = OpConstantNull %_arr_S_std140_uint_4
-%_ptr_Function_S = OpTypePointer Function %S
-%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
-     %uint_1 = OpConstant %uint 1
-         %65 = OpTypeFunction %mat4v2float
-     %uint_0 = OpConstant %uint 0
-     %uint_2 = OpConstant %uint 2
-%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
-%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
-     %uint_3 = OpConstant %uint 3
-       %void = OpTypeVoid
-         %88 = OpTypeFunction %void %uint
-%_ptr_Workgroup_S = OpTypePointer Workgroup %S
-        %106 = OpConstantNull %S
-   %uint_264 = OpConstant %uint 264
-%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
-      %int_1 = OpConstant %int 1
-      %int_3 = OpConstant %int 3
-%_ptr_Workgroup_mat4v2float = OpTypePointer Workgroup %mat4v2float
-        %124 = OpConstantNull %int
-%_ptr_Workgroup_v2float = OpTypePointer Workgroup %v2float
-        %130 = OpTypeFunction %void
-     %conv_S = OpFunction %S None %18
-        %val = OpFunctionParameter %S_std140
-         %21 = OpLabel
-         %22 = OpCompositeExtract %int %val 0
-         %23 = OpCompositeExtract %v2float %val 1
-         %24 = OpCompositeExtract %v2float %val 2
-         %25 = OpCompositeExtract %v2float %val 3
-         %26 = OpCompositeExtract %v2float %val 4
-         %27 = OpCompositeConstruct %mat4v2float %23 %24 %25 %26
-         %28 = OpCompositeExtract %int %val 5
-         %29 = OpCompositeConstruct %S %22 %27 %28
-               OpReturnValue %29
-               OpFunctionEnd
-%conv_arr4_S = OpFunction %_arr_S_uint_4 None %30
-      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
-         %33 = OpLabel
-        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %36
-          %i = OpVariable %_ptr_Function_uint Function %39
-%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %52
-               OpBranch %40
-         %40 = OpLabel
-               OpLoopMerge %41 %42 None
-               OpBranch %43
-         %43 = OpLabel
-         %45 = OpLoad %uint %i
-         %46 = OpULessThan %bool %45 %uint_4
-         %44 = OpLogicalNot %bool %46
-               OpSelectionMerge %48 None
-               OpBranchConditional %44 %49 %48
-         %49 = OpLabel
-               OpBranch %41
-         %48 = OpLabel
-               OpStore %var_for_index %val_0
-         %53 = OpLoad %uint %i
-         %55 = OpAccessChain %_ptr_Function_S %arr %53
-         %57 = OpLoad %uint %i
-         %59 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %57
-         %60 = OpLoad %S_std140 %59
-         %56 = OpFunctionCall %S %conv_S %60
-               OpStore %55 %56
-               OpBranch %42
-         %42 = OpLabel
-         %61 = OpLoad %uint %i
-         %63 = OpIAdd %uint %61 %uint_1
-               OpStore %i %63
-               OpBranch %40
-         %41 = OpLabel
-         %64 = OpLoad %_arr_S_uint_4 %arr
-               OpReturnValue %64
-               OpFunctionEnd
-%load_u_inner_2_m = OpFunction %mat4v2float None %65
-         %67 = OpLabel
-         %72 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
-         %75 = OpAccessChain %_ptr_Uniform_v2float %72 %uint_1
-         %76 = OpLoad %v2float %75
-         %78 = OpAccessChain %_ptr_Uniform_v2float %72 %uint_2
-         %79 = OpLoad %v2float %78
-         %82 = OpAccessChain %_ptr_Uniform_v2float %72 %uint_3
-         %83 = OpLoad %v2float %82
-         %85 = OpAccessChain %_ptr_Uniform_v2float %72 %uint_4
-         %86 = OpLoad %v2float %85
-         %87 = OpCompositeConstruct %mat4v2float %76 %79 %83 %86
-               OpReturnValue %87
-               OpFunctionEnd
-    %f_inner = OpFunction %void None %88
-%local_invocation_index = OpFunctionParameter %uint
-         %92 = OpLabel
-        %idx = OpVariable %_ptr_Function_uint Function %39
-               OpStore %idx %local_invocation_index
-               OpBranch %94
-         %94 = OpLabel
-               OpLoopMerge %95 %96 None
-               OpBranch %97
-         %97 = OpLabel
-         %99 = OpLoad %uint %idx
-        %100 = OpULessThan %bool %99 %uint_4
-         %98 = OpLogicalNot %bool %100
-               OpSelectionMerge %101 None
-               OpBranchConditional %98 %102 %101
-        %102 = OpLabel
-               OpBranch %95
-        %101 = OpLabel
-        %103 = OpLoad %uint %idx
-        %105 = OpAccessChain %_ptr_Workgroup_S %w %103
-               OpStore %105 %106
-               OpBranch %96
-         %96 = OpLabel
-        %107 = OpLoad %uint %idx
-        %108 = OpIAdd %uint %107 %uint_1
-               OpStore %idx %108
-               OpBranch %94
-         %95 = OpLabel
-               OpControlBarrier %uint_2 %uint_2 %uint_264
-        %113 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
-        %114 = OpLoad %_arr_S_std140_uint_4 %113
-        %111 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %114
-               OpStore %w %111
-        %116 = OpAccessChain %_ptr_Workgroup_S %w %int_1
-        %118 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
-        %119 = OpLoad %S_std140 %118
-        %117 = OpFunctionCall %S %conv_S %119
-               OpStore %116 %117
-        %122 = OpAccessChain %_ptr_Workgroup_mat4v2float %w %int_3 %uint_1
-        %123 = OpFunctionCall %mat4v2float %load_u_inner_2_m
-               OpStore %122 %123
-        %126 = OpAccessChain %_ptr_Workgroup_v2float %w %int_1 %uint_1 %124
-        %127 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %39 %uint_2
-        %128 = OpLoad %v2float %127
-        %129 = OpVectorShuffle %v2float %128 %128 1 0
-               OpStore %126 %129
-               OpReturn
-               OpFunctionEnd
-          %f = OpFunction %void None %130
-        %132 = OpLabel
-        %134 = OpLoad %uint %local_invocation_index_1
-        %133 = OpFunctionCall %void %f_inner %134
-               OpReturn
-               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x2/to_workgroup.wgsl.expected.wgsl
deleted file mode 100644
index bb53c7e..0000000
--- a/test/tint/buffer/uniform/std140/struct/mat4x2/to_workgroup.wgsl.expected.wgsl
+++ /dev/null
@@ -1,17 +0,0 @@
-struct S {
-  before : i32,
-  m : mat4x2<f32>,
-  after : i32,
-}
-
-@group(0) @binding(0) var<uniform> u : array<S, 4>;
-
-var<workgroup> w : array<S, 4>;
-
-@compute @workgroup_size(1)
-fn f() {
-  w = u;
-  w[1] = u[2];
-  w[3].m = u[2].m;
-  w[1].m[0] = u[0].m[1].yx;
-}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/dynamic_index_via_ptr.wgsl
new file mode 100644
index 0000000..d88426b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/dynamic_index_via_ptr.wgsl
@@ -0,0 +1,34 @@
+enable f16;
+
+struct Inner {
+  @size(64)
+  m : mat4x2<f16>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a           = &a;
+  let p_a_i         = &((*p_a)[i()]);
+  let p_a_i_a       = &((*p_a_i).a);
+  let p_a_i_a_i     = &((*p_a_i_a)[i()]);
+  let p_a_i_a_i_m   = &((*p_a_i_a_i).m);
+  let p_a_i_a_i_m_i = &((*p_a_i_a_i_m)[i()]);
+
+
+  let l_a             : array<Outer, 4> =  *p_a;
+  let l_a_i           : Outer           =  *p_a_i;
+  let l_a_i_a         : array<Inner, 4> =  *p_a_i_a;
+  let l_a_i_a_i       : Inner           =  *p_a_i_a_i;
+  let l_a_i_a_i_m     : mat4x2<f16>     =  *p_a_i_a_i_m;
+  let l_a_i_a_i_m_i   : vec2<f16>       =  *p_a_i_a_i_m_i;
+  let l_a_i_a_i_m_i_i : f16             = (*p_a_i_a_i_m_i)[i()];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..2b3b666
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,83 @@
+struct Inner {
+  matrix<float16_t, 4, 2> m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 4, 2> tint_symbol_8(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const uint scalar_offset_3 = ((offset + 12u)) / 4;
+  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+}
+
+Inner tint_symbol_7(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_11 = {tint_symbol_8(buffer, (offset + 0u))};
+  return tint_symbol_11;
+}
+
+typedef Inner tint_symbol_6_ret[4];
+tint_symbol_6_ret tint_symbol_6(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_7(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_5(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_12 = {tint_symbol_6(buffer, (offset + 0u))};
+  return tint_symbol_12;
+}
+
+typedef Outer tint_symbol_4_ret[4];
+tint_symbol_4_ret tint_symbol_4(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
+      arr_1[i_2] = tint_symbol_5(buffer, (offset + (i_2 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_a_i_save = i();
+  const int p_a_i_a_i_m_i_save = i();
+  const Outer l_a[4] = tint_symbol_4(a, 0u);
+  const Outer l_a_i = tint_symbol_5(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a[4] = tint_symbol_6(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a_i = tint_symbol_7(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const matrix<float16_t, 4, 2> l_a_i_a_i_m = tint_symbol_8(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const uint scalar_offset_4 = ((((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))) + (4u * uint(p_a_i_a_i_m_i_save)))) / 4;
+  uint ubo_load_4 = a[scalar_offset_4 / 4][scalar_offset_4 % 4];
+  const vector<float16_t, 2> l_a_i_a_i_m_i = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16)));
+  const int tint_symbol = p_a_i_save;
+  const int tint_symbol_1 = p_a_i_a_i_save;
+  const int tint_symbol_2 = p_a_i_a_i_m_i_save;
+  const int tint_symbol_3 = i();
+  const uint scalar_offset_bytes = (((((256u * uint(tint_symbol)) + (64u * uint(tint_symbol_1))) + (4u * uint(tint_symbol_2))) + (2u * uint(tint_symbol_3))));
+  const uint scalar_offset_index = scalar_offset_bytes / 4;
+  const float16_t l_a_i_a_i_m_i_i = float16_t(f16tof32(((a[scalar_offset_index / 4][scalar_offset_index % 4] >> (scalar_offset_bytes % 4 == 0 ? 0 : 16)) & 0xFFFF)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..c6eb34d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,88 @@
+SKIP: FAILED
+
+struct Inner {
+  matrix<float16_t, 4, 2> m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 4, 2> tint_symbol_8(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const uint scalar_offset_3 = ((offset + 12u)) / 4;
+  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+}
+
+Inner tint_symbol_7(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_11 = {tint_symbol_8(buffer, (offset + 0u))};
+  return tint_symbol_11;
+}
+
+typedef Inner tint_symbol_6_ret[4];
+tint_symbol_6_ret tint_symbol_6(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_7(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_5(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_12 = {tint_symbol_6(buffer, (offset + 0u))};
+  return tint_symbol_12;
+}
+
+typedef Outer tint_symbol_4_ret[4];
+tint_symbol_4_ret tint_symbol_4(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
+      arr_1[i_2] = tint_symbol_5(buffer, (offset + (i_2 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_a_i_save = i();
+  const int p_a_i_a_i_m_i_save = i();
+  const Outer l_a[4] = tint_symbol_4(a, 0u);
+  const Outer l_a_i = tint_symbol_5(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a[4] = tint_symbol_6(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a_i = tint_symbol_7(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const matrix<float16_t, 4, 2> l_a_i_a_i_m = tint_symbol_8(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const uint scalar_offset_4 = ((((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))) + (4u * uint(p_a_i_a_i_m_i_save)))) / 4;
+  uint ubo_load_4 = a[scalar_offset_4 / 4][scalar_offset_4 % 4];
+  const vector<float16_t, 2> l_a_i_a_i_m_i = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16)));
+  const int tint_symbol = p_a_i_save;
+  const int tint_symbol_1 = p_a_i_a_i_save;
+  const int tint_symbol_2 = p_a_i_a_i_m_i_save;
+  const int tint_symbol_3 = i();
+  const uint scalar_offset_bytes = (((((256u * uint(tint_symbol)) + (64u * uint(tint_symbol_1))) + (4u * uint(tint_symbol_2))) + (2u * uint(tint_symbol_3))));
+  const uint scalar_offset_index = scalar_offset_bytes / 4;
+  const float16_t l_a_i_a_i_m_i_i = float16_t(f16tof32(((a[scalar_offset_index / 4][scalar_offset_index % 4] >> (scalar_offset_bytes % 4 == 0 ? 0 : 16)) & 0xFFFF)));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x00000216C74B2530(2,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..3ef37e6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,165 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct Inner {
+  f16mat4x2 m;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+};
+
+struct Inner_std140 {
+  f16vec2 m_0;
+  f16vec2 m_1;
+  f16vec2 m_2;
+  f16vec2 m_3;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+};
+
+struct Outer {
+  Inner a[4];
+};
+
+struct Outer_std140 {
+  Inner_std140 a[4];
+};
+
+layout(binding = 0, std140) uniform a_block_std140_ubo {
+  Outer_std140 inner[4];
+} a;
+
+int counter = 0;
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+Inner conv_Inner(Inner_std140 val) {
+  return Inner(f16mat4x2(val.m_0, val.m_1, val.m_2, val.m_3), val.pad, val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.pad_11);
+}
+
+Inner[4] conv_arr4_Inner(Inner_std140 val[4]) {
+  Inner arr[4] = Inner[4](Inner(f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_Inner(val[i]);
+    }
+  }
+  return arr;
+}
+
+Outer conv_Outer(Outer_std140 val) {
+  return Outer(conv_arr4_Inner(val.a));
+}
+
+Outer[4] conv_arr4_Outer(Outer_std140 val[4]) {
+  Outer arr[4] = Outer[4](Outer(Inner[4](Inner(f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_Outer(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat4x2 load_a_inner_p0_a_p1_m(uint p0, uint p1) {
+  uint s_save = p0;
+  uint s_save_1 = p1;
+  return f16mat4x2(a.inner[s_save].a[s_save_1].m_0, a.inner[s_save].a[s_save_1].m_1, a.inner[s_save].a[s_save_1].m_2, a.inner[s_save].a[s_save_1].m_3);
+}
+
+f16vec2 load_a_inner_p0_a_p1_m_p2(uint p0, uint p1, uint p2) {
+  switch(p2) {
+    case 0u: {
+      return a.inner[p0].a[p1].m_0;
+      break;
+    }
+    case 1u: {
+      return a.inner[p0].a[p1].m_1;
+      break;
+    }
+    case 2u: {
+      return a.inner[p0].a[p1].m_2;
+      break;
+    }
+    case 3u: {
+      return a.inner[p0].a[p1].m_3;
+      break;
+    }
+    default: {
+      return f16vec2(0.0hf);
+      break;
+    }
+  }
+}
+
+float16_t load_a_inner_p0_a_p1_m_p2_p3(uint p0, uint p1, uint p2, uint p3) {
+  switch(p2) {
+    case 0u: {
+      return a.inner[p0].a[p1].m_0[p3];
+      break;
+    }
+    case 1u: {
+      return a.inner[p0].a[p1].m_1[p3];
+      break;
+    }
+    case 2u: {
+      return a.inner[p0].a[p1].m_2[p3];
+      break;
+    }
+    case 3u: {
+      return a.inner[p0].a[p1].m_3[p3];
+      break;
+    }
+    default: {
+      return 0.0hf;
+      break;
+    }
+  }
+}
+
+void f() {
+  Outer p_a[4] = conv_arr4_Outer(a.inner);
+  int tint_symbol = i();
+  Outer p_a_i = conv_Outer(a.inner[tint_symbol]);
+  Inner p_a_i_a[4] = conv_arr4_Inner(a.inner[tint_symbol].a);
+  int tint_symbol_1 = i();
+  Inner p_a_i_a_i = conv_Inner(a.inner[tint_symbol].a[tint_symbol_1]);
+  f16mat4x2 p_a_i_a_i_m = load_a_inner_p0_a_p1_m(uint(tint_symbol), uint(tint_symbol_1));
+  int tint_symbol_2 = i();
+  f16vec2 p_a_i_a_i_m_i = load_a_inner_p0_a_p1_m_p2(uint(tint_symbol), uint(tint_symbol_1), uint(tint_symbol_2));
+  Outer l_a[4] = conv_arr4_Outer(a.inner);
+  Outer l_a_i = conv_Outer(a.inner[tint_symbol]);
+  Inner l_a_i_a[4] = conv_arr4_Inner(a.inner[tint_symbol].a);
+  Inner l_a_i_a_i = conv_Inner(a.inner[tint_symbol].a[tint_symbol_1]);
+  f16mat4x2 l_a_i_a_i_m = load_a_inner_p0_a_p1_m(uint(tint_symbol), uint(tint_symbol_1));
+  f16vec2 l_a_i_a_i_m_i = load_a_inner_p0_a_p1_m_p2(uint(tint_symbol), uint(tint_symbol_1), uint(tint_symbol_2));
+  int tint_symbol_3 = i();
+  float16_t l_a_i_a_i_m_i_i = load_a_inner_p0_a_p1_m_p2_p3(uint(tint_symbol), uint(tint_symbol_1), uint(tint_symbol_2), uint(tint_symbol_3));
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..2ff783e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,49 @@
+#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 Inner {
+  /* 0x0000 */ half4x2 m;
+  /* 0x0010 */ tint_array<int8_t, 48> tint_pad;
+};
+
+struct Outer {
+  /* 0x0000 */ tint_array<Inner, 4> a;
+};
+
+int i() {
+  thread int tint_symbol_4 = 0;
+  tint_symbol_4 = as_type<int>((as_type<uint>(tint_symbol_4) + as_type<uint>(1)));
+  return tint_symbol_4;
+}
+
+kernel void f(const constant tint_array<Outer, 4>* tint_symbol_5 [[buffer(0)]]) {
+  int const tint_symbol = i();
+  int const p_a_i_save = tint_symbol;
+  int const tint_symbol_1 = i();
+  int const p_a_i_a_i_save = tint_symbol_1;
+  int const tint_symbol_2 = i();
+  int const p_a_i_a_i_m_i_save = tint_symbol_2;
+  tint_array<Outer, 4> const l_a = *(tint_symbol_5);
+  Outer const l_a_i = (*(tint_symbol_5))[p_a_i_save];
+  tint_array<Inner, 4> const l_a_i_a = (*(tint_symbol_5))[p_a_i_save].a;
+  Inner const l_a_i_a_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save];
+  half4x2 const l_a_i_a_i_m = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m;
+  half2 const l_a_i_a_i_m_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save];
+  int const tint_symbol_3 = i();
+  half const l_a_i_a_i_m_i_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save][tint_symbol_3];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..b52433a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,338 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 215
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block_std140 "a_block_std140"
+               OpMemberName %a_block_std140 0 "inner"
+               OpName %Outer_std140 "Outer_std140"
+               OpMemberName %Outer_std140 0 "a"
+               OpName %Inner_std140 "Inner_std140"
+               OpMemberName %Inner_std140 0 "m_0"
+               OpMemberName %Inner_std140 1 "m_1"
+               OpMemberName %Inner_std140 2 "m_2"
+               OpMemberName %Inner_std140 3 "m_3"
+               OpName %a "a"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %Inner "Inner"
+               OpMemberName %Inner 0 "m"
+               OpName %conv_Inner "conv_Inner"
+               OpName %val "val"
+               OpName %conv_arr4_Inner "conv_arr4_Inner"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i_0 "i"
+               OpName %var_for_index_1 "var_for_index_1"
+               OpName %Outer "Outer"
+               OpMemberName %Outer 0 "a"
+               OpName %conv_Outer "conv_Outer"
+               OpName %val_1 "val"
+               OpName %conv_arr4_Outer "conv_arr4_Outer"
+               OpName %val_2 "val"
+               OpName %arr_0 "arr"
+               OpName %i_1 "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_a_inner_p0_a_p1_m "load_a_inner_p0_a_p1_m"
+               OpName %p0 "p0"
+               OpName %p1 "p1"
+               OpName %load_a_inner_p0_a_p1_m_p2 "load_a_inner_p0_a_p1_m_p2"
+               OpName %p0_0 "p0"
+               OpName %p1_0 "p1"
+               OpName %p2 "p2"
+               OpName %load_a_inner_p0_a_p1_m_p2_p3 "load_a_inner_p0_a_p1_m_p2_p3"
+               OpName %p0_1 "p0"
+               OpName %p1_1 "p1"
+               OpName %p2_0 "p2"
+               OpName %p3 "p3"
+               OpName %f "f"
+               OpDecorate %a_block_std140 Block
+               OpMemberDecorate %a_block_std140 0 Offset 0
+               OpMemberDecorate %Outer_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 1 Offset 4
+               OpMemberDecorate %Inner_std140 2 Offset 8
+               OpMemberDecorate %Inner_std140 3 Offset 12
+               OpDecorate %_arr_Inner_std140_uint_4 ArrayStride 64
+               OpDecorate %_arr_Outer_std140_uint_4 ArrayStride 256
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+               OpMemberDecorate %Inner 0 Offset 0
+               OpMemberDecorate %Inner 0 ColMajor
+               OpMemberDecorate %Inner 0 MatrixStride 4
+               OpDecorate %_arr_Inner_uint_4 ArrayStride 64
+               OpMemberDecorate %Outer 0 Offset 0
+               OpDecorate %_arr_Outer_uint_4 ArrayStride 256
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+%Inner_std140 = OpTypeStruct %v2half %v2half %v2half %v2half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_Inner_std140_uint_4 = OpTypeArray %Inner_std140 %uint_4
+%Outer_std140 = OpTypeStruct %_arr_Inner_std140_uint_4
+%_arr_Outer_std140_uint_4 = OpTypeArray %Outer_std140 %uint_4
+%a_block_std140 = OpTypeStruct %_arr_Outer_std140_uint_4
+%_ptr_Uniform_a_block_std140 = OpTypePointer Uniform %a_block_std140
+          %a = OpVariable %_ptr_Uniform_a_block_std140 Uniform
+        %int = OpTypeInt 32 1
+         %13 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %13
+         %16 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+ %mat4v2half = OpTypeMatrix %v2half 4
+      %Inner = OpTypeStruct %mat4v2half
+         %23 = OpTypeFunction %Inner %Inner_std140
+%_arr_Inner_uint_4 = OpTypeArray %Inner %uint_4
+         %35 = OpTypeFunction %_arr_Inner_uint_4 %_arr_Inner_std140_uint_4
+%_ptr_Function__arr_Inner_uint_4 = OpTypePointer Function %_arr_Inner_uint_4
+         %42 = OpConstantNull %_arr_Inner_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %45 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_Inner_std140_uint_4 = OpTypePointer Function %_arr_Inner_std140_uint_4
+         %58 = OpConstantNull %_arr_Inner_std140_uint_4
+%_ptr_Function_Inner = OpTypePointer Function %Inner
+%_ptr_Function_Inner_std140 = OpTypePointer Function %Inner_std140
+     %uint_1 = OpConstant %uint 1
+      %Outer = OpTypeStruct %_arr_Inner_uint_4
+         %71 = OpTypeFunction %Outer %Outer_std140
+%_arr_Outer_uint_4 = OpTypeArray %Outer %uint_4
+         %79 = OpTypeFunction %_arr_Outer_uint_4 %_arr_Outer_std140_uint_4
+%_ptr_Function__arr_Outer_uint_4 = OpTypePointer Function %_arr_Outer_uint_4
+         %86 = OpConstantNull %_arr_Outer_uint_4
+%_ptr_Function__arr_Outer_std140_uint_4 = OpTypePointer Function %_arr_Outer_std140_uint_4
+         %99 = OpConstantNull %_arr_Outer_std140_uint_4
+%_ptr_Function_Outer = OpTypePointer Function %Outer
+%_ptr_Function_Outer_std140 = OpTypePointer Function %Outer_std140
+        %111 = OpTypeFunction %mat4v2half %uint %uint
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_Inner_std140 = OpTypePointer Uniform %Inner_std140
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+        %136 = OpTypeFunction %v2half %uint %uint %uint
+        %156 = OpConstantNull %v2half
+        %157 = OpTypeFunction %half %uint %uint %uint %uint
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+        %179 = OpConstantNull %half
+       %void = OpTypeVoid
+        %180 = OpTypeFunction %void
+%_ptr_Uniform__arr_Outer_std140_uint_4 = OpTypePointer Uniform %_arr_Outer_std140_uint_4
+%_ptr_Uniform_Outer_std140 = OpTypePointer Uniform %Outer_std140
+%_ptr_Uniform__arr_Inner_std140_uint_4 = OpTypePointer Uniform %_arr_Inner_std140_uint_4
+          %i = OpFunction %int None %16
+         %18 = OpLabel
+         %19 = OpLoad %int %counter
+         %21 = OpIAdd %int %19 %int_1
+               OpStore %counter %21
+         %22 = OpLoad %int %counter
+               OpReturnValue %22
+               OpFunctionEnd
+ %conv_Inner = OpFunction %Inner None %23
+        %val = OpFunctionParameter %Inner_std140
+         %28 = OpLabel
+         %29 = OpCompositeExtract %v2half %val 0
+         %30 = OpCompositeExtract %v2half %val 1
+         %31 = OpCompositeExtract %v2half %val 2
+         %32 = OpCompositeExtract %v2half %val 3
+         %33 = OpCompositeConstruct %mat4v2half %29 %30 %31 %32
+         %34 = OpCompositeConstruct %Inner %33
+               OpReturnValue %34
+               OpFunctionEnd
+%conv_arr4_Inner = OpFunction %_arr_Inner_uint_4 None %35
+      %val_0 = OpFunctionParameter %_arr_Inner_std140_uint_4
+         %39 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_Inner_uint_4 Function %42
+        %i_0 = OpVariable %_ptr_Function_uint Function %45
+%var_for_index_1 = OpVariable %_ptr_Function__arr_Inner_std140_uint_4 Function %58
+               OpBranch %46
+         %46 = OpLabel
+               OpLoopMerge %47 %48 None
+               OpBranch %49
+         %49 = OpLabel
+         %51 = OpLoad %uint %i_0
+         %52 = OpULessThan %bool %51 %uint_4
+         %50 = OpLogicalNot %bool %52
+               OpSelectionMerge %54 None
+               OpBranchConditional %50 %55 %54
+         %55 = OpLabel
+               OpBranch %47
+         %54 = OpLabel
+               OpStore %var_for_index_1 %val_0
+         %59 = OpLoad %uint %i_0
+         %61 = OpAccessChain %_ptr_Function_Inner %arr %59
+         %63 = OpLoad %uint %i_0
+         %65 = OpAccessChain %_ptr_Function_Inner_std140 %var_for_index_1 %63
+         %66 = OpLoad %Inner_std140 %65
+         %62 = OpFunctionCall %Inner %conv_Inner %66
+               OpStore %61 %62
+               OpBranch %48
+         %48 = OpLabel
+         %67 = OpLoad %uint %i_0
+         %69 = OpIAdd %uint %67 %uint_1
+               OpStore %i_0 %69
+               OpBranch %46
+         %47 = OpLabel
+         %70 = OpLoad %_arr_Inner_uint_4 %arr
+               OpReturnValue %70
+               OpFunctionEnd
+ %conv_Outer = OpFunction %Outer None %71
+      %val_1 = OpFunctionParameter %Outer_std140
+         %75 = OpLabel
+         %77 = OpCompositeExtract %_arr_Inner_std140_uint_4 %val_1 0
+         %76 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %77
+         %78 = OpCompositeConstruct %Outer %76
+               OpReturnValue %78
+               OpFunctionEnd
+%conv_arr4_Outer = OpFunction %_arr_Outer_uint_4 None %79
+      %val_2 = OpFunctionParameter %_arr_Outer_std140_uint_4
+         %83 = OpLabel
+      %arr_0 = OpVariable %_ptr_Function__arr_Outer_uint_4 Function %86
+        %i_1 = OpVariable %_ptr_Function_uint Function %45
+%var_for_index = OpVariable %_ptr_Function__arr_Outer_std140_uint_4 Function %99
+               OpBranch %88
+         %88 = OpLabel
+               OpLoopMerge %89 %90 None
+               OpBranch %91
+         %91 = OpLabel
+         %93 = OpLoad %uint %i_1
+         %94 = OpULessThan %bool %93 %uint_4
+         %92 = OpLogicalNot %bool %94
+               OpSelectionMerge %95 None
+               OpBranchConditional %92 %96 %95
+         %96 = OpLabel
+               OpBranch %89
+         %95 = OpLabel
+               OpStore %var_for_index %val_2
+        %100 = OpLoad %uint %i_1
+        %102 = OpAccessChain %_ptr_Function_Outer %arr_0 %100
+        %104 = OpLoad %uint %i_1
+        %106 = OpAccessChain %_ptr_Function_Outer_std140 %var_for_index %104
+        %107 = OpLoad %Outer_std140 %106
+        %103 = OpFunctionCall %Outer %conv_Outer %107
+               OpStore %102 %103
+               OpBranch %90
+         %90 = OpLabel
+        %108 = OpLoad %uint %i_1
+        %109 = OpIAdd %uint %108 %uint_1
+               OpStore %i_1 %109
+               OpBranch %88
+         %89 = OpLabel
+        %110 = OpLoad %_arr_Outer_uint_4 %arr_0
+               OpReturnValue %110
+               OpFunctionEnd
+%load_a_inner_p0_a_p1_m = OpFunction %mat4v2half None %111
+         %p0 = OpFunctionParameter %uint
+         %p1 = OpFunctionParameter %uint
+        %115 = OpLabel
+        %119 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %p0 %uint_0 %p1
+        %122 = OpAccessChain %_ptr_Uniform_v2half %119 %uint_0
+        %123 = OpLoad %v2half %122
+        %125 = OpAccessChain %_ptr_Uniform_v2half %119 %uint_1
+        %126 = OpLoad %v2half %125
+        %129 = OpAccessChain %_ptr_Uniform_v2half %119 %uint_2
+        %130 = OpLoad %v2half %129
+        %133 = OpAccessChain %_ptr_Uniform_v2half %119 %uint_3
+        %134 = OpLoad %v2half %133
+        %135 = OpCompositeConstruct %mat4v2half %123 %126 %130 %134
+               OpReturnValue %135
+               OpFunctionEnd
+%load_a_inner_p0_a_p1_m_p2 = OpFunction %v2half None %136
+       %p0_0 = OpFunctionParameter %uint
+       %p1_0 = OpFunctionParameter %uint
+         %p2 = OpFunctionParameter %uint
+        %141 = OpLabel
+               OpSelectionMerge %142 None
+               OpSwitch %p2 %143 0 %144 1 %145 2 %146 3 %147
+        %144 = OpLabel
+        %148 = OpAccessChain %_ptr_Uniform_v2half %a %uint_0 %p0_0 %uint_0 %p1_0 %uint_0
+        %149 = OpLoad %v2half %148
+               OpReturnValue %149
+        %145 = OpLabel
+        %150 = OpAccessChain %_ptr_Uniform_v2half %a %uint_0 %p0_0 %uint_0 %p1_0 %uint_1
+        %151 = OpLoad %v2half %150
+               OpReturnValue %151
+        %146 = OpLabel
+        %152 = OpAccessChain %_ptr_Uniform_v2half %a %uint_0 %p0_0 %uint_0 %p1_0 %uint_2
+        %153 = OpLoad %v2half %152
+               OpReturnValue %153
+        %147 = OpLabel
+        %154 = OpAccessChain %_ptr_Uniform_v2half %a %uint_0 %p0_0 %uint_0 %p1_0 %uint_3
+        %155 = OpLoad %v2half %154
+               OpReturnValue %155
+        %143 = OpLabel
+               OpReturnValue %156
+        %142 = OpLabel
+               OpReturnValue %156
+               OpFunctionEnd
+%load_a_inner_p0_a_p1_m_p2_p3 = OpFunction %half None %157
+       %p0_1 = OpFunctionParameter %uint
+       %p1_1 = OpFunctionParameter %uint
+       %p2_0 = OpFunctionParameter %uint
+         %p3 = OpFunctionParameter %uint
+        %163 = OpLabel
+               OpSelectionMerge %164 None
+               OpSwitch %p2_0 %165 0 %166 1 %167 2 %168 3 %169
+        %166 = OpLabel
+        %171 = OpAccessChain %_ptr_Uniform_half %a %uint_0 %p0_1 %uint_0 %p1_1 %uint_0 %p3
+        %172 = OpLoad %half %171
+               OpReturnValue %172
+        %167 = OpLabel
+        %173 = OpAccessChain %_ptr_Uniform_half %a %uint_0 %p0_1 %uint_0 %p1_1 %uint_1 %p3
+        %174 = OpLoad %half %173
+               OpReturnValue %174
+        %168 = OpLabel
+        %175 = OpAccessChain %_ptr_Uniform_half %a %uint_0 %p0_1 %uint_0 %p1_1 %uint_2 %p3
+        %176 = OpLoad %half %175
+               OpReturnValue %176
+        %169 = OpLabel
+        %177 = OpAccessChain %_ptr_Uniform_half %a %uint_0 %p0_1 %uint_0 %p1_1 %uint_3 %p3
+        %178 = OpLoad %half %177
+               OpReturnValue %178
+        %165 = OpLabel
+               OpReturnValue %179
+        %164 = OpLabel
+               OpReturnValue %179
+               OpFunctionEnd
+          %f = OpFunction %void None %180
+        %183 = OpLabel
+        %184 = OpFunctionCall %int %i
+        %185 = OpFunctionCall %int %i
+        %186 = OpFunctionCall %int %i
+        %189 = OpAccessChain %_ptr_Uniform__arr_Outer_std140_uint_4 %a %uint_0
+        %190 = OpLoad %_arr_Outer_std140_uint_4 %189
+        %187 = OpFunctionCall %_arr_Outer_uint_4 %conv_arr4_Outer %190
+        %193 = OpAccessChain %_ptr_Uniform_Outer_std140 %a %uint_0 %184
+        %194 = OpLoad %Outer_std140 %193
+        %191 = OpFunctionCall %Outer %conv_Outer %194
+        %197 = OpAccessChain %_ptr_Uniform__arr_Inner_std140_uint_4 %a %uint_0 %184 %uint_0
+        %198 = OpLoad %_arr_Inner_std140_uint_4 %197
+        %195 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %198
+        %200 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %184 %uint_0 %185
+        %201 = OpLoad %Inner_std140 %200
+        %199 = OpFunctionCall %Inner %conv_Inner %201
+        %203 = OpBitcast %uint %184
+        %204 = OpBitcast %uint %185
+        %202 = OpFunctionCall %mat4v2half %load_a_inner_p0_a_p1_m %203 %204
+        %206 = OpBitcast %uint %184
+        %207 = OpBitcast %uint %185
+        %208 = OpBitcast %uint %186
+        %205 = OpFunctionCall %v2half %load_a_inner_p0_a_p1_m_p2 %206 %207 %208
+        %209 = OpFunctionCall %int %i
+        %211 = OpBitcast %uint %184
+        %212 = OpBitcast %uint %185
+        %213 = OpBitcast %uint %186
+        %214 = OpBitcast %uint %209
+        %210 = OpFunctionCall %half %load_a_inner_p0_a_p1_m_p2_p3 %211 %212 %213 %214
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..af6d6d9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,36 @@
+enable f16;
+
+struct Inner {
+  @size(64)
+  m : mat4x2<f16>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_i = &((*(p_a))[i()]);
+  let p_a_i_a = &((*(p_a_i)).a);
+  let p_a_i_a_i = &((*(p_a_i_a))[i()]);
+  let p_a_i_a_i_m = &((*(p_a_i_a_i)).m);
+  let p_a_i_a_i_m_i = &((*(p_a_i_a_i_m))[i()]);
+  let l_a : array<Outer, 4> = *(p_a);
+  let l_a_i : Outer = *(p_a_i);
+  let l_a_i_a : array<Inner, 4> = *(p_a_i_a);
+  let l_a_i_a_i : Inner = *(p_a_i_a_i);
+  let l_a_i_a_i_m : mat4x2<f16> = *(p_a_i_a_i_m);
+  let l_a_i_a_i_m_i : vec2<f16> = *(p_a_i_a_i_m_i);
+  let l_a_i_a_i_m_i_i : f16 = (*(p_a_i_a_i_m_i))[i()];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/static_index_via_ptr.wgsl
new file mode 100644
index 0000000..195dc77
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/static_index_via_ptr.wgsl
@@ -0,0 +1,31 @@
+enable f16;
+
+struct Inner {
+  @size(64)
+  m : mat4x2<f16>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &a;
+  let p_a_3 = &((*p_a)[3]);
+  let p_a_3_a = &((*p_a_3).a);
+  let p_a_3_a_2 = &((*p_a_3_a)[2]);
+  let p_a_3_a_2_m = &((*p_a_3_a_2).m);
+  let p_a_3_a_2_m_1 = &((*p_a_3_a_2_m)[1]);
+
+
+  let l_a             : array<Outer, 4> = *p_a;
+  let l_a_3           : Outer           = *p_a_3;
+  let l_a_3_a         : array<Inner, 4> = *p_a_3_a;
+  let l_a_3_a_2       : Inner           = *p_a_3_a_2;
+  let l_a_3_a_2_m     : mat4x2<f16>     = *p_a_3_a_2_m;
+  let l_a_3_a_2_m_1   : vec2<f16>       = *p_a_3_a_2_m_1;
+  let l_a_3_a_2_m_1_0 : f16             = (*p_a_3_a_2_m_1)[0];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..5da92cb
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,67 @@
+struct Inner {
+  matrix<float16_t, 4, 2> m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+
+matrix<float16_t, 4, 2> tint_symbol_4(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const uint scalar_offset_3 = ((offset + 12u)) / 4;
+  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+}
+
+Inner tint_symbol_3(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_7 = {tint_symbol_4(buffer, (offset + 0u))};
+  return tint_symbol_7;
+}
+
+typedef Inner tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_3(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_1(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_8 = {tint_symbol_2(buffer, (offset + 0u))};
+  return tint_symbol_8;
+}
+
+typedef Outer tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr_1[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const Outer l_a[4] = tint_symbol(a, 0u);
+  const Outer l_a_3 = tint_symbol_1(a, 768u);
+  const Inner l_a_3_a[4] = tint_symbol_2(a, 768u);
+  const Inner l_a_3_a_2 = tint_symbol_3(a, 896u);
+  const matrix<float16_t, 4, 2> l_a_3_a_2_m = tint_symbol_4(a, 896u);
+  uint ubo_load_4 = a[56].y;
+  const vector<float16_t, 2> l_a_3_a_2_m_1 = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16)));
+  const float16_t l_a_3_a_2_m_1_0 = float16_t(f16tof32(((a[56].y) & 0xFFFF)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..5745198
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,72 @@
+SKIP: FAILED
+
+struct Inner {
+  matrix<float16_t, 4, 2> m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+
+matrix<float16_t, 4, 2> tint_symbol_4(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const uint scalar_offset_3 = ((offset + 12u)) / 4;
+  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+}
+
+Inner tint_symbol_3(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_7 = {tint_symbol_4(buffer, (offset + 0u))};
+  return tint_symbol_7;
+}
+
+typedef Inner tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_3(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_1(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_8 = {tint_symbol_2(buffer, (offset + 0u))};
+  return tint_symbol_8;
+}
+
+typedef Outer tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr_1[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const Outer l_a[4] = tint_symbol(a, 0u);
+  const Outer l_a_3 = tint_symbol_1(a, 768u);
+  const Inner l_a_3_a[4] = tint_symbol_2(a, 768u);
+  const Inner l_a_3_a_2 = tint_symbol_3(a, 896u);
+  const matrix<float16_t, 4, 2> l_a_3_a_2_m = tint_symbol_4(a, 896u);
+  uint ubo_load_4 = a[56].y;
+  const vector<float16_t, 2> l_a_3_a_2_m_1 = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16)));
+  const float16_t l_a_3_a_2_m_1_0 = float16_t(f16tof32(((a[56].y) & 0xFFFF)));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000026E60B9E9C0(2,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/static_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..ec129b4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/static_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,103 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct Inner {
+  f16mat4x2 m;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+};
+
+struct Inner_std140 {
+  f16vec2 m_0;
+  f16vec2 m_1;
+  f16vec2 m_2;
+  f16vec2 m_3;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+};
+
+struct Outer {
+  Inner a[4];
+};
+
+struct Outer_std140 {
+  Inner_std140 a[4];
+};
+
+layout(binding = 0, std140) uniform a_block_std140_ubo {
+  Outer_std140 inner[4];
+} a;
+
+Inner conv_Inner(Inner_std140 val) {
+  return Inner(f16mat4x2(val.m_0, val.m_1, val.m_2, val.m_3), val.pad, val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.pad_11);
+}
+
+Inner[4] conv_arr4_Inner(Inner_std140 val[4]) {
+  Inner arr[4] = Inner[4](Inner(f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_Inner(val[i]);
+    }
+  }
+  return arr;
+}
+
+Outer conv_Outer(Outer_std140 val) {
+  return Outer(conv_arr4_Inner(val.a));
+}
+
+Outer[4] conv_arr4_Outer(Outer_std140 val[4]) {
+  Outer arr[4] = Outer[4](Outer(Inner[4](Inner(f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_Outer(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat4x2 load_a_inner_3_a_2_m() {
+  return f16mat4x2(a.inner[3u].a[2u].m_0, a.inner[3u].a[2u].m_1, a.inner[3u].a[2u].m_2, a.inner[3u].a[2u].m_3);
+}
+
+void f() {
+  Outer p_a[4] = conv_arr4_Outer(a.inner);
+  Outer p_a_3 = conv_Outer(a.inner[3u]);
+  Inner p_a_3_a[4] = conv_arr4_Inner(a.inner[3u].a);
+  Inner p_a_3_a_2 = conv_Inner(a.inner[3u].a[2u]);
+  f16mat4x2 p_a_3_a_2_m = load_a_inner_3_a_2_m();
+  f16vec2 p_a_3_a_2_m_1 = a.inner[3u].a[2u].m_1;
+  Outer l_a[4] = conv_arr4_Outer(a.inner);
+  Outer l_a_3 = conv_Outer(a.inner[3u]);
+  Inner l_a_3_a[4] = conv_arr4_Inner(a.inner[3u].a);
+  Inner l_a_3_a_2 = conv_Inner(a.inner[3u].a[2u]);
+  f16mat4x2 l_a_3_a_2_m = load_a_inner_3_a_2_m();
+  f16vec2 l_a_3_a_2_m_1 = a.inner[3u].a[2u].m_1;
+  float16_t l_a_3_a_2_m_1_0 = a.inner[3u].a[2u].m_1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/static_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..3dee8fd
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/static_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,36 @@
+#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 Inner {
+  /* 0x0000 */ half4x2 m;
+  /* 0x0010 */ tint_array<int8_t, 48> tint_pad;
+};
+
+struct Outer {
+  /* 0x0000 */ tint_array<Inner, 4> a;
+};
+
+kernel void f(const constant tint_array<Outer, 4>* tint_symbol [[buffer(0)]]) {
+  tint_array<Outer, 4> const l_a = *(tint_symbol);
+  Outer const l_a_3 = (*(tint_symbol))[3];
+  tint_array<Inner, 4> const l_a_3_a = (*(tint_symbol))[3].a;
+  Inner const l_a_3_a_2 = (*(tint_symbol))[3].a[2];
+  half4x2 const l_a_3_a_2_m = (*(tint_symbol))[3].a[2].m;
+  half2 const l_a_3_a_2_m_1 = (*(tint_symbol))[3].a[2].m[1];
+  half const l_a_3_a_2_m_1_0 = (*(tint_symbol))[3].a[2].m[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/static_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..c335f50
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/static_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,237 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 148
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block_std140 "a_block_std140"
+               OpMemberName %a_block_std140 0 "inner"
+               OpName %Outer_std140 "Outer_std140"
+               OpMemberName %Outer_std140 0 "a"
+               OpName %Inner_std140 "Inner_std140"
+               OpMemberName %Inner_std140 0 "m_0"
+               OpMemberName %Inner_std140 1 "m_1"
+               OpMemberName %Inner_std140 2 "m_2"
+               OpMemberName %Inner_std140 3 "m_3"
+               OpName %a "a"
+               OpName %Inner "Inner"
+               OpMemberName %Inner 0 "m"
+               OpName %conv_Inner "conv_Inner"
+               OpName %val "val"
+               OpName %conv_arr4_Inner "conv_arr4_Inner"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index_1 "var_for_index_1"
+               OpName %Outer "Outer"
+               OpMemberName %Outer 0 "a"
+               OpName %conv_Outer "conv_Outer"
+               OpName %val_1 "val"
+               OpName %conv_arr4_Outer "conv_arr4_Outer"
+               OpName %val_2 "val"
+               OpName %arr_0 "arr"
+               OpName %i_0 "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_a_inner_3_a_2_m "load_a_inner_3_a_2_m"
+               OpName %f "f"
+               OpDecorate %a_block_std140 Block
+               OpMemberDecorate %a_block_std140 0 Offset 0
+               OpMemberDecorate %Outer_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 1 Offset 4
+               OpMemberDecorate %Inner_std140 2 Offset 8
+               OpMemberDecorate %Inner_std140 3 Offset 12
+               OpDecorate %_arr_Inner_std140_uint_4 ArrayStride 64
+               OpDecorate %_arr_Outer_std140_uint_4 ArrayStride 256
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+               OpMemberDecorate %Inner 0 Offset 0
+               OpMemberDecorate %Inner 0 ColMajor
+               OpMemberDecorate %Inner 0 MatrixStride 4
+               OpDecorate %_arr_Inner_uint_4 ArrayStride 64
+               OpMemberDecorate %Outer 0 Offset 0
+               OpDecorate %_arr_Outer_uint_4 ArrayStride 256
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+%Inner_std140 = OpTypeStruct %v2half %v2half %v2half %v2half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_Inner_std140_uint_4 = OpTypeArray %Inner_std140 %uint_4
+%Outer_std140 = OpTypeStruct %_arr_Inner_std140_uint_4
+%_arr_Outer_std140_uint_4 = OpTypeArray %Outer_std140 %uint_4
+%a_block_std140 = OpTypeStruct %_arr_Outer_std140_uint_4
+%_ptr_Uniform_a_block_std140 = OpTypePointer Uniform %a_block_std140
+          %a = OpVariable %_ptr_Uniform_a_block_std140 Uniform
+ %mat4v2half = OpTypeMatrix %v2half 4
+      %Inner = OpTypeStruct %mat4v2half
+         %12 = OpTypeFunction %Inner %Inner_std140
+%_arr_Inner_uint_4 = OpTypeArray %Inner %uint_4
+         %24 = OpTypeFunction %_arr_Inner_uint_4 %_arr_Inner_std140_uint_4
+%_ptr_Function__arr_Inner_uint_4 = OpTypePointer Function %_arr_Inner_uint_4
+         %31 = OpConstantNull %_arr_Inner_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %34 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_Inner_std140_uint_4 = OpTypePointer Function %_arr_Inner_std140_uint_4
+         %47 = OpConstantNull %_arr_Inner_std140_uint_4
+%_ptr_Function_Inner = OpTypePointer Function %Inner
+%_ptr_Function_Inner_std140 = OpTypePointer Function %Inner_std140
+     %uint_1 = OpConstant %uint 1
+      %Outer = OpTypeStruct %_arr_Inner_uint_4
+         %60 = OpTypeFunction %Outer %Outer_std140
+%_arr_Outer_uint_4 = OpTypeArray %Outer %uint_4
+         %68 = OpTypeFunction %_arr_Outer_uint_4 %_arr_Outer_std140_uint_4
+%_ptr_Function__arr_Outer_uint_4 = OpTypePointer Function %_arr_Outer_uint_4
+         %75 = OpConstantNull %_arr_Outer_uint_4
+%_ptr_Function__arr_Outer_std140_uint_4 = OpTypePointer Function %_arr_Outer_std140_uint_4
+         %88 = OpConstantNull %_arr_Outer_std140_uint_4
+%_ptr_Function_Outer = OpTypePointer Function %Outer
+%_ptr_Function_Outer_std140 = OpTypePointer Function %Outer_std140
+        %100 = OpTypeFunction %mat4v2half
+     %uint_0 = OpConstant %uint 0
+     %uint_3 = OpConstant %uint 3
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_Inner_std140 = OpTypePointer Uniform %Inner_std140
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+       %void = OpTypeVoid
+        %123 = OpTypeFunction %void
+%_ptr_Uniform__arr_Outer_std140_uint_4 = OpTypePointer Uniform %_arr_Outer_std140_uint_4
+%_ptr_Uniform_Outer_std140 = OpTypePointer Uniform %Outer_std140
+%_ptr_Uniform__arr_Inner_std140_uint_4 = OpTypePointer Uniform %_arr_Inner_std140_uint_4
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+ %conv_Inner = OpFunction %Inner None %12
+        %val = OpFunctionParameter %Inner_std140
+         %17 = OpLabel
+         %18 = OpCompositeExtract %v2half %val 0
+         %19 = OpCompositeExtract %v2half %val 1
+         %20 = OpCompositeExtract %v2half %val 2
+         %21 = OpCompositeExtract %v2half %val 3
+         %22 = OpCompositeConstruct %mat4v2half %18 %19 %20 %21
+         %23 = OpCompositeConstruct %Inner %22
+               OpReturnValue %23
+               OpFunctionEnd
+%conv_arr4_Inner = OpFunction %_arr_Inner_uint_4 None %24
+      %val_0 = OpFunctionParameter %_arr_Inner_std140_uint_4
+         %28 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_Inner_uint_4 Function %31
+          %i = OpVariable %_ptr_Function_uint Function %34
+%var_for_index_1 = OpVariable %_ptr_Function__arr_Inner_std140_uint_4 Function %47
+               OpBranch %35
+         %35 = OpLabel
+               OpLoopMerge %36 %37 None
+               OpBranch %38
+         %38 = OpLabel
+         %40 = OpLoad %uint %i
+         %41 = OpULessThan %bool %40 %uint_4
+         %39 = OpLogicalNot %bool %41
+               OpSelectionMerge %43 None
+               OpBranchConditional %39 %44 %43
+         %44 = OpLabel
+               OpBranch %36
+         %43 = OpLabel
+               OpStore %var_for_index_1 %val_0
+         %48 = OpLoad %uint %i
+         %50 = OpAccessChain %_ptr_Function_Inner %arr %48
+         %52 = OpLoad %uint %i
+         %54 = OpAccessChain %_ptr_Function_Inner_std140 %var_for_index_1 %52
+         %55 = OpLoad %Inner_std140 %54
+         %51 = OpFunctionCall %Inner %conv_Inner %55
+               OpStore %50 %51
+               OpBranch %37
+         %37 = OpLabel
+         %56 = OpLoad %uint %i
+         %58 = OpIAdd %uint %56 %uint_1
+               OpStore %i %58
+               OpBranch %35
+         %36 = OpLabel
+         %59 = OpLoad %_arr_Inner_uint_4 %arr
+               OpReturnValue %59
+               OpFunctionEnd
+ %conv_Outer = OpFunction %Outer None %60
+      %val_1 = OpFunctionParameter %Outer_std140
+         %64 = OpLabel
+         %66 = OpCompositeExtract %_arr_Inner_std140_uint_4 %val_1 0
+         %65 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %66
+         %67 = OpCompositeConstruct %Outer %65
+               OpReturnValue %67
+               OpFunctionEnd
+%conv_arr4_Outer = OpFunction %_arr_Outer_uint_4 None %68
+      %val_2 = OpFunctionParameter %_arr_Outer_std140_uint_4
+         %72 = OpLabel
+      %arr_0 = OpVariable %_ptr_Function__arr_Outer_uint_4 Function %75
+        %i_0 = OpVariable %_ptr_Function_uint Function %34
+%var_for_index = OpVariable %_ptr_Function__arr_Outer_std140_uint_4 Function %88
+               OpBranch %77
+         %77 = OpLabel
+               OpLoopMerge %78 %79 None
+               OpBranch %80
+         %80 = OpLabel
+         %82 = OpLoad %uint %i_0
+         %83 = OpULessThan %bool %82 %uint_4
+         %81 = OpLogicalNot %bool %83
+               OpSelectionMerge %84 None
+               OpBranchConditional %81 %85 %84
+         %85 = OpLabel
+               OpBranch %78
+         %84 = OpLabel
+               OpStore %var_for_index %val_2
+         %89 = OpLoad %uint %i_0
+         %91 = OpAccessChain %_ptr_Function_Outer %arr_0 %89
+         %93 = OpLoad %uint %i_0
+         %95 = OpAccessChain %_ptr_Function_Outer_std140 %var_for_index %93
+         %96 = OpLoad %Outer_std140 %95
+         %92 = OpFunctionCall %Outer %conv_Outer %96
+               OpStore %91 %92
+               OpBranch %79
+         %79 = OpLabel
+         %97 = OpLoad %uint %i_0
+         %98 = OpIAdd %uint %97 %uint_1
+               OpStore %i_0 %98
+               OpBranch %77
+         %78 = OpLabel
+         %99 = OpLoad %_arr_Outer_uint_4 %arr_0
+               OpReturnValue %99
+               OpFunctionEnd
+%load_a_inner_3_a_2_m = OpFunction %mat4v2half None %100
+        %102 = OpLabel
+        %108 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %uint_3 %uint_0 %uint_2
+        %111 = OpAccessChain %_ptr_Uniform_v2half %108 %uint_0
+        %112 = OpLoad %v2half %111
+        %114 = OpAccessChain %_ptr_Uniform_v2half %108 %uint_1
+        %115 = OpLoad %v2half %114
+        %117 = OpAccessChain %_ptr_Uniform_v2half %108 %uint_2
+        %118 = OpLoad %v2half %117
+        %120 = OpAccessChain %_ptr_Uniform_v2half %108 %uint_3
+        %121 = OpLoad %v2half %120
+        %122 = OpCompositeConstruct %mat4v2half %112 %115 %118 %121
+               OpReturnValue %122
+               OpFunctionEnd
+          %f = OpFunction %void None %123
+        %126 = OpLabel
+        %129 = OpAccessChain %_ptr_Uniform__arr_Outer_std140_uint_4 %a %uint_0
+        %130 = OpLoad %_arr_Outer_std140_uint_4 %129
+        %127 = OpFunctionCall %_arr_Outer_uint_4 %conv_arr4_Outer %130
+        %133 = OpAccessChain %_ptr_Uniform_Outer_std140 %a %uint_0 %uint_3
+        %134 = OpLoad %Outer_std140 %133
+        %131 = OpFunctionCall %Outer %conv_Outer %134
+        %137 = OpAccessChain %_ptr_Uniform__arr_Inner_std140_uint_4 %a %uint_0 %uint_3 %uint_0
+        %138 = OpLoad %_arr_Inner_std140_uint_4 %137
+        %135 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %138
+        %140 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %uint_3 %uint_0 %uint_2
+        %141 = OpLoad %Inner_std140 %140
+        %139 = OpFunctionCall %Inner %conv_Inner %141
+        %142 = OpFunctionCall %mat4v2half %load_a_inner_3_a_2_m
+        %143 = OpAccessChain %_ptr_Uniform_v2half %a %uint_0 %uint_3 %uint_0 %uint_2 %uint_1
+        %144 = OpLoad %v2half %143
+        %146 = OpAccessChain %_ptr_Uniform_half %a %uint_0 %uint_3 %uint_0 %uint_2 %uint_1 %34
+        %147 = OpLoad %half %146
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/static_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..c3405e4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/static_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,29 @@
+enable f16;
+
+struct Inner {
+  @size(64)
+  m : mat4x2<f16>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_3 = &((*(p_a))[3]);
+  let p_a_3_a = &((*(p_a_3)).a);
+  let p_a_3_a_2 = &((*(p_a_3_a))[2]);
+  let p_a_3_a_2_m = &((*(p_a_3_a_2)).m);
+  let p_a_3_a_2_m_1 = &((*(p_a_3_a_2_m))[1]);
+  let l_a : array<Outer, 4> = *(p_a);
+  let l_a_3 : Outer = *(p_a_3);
+  let l_a_3_a : array<Inner, 4> = *(p_a_3_a);
+  let l_a_3_a_2 : Inner = *(p_a_3_a_2);
+  let l_a_3_a_2_m : mat4x2<f16> = *(p_a_3_a_2_m);
+  let l_a_3_a_2_m_1 : vec2<f16> = *(p_a_3_a_2_m_1);
+  let l_a_3_a_2_m_1_0 : f16 = (*(p_a_3_a_2_m_1))[0];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_builtin.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_builtin.wgsl
new file mode 100644
index 0000000..254c166
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_builtin.wgsl
@@ -0,0 +1,17 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat4x2<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    let t = transpose(u[2].m);
+    let l = length(u[0].m[1].yx);
+    let a = abs(u[0].m[1].yx.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_builtin.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..81cfbc4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_builtin.wgsl.expected.dxc.hlsl
@@ -0,0 +1,25 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+matrix<float16_t, 4, 2> tint_symbol(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const uint scalar_offset_3 = ((offset + 12u)) / 4;
+  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 2, 4> t = transpose(tint_symbol(u, 260u));
+  uint ubo_load_4 = u[0].z;
+  const float16_t l = length(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16))).yx);
+  uint ubo_load_5 = u[0].z;
+  const float16_t a = abs(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_5 & 0xFFFF)), float16_t(f16tof32(ubo_load_5 >> 16))).yx.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_builtin.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..2786ec4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_builtin.wgsl.expected.fxc.hlsl
@@ -0,0 +1,30 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+matrix<float16_t, 4, 2> tint_symbol(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const uint scalar_offset_3 = ((offset + 12u)) / 4;
+  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 2, 4> t = transpose(tint_symbol(u, 260u));
+  uint ubo_load_4 = u[0].z;
+  const float16_t l = length(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16))).yx);
+  uint ubo_load_5 = u[0].z;
+  const float16_t a = abs(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_5 & 0xFFFF)), float16_t(f16tof32(ubo_load_5 >> 16))).yx.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001CC7C77CFC0(5,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_builtin.wgsl.expected.glsl
new file mode 100644
index 0000000..ee9719f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_builtin.wgsl.expected.glsl
@@ -0,0 +1,89 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct S {
+  int before;
+  f16mat4x2 m;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  int after;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+};
+
+struct S_std140 {
+  int before;
+  f16vec2 m_0;
+  f16vec2 m_1;
+  f16vec2 m_2;
+  f16vec2 m_3;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  int after;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+f16mat4x2 load_u_inner_2_m() {
+  return f16mat4x2(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2, u.inner[2u].m_3);
+}
+
+void f() {
+  f16mat2x4 t = transpose(load_u_inner_2_m());
+  float16_t l = length(u.inner[0u].m_1.yx);
+  float16_t a = abs(u.inner[0u].m_1.yx[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_builtin.wgsl.expected.msl
new file mode 100644
index 0000000..49c1370
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_builtin.wgsl.expected.msl
@@ -0,0 +1,31 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ half4x2 m;
+  /* 0x0014 */ tint_array<int8_t, 44> tint_pad;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_1;
+};
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol [[buffer(0)]]) {
+  half2x4 const t = transpose((*(tint_symbol))[2].m);
+  half const l = length(half2((*(tint_symbol))[0].m[1]).yx);
+  half const a = fabs(half2((*(tint_symbol))[0].m[1]).yx[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_builtin.wgsl.expected.spvasm
new file mode 100644
index 0000000..08337b2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_builtin.wgsl.expected.spvasm
@@ -0,0 +1,90 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 55
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+         %45 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "m_2"
+               OpMemberName %S_std140 4 "m_3"
+               OpMemberName %S_std140 5 "after"
+               OpName %u "u"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 4
+               OpMemberDecorate %S_std140 2 Offset 8
+               OpMemberDecorate %S_std140 3 Offset 12
+               OpMemberDecorate %S_std140 4 Offset 16
+               OpMemberDecorate %S_std140 5 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+   %S_std140 = OpTypeStruct %int %v2half %v2half %v2half %v2half %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat4v2half = OpTypeMatrix %v2half 4
+         %11 = OpTypeFunction %mat4v2half
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+     %uint_1 = OpConstant %uint 1
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %36 = OpTypeFunction %void
+     %v4half = OpTypeVector %half 4
+ %mat2v4half = OpTypeMatrix %v4half 2
+         %46 = OpConstantNull %uint
+%load_u_inner_2_m = OpFunction %mat4v2half None %11
+         %14 = OpLabel
+         %19 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %23 = OpAccessChain %_ptr_Uniform_v2half %19 %uint_1
+         %24 = OpLoad %v2half %23
+         %26 = OpAccessChain %_ptr_Uniform_v2half %19 %uint_2
+         %27 = OpLoad %v2half %26
+         %30 = OpAccessChain %_ptr_Uniform_v2half %19 %uint_3
+         %31 = OpLoad %v2half %30
+         %33 = OpAccessChain %_ptr_Uniform_v2half %19 %uint_4
+         %34 = OpLoad %v2half %33
+         %35 = OpCompositeConstruct %mat4v2half %24 %27 %31 %34
+               OpReturnValue %35
+               OpFunctionEnd
+          %f = OpFunction %void None %36
+         %39 = OpLabel
+         %43 = OpFunctionCall %mat4v2half %load_u_inner_2_m
+         %40 = OpTranspose %mat2v4half %43
+         %47 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0 %46 %uint_2
+         %48 = OpLoad %v2half %47
+         %49 = OpVectorShuffle %v2half %48 %48 1 0
+         %44 = OpExtInst %half %45 Length %49
+         %51 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0 %46 %uint_2
+         %52 = OpLoad %v2half %51
+         %53 = OpVectorShuffle %v2half %52 %52 1 0
+         %54 = OpCompositeExtract %half %53 0
+         %50 = OpExtInst %half %45 FAbs %54
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_builtin.wgsl.expected.wgsl
new file mode 100644
index 0000000..61a17a6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_builtin.wgsl.expected.wgsl
@@ -0,0 +1,17 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat4x2<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let t = transpose(u[2].m);
+  let l = length(u[0].m[1].yx);
+  let a = abs(u[0].m[1].yx.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_fn.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_fn.wgsl
new file mode 100644
index 0000000..8ddc186
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_fn.wgsl
@@ -0,0 +1,25 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat4x2<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+fn a(a : array<S, 4>) {}
+fn b(s : S) {}
+fn c(m : mat4x2<f16>) {}
+fn d(v : vec2<f16>) {}
+fn e(f : f16) {}
+
+@compute @workgroup_size(1)
+fn f() {
+    a(u);
+    b(u[2]);
+    c(u[2].m);
+    d(u[0].m[1].yx);
+    e(u[0].m[1].yx.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_fn.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..7620fd9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_fn.wgsl.expected.dxc.hlsl
@@ -0,0 +1,66 @@
+struct S {
+  int before;
+  matrix<float16_t, 4, 2> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(matrix<float16_t, 4, 2> m) {
+}
+
+void d(vector<float16_t, 2> v) {
+}
+
+void e(float16_t f_1) {
+}
+
+matrix<float16_t, 4, 2> tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const uint scalar_offset_3 = ((offset + 12u)) / 4;
+  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_3(buffer, (offset + 4u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 256u));
+  c(tint_symbol_3(u, 260u));
+  uint ubo_load_4 = u[0].z;
+  d(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16))).yx);
+  uint ubo_load_5 = u[0].z;
+  e(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_5 & 0xFFFF)), float16_t(f16tof32(ubo_load_5 >> 16))).yx.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_fn.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..4db57b9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_fn.wgsl.expected.fxc.hlsl
@@ -0,0 +1,71 @@
+SKIP: FAILED
+
+struct S {
+  int before;
+  matrix<float16_t, 4, 2> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(matrix<float16_t, 4, 2> m) {
+}
+
+void d(vector<float16_t, 2> v) {
+}
+
+void e(float16_t f_1) {
+}
+
+matrix<float16_t, 4, 2> tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const uint scalar_offset_3 = ((offset + 12u)) / 4;
+  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_3(buffer, (offset + 4u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 256u));
+  c(tint_symbol_3(u, 260u));
+  uint ubo_load_4 = u[0].z;
+  d(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16))).yx);
+  uint ubo_load_5 = u[0].z;
+  e(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_5 & 0xFFFF)), float16_t(f16tof32(ubo_load_5 >> 16))).yx.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001CA88A4FDA0(3,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_fn.wgsl.expected.glsl
new file mode 100644
index 0000000..abb3943
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_fn.wgsl.expected.glsl
@@ -0,0 +1,120 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct S {
+  int before;
+  f16mat4x2 m;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  int after;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+};
+
+struct S_std140 {
+  int before;
+  f16vec2 m_0;
+  f16vec2 m_1;
+  f16vec2 m_2;
+  f16vec2 m_3;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  int after;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(f16mat4x2 m) {
+}
+
+void d(f16vec2 v) {
+}
+
+void e(float16_t f_1) {
+}
+
+S conv_S(S_std140 val) {
+  return S(val.before, f16mat4x2(val.m_0, val.m_1, val.m_2, val.m_3), val.pad, val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.after, val.pad_11, val.pad_12, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21, val.pad_22, val.pad_23, val.pad_24, val.pad_25);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat4x2 load_u_inner_2_m() {
+  return f16mat4x2(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2, u.inner[2u].m_3);
+}
+
+void f() {
+  a(conv_arr4_S(u.inner));
+  b(conv_S(u.inner[2u]));
+  c(load_u_inner_2_m());
+  d(u.inner[0u].m_1.yx);
+  e(u.inner[0u].m_1.yx[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_fn.wgsl.expected.msl
new file mode 100644
index 0000000..527770e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_fn.wgsl.expected.msl
@@ -0,0 +1,48 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ half4x2 m;
+  /* 0x0014 */ tint_array<int8_t, 44> tint_pad;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_1;
+};
+
+void a(tint_array<S, 4> a_1) {
+}
+
+void b(S s) {
+}
+
+void c(half4x2 m) {
+}
+
+void d(half2 v) {
+}
+
+void e(half f_1) {
+}
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol [[buffer(0)]]) {
+  a(*(tint_symbol));
+  b((*(tint_symbol))[2]);
+  c((*(tint_symbol))[2].m);
+  d(half2((*(tint_symbol))[0].m[1]).yx);
+  e(half2((*(tint_symbol))[0].m[1]).yx[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_fn.wgsl.expected.spvasm
new file mode 100644
index 0000000..3174741
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_fn.wgsl.expected.spvasm
@@ -0,0 +1,215 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 128
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "m_2"
+               OpMemberName %S_std140 4 "m_3"
+               OpMemberName %S_std140 5 "after"
+               OpName %u "u"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %a "a"
+               OpName %a_1 "a_1"
+               OpName %b "b"
+               OpName %s "s"
+               OpName %c "c"
+               OpName %m "m"
+               OpName %d "d"
+               OpName %v "v"
+               OpName %e "e"
+               OpName %f_1 "f_1"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 4
+               OpMemberDecorate %S_std140 2 Offset 8
+               OpMemberDecorate %S_std140 3 Offset 12
+               OpMemberDecorate %S_std140 4 Offset 16
+               OpMemberDecorate %S_std140 5 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 4
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 4
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+   %S_std140 = OpTypeStruct %int %v2half %v2half %v2half %v2half %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+       %void = OpTypeVoid
+ %mat4v2half = OpTypeMatrix %v2half 4
+          %S = OpTypeStruct %int %mat4v2half %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+         %11 = OpTypeFunction %void %_arr_S_uint_4
+         %19 = OpTypeFunction %void %S
+         %23 = OpTypeFunction %void %mat4v2half
+         %27 = OpTypeFunction %void %v2half
+         %31 = OpTypeFunction %void %half
+         %35 = OpTypeFunction %S %S_std140
+         %47 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+         %53 = OpConstantNull %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %56 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %69 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %82 = OpTypeFunction %mat4v2half
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+     %uint_3 = OpConstant %uint 3
+        %105 = OpTypeFunction %void
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+          %a = OpFunction %void None %11
+        %a_1 = OpFunctionParameter %_arr_S_uint_4
+         %18 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %b = OpFunction %void None %19
+          %s = OpFunctionParameter %S
+         %22 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %c = OpFunction %void None %23
+          %m = OpFunctionParameter %mat4v2half
+         %26 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %d = OpFunction %void None %27
+          %v = OpFunctionParameter %v2half
+         %30 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %e = OpFunction %void None %31
+        %f_1 = OpFunctionParameter %half
+         %34 = OpLabel
+               OpReturn
+               OpFunctionEnd
+     %conv_S = OpFunction %S None %35
+        %val = OpFunctionParameter %S_std140
+         %38 = OpLabel
+         %39 = OpCompositeExtract %int %val 0
+         %40 = OpCompositeExtract %v2half %val 1
+         %41 = OpCompositeExtract %v2half %val 2
+         %42 = OpCompositeExtract %v2half %val 3
+         %43 = OpCompositeExtract %v2half %val 4
+         %44 = OpCompositeConstruct %mat4v2half %40 %41 %42 %43
+         %45 = OpCompositeExtract %int %val 5
+         %46 = OpCompositeConstruct %S %39 %44 %45
+               OpReturnValue %46
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %47
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %50 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %53
+          %i = OpVariable %_ptr_Function_uint Function %56
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %69
+               OpBranch %57
+         %57 = OpLabel
+               OpLoopMerge %58 %59 None
+               OpBranch %60
+         %60 = OpLabel
+         %62 = OpLoad %uint %i
+         %63 = OpULessThan %bool %62 %uint_4
+         %61 = OpLogicalNot %bool %63
+               OpSelectionMerge %65 None
+               OpBranchConditional %61 %66 %65
+         %66 = OpLabel
+               OpBranch %58
+         %65 = OpLabel
+               OpStore %var_for_index %val_0
+         %70 = OpLoad %uint %i
+         %72 = OpAccessChain %_ptr_Function_S %arr %70
+         %74 = OpLoad %uint %i
+         %76 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %74
+         %77 = OpLoad %S_std140 %76
+         %73 = OpFunctionCall %S %conv_S %77
+               OpStore %72 %73
+               OpBranch %59
+         %59 = OpLabel
+         %78 = OpLoad %uint %i
+         %80 = OpIAdd %uint %78 %uint_1
+               OpStore %i %80
+               OpBranch %57
+         %58 = OpLabel
+         %81 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %81
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat4v2half None %82
+         %84 = OpLabel
+         %89 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %92 = OpAccessChain %_ptr_Uniform_v2half %89 %uint_1
+         %93 = OpLoad %v2half %92
+         %95 = OpAccessChain %_ptr_Uniform_v2half %89 %uint_2
+         %96 = OpLoad %v2half %95
+         %99 = OpAccessChain %_ptr_Uniform_v2half %89 %uint_3
+        %100 = OpLoad %v2half %99
+        %102 = OpAccessChain %_ptr_Uniform_v2half %89 %uint_4
+        %103 = OpLoad %v2half %102
+        %104 = OpCompositeConstruct %mat4v2half %93 %96 %100 %103
+               OpReturnValue %104
+               OpFunctionEnd
+          %f = OpFunction %void None %105
+        %107 = OpLabel
+        %111 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+        %112 = OpLoad %_arr_S_std140_uint_4 %111
+        %109 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %112
+        %108 = OpFunctionCall %void %a %109
+        %115 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+        %116 = OpLoad %S_std140 %115
+        %114 = OpFunctionCall %S %conv_S %116
+        %113 = OpFunctionCall %void %b %114
+        %118 = OpFunctionCall %mat4v2half %load_u_inner_2_m
+        %117 = OpFunctionCall %void %c %118
+        %120 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0 %56 %uint_2
+        %121 = OpLoad %v2half %120
+        %122 = OpVectorShuffle %v2half %121 %121 1 0
+        %119 = OpFunctionCall %void %d %122
+        %124 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0 %56 %uint_2
+        %125 = OpLoad %v2half %124
+        %126 = OpVectorShuffle %v2half %125 %125 1 0
+        %127 = OpCompositeExtract %half %126 0
+        %123 = OpFunctionCall %void %e %127
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_fn.wgsl.expected.wgsl
new file mode 100644
index 0000000..61c115b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_fn.wgsl.expected.wgsl
@@ -0,0 +1,34 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat4x2<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+fn a(a : array<S, 4>) {
+}
+
+fn b(s : S) {
+}
+
+fn c(m : mat4x2<f16>) {
+}
+
+fn d(v : vec2<f16>) {
+}
+
+fn e(f : f16) {
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  a(u);
+  b(u[2]);
+  c(u[2].m);
+  d(u[0].m[1].yx);
+  e(u[0].m[1].yx.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_private.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_private.wgsl
new file mode 100644
index 0000000..101080f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_private.wgsl
@@ -0,0 +1,19 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat4x2<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+var<private> p : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[2];
+    p[3].m = u[2].m;
+    p[1].m[0] = u[0].m[1].yx;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_private.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..717e390
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_private.wgsl.expected.dxc.hlsl
@@ -0,0 +1,50 @@
+struct S {
+  int before;
+  matrix<float16_t, 4, 2> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+static S p[4] = (S[4])0;
+
+matrix<float16_t, 4, 2> tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const uint scalar_offset_3 = ((offset + 12u)) / 4;
+  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_3(buffer, (offset + 4u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 256u);
+  p[3].m = tint_symbol_3(u, 260u);
+  uint ubo_load_4 = u[0].z;
+  p[1].m[0] = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16))).yx;
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_private.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..12b11cc
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_private.wgsl.expected.fxc.hlsl
@@ -0,0 +1,55 @@
+SKIP: FAILED
+
+struct S {
+  int before;
+  matrix<float16_t, 4, 2> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+static S p[4] = (S[4])0;
+
+matrix<float16_t, 4, 2> tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const uint scalar_offset_3 = ((offset + 12u)) / 4;
+  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_3(buffer, (offset + 4u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 256u);
+  p[3].m = tint_symbol_3(u, 260u);
+  uint ubo_load_4 = u[0].z;
+  p[1].m[0] = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16))).yx;
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000002074AC3FD30(3,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..4020bea
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_private.wgsl.expected.glsl
@@ -0,0 +1,105 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct S {
+  int before;
+  f16mat4x2 m;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  int after;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+};
+
+struct S_std140 {
+  int before;
+  f16vec2 m_0;
+  f16vec2 m_1;
+  f16vec2 m_2;
+  f16vec2 m_3;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  int after;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+S p[4] = S[4](S(0, f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+S conv_S(S_std140 val) {
+  return S(val.before, f16mat4x2(val.m_0, val.m_1, val.m_2, val.m_3), val.pad, val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.after, val.pad_11, val.pad_12, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21, val.pad_22, val.pad_23, val.pad_24, val.pad_25);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat4x2 load_u_inner_2_m() {
+  return f16mat4x2(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2, u.inner[2u].m_3);
+}
+
+void f() {
+  p = conv_arr4_S(u.inner);
+  p[1] = conv_S(u.inner[2u]);
+  p[3].m = load_u_inner_2_m();
+  p[1].m[0] = u.inner[0u].m_1.yx;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..a941446
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_private.wgsl.expected.msl
@@ -0,0 +1,33 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ half4x2 m;
+  /* 0x0014 */ tint_array<int8_t, 44> tint_pad;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_1;
+};
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol_1 [[buffer(0)]]) {
+  thread tint_array<S, 4> tint_symbol = {};
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[2];
+  tint_symbol[3].m = (*(tint_symbol_1))[2].m;
+  tint_symbol[1].m[0] = half2((*(tint_symbol_1))[0].m[1]).yx;
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_private.wgsl.expected.spvasm
new file mode 100644
index 0000000..705a738
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_private.wgsl.expected.spvasm
@@ -0,0 +1,182 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 110
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "m_2"
+               OpMemberName %S_std140 4 "m_3"
+               OpMemberName %S_std140 5 "after"
+               OpName %u "u"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %p "p"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 4
+               OpMemberDecorate %S_std140 2 Offset 8
+               OpMemberDecorate %S_std140 3 Offset 12
+               OpMemberDecorate %S_std140 4 Offset 16
+               OpMemberDecorate %S_std140 5 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 4
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 4
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+   %S_std140 = OpTypeStruct %int %v2half %v2half %v2half %v2half %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat4v2half = OpTypeMatrix %v2half 4
+          %S = OpTypeStruct %int %mat4v2half %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+%_ptr_Private__arr_S_uint_4 = OpTypePointer Private %_arr_S_uint_4
+         %16 = OpConstantNull %_arr_S_uint_4
+          %p = OpVariable %_ptr_Private__arr_S_uint_4 Private %16
+         %17 = OpTypeFunction %S %S_std140
+         %29 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %37 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %50 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %63 = OpTypeFunction %mat4v2half
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %86 = OpTypeFunction %void
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+      %int_1 = OpConstant %int 1
+%_ptr_Private_S = OpTypePointer Private %S
+      %int_3 = OpConstant %int 3
+%_ptr_Private_mat4v2half = OpTypePointer Private %mat4v2half
+        %104 = OpConstantNull %int
+%_ptr_Private_v2half = OpTypePointer Private %v2half
+     %conv_S = OpFunction %S None %17
+        %val = OpFunctionParameter %S_std140
+         %20 = OpLabel
+         %21 = OpCompositeExtract %int %val 0
+         %22 = OpCompositeExtract %v2half %val 1
+         %23 = OpCompositeExtract %v2half %val 2
+         %24 = OpCompositeExtract %v2half %val 3
+         %25 = OpCompositeExtract %v2half %val 4
+         %26 = OpCompositeConstruct %mat4v2half %22 %23 %24 %25
+         %27 = OpCompositeExtract %int %val 5
+         %28 = OpCompositeConstruct %S %21 %26 %27
+               OpReturnValue %28
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %29
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %32 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %16
+          %i = OpVariable %_ptr_Function_uint Function %37
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %50
+               OpBranch %38
+         %38 = OpLabel
+               OpLoopMerge %39 %40 None
+               OpBranch %41
+         %41 = OpLabel
+         %43 = OpLoad %uint %i
+         %44 = OpULessThan %bool %43 %uint_4
+         %42 = OpLogicalNot %bool %44
+               OpSelectionMerge %46 None
+               OpBranchConditional %42 %47 %46
+         %47 = OpLabel
+               OpBranch %39
+         %46 = OpLabel
+               OpStore %var_for_index %val_0
+         %51 = OpLoad %uint %i
+         %53 = OpAccessChain %_ptr_Function_S %arr %51
+         %55 = OpLoad %uint %i
+         %57 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %55
+         %58 = OpLoad %S_std140 %57
+         %54 = OpFunctionCall %S %conv_S %58
+               OpStore %53 %54
+               OpBranch %40
+         %40 = OpLabel
+         %59 = OpLoad %uint %i
+         %61 = OpIAdd %uint %59 %uint_1
+               OpStore %i %61
+               OpBranch %38
+         %39 = OpLabel
+         %62 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %62
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat4v2half None %63
+         %65 = OpLabel
+         %70 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %73 = OpAccessChain %_ptr_Uniform_v2half %70 %uint_1
+         %74 = OpLoad %v2half %73
+         %76 = OpAccessChain %_ptr_Uniform_v2half %70 %uint_2
+         %77 = OpLoad %v2half %76
+         %80 = OpAccessChain %_ptr_Uniform_v2half %70 %uint_3
+         %81 = OpLoad %v2half %80
+         %83 = OpAccessChain %_ptr_Uniform_v2half %70 %uint_4
+         %84 = OpLoad %v2half %83
+         %85 = OpCompositeConstruct %mat4v2half %74 %77 %81 %84
+               OpReturnValue %85
+               OpFunctionEnd
+          %f = OpFunction %void None %86
+         %89 = OpLabel
+         %92 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+         %93 = OpLoad %_arr_S_std140_uint_4 %92
+         %90 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %93
+               OpStore %p %90
+         %96 = OpAccessChain %_ptr_Private_S %p %int_1
+         %98 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %99 = OpLoad %S_std140 %98
+         %97 = OpFunctionCall %S %conv_S %99
+               OpStore %96 %97
+        %102 = OpAccessChain %_ptr_Private_mat4v2half %p %int_3 %uint_1
+        %103 = OpFunctionCall %mat4v2half %load_u_inner_2_m
+               OpStore %102 %103
+        %106 = OpAccessChain %_ptr_Private_v2half %p %int_1 %uint_1 %104
+        %107 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0 %37 %uint_2
+        %108 = OpLoad %v2half %107
+        %109 = OpVectorShuffle %v2half %108 %108 1 0
+               OpStore %106 %109
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..be2d781
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_private.wgsl.expected.wgsl
@@ -0,0 +1,20 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat4x2<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+var<private> p : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[2];
+  p[3].m = u[2].m;
+  p[1].m[0] = u[0].m[1].yx;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_storage.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_storage.wgsl
new file mode 100644
index 0000000..3d014af
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_storage.wgsl
@@ -0,0 +1,19 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat4x2<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+@group(0) @binding(1) var<storage, read_write> s : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[2];
+    s[3].m = u[2].m;
+    s[1].m[0] = u[0].m[1].yx;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_storage.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..180ae47
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_storage.wgsl.expected.dxc.hlsl
@@ -0,0 +1,72 @@
+struct S {
+  int before;
+  matrix<float16_t, 4, 2> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_3(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 2> value) {
+  buffer.Store<vector<float16_t, 2> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 4u), value[1u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 8u), value[2u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 12u), value[3u]);
+}
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, S value) {
+  buffer.Store((offset + 0u), asuint(value.before));
+  tint_symbol_3(buffer, (offset + 4u), value.m);
+  buffer.Store((offset + 64u), asuint(value.after));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, S value[4]) {
+  S array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 128u)), array[i]);
+    }
+  }
+}
+
+matrix<float16_t, 4, 2> tint_symbol_8(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const uint scalar_offset_3 = ((offset + 12u)) / 4;
+  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+}
+
+S tint_symbol_6(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 64u)) / 4;
+  const S tint_symbol_10 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_8(buffer, (offset + 4u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_10;
+}
+
+typedef S tint_symbol_5_ret[4];
+tint_symbol_5_ret tint_symbol_5(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_6(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_5(u, 0u));
+  tint_symbol_1(s, 128u, tint_symbol_6(u, 256u));
+  tint_symbol_3(s, 388u, tint_symbol_8(u, 260u));
+  uint ubo_load_4 = u[0].z;
+  s.Store<vector<float16_t, 2> >(132u, vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16))).yx);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_storage.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..fc9ff30
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_storage.wgsl.expected.fxc.hlsl
@@ -0,0 +1,77 @@
+SKIP: FAILED
+
+struct S {
+  int before;
+  matrix<float16_t, 4, 2> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_3(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 2> value) {
+  buffer.Store<vector<float16_t, 2> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 4u), value[1u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 8u), value[2u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 12u), value[3u]);
+}
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, S value) {
+  buffer.Store((offset + 0u), asuint(value.before));
+  tint_symbol_3(buffer, (offset + 4u), value.m);
+  buffer.Store((offset + 64u), asuint(value.after));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, S value[4]) {
+  S array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 128u)), array[i]);
+    }
+  }
+}
+
+matrix<float16_t, 4, 2> tint_symbol_8(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const uint scalar_offset_3 = ((offset + 12u)) / 4;
+  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+}
+
+S tint_symbol_6(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 64u)) / 4;
+  const S tint_symbol_10 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_8(buffer, (offset + 4u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_10;
+}
+
+typedef S tint_symbol_5_ret[4];
+tint_symbol_5_ret tint_symbol_5(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_6(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_5(u, 0u));
+  tint_symbol_1(s, 128u, tint_symbol_6(u, 256u));
+  tint_symbol_3(s, 388u, tint_symbol_8(u, 260u));
+  uint ubo_load_4 = u[0].z;
+  s.Store<vector<float16_t, 2> >(132u, vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16))).yx);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x00000185CE589540(3,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..2e843e1
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_storage.wgsl.expected.glsl
@@ -0,0 +1,108 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct S {
+  int before;
+  f16mat4x2 m;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  int after;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+};
+
+struct S_std140 {
+  int before;
+  f16vec2 m_0;
+  f16vec2 m_1;
+  f16vec2 m_2;
+  f16vec2 m_3;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  int after;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  S inner[4];
+} s;
+
+S conv_S(S_std140 val) {
+  return S(val.before, f16mat4x2(val.m_0, val.m_1, val.m_2, val.m_3), val.pad, val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.after, val.pad_11, val.pad_12, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21, val.pad_22, val.pad_23, val.pad_24, val.pad_25);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat4x2 load_u_inner_2_m() {
+  return f16mat4x2(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2, u.inner[2u].m_3);
+}
+
+void f() {
+  s.inner = conv_arr4_S(u.inner);
+  s.inner[1] = conv_S(u.inner[2u]);
+  s.inner[3].m = load_u_inner_2_m();
+  s.inner[1].m[0] = u.inner[0u].m_1.yx;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..b266704
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_storage.wgsl.expected.msl
@@ -0,0 +1,32 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ half4x2 m;
+  /* 0x0014 */ tint_array<int8_t, 44> tint_pad;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_1;
+};
+
+kernel void f(device tint_array<S, 4>* tint_symbol [[buffer(1)]], const constant tint_array<S, 4>* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
+  (*(tint_symbol))[3].m = (*(tint_symbol_1))[2].m;
+  (*(tint_symbol))[1].m[0] = half2((*(tint_symbol_1))[0].m[1]).yx;
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_storage.wgsl.expected.spvasm
new file mode 100644
index 0000000..f9fa6f4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_storage.wgsl.expected.spvasm
@@ -0,0 +1,191 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 113
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "m_2"
+               OpMemberName %S_std140 4 "m_3"
+               OpMemberName %S_std140 5 "after"
+               OpName %u "u"
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %s "s"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 4
+               OpMemberDecorate %S_std140 2 Offset 8
+               OpMemberDecorate %S_std140 3 Offset 12
+               OpMemberDecorate %S_std140 4 Offset 16
+               OpMemberDecorate %S_std140 5 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 4
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 4
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+               OpDecorate %s DescriptorSet 0
+               OpDecorate %s Binding 1
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+   %S_std140 = OpTypeStruct %int %v2half %v2half %v2half %v2half %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat4v2half = OpTypeMatrix %v2half 4
+          %S = OpTypeStruct %int %mat4v2half %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+    %u_block = OpTypeStruct %_arr_S_uint_4
+%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
+          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+         %17 = OpTypeFunction %S %S_std140
+         %29 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+         %35 = OpConstantNull %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %38 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %51 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %64 = OpTypeFunction %mat4v2half
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %87 = OpTypeFunction %void
+%_ptr_StorageBuffer__arr_S_uint_4 = OpTypePointer StorageBuffer %_arr_S_uint_4
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+      %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
+      %int_3 = OpConstant %int 3
+%_ptr_StorageBuffer_mat4v2half = OpTypePointer StorageBuffer %mat4v2half
+        %107 = OpConstantNull %int
+%_ptr_StorageBuffer_v2half = OpTypePointer StorageBuffer %v2half
+     %conv_S = OpFunction %S None %17
+        %val = OpFunctionParameter %S_std140
+         %20 = OpLabel
+         %21 = OpCompositeExtract %int %val 0
+         %22 = OpCompositeExtract %v2half %val 1
+         %23 = OpCompositeExtract %v2half %val 2
+         %24 = OpCompositeExtract %v2half %val 3
+         %25 = OpCompositeExtract %v2half %val 4
+         %26 = OpCompositeConstruct %mat4v2half %22 %23 %24 %25
+         %27 = OpCompositeExtract %int %val 5
+         %28 = OpCompositeConstruct %S %21 %26 %27
+               OpReturnValue %28
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %29
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %32 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %35
+          %i = OpVariable %_ptr_Function_uint Function %38
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %51
+               OpBranch %39
+         %39 = OpLabel
+               OpLoopMerge %40 %41 None
+               OpBranch %42
+         %42 = OpLabel
+         %44 = OpLoad %uint %i
+         %45 = OpULessThan %bool %44 %uint_4
+         %43 = OpLogicalNot %bool %45
+               OpSelectionMerge %47 None
+               OpBranchConditional %43 %48 %47
+         %48 = OpLabel
+               OpBranch %40
+         %47 = OpLabel
+               OpStore %var_for_index %val_0
+         %52 = OpLoad %uint %i
+         %54 = OpAccessChain %_ptr_Function_S %arr %52
+         %56 = OpLoad %uint %i
+         %58 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %56
+         %59 = OpLoad %S_std140 %58
+         %55 = OpFunctionCall %S %conv_S %59
+               OpStore %54 %55
+               OpBranch %41
+         %41 = OpLabel
+         %60 = OpLoad %uint %i
+         %62 = OpIAdd %uint %60 %uint_1
+               OpStore %i %62
+               OpBranch %39
+         %40 = OpLabel
+         %63 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %63
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat4v2half None %64
+         %66 = OpLabel
+         %71 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %74 = OpAccessChain %_ptr_Uniform_v2half %71 %uint_1
+         %75 = OpLoad %v2half %74
+         %77 = OpAccessChain %_ptr_Uniform_v2half %71 %uint_2
+         %78 = OpLoad %v2half %77
+         %81 = OpAccessChain %_ptr_Uniform_v2half %71 %uint_3
+         %82 = OpLoad %v2half %81
+         %84 = OpAccessChain %_ptr_Uniform_v2half %71 %uint_4
+         %85 = OpLoad %v2half %84
+         %86 = OpCompositeConstruct %mat4v2half %75 %78 %82 %85
+               OpReturnValue %86
+               OpFunctionEnd
+          %f = OpFunction %void None %87
+         %90 = OpLabel
+         %92 = OpAccessChain %_ptr_StorageBuffer__arr_S_uint_4 %s %uint_0
+         %95 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+         %96 = OpLoad %_arr_S_std140_uint_4 %95
+         %93 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %96
+               OpStore %92 %93
+         %99 = OpAccessChain %_ptr_StorageBuffer_S %s %uint_0 %int_1
+        %101 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+        %102 = OpLoad %S_std140 %101
+        %100 = OpFunctionCall %S %conv_S %102
+               OpStore %99 %100
+        %105 = OpAccessChain %_ptr_StorageBuffer_mat4v2half %s %uint_0 %int_3 %uint_1
+        %106 = OpFunctionCall %mat4v2half %load_u_inner_2_m
+               OpStore %105 %106
+        %109 = OpAccessChain %_ptr_StorageBuffer_v2half %s %uint_0 %int_1 %uint_1 %107
+        %110 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0 %38 %uint_2
+        %111 = OpLoad %v2half %110
+        %112 = OpVectorShuffle %v2half %111 %111 1 0
+               OpStore %109 %112
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..f360114
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,20 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat4x2<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@group(0) @binding(1) var<storage, read_write> s : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[2];
+  s[3].m = u[2].m;
+  s[1].m[0] = u[0].m[1].yx;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_workgroup.wgsl
new file mode 100644
index 0000000..b6a276d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_workgroup.wgsl
@@ -0,0 +1,19 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat4x2<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+var<workgroup> w : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[2];
+    w[3].m = u[2].m;
+    w[1].m[0] = u[0].m[1].yx;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_workgroup.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..334fe1e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_workgroup.wgsl.expected.dxc.hlsl
@@ -0,0 +1,66 @@
+struct S {
+  int before;
+  matrix<float16_t, 4, 2> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+groupshared S w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 4, 2> tint_symbol_5(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const uint scalar_offset_3 = ((offset + 12u)) / 4;
+  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+}
+
+S tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 64u)) / 4;
+  const S tint_symbol_8 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_5(buffer, (offset + 4u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_8;
+}
+
+typedef S tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      const S tint_symbol_7 = (S)0;
+      w[i] = tint_symbol_7;
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 256u);
+  w[3].m = tint_symbol_5(u, 260u);
+  uint ubo_load_4 = u[0].z;
+  w[1].m[0] = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16))).yx;
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_workgroup.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..7f448db
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_workgroup.wgsl.expected.fxc.hlsl
@@ -0,0 +1,71 @@
+SKIP: FAILED
+
+struct S {
+  int before;
+  matrix<float16_t, 4, 2> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+groupshared S w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 4, 2> tint_symbol_5(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const uint scalar_offset_3 = ((offset + 12u)) / 4;
+  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+}
+
+S tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 64u)) / 4;
+  const S tint_symbol_8 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_5(buffer, (offset + 4u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_8;
+}
+
+typedef S tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      const S tint_symbol_7 = (S)0;
+      w[i] = tint_symbol_7;
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 256u);
+  w[3].m = tint_symbol_5(u, 260u);
+  uint ubo_load_4 = u[0].z;
+  w[1].m[0] = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16))).yx;
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001B8BDB52100(3,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..b6a2696
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,113 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct S {
+  int before;
+  f16mat4x2 m;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  int after;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+};
+
+struct S_std140 {
+  int before;
+  f16vec2 m_0;
+  f16vec2 m_1;
+  f16vec2 m_2;
+  f16vec2 m_3;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  int after;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+shared S w[4];
+S conv_S(S_std140 val) {
+  return S(val.before, f16mat4x2(val.m_0, val.m_1, val.m_2, val.m_3), val.pad, val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.after, val.pad_11, val.pad_12, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21, val.pad_22, val.pad_23, val.pad_24, val.pad_25);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat4x2 load_u_inner_2_m() {
+  return f16mat4x2(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2, u.inner[2u].m_3);
+}
+
+void f(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      uint i = idx;
+      S tint_symbol = S(0, f16mat4x2(f16vec2(0.0hf), f16vec2(0.0hf), f16vec2(0.0hf), f16vec2(0.0hf)), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u);
+      w[i] = tint_symbol;
+    }
+  }
+  barrier();
+  w = conv_arr4_S(u.inner);
+  w[1] = conv_S(u.inner[2u]);
+  w[3].m = load_u_inner_2_m();
+  w[1].m[0] = u.inner[0u].m_1.yx;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..41f9255
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,47 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ half4x2 m;
+  /* 0x0014 */ tint_array<int8_t, 44> tint_pad;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_1;
+};
+
+struct tint_symbol_6 {
+  tint_array<S, 4> w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup tint_array<S, 4>* const tint_symbol_1, const constant tint_array<S, 4>* const tint_symbol_2) {
+  for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+    uint const i = idx;
+    S const tint_symbol = S{};
+    (*(tint_symbol_1))[i] = tint_symbol;
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol_1) = *(tint_symbol_2);
+  (*(tint_symbol_1))[1] = (*(tint_symbol_2))[2];
+  (*(tint_symbol_1))[3].m = (*(tint_symbol_2))[2].m;
+  (*(tint_symbol_1))[1].m[0] = half2((*(tint_symbol_2))[0].m[1]).yx;
+}
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol_5 [[buffer(0)]], threadgroup tint_symbol_6* tint_symbol_4 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup tint_array<S, 4>* const tint_symbol_3 = &((*(tint_symbol_4)).w);
+  f_inner(local_invocation_index, tint_symbol_3, tint_symbol_5);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_workgroup.wgsl.expected.spvasm
new file mode 100644
index 0000000..03db478
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_workgroup.wgsl.expected.spvasm
@@ -0,0 +1,225 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 135
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %local_invocation_index_1 "local_invocation_index_1"
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "m_2"
+               OpMemberName %S_std140 4 "m_3"
+               OpMemberName %S_std140 5 "after"
+               OpName %u "u"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %w "w"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f_inner "f_inner"
+               OpName %local_invocation_index "local_invocation_index"
+               OpName %idx "idx"
+               OpName %f "f"
+               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 4
+               OpMemberDecorate %S_std140 2 Offset 8
+               OpMemberDecorate %S_std140 3 Offset 12
+               OpMemberDecorate %S_std140 4 Offset 16
+               OpMemberDecorate %S_std140 5 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 4
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 4
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+   %S_std140 = OpTypeStruct %int %v2half %v2half %v2half %v2half %int
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat4v2half = OpTypeMatrix %v2half 4
+          %S = OpTypeStruct %int %mat4v2half %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+%_ptr_Workgroup__arr_S_uint_4 = OpTypePointer Workgroup %_arr_S_uint_4
+          %w = OpVariable %_ptr_Workgroup__arr_S_uint_4 Workgroup
+         %18 = OpTypeFunction %S %S_std140
+         %30 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+         %36 = OpConstantNull %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %39 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %52 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %65 = OpTypeFunction %mat4v2half
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %88 = OpTypeFunction %void %uint
+%_ptr_Workgroup_S = OpTypePointer Workgroup %S
+        %106 = OpConstantNull %S
+   %uint_264 = OpConstant %uint 264
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+      %int_1 = OpConstant %int 1
+      %int_3 = OpConstant %int 3
+%_ptr_Workgroup_mat4v2half = OpTypePointer Workgroup %mat4v2half
+        %124 = OpConstantNull %int
+%_ptr_Workgroup_v2half = OpTypePointer Workgroup %v2half
+        %130 = OpTypeFunction %void
+     %conv_S = OpFunction %S None %18
+        %val = OpFunctionParameter %S_std140
+         %21 = OpLabel
+         %22 = OpCompositeExtract %int %val 0
+         %23 = OpCompositeExtract %v2half %val 1
+         %24 = OpCompositeExtract %v2half %val 2
+         %25 = OpCompositeExtract %v2half %val 3
+         %26 = OpCompositeExtract %v2half %val 4
+         %27 = OpCompositeConstruct %mat4v2half %23 %24 %25 %26
+         %28 = OpCompositeExtract %int %val 5
+         %29 = OpCompositeConstruct %S %22 %27 %28
+               OpReturnValue %29
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %30
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %33 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %36
+          %i = OpVariable %_ptr_Function_uint Function %39
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %52
+               OpBranch %40
+         %40 = OpLabel
+               OpLoopMerge %41 %42 None
+               OpBranch %43
+         %43 = OpLabel
+         %45 = OpLoad %uint %i
+         %46 = OpULessThan %bool %45 %uint_4
+         %44 = OpLogicalNot %bool %46
+               OpSelectionMerge %48 None
+               OpBranchConditional %44 %49 %48
+         %49 = OpLabel
+               OpBranch %41
+         %48 = OpLabel
+               OpStore %var_for_index %val_0
+         %53 = OpLoad %uint %i
+         %55 = OpAccessChain %_ptr_Function_S %arr %53
+         %57 = OpLoad %uint %i
+         %59 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %57
+         %60 = OpLoad %S_std140 %59
+         %56 = OpFunctionCall %S %conv_S %60
+               OpStore %55 %56
+               OpBranch %42
+         %42 = OpLabel
+         %61 = OpLoad %uint %i
+         %63 = OpIAdd %uint %61 %uint_1
+               OpStore %i %63
+               OpBranch %40
+         %41 = OpLabel
+         %64 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %64
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat4v2half None %65
+         %67 = OpLabel
+         %72 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %75 = OpAccessChain %_ptr_Uniform_v2half %72 %uint_1
+         %76 = OpLoad %v2half %75
+         %78 = OpAccessChain %_ptr_Uniform_v2half %72 %uint_2
+         %79 = OpLoad %v2half %78
+         %82 = OpAccessChain %_ptr_Uniform_v2half %72 %uint_3
+         %83 = OpLoad %v2half %82
+         %85 = OpAccessChain %_ptr_Uniform_v2half %72 %uint_4
+         %86 = OpLoad %v2half %85
+         %87 = OpCompositeConstruct %mat4v2half %76 %79 %83 %86
+               OpReturnValue %87
+               OpFunctionEnd
+    %f_inner = OpFunction %void None %88
+%local_invocation_index = OpFunctionParameter %uint
+         %92 = OpLabel
+        %idx = OpVariable %_ptr_Function_uint Function %39
+               OpStore %idx %local_invocation_index
+               OpBranch %94
+         %94 = OpLabel
+               OpLoopMerge %95 %96 None
+               OpBranch %97
+         %97 = OpLabel
+         %99 = OpLoad %uint %idx
+        %100 = OpULessThan %bool %99 %uint_4
+         %98 = OpLogicalNot %bool %100
+               OpSelectionMerge %101 None
+               OpBranchConditional %98 %102 %101
+        %102 = OpLabel
+               OpBranch %95
+        %101 = OpLabel
+        %103 = OpLoad %uint %idx
+        %105 = OpAccessChain %_ptr_Workgroup_S %w %103
+               OpStore %105 %106
+               OpBranch %96
+         %96 = OpLabel
+        %107 = OpLoad %uint %idx
+        %108 = OpIAdd %uint %107 %uint_1
+               OpStore %idx %108
+               OpBranch %94
+         %95 = OpLabel
+               OpControlBarrier %uint_2 %uint_2 %uint_264
+        %113 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+        %114 = OpLoad %_arr_S_std140_uint_4 %113
+        %111 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %114
+               OpStore %w %111
+        %116 = OpAccessChain %_ptr_Workgroup_S %w %int_1
+        %118 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+        %119 = OpLoad %S_std140 %118
+        %117 = OpFunctionCall %S %conv_S %119
+               OpStore %116 %117
+        %122 = OpAccessChain %_ptr_Workgroup_mat4v2half %w %int_3 %uint_1
+        %123 = OpFunctionCall %mat4v2half %load_u_inner_2_m
+               OpStore %122 %123
+        %126 = OpAccessChain %_ptr_Workgroup_v2half %w %int_1 %uint_1 %124
+        %127 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0 %39 %uint_2
+        %128 = OpLoad %v2half %127
+        %129 = OpVectorShuffle %v2half %128 %128 1 0
+               OpStore %126 %129
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %130
+        %132 = OpLabel
+        %134 = OpLoad %uint %local_invocation_index_1
+        %133 = OpFunctionCall %void %f_inner %134
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..de7011b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f16/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,20 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat4x2<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+var<workgroup> w : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[2];
+  w[3].m = u[2].m;
+  w[1].m[0] = u[0].m[1].yx;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/dynamic_index_via_ptr.wgsl
new file mode 100644
index 0000000..2d874a7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/dynamic_index_via_ptr.wgsl
@@ -0,0 +1,32 @@
+struct Inner {
+  @size(64)
+  m : mat4x2<f32>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a           = &a;
+  let p_a_i         = &((*p_a)[i()]);
+  let p_a_i_a       = &((*p_a_i).a);
+  let p_a_i_a_i     = &((*p_a_i_a)[i()]);
+  let p_a_i_a_i_m   = &((*p_a_i_a_i).m);
+  let p_a_i_a_i_m_i = &((*p_a_i_a_i_m)[i()]);
+
+
+  let l_a             : array<Outer, 4> =  *p_a;
+  let l_a_i           : Outer           =  *p_a_i;
+  let l_a_i_a         : array<Inner, 4> =  *p_a_i_a;
+  let l_a_i_a_i       : Inner           =  *p_a_i_a_i;
+  let l_a_i_a_i_m     : mat4x2<f32>     =  *p_a_i_a_i_m;
+  let l_a_i_a_i_m_i   : vec2<f32>       =  *p_a_i_a_i_m_i;
+  let l_a_i_a_i_m_i_i : f32             = (*p_a_i_a_i_m_i)[i()];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..0554769
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,82 @@
+struct Inner {
+  float4x2 m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float4x2 tint_symbol_8(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_3 / 4];
+  return float4x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)), asfloat(((scalar_offset_3 & 2) ? ubo_load_3.zw : ubo_load_3.xy)));
+}
+
+Inner tint_symbol_7(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_11 = {tint_symbol_8(buffer, (offset + 0u))};
+  return tint_symbol_11;
+}
+
+typedef Inner tint_symbol_6_ret[4];
+tint_symbol_6_ret tint_symbol_6(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_7(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_5(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_12 = {tint_symbol_6(buffer, (offset + 0u))};
+  return tint_symbol_12;
+}
+
+typedef Outer tint_symbol_4_ret[4];
+tint_symbol_4_ret tint_symbol_4(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
+      arr_1[i_2] = tint_symbol_5(buffer, (offset + (i_2 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_a_i_save = i();
+  const int p_a_i_a_i_m_i_save = i();
+  const Outer l_a[4] = tint_symbol_4(a, 0u);
+  const Outer l_a_i = tint_symbol_5(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a[4] = tint_symbol_6(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a_i = tint_symbol_7(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const float4x2 l_a_i_a_i_m = tint_symbol_8(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const uint scalar_offset_4 = ((((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))) + (8u * uint(p_a_i_a_i_m_i_save)))) / 4;
+  uint4 ubo_load_4 = a[scalar_offset_4 / 4];
+  const float2 l_a_i_a_i_m_i = asfloat(((scalar_offset_4 & 2) ? ubo_load_4.zw : ubo_load_4.xy));
+  const int tint_symbol = p_a_i_save;
+  const int tint_symbol_1 = p_a_i_a_i_save;
+  const int tint_symbol_2 = p_a_i_a_i_m_i_save;
+  const int tint_symbol_3 = i();
+  const uint scalar_offset_5 = (((((256u * uint(tint_symbol)) + (64u * uint(tint_symbol_1))) + (8u * uint(tint_symbol_2))) + (4u * uint(tint_symbol_3)))) / 4;
+  const float l_a_i_a_i_m_i_i = asfloat(a[scalar_offset_5 / 4][scalar_offset_5 % 4]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..0554769
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,82 @@
+struct Inner {
+  float4x2 m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float4x2 tint_symbol_8(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_3 / 4];
+  return float4x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)), asfloat(((scalar_offset_3 & 2) ? ubo_load_3.zw : ubo_load_3.xy)));
+}
+
+Inner tint_symbol_7(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_11 = {tint_symbol_8(buffer, (offset + 0u))};
+  return tint_symbol_11;
+}
+
+typedef Inner tint_symbol_6_ret[4];
+tint_symbol_6_ret tint_symbol_6(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_7(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_5(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_12 = {tint_symbol_6(buffer, (offset + 0u))};
+  return tint_symbol_12;
+}
+
+typedef Outer tint_symbol_4_ret[4];
+tint_symbol_4_ret tint_symbol_4(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
+      arr_1[i_2] = tint_symbol_5(buffer, (offset + (i_2 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_a_i_save = i();
+  const int p_a_i_a_i_m_i_save = i();
+  const Outer l_a[4] = tint_symbol_4(a, 0u);
+  const Outer l_a_i = tint_symbol_5(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a[4] = tint_symbol_6(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a_i = tint_symbol_7(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const float4x2 l_a_i_a_i_m = tint_symbol_8(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const uint scalar_offset_4 = ((((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))) + (8u * uint(p_a_i_a_i_m_i_save)))) / 4;
+  uint4 ubo_load_4 = a[scalar_offset_4 / 4];
+  const float2 l_a_i_a_i_m_i = asfloat(((scalar_offset_4 & 2) ? ubo_load_4.zw : ubo_load_4.xy));
+  const int tint_symbol = p_a_i_save;
+  const int tint_symbol_1 = p_a_i_a_i_save;
+  const int tint_symbol_2 = p_a_i_a_i_m_i_save;
+  const int tint_symbol_3 = i();
+  const uint scalar_offset_5 = (((((256u * uint(tint_symbol)) + (64u * uint(tint_symbol_1))) + (8u * uint(tint_symbol_2))) + (4u * uint(tint_symbol_3)))) / 4;
+  const float l_a_i_a_i_m_i_i = asfloat(a[scalar_offset_5 / 4][scalar_offset_5 % 4]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/dynamic_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..5de9287
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,156 @@
+#version 310 es
+
+struct Inner {
+  mat4x2 m;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+};
+
+struct Inner_std140 {
+  vec2 m_0;
+  vec2 m_1;
+  vec2 m_2;
+  vec2 m_3;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+};
+
+struct Outer {
+  Inner a[4];
+};
+
+struct Outer_std140 {
+  Inner_std140 a[4];
+};
+
+layout(binding = 0, std140) uniform a_block_std140_ubo {
+  Outer_std140 inner[4];
+} a;
+
+int counter = 0;
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+Inner conv_Inner(Inner_std140 val) {
+  return Inner(mat4x2(val.m_0, val.m_1, val.m_2, val.m_3), val.pad, val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7);
+}
+
+Inner[4] conv_arr4_Inner(Inner_std140 val[4]) {
+  Inner arr[4] = Inner[4](Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_Inner(val[i]);
+    }
+  }
+  return arr;
+}
+
+Outer conv_Outer(Outer_std140 val) {
+  return Outer(conv_arr4_Inner(val.a));
+}
+
+Outer[4] conv_arr4_Outer(Outer_std140 val[4]) {
+  Outer arr[4] = Outer[4](Outer(Inner[4](Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_Outer(val[i]);
+    }
+  }
+  return arr;
+}
+
+mat4x2 load_a_inner_p0_a_p1_m(uint p0, uint p1) {
+  uint s_save = p0;
+  uint s_save_1 = p1;
+  return mat4x2(a.inner[s_save].a[s_save_1].m_0, a.inner[s_save].a[s_save_1].m_1, a.inner[s_save].a[s_save_1].m_2, a.inner[s_save].a[s_save_1].m_3);
+}
+
+vec2 load_a_inner_p0_a_p1_m_p2(uint p0, uint p1, uint p2) {
+  switch(p2) {
+    case 0u: {
+      return a.inner[p0].a[p1].m_0;
+      break;
+    }
+    case 1u: {
+      return a.inner[p0].a[p1].m_1;
+      break;
+    }
+    case 2u: {
+      return a.inner[p0].a[p1].m_2;
+      break;
+    }
+    case 3u: {
+      return a.inner[p0].a[p1].m_3;
+      break;
+    }
+    default: {
+      return vec2(0.0f);
+      break;
+    }
+  }
+}
+
+float load_a_inner_p0_a_p1_m_p2_p3(uint p0, uint p1, uint p2, uint p3) {
+  switch(p2) {
+    case 0u: {
+      return a.inner[p0].a[p1].m_0[p3];
+      break;
+    }
+    case 1u: {
+      return a.inner[p0].a[p1].m_1[p3];
+      break;
+    }
+    case 2u: {
+      return a.inner[p0].a[p1].m_2[p3];
+      break;
+    }
+    case 3u: {
+      return a.inner[p0].a[p1].m_3[p3];
+      break;
+    }
+    default: {
+      return 0.0f;
+      break;
+    }
+  }
+}
+
+void f() {
+  Outer p_a[4] = conv_arr4_Outer(a.inner);
+  int tint_symbol = i();
+  Outer p_a_i = conv_Outer(a.inner[tint_symbol]);
+  Inner p_a_i_a[4] = conv_arr4_Inner(a.inner[tint_symbol].a);
+  int tint_symbol_1 = i();
+  Inner p_a_i_a_i = conv_Inner(a.inner[tint_symbol].a[tint_symbol_1]);
+  mat4x2 p_a_i_a_i_m = load_a_inner_p0_a_p1_m(uint(tint_symbol), uint(tint_symbol_1));
+  int tint_symbol_2 = i();
+  vec2 p_a_i_a_i_m_i = load_a_inner_p0_a_p1_m_p2(uint(tint_symbol), uint(tint_symbol_1), uint(tint_symbol_2));
+  Outer l_a[4] = conv_arr4_Outer(a.inner);
+  Outer l_a_i = conv_Outer(a.inner[tint_symbol]);
+  Inner l_a_i_a[4] = conv_arr4_Inner(a.inner[tint_symbol].a);
+  Inner l_a_i_a_i = conv_Inner(a.inner[tint_symbol].a[tint_symbol_1]);
+  mat4x2 l_a_i_a_i_m = load_a_inner_p0_a_p1_m(uint(tint_symbol), uint(tint_symbol_1));
+  vec2 l_a_i_a_i_m_i = load_a_inner_p0_a_p1_m_p2(uint(tint_symbol), uint(tint_symbol_1), uint(tint_symbol_2));
+  int tint_symbol_3 = i();
+  float l_a_i_a_i_m_i_i = load_a_inner_p0_a_p1_m_p2_p3(uint(tint_symbol), uint(tint_symbol_1), uint(tint_symbol_2), uint(tint_symbol_3));
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/dynamic_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..eca377a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/dynamic_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,49 @@
+#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 Inner {
+  /* 0x0000 */ float4x2 m;
+  /* 0x0020 */ tint_array<int8_t, 32> tint_pad;
+};
+
+struct Outer {
+  /* 0x0000 */ tint_array<Inner, 4> a;
+};
+
+int i() {
+  thread int tint_symbol_4 = 0;
+  tint_symbol_4 = as_type<int>((as_type<uint>(tint_symbol_4) + as_type<uint>(1)));
+  return tint_symbol_4;
+}
+
+kernel void f(const constant tint_array<Outer, 4>* tint_symbol_5 [[buffer(0)]]) {
+  int const tint_symbol = i();
+  int const p_a_i_save = tint_symbol;
+  int const tint_symbol_1 = i();
+  int const p_a_i_a_i_save = tint_symbol_1;
+  int const tint_symbol_2 = i();
+  int const p_a_i_a_i_m_i_save = tint_symbol_2;
+  tint_array<Outer, 4> const l_a = *(tint_symbol_5);
+  Outer const l_a_i = (*(tint_symbol_5))[p_a_i_save];
+  tint_array<Inner, 4> const l_a_i_a = (*(tint_symbol_5))[p_a_i_save].a;
+  Inner const l_a_i_a_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save];
+  float4x2 const l_a_i_a_i_m = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m;
+  float2 const l_a_i_a_i_m_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save];
+  int const tint_symbol_3 = i();
+  float const l_a_i_a_i_m_i_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save][tint_symbol_3];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..b52f94a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,334 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 215
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block_std140 "a_block_std140"
+               OpMemberName %a_block_std140 0 "inner"
+               OpName %Outer_std140 "Outer_std140"
+               OpMemberName %Outer_std140 0 "a"
+               OpName %Inner_std140 "Inner_std140"
+               OpMemberName %Inner_std140 0 "m_0"
+               OpMemberName %Inner_std140 1 "m_1"
+               OpMemberName %Inner_std140 2 "m_2"
+               OpMemberName %Inner_std140 3 "m_3"
+               OpName %a "a"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %Inner "Inner"
+               OpMemberName %Inner 0 "m"
+               OpName %conv_Inner "conv_Inner"
+               OpName %val "val"
+               OpName %conv_arr4_Inner "conv_arr4_Inner"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i_0 "i"
+               OpName %var_for_index_1 "var_for_index_1"
+               OpName %Outer "Outer"
+               OpMemberName %Outer 0 "a"
+               OpName %conv_Outer "conv_Outer"
+               OpName %val_1 "val"
+               OpName %conv_arr4_Outer "conv_arr4_Outer"
+               OpName %val_2 "val"
+               OpName %arr_0 "arr"
+               OpName %i_1 "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_a_inner_p0_a_p1_m "load_a_inner_p0_a_p1_m"
+               OpName %p0 "p0"
+               OpName %p1 "p1"
+               OpName %load_a_inner_p0_a_p1_m_p2 "load_a_inner_p0_a_p1_m_p2"
+               OpName %p0_0 "p0"
+               OpName %p1_0 "p1"
+               OpName %p2 "p2"
+               OpName %load_a_inner_p0_a_p1_m_p2_p3 "load_a_inner_p0_a_p1_m_p2_p3"
+               OpName %p0_1 "p0"
+               OpName %p1_1 "p1"
+               OpName %p2_0 "p2"
+               OpName %p3 "p3"
+               OpName %f "f"
+               OpDecorate %a_block_std140 Block
+               OpMemberDecorate %a_block_std140 0 Offset 0
+               OpMemberDecorate %Outer_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 1 Offset 8
+               OpMemberDecorate %Inner_std140 2 Offset 16
+               OpMemberDecorate %Inner_std140 3 Offset 24
+               OpDecorate %_arr_Inner_std140_uint_4 ArrayStride 64
+               OpDecorate %_arr_Outer_std140_uint_4 ArrayStride 256
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+               OpMemberDecorate %Inner 0 Offset 0
+               OpMemberDecorate %Inner 0 ColMajor
+               OpMemberDecorate %Inner 0 MatrixStride 8
+               OpDecorate %_arr_Inner_uint_4 ArrayStride 64
+               OpMemberDecorate %Outer 0 Offset 0
+               OpDecorate %_arr_Outer_uint_4 ArrayStride 256
+      %float = OpTypeFloat 32
+    %v2float = OpTypeVector %float 2
+%Inner_std140 = OpTypeStruct %v2float %v2float %v2float %v2float
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_Inner_std140_uint_4 = OpTypeArray %Inner_std140 %uint_4
+%Outer_std140 = OpTypeStruct %_arr_Inner_std140_uint_4
+%_arr_Outer_std140_uint_4 = OpTypeArray %Outer_std140 %uint_4
+%a_block_std140 = OpTypeStruct %_arr_Outer_std140_uint_4
+%_ptr_Uniform_a_block_std140 = OpTypePointer Uniform %a_block_std140
+          %a = OpVariable %_ptr_Uniform_a_block_std140 Uniform
+        %int = OpTypeInt 32 1
+         %13 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %13
+         %16 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+%mat4v2float = OpTypeMatrix %v2float 4
+      %Inner = OpTypeStruct %mat4v2float
+         %23 = OpTypeFunction %Inner %Inner_std140
+%_arr_Inner_uint_4 = OpTypeArray %Inner %uint_4
+         %35 = OpTypeFunction %_arr_Inner_uint_4 %_arr_Inner_std140_uint_4
+%_ptr_Function__arr_Inner_uint_4 = OpTypePointer Function %_arr_Inner_uint_4
+         %42 = OpConstantNull %_arr_Inner_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %45 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_Inner_std140_uint_4 = OpTypePointer Function %_arr_Inner_std140_uint_4
+         %58 = OpConstantNull %_arr_Inner_std140_uint_4
+%_ptr_Function_Inner = OpTypePointer Function %Inner
+%_ptr_Function_Inner_std140 = OpTypePointer Function %Inner_std140
+     %uint_1 = OpConstant %uint 1
+      %Outer = OpTypeStruct %_arr_Inner_uint_4
+         %71 = OpTypeFunction %Outer %Outer_std140
+%_arr_Outer_uint_4 = OpTypeArray %Outer %uint_4
+         %79 = OpTypeFunction %_arr_Outer_uint_4 %_arr_Outer_std140_uint_4
+%_ptr_Function__arr_Outer_uint_4 = OpTypePointer Function %_arr_Outer_uint_4
+         %86 = OpConstantNull %_arr_Outer_uint_4
+%_ptr_Function__arr_Outer_std140_uint_4 = OpTypePointer Function %_arr_Outer_std140_uint_4
+         %99 = OpConstantNull %_arr_Outer_std140_uint_4
+%_ptr_Function_Outer = OpTypePointer Function %Outer
+%_ptr_Function_Outer_std140 = OpTypePointer Function %Outer_std140
+        %111 = OpTypeFunction %mat4v2float %uint %uint
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_Inner_std140 = OpTypePointer Uniform %Inner_std140
+%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+        %136 = OpTypeFunction %v2float %uint %uint %uint
+        %156 = OpConstantNull %v2float
+        %157 = OpTypeFunction %float %uint %uint %uint %uint
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+        %179 = OpConstantNull %float
+       %void = OpTypeVoid
+        %180 = OpTypeFunction %void
+%_ptr_Uniform__arr_Outer_std140_uint_4 = OpTypePointer Uniform %_arr_Outer_std140_uint_4
+%_ptr_Uniform_Outer_std140 = OpTypePointer Uniform %Outer_std140
+%_ptr_Uniform__arr_Inner_std140_uint_4 = OpTypePointer Uniform %_arr_Inner_std140_uint_4
+          %i = OpFunction %int None %16
+         %18 = OpLabel
+         %19 = OpLoad %int %counter
+         %21 = OpIAdd %int %19 %int_1
+               OpStore %counter %21
+         %22 = OpLoad %int %counter
+               OpReturnValue %22
+               OpFunctionEnd
+ %conv_Inner = OpFunction %Inner None %23
+        %val = OpFunctionParameter %Inner_std140
+         %28 = OpLabel
+         %29 = OpCompositeExtract %v2float %val 0
+         %30 = OpCompositeExtract %v2float %val 1
+         %31 = OpCompositeExtract %v2float %val 2
+         %32 = OpCompositeExtract %v2float %val 3
+         %33 = OpCompositeConstruct %mat4v2float %29 %30 %31 %32
+         %34 = OpCompositeConstruct %Inner %33
+               OpReturnValue %34
+               OpFunctionEnd
+%conv_arr4_Inner = OpFunction %_arr_Inner_uint_4 None %35
+      %val_0 = OpFunctionParameter %_arr_Inner_std140_uint_4
+         %39 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_Inner_uint_4 Function %42
+        %i_0 = OpVariable %_ptr_Function_uint Function %45
+%var_for_index_1 = OpVariable %_ptr_Function__arr_Inner_std140_uint_4 Function %58
+               OpBranch %46
+         %46 = OpLabel
+               OpLoopMerge %47 %48 None
+               OpBranch %49
+         %49 = OpLabel
+         %51 = OpLoad %uint %i_0
+         %52 = OpULessThan %bool %51 %uint_4
+         %50 = OpLogicalNot %bool %52
+               OpSelectionMerge %54 None
+               OpBranchConditional %50 %55 %54
+         %55 = OpLabel
+               OpBranch %47
+         %54 = OpLabel
+               OpStore %var_for_index_1 %val_0
+         %59 = OpLoad %uint %i_0
+         %61 = OpAccessChain %_ptr_Function_Inner %arr %59
+         %63 = OpLoad %uint %i_0
+         %65 = OpAccessChain %_ptr_Function_Inner_std140 %var_for_index_1 %63
+         %66 = OpLoad %Inner_std140 %65
+         %62 = OpFunctionCall %Inner %conv_Inner %66
+               OpStore %61 %62
+               OpBranch %48
+         %48 = OpLabel
+         %67 = OpLoad %uint %i_0
+         %69 = OpIAdd %uint %67 %uint_1
+               OpStore %i_0 %69
+               OpBranch %46
+         %47 = OpLabel
+         %70 = OpLoad %_arr_Inner_uint_4 %arr
+               OpReturnValue %70
+               OpFunctionEnd
+ %conv_Outer = OpFunction %Outer None %71
+      %val_1 = OpFunctionParameter %Outer_std140
+         %75 = OpLabel
+         %77 = OpCompositeExtract %_arr_Inner_std140_uint_4 %val_1 0
+         %76 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %77
+         %78 = OpCompositeConstruct %Outer %76
+               OpReturnValue %78
+               OpFunctionEnd
+%conv_arr4_Outer = OpFunction %_arr_Outer_uint_4 None %79
+      %val_2 = OpFunctionParameter %_arr_Outer_std140_uint_4
+         %83 = OpLabel
+      %arr_0 = OpVariable %_ptr_Function__arr_Outer_uint_4 Function %86
+        %i_1 = OpVariable %_ptr_Function_uint Function %45
+%var_for_index = OpVariable %_ptr_Function__arr_Outer_std140_uint_4 Function %99
+               OpBranch %88
+         %88 = OpLabel
+               OpLoopMerge %89 %90 None
+               OpBranch %91
+         %91 = OpLabel
+         %93 = OpLoad %uint %i_1
+         %94 = OpULessThan %bool %93 %uint_4
+         %92 = OpLogicalNot %bool %94
+               OpSelectionMerge %95 None
+               OpBranchConditional %92 %96 %95
+         %96 = OpLabel
+               OpBranch %89
+         %95 = OpLabel
+               OpStore %var_for_index %val_2
+        %100 = OpLoad %uint %i_1
+        %102 = OpAccessChain %_ptr_Function_Outer %arr_0 %100
+        %104 = OpLoad %uint %i_1
+        %106 = OpAccessChain %_ptr_Function_Outer_std140 %var_for_index %104
+        %107 = OpLoad %Outer_std140 %106
+        %103 = OpFunctionCall %Outer %conv_Outer %107
+               OpStore %102 %103
+               OpBranch %90
+         %90 = OpLabel
+        %108 = OpLoad %uint %i_1
+        %109 = OpIAdd %uint %108 %uint_1
+               OpStore %i_1 %109
+               OpBranch %88
+         %89 = OpLabel
+        %110 = OpLoad %_arr_Outer_uint_4 %arr_0
+               OpReturnValue %110
+               OpFunctionEnd
+%load_a_inner_p0_a_p1_m = OpFunction %mat4v2float None %111
+         %p0 = OpFunctionParameter %uint
+         %p1 = OpFunctionParameter %uint
+        %115 = OpLabel
+        %119 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %p0 %uint_0 %p1
+        %122 = OpAccessChain %_ptr_Uniform_v2float %119 %uint_0
+        %123 = OpLoad %v2float %122
+        %125 = OpAccessChain %_ptr_Uniform_v2float %119 %uint_1
+        %126 = OpLoad %v2float %125
+        %129 = OpAccessChain %_ptr_Uniform_v2float %119 %uint_2
+        %130 = OpLoad %v2float %129
+        %133 = OpAccessChain %_ptr_Uniform_v2float %119 %uint_3
+        %134 = OpLoad %v2float %133
+        %135 = OpCompositeConstruct %mat4v2float %123 %126 %130 %134
+               OpReturnValue %135
+               OpFunctionEnd
+%load_a_inner_p0_a_p1_m_p2 = OpFunction %v2float None %136
+       %p0_0 = OpFunctionParameter %uint
+       %p1_0 = OpFunctionParameter %uint
+         %p2 = OpFunctionParameter %uint
+        %141 = OpLabel
+               OpSelectionMerge %142 None
+               OpSwitch %p2 %143 0 %144 1 %145 2 %146 3 %147
+        %144 = OpLabel
+        %148 = OpAccessChain %_ptr_Uniform_v2float %a %uint_0 %p0_0 %uint_0 %p1_0 %uint_0
+        %149 = OpLoad %v2float %148
+               OpReturnValue %149
+        %145 = OpLabel
+        %150 = OpAccessChain %_ptr_Uniform_v2float %a %uint_0 %p0_0 %uint_0 %p1_0 %uint_1
+        %151 = OpLoad %v2float %150
+               OpReturnValue %151
+        %146 = OpLabel
+        %152 = OpAccessChain %_ptr_Uniform_v2float %a %uint_0 %p0_0 %uint_0 %p1_0 %uint_2
+        %153 = OpLoad %v2float %152
+               OpReturnValue %153
+        %147 = OpLabel
+        %154 = OpAccessChain %_ptr_Uniform_v2float %a %uint_0 %p0_0 %uint_0 %p1_0 %uint_3
+        %155 = OpLoad %v2float %154
+               OpReturnValue %155
+        %143 = OpLabel
+               OpReturnValue %156
+        %142 = OpLabel
+               OpReturnValue %156
+               OpFunctionEnd
+%load_a_inner_p0_a_p1_m_p2_p3 = OpFunction %float None %157
+       %p0_1 = OpFunctionParameter %uint
+       %p1_1 = OpFunctionParameter %uint
+       %p2_0 = OpFunctionParameter %uint
+         %p3 = OpFunctionParameter %uint
+        %163 = OpLabel
+               OpSelectionMerge %164 None
+               OpSwitch %p2_0 %165 0 %166 1 %167 2 %168 3 %169
+        %166 = OpLabel
+        %171 = OpAccessChain %_ptr_Uniform_float %a %uint_0 %p0_1 %uint_0 %p1_1 %uint_0 %p3
+        %172 = OpLoad %float %171
+               OpReturnValue %172
+        %167 = OpLabel
+        %173 = OpAccessChain %_ptr_Uniform_float %a %uint_0 %p0_1 %uint_0 %p1_1 %uint_1 %p3
+        %174 = OpLoad %float %173
+               OpReturnValue %174
+        %168 = OpLabel
+        %175 = OpAccessChain %_ptr_Uniform_float %a %uint_0 %p0_1 %uint_0 %p1_1 %uint_2 %p3
+        %176 = OpLoad %float %175
+               OpReturnValue %176
+        %169 = OpLabel
+        %177 = OpAccessChain %_ptr_Uniform_float %a %uint_0 %p0_1 %uint_0 %p1_1 %uint_3 %p3
+        %178 = OpLoad %float %177
+               OpReturnValue %178
+        %165 = OpLabel
+               OpReturnValue %179
+        %164 = OpLabel
+               OpReturnValue %179
+               OpFunctionEnd
+          %f = OpFunction %void None %180
+        %183 = OpLabel
+        %184 = OpFunctionCall %int %i
+        %185 = OpFunctionCall %int %i
+        %186 = OpFunctionCall %int %i
+        %189 = OpAccessChain %_ptr_Uniform__arr_Outer_std140_uint_4 %a %uint_0
+        %190 = OpLoad %_arr_Outer_std140_uint_4 %189
+        %187 = OpFunctionCall %_arr_Outer_uint_4 %conv_arr4_Outer %190
+        %193 = OpAccessChain %_ptr_Uniform_Outer_std140 %a %uint_0 %184
+        %194 = OpLoad %Outer_std140 %193
+        %191 = OpFunctionCall %Outer %conv_Outer %194
+        %197 = OpAccessChain %_ptr_Uniform__arr_Inner_std140_uint_4 %a %uint_0 %184 %uint_0
+        %198 = OpLoad %_arr_Inner_std140_uint_4 %197
+        %195 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %198
+        %200 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %184 %uint_0 %185
+        %201 = OpLoad %Inner_std140 %200
+        %199 = OpFunctionCall %Inner %conv_Inner %201
+        %203 = OpBitcast %uint %184
+        %204 = OpBitcast %uint %185
+        %202 = OpFunctionCall %mat4v2float %load_a_inner_p0_a_p1_m %203 %204
+        %206 = OpBitcast %uint %184
+        %207 = OpBitcast %uint %185
+        %208 = OpBitcast %uint %186
+        %205 = OpFunctionCall %v2float %load_a_inner_p0_a_p1_m_p2 %206 %207 %208
+        %209 = OpFunctionCall %int %i
+        %211 = OpBitcast %uint %184
+        %212 = OpBitcast %uint %185
+        %213 = OpBitcast %uint %186
+        %214 = OpBitcast %uint %209
+        %210 = OpFunctionCall %float %load_a_inner_p0_a_p1_m_p2_p3 %211 %212 %213 %214
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..8fc4c1a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,34 @@
+struct Inner {
+  @size(64)
+  m : mat4x2<f32>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_i = &((*(p_a))[i()]);
+  let p_a_i_a = &((*(p_a_i)).a);
+  let p_a_i_a_i = &((*(p_a_i_a))[i()]);
+  let p_a_i_a_i_m = &((*(p_a_i_a_i)).m);
+  let p_a_i_a_i_m_i = &((*(p_a_i_a_i_m))[i()]);
+  let l_a : array<Outer, 4> = *(p_a);
+  let l_a_i : Outer = *(p_a_i);
+  let l_a_i_a : array<Inner, 4> = *(p_a_i_a);
+  let l_a_i_a_i : Inner = *(p_a_i_a_i);
+  let l_a_i_a_i_m : mat4x2<f32> = *(p_a_i_a_i_m);
+  let l_a_i_a_i_m_i : vec2<f32> = *(p_a_i_a_i_m_i);
+  let l_a_i_a_i_m_i_i : f32 = (*(p_a_i_a_i_m_i))[i()];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/static_index_via_ptr.wgsl
new file mode 100644
index 0000000..b5b71dd
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/static_index_via_ptr.wgsl
@@ -0,0 +1,29 @@
+struct Inner {
+  @size(64)
+  m : mat4x2<f32>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &a;
+  let p_a_3 = &((*p_a)[3]);
+  let p_a_3_a = &((*p_a_3).a);
+  let p_a_3_a_2 = &((*p_a_3_a)[2]);
+  let p_a_3_a_2_m = &((*p_a_3_a_2).m);
+  let p_a_3_a_2_m_1 = &((*p_a_3_a_2_m)[1]);
+
+
+  let l_a             : array<Outer, 4> = *p_a;
+  let l_a_3           : Outer           = *p_a_3;
+  let l_a_3_a         : array<Inner, 4> = *p_a_3_a;
+  let l_a_3_a_2       : Inner           = *p_a_3_a_2;
+  let l_a_3_a_2_m     : mat4x2<f32>     = *p_a_3_a_2_m;
+  let l_a_3_a_2_m_1   : vec2<f32>       = *p_a_3_a_2_m_1;
+  let l_a_3_a_2_m_1_0 : f32             = (*p_a_3_a_2_m_1)[0];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..ec07ff8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,66 @@
+struct Inner {
+  float4x2 m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+
+float4x2 tint_symbol_4(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_3 / 4];
+  return float4x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)), asfloat(((scalar_offset_3 & 2) ? ubo_load_3.zw : ubo_load_3.xy)));
+}
+
+Inner tint_symbol_3(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_7 = {tint_symbol_4(buffer, (offset + 0u))};
+  return tint_symbol_7;
+}
+
+typedef Inner tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_3(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_1(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_8 = {tint_symbol_2(buffer, (offset + 0u))};
+  return tint_symbol_8;
+}
+
+typedef Outer tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr_1[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const Outer l_a[4] = tint_symbol(a, 0u);
+  const Outer l_a_3 = tint_symbol_1(a, 768u);
+  const Inner l_a_3_a[4] = tint_symbol_2(a, 768u);
+  const Inner l_a_3_a_2 = tint_symbol_3(a, 896u);
+  const float4x2 l_a_3_a_2_m = tint_symbol_4(a, 896u);
+  const float2 l_a_3_a_2_m_1 = asfloat(a[56].zw);
+  const float l_a_3_a_2_m_1_0 = asfloat(a[56].z);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..ec07ff8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,66 @@
+struct Inner {
+  float4x2 m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+
+float4x2 tint_symbol_4(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_3 / 4];
+  return float4x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)), asfloat(((scalar_offset_3 & 2) ? ubo_load_3.zw : ubo_load_3.xy)));
+}
+
+Inner tint_symbol_3(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_7 = {tint_symbol_4(buffer, (offset + 0u))};
+  return tint_symbol_7;
+}
+
+typedef Inner tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_3(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_1(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_8 = {tint_symbol_2(buffer, (offset + 0u))};
+  return tint_symbol_8;
+}
+
+typedef Outer tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr_1[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const Outer l_a[4] = tint_symbol(a, 0u);
+  const Outer l_a_3 = tint_symbol_1(a, 768u);
+  const Inner l_a_3_a[4] = tint_symbol_2(a, 768u);
+  const Inner l_a_3_a_2 = tint_symbol_3(a, 896u);
+  const float4x2 l_a_3_a_2_m = tint_symbol_4(a, 896u);
+  const float2 l_a_3_a_2_m_1 = asfloat(a[56].zw);
+  const float l_a_3_a_2_m_1_0 = asfloat(a[56].z);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/static_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..45048a2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/static_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,94 @@
+#version 310 es
+
+struct Inner {
+  mat4x2 m;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+};
+
+struct Inner_std140 {
+  vec2 m_0;
+  vec2 m_1;
+  vec2 m_2;
+  vec2 m_3;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+};
+
+struct Outer {
+  Inner a[4];
+};
+
+struct Outer_std140 {
+  Inner_std140 a[4];
+};
+
+layout(binding = 0, std140) uniform a_block_std140_ubo {
+  Outer_std140 inner[4];
+} a;
+
+Inner conv_Inner(Inner_std140 val) {
+  return Inner(mat4x2(val.m_0, val.m_1, val.m_2, val.m_3), val.pad, val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7);
+}
+
+Inner[4] conv_arr4_Inner(Inner_std140 val[4]) {
+  Inner arr[4] = Inner[4](Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_Inner(val[i]);
+    }
+  }
+  return arr;
+}
+
+Outer conv_Outer(Outer_std140 val) {
+  return Outer(conv_arr4_Inner(val.a));
+}
+
+Outer[4] conv_arr4_Outer(Outer_std140 val[4]) {
+  Outer arr[4] = Outer[4](Outer(Inner[4](Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_Outer(val[i]);
+    }
+  }
+  return arr;
+}
+
+mat4x2 load_a_inner_3_a_2_m() {
+  return mat4x2(a.inner[3u].a[2u].m_0, a.inner[3u].a[2u].m_1, a.inner[3u].a[2u].m_2, a.inner[3u].a[2u].m_3);
+}
+
+void f() {
+  Outer p_a[4] = conv_arr4_Outer(a.inner);
+  Outer p_a_3 = conv_Outer(a.inner[3u]);
+  Inner p_a_3_a[4] = conv_arr4_Inner(a.inner[3u].a);
+  Inner p_a_3_a_2 = conv_Inner(a.inner[3u].a[2u]);
+  mat4x2 p_a_3_a_2_m = load_a_inner_3_a_2_m();
+  vec2 p_a_3_a_2_m_1 = a.inner[3u].a[2u].m_1;
+  Outer l_a[4] = conv_arr4_Outer(a.inner);
+  Outer l_a_3 = conv_Outer(a.inner[3u]);
+  Inner l_a_3_a[4] = conv_arr4_Inner(a.inner[3u].a);
+  Inner l_a_3_a_2 = conv_Inner(a.inner[3u].a[2u]);
+  mat4x2 l_a_3_a_2_m = load_a_inner_3_a_2_m();
+  vec2 l_a_3_a_2_m_1 = a.inner[3u].a[2u].m_1;
+  float l_a_3_a_2_m_1_0 = a.inner[3u].a[2u].m_1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/static_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..9eb83d5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/static_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,36 @@
+#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 Inner {
+  /* 0x0000 */ float4x2 m;
+  /* 0x0020 */ tint_array<int8_t, 32> tint_pad;
+};
+
+struct Outer {
+  /* 0x0000 */ tint_array<Inner, 4> a;
+};
+
+kernel void f(const constant tint_array<Outer, 4>* tint_symbol [[buffer(0)]]) {
+  tint_array<Outer, 4> const l_a = *(tint_symbol);
+  Outer const l_a_3 = (*(tint_symbol))[3];
+  tint_array<Inner, 4> const l_a_3_a = (*(tint_symbol))[3].a;
+  Inner const l_a_3_a_2 = (*(tint_symbol))[3].a[2];
+  float4x2 const l_a_3_a_2_m = (*(tint_symbol))[3].a[2].m;
+  float2 const l_a_3_a_2_m_1 = (*(tint_symbol))[3].a[2].m[1];
+  float const l_a_3_a_2_m_1_0 = (*(tint_symbol))[3].a[2].m[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/static_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..36d316d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/static_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,233 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 148
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block_std140 "a_block_std140"
+               OpMemberName %a_block_std140 0 "inner"
+               OpName %Outer_std140 "Outer_std140"
+               OpMemberName %Outer_std140 0 "a"
+               OpName %Inner_std140 "Inner_std140"
+               OpMemberName %Inner_std140 0 "m_0"
+               OpMemberName %Inner_std140 1 "m_1"
+               OpMemberName %Inner_std140 2 "m_2"
+               OpMemberName %Inner_std140 3 "m_3"
+               OpName %a "a"
+               OpName %Inner "Inner"
+               OpMemberName %Inner 0 "m"
+               OpName %conv_Inner "conv_Inner"
+               OpName %val "val"
+               OpName %conv_arr4_Inner "conv_arr4_Inner"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index_1 "var_for_index_1"
+               OpName %Outer "Outer"
+               OpMemberName %Outer 0 "a"
+               OpName %conv_Outer "conv_Outer"
+               OpName %val_1 "val"
+               OpName %conv_arr4_Outer "conv_arr4_Outer"
+               OpName %val_2 "val"
+               OpName %arr_0 "arr"
+               OpName %i_0 "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_a_inner_3_a_2_m "load_a_inner_3_a_2_m"
+               OpName %f "f"
+               OpDecorate %a_block_std140 Block
+               OpMemberDecorate %a_block_std140 0 Offset 0
+               OpMemberDecorate %Outer_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 1 Offset 8
+               OpMemberDecorate %Inner_std140 2 Offset 16
+               OpMemberDecorate %Inner_std140 3 Offset 24
+               OpDecorate %_arr_Inner_std140_uint_4 ArrayStride 64
+               OpDecorate %_arr_Outer_std140_uint_4 ArrayStride 256
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+               OpMemberDecorate %Inner 0 Offset 0
+               OpMemberDecorate %Inner 0 ColMajor
+               OpMemberDecorate %Inner 0 MatrixStride 8
+               OpDecorate %_arr_Inner_uint_4 ArrayStride 64
+               OpMemberDecorate %Outer 0 Offset 0
+               OpDecorate %_arr_Outer_uint_4 ArrayStride 256
+      %float = OpTypeFloat 32
+    %v2float = OpTypeVector %float 2
+%Inner_std140 = OpTypeStruct %v2float %v2float %v2float %v2float
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_Inner_std140_uint_4 = OpTypeArray %Inner_std140 %uint_4
+%Outer_std140 = OpTypeStruct %_arr_Inner_std140_uint_4
+%_arr_Outer_std140_uint_4 = OpTypeArray %Outer_std140 %uint_4
+%a_block_std140 = OpTypeStruct %_arr_Outer_std140_uint_4
+%_ptr_Uniform_a_block_std140 = OpTypePointer Uniform %a_block_std140
+          %a = OpVariable %_ptr_Uniform_a_block_std140 Uniform
+%mat4v2float = OpTypeMatrix %v2float 4
+      %Inner = OpTypeStruct %mat4v2float
+         %12 = OpTypeFunction %Inner %Inner_std140
+%_arr_Inner_uint_4 = OpTypeArray %Inner %uint_4
+         %24 = OpTypeFunction %_arr_Inner_uint_4 %_arr_Inner_std140_uint_4
+%_ptr_Function__arr_Inner_uint_4 = OpTypePointer Function %_arr_Inner_uint_4
+         %31 = OpConstantNull %_arr_Inner_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %34 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_Inner_std140_uint_4 = OpTypePointer Function %_arr_Inner_std140_uint_4
+         %47 = OpConstantNull %_arr_Inner_std140_uint_4
+%_ptr_Function_Inner = OpTypePointer Function %Inner
+%_ptr_Function_Inner_std140 = OpTypePointer Function %Inner_std140
+     %uint_1 = OpConstant %uint 1
+      %Outer = OpTypeStruct %_arr_Inner_uint_4
+         %60 = OpTypeFunction %Outer %Outer_std140
+%_arr_Outer_uint_4 = OpTypeArray %Outer %uint_4
+         %68 = OpTypeFunction %_arr_Outer_uint_4 %_arr_Outer_std140_uint_4
+%_ptr_Function__arr_Outer_uint_4 = OpTypePointer Function %_arr_Outer_uint_4
+         %75 = OpConstantNull %_arr_Outer_uint_4
+%_ptr_Function__arr_Outer_std140_uint_4 = OpTypePointer Function %_arr_Outer_std140_uint_4
+         %88 = OpConstantNull %_arr_Outer_std140_uint_4
+%_ptr_Function_Outer = OpTypePointer Function %Outer
+%_ptr_Function_Outer_std140 = OpTypePointer Function %Outer_std140
+        %100 = OpTypeFunction %mat4v2float
+     %uint_0 = OpConstant %uint 0
+     %uint_3 = OpConstant %uint 3
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_Inner_std140 = OpTypePointer Uniform %Inner_std140
+%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
+       %void = OpTypeVoid
+        %123 = OpTypeFunction %void
+%_ptr_Uniform__arr_Outer_std140_uint_4 = OpTypePointer Uniform %_arr_Outer_std140_uint_4
+%_ptr_Uniform_Outer_std140 = OpTypePointer Uniform %Outer_std140
+%_ptr_Uniform__arr_Inner_std140_uint_4 = OpTypePointer Uniform %_arr_Inner_std140_uint_4
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+ %conv_Inner = OpFunction %Inner None %12
+        %val = OpFunctionParameter %Inner_std140
+         %17 = OpLabel
+         %18 = OpCompositeExtract %v2float %val 0
+         %19 = OpCompositeExtract %v2float %val 1
+         %20 = OpCompositeExtract %v2float %val 2
+         %21 = OpCompositeExtract %v2float %val 3
+         %22 = OpCompositeConstruct %mat4v2float %18 %19 %20 %21
+         %23 = OpCompositeConstruct %Inner %22
+               OpReturnValue %23
+               OpFunctionEnd
+%conv_arr4_Inner = OpFunction %_arr_Inner_uint_4 None %24
+      %val_0 = OpFunctionParameter %_arr_Inner_std140_uint_4
+         %28 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_Inner_uint_4 Function %31
+          %i = OpVariable %_ptr_Function_uint Function %34
+%var_for_index_1 = OpVariable %_ptr_Function__arr_Inner_std140_uint_4 Function %47
+               OpBranch %35
+         %35 = OpLabel
+               OpLoopMerge %36 %37 None
+               OpBranch %38
+         %38 = OpLabel
+         %40 = OpLoad %uint %i
+         %41 = OpULessThan %bool %40 %uint_4
+         %39 = OpLogicalNot %bool %41
+               OpSelectionMerge %43 None
+               OpBranchConditional %39 %44 %43
+         %44 = OpLabel
+               OpBranch %36
+         %43 = OpLabel
+               OpStore %var_for_index_1 %val_0
+         %48 = OpLoad %uint %i
+         %50 = OpAccessChain %_ptr_Function_Inner %arr %48
+         %52 = OpLoad %uint %i
+         %54 = OpAccessChain %_ptr_Function_Inner_std140 %var_for_index_1 %52
+         %55 = OpLoad %Inner_std140 %54
+         %51 = OpFunctionCall %Inner %conv_Inner %55
+               OpStore %50 %51
+               OpBranch %37
+         %37 = OpLabel
+         %56 = OpLoad %uint %i
+         %58 = OpIAdd %uint %56 %uint_1
+               OpStore %i %58
+               OpBranch %35
+         %36 = OpLabel
+         %59 = OpLoad %_arr_Inner_uint_4 %arr
+               OpReturnValue %59
+               OpFunctionEnd
+ %conv_Outer = OpFunction %Outer None %60
+      %val_1 = OpFunctionParameter %Outer_std140
+         %64 = OpLabel
+         %66 = OpCompositeExtract %_arr_Inner_std140_uint_4 %val_1 0
+         %65 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %66
+         %67 = OpCompositeConstruct %Outer %65
+               OpReturnValue %67
+               OpFunctionEnd
+%conv_arr4_Outer = OpFunction %_arr_Outer_uint_4 None %68
+      %val_2 = OpFunctionParameter %_arr_Outer_std140_uint_4
+         %72 = OpLabel
+      %arr_0 = OpVariable %_ptr_Function__arr_Outer_uint_4 Function %75
+        %i_0 = OpVariable %_ptr_Function_uint Function %34
+%var_for_index = OpVariable %_ptr_Function__arr_Outer_std140_uint_4 Function %88
+               OpBranch %77
+         %77 = OpLabel
+               OpLoopMerge %78 %79 None
+               OpBranch %80
+         %80 = OpLabel
+         %82 = OpLoad %uint %i_0
+         %83 = OpULessThan %bool %82 %uint_4
+         %81 = OpLogicalNot %bool %83
+               OpSelectionMerge %84 None
+               OpBranchConditional %81 %85 %84
+         %85 = OpLabel
+               OpBranch %78
+         %84 = OpLabel
+               OpStore %var_for_index %val_2
+         %89 = OpLoad %uint %i_0
+         %91 = OpAccessChain %_ptr_Function_Outer %arr_0 %89
+         %93 = OpLoad %uint %i_0
+         %95 = OpAccessChain %_ptr_Function_Outer_std140 %var_for_index %93
+         %96 = OpLoad %Outer_std140 %95
+         %92 = OpFunctionCall %Outer %conv_Outer %96
+               OpStore %91 %92
+               OpBranch %79
+         %79 = OpLabel
+         %97 = OpLoad %uint %i_0
+         %98 = OpIAdd %uint %97 %uint_1
+               OpStore %i_0 %98
+               OpBranch %77
+         %78 = OpLabel
+         %99 = OpLoad %_arr_Outer_uint_4 %arr_0
+               OpReturnValue %99
+               OpFunctionEnd
+%load_a_inner_3_a_2_m = OpFunction %mat4v2float None %100
+        %102 = OpLabel
+        %108 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %uint_3 %uint_0 %uint_2
+        %111 = OpAccessChain %_ptr_Uniform_v2float %108 %uint_0
+        %112 = OpLoad %v2float %111
+        %114 = OpAccessChain %_ptr_Uniform_v2float %108 %uint_1
+        %115 = OpLoad %v2float %114
+        %117 = OpAccessChain %_ptr_Uniform_v2float %108 %uint_2
+        %118 = OpLoad %v2float %117
+        %120 = OpAccessChain %_ptr_Uniform_v2float %108 %uint_3
+        %121 = OpLoad %v2float %120
+        %122 = OpCompositeConstruct %mat4v2float %112 %115 %118 %121
+               OpReturnValue %122
+               OpFunctionEnd
+          %f = OpFunction %void None %123
+        %126 = OpLabel
+        %129 = OpAccessChain %_ptr_Uniform__arr_Outer_std140_uint_4 %a %uint_0
+        %130 = OpLoad %_arr_Outer_std140_uint_4 %129
+        %127 = OpFunctionCall %_arr_Outer_uint_4 %conv_arr4_Outer %130
+        %133 = OpAccessChain %_ptr_Uniform_Outer_std140 %a %uint_0 %uint_3
+        %134 = OpLoad %Outer_std140 %133
+        %131 = OpFunctionCall %Outer %conv_Outer %134
+        %137 = OpAccessChain %_ptr_Uniform__arr_Inner_std140_uint_4 %a %uint_0 %uint_3 %uint_0
+        %138 = OpLoad %_arr_Inner_std140_uint_4 %137
+        %135 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %138
+        %140 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %uint_3 %uint_0 %uint_2
+        %141 = OpLoad %Inner_std140 %140
+        %139 = OpFunctionCall %Inner %conv_Inner %141
+        %142 = OpFunctionCall %mat4v2float %load_a_inner_3_a_2_m
+        %143 = OpAccessChain %_ptr_Uniform_v2float %a %uint_0 %uint_3 %uint_0 %uint_2 %uint_1
+        %144 = OpLoad %v2float %143
+        %146 = OpAccessChain %_ptr_Uniform_float %a %uint_0 %uint_3 %uint_0 %uint_2 %uint_1 %34
+        %147 = OpLoad %float %146
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/static_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..894d1f8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/static_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,27 @@
+struct Inner {
+  @size(64)
+  m : mat4x2<f32>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_3 = &((*(p_a))[3]);
+  let p_a_3_a = &((*(p_a_3)).a);
+  let p_a_3_a_2 = &((*(p_a_3_a))[2]);
+  let p_a_3_a_2_m = &((*(p_a_3_a_2)).m);
+  let p_a_3_a_2_m_1 = &((*(p_a_3_a_2_m))[1]);
+  let l_a : array<Outer, 4> = *(p_a);
+  let l_a_3 : Outer = *(p_a_3);
+  let l_a_3_a : array<Inner, 4> = *(p_a_3_a);
+  let l_a_3_a_2 : Inner = *(p_a_3_a_2);
+  let l_a_3_a_2_m : mat4x2<f32> = *(p_a_3_a_2_m);
+  let l_a_3_a_2_m_1 : vec2<f32> = *(p_a_3_a_2_m_1);
+  let l_a_3_a_2_m_1_0 : f32 = (*(p_a_3_a_2_m_1))[0];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_builtin.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_builtin.wgsl
new file mode 100644
index 0000000..d3fa958
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_builtin.wgsl
@@ -0,0 +1,15 @@
+struct S {
+  before : i32,
+  m : mat4x2<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    let t = transpose(u[2].m);
+    let l = length(u[0].m[1].yx);
+    let a = abs(u[0].m[1].yx.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_builtin.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..2d53757
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_builtin.wgsl.expected.dxc.hlsl
@@ -0,0 +1,23 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+float4x2 tint_symbol(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_3 / 4];
+  return float4x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)), asfloat(((scalar_offset_3 & 2) ? ubo_load_3.zw : ubo_load_3.xy)));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float2x4 t = transpose(tint_symbol(u, 264u));
+  const float l = length(asfloat(u[1].xy).yx);
+  const float a = abs(asfloat(u[1].xy).yx.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_builtin.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..2d53757
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_builtin.wgsl.expected.fxc.hlsl
@@ -0,0 +1,23 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+float4x2 tint_symbol(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_3 / 4];
+  return float4x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)), asfloat(((scalar_offset_3 & 2) ? ubo_load_3.zw : ubo_load_3.xy)));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float2x4 t = transpose(tint_symbol(u, 264u));
+  const float l = length(asfloat(u[1].xy).yx);
+  const float a = abs(asfloat(u[1].xy).yx.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_builtin.wgsl.expected.glsl
new file mode 100644
index 0000000..e469dd4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_builtin.wgsl.expected.glsl
@@ -0,0 +1,80 @@
+#version 310 es
+
+struct S {
+  int before;
+  uint pad;
+  mat4x2 m;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  int after;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+};
+
+struct S_std140 {
+  int before;
+  uint pad;
+  vec2 m_0;
+  vec2 m_1;
+  vec2 m_2;
+  vec2 m_3;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  int after;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+mat4x2 load_u_inner_2_m() {
+  return mat4x2(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2, u.inner[2u].m_3);
+}
+
+void f() {
+  mat2x4 t = transpose(load_u_inner_2_m());
+  float l = length(u.inner[0u].m_1.yx);
+  float a = abs(u.inner[0u].m_1.yx[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_builtin.wgsl.expected.msl
new file mode 100644
index 0000000..9684c69
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_builtin.wgsl.expected.msl
@@ -0,0 +1,32 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0008 */ float4x2 m;
+  /* 0x0028 */ tint_array<int8_t, 24> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol [[buffer(0)]]) {
+  float2x4 const t = transpose((*(tint_symbol))[2].m);
+  float const l = length(float2((*(tint_symbol))[0].m[1]).yx);
+  float const a = fabs(float2((*(tint_symbol))[0].m[1]).yx[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_builtin.wgsl.expected.spvasm
new file mode 100644
index 0000000..5df4a4b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_builtin.wgsl.expected.spvasm
@@ -0,0 +1,86 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 55
+; Schema: 0
+               OpCapability Shader
+         %45 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "m_2"
+               OpMemberName %S_std140 4 "m_3"
+               OpMemberName %S_std140 5 "after"
+               OpName %u "u"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 8
+               OpMemberDecorate %S_std140 2 Offset 16
+               OpMemberDecorate %S_std140 3 Offset 24
+               OpMemberDecorate %S_std140 4 Offset 32
+               OpMemberDecorate %S_std140 5 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v2float = OpTypeVector %float 2
+   %S_std140 = OpTypeStruct %int %v2float %v2float %v2float %v2float %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+%mat4v2float = OpTypeMatrix %v2float 4
+         %11 = OpTypeFunction %mat4v2float
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+     %uint_1 = OpConstant %uint 1
+%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %36 = OpTypeFunction %void
+    %v4float = OpTypeVector %float 4
+%mat2v4float = OpTypeMatrix %v4float 2
+         %46 = OpConstantNull %uint
+%load_u_inner_2_m = OpFunction %mat4v2float None %11
+         %14 = OpLabel
+         %19 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %23 = OpAccessChain %_ptr_Uniform_v2float %19 %uint_1
+         %24 = OpLoad %v2float %23
+         %26 = OpAccessChain %_ptr_Uniform_v2float %19 %uint_2
+         %27 = OpLoad %v2float %26
+         %30 = OpAccessChain %_ptr_Uniform_v2float %19 %uint_3
+         %31 = OpLoad %v2float %30
+         %33 = OpAccessChain %_ptr_Uniform_v2float %19 %uint_4
+         %34 = OpLoad %v2float %33
+         %35 = OpCompositeConstruct %mat4v2float %24 %27 %31 %34
+               OpReturnValue %35
+               OpFunctionEnd
+          %f = OpFunction %void None %36
+         %39 = OpLabel
+         %43 = OpFunctionCall %mat4v2float %load_u_inner_2_m
+         %40 = OpTranspose %mat2v4float %43
+         %47 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %46 %uint_2
+         %48 = OpLoad %v2float %47
+         %49 = OpVectorShuffle %v2float %48 %48 1 0
+         %44 = OpExtInst %float %45 Length %49
+         %51 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %46 %uint_2
+         %52 = OpLoad %v2float %51
+         %53 = OpVectorShuffle %v2float %52 %52 1 0
+         %54 = OpCompositeExtract %float %53 0
+         %50 = OpExtInst %float %45 FAbs %54
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_builtin.wgsl.expected.wgsl
new file mode 100644
index 0000000..24e8b4a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_builtin.wgsl.expected.wgsl
@@ -0,0 +1,15 @@
+struct S {
+  before : i32,
+  m : mat4x2<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let t = transpose(u[2].m);
+  let l = length(u[0].m[1].yx);
+  let a = abs(u[0].m[1].yx.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_fn.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_fn.wgsl
new file mode 100644
index 0000000..1364229
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_fn.wgsl
@@ -0,0 +1,23 @@
+struct S {
+  before : i32,
+  m : mat4x2<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+fn a(a : array<S, 4>) {}
+fn b(s : S) {}
+fn c(m : mat4x2<f32>) {}
+fn d(v : vec2<f32>) {}
+fn e(f : f32) {}
+
+@compute @workgroup_size(1)
+fn f() {
+    a(u);
+    b(u[2]);
+    c(u[2].m);
+    d(u[0].m[1].yx);
+    e(u[0].m[1].yx.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_fn.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..393469d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_fn.wgsl.expected.dxc.hlsl
@@ -0,0 +1,64 @@
+struct S {
+  int before;
+  float4x2 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(float4x2 m) {
+}
+
+void d(float2 v) {
+}
+
+void e(float f_1) {
+}
+
+float4x2 tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_3 / 4];
+  return float4x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)), asfloat(((scalar_offset_3 & 2) ? ubo_load_3.zw : ubo_load_3.xy)));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 256u));
+  c(tint_symbol_3(u, 264u));
+  d(asfloat(u[1].xy).yx);
+  e(asfloat(u[1].xy).yx.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_fn.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..393469d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_fn.wgsl.expected.fxc.hlsl
@@ -0,0 +1,64 @@
+struct S {
+  int before;
+  float4x2 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(float4x2 m) {
+}
+
+void d(float2 v) {
+}
+
+void e(float f_1) {
+}
+
+float4x2 tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_3 / 4];
+  return float4x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)), asfloat(((scalar_offset_3 & 2) ? ubo_load_3.zw : ubo_load_3.xy)));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 256u));
+  c(tint_symbol_3(u, 264u));
+  d(asfloat(u[1].xy).yx);
+  e(asfloat(u[1].xy).yx.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_fn.wgsl.expected.glsl
new file mode 100644
index 0000000..0fa73a0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_fn.wgsl.expected.glsl
@@ -0,0 +1,111 @@
+#version 310 es
+
+struct S {
+  int before;
+  uint pad;
+  mat4x2 m;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  int after;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+};
+
+struct S_std140 {
+  int before;
+  uint pad;
+  vec2 m_0;
+  vec2 m_1;
+  vec2 m_2;
+  vec2 m_3;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  int after;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(mat4x2 m) {
+}
+
+void d(vec2 v) {
+}
+
+void e(float f_1) {
+}
+
+S conv_S(S_std140 val) {
+  return S(val.before, val.pad, mat4x2(val.m_0, val.m_1, val.m_2, val.m_3), val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.after, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.pad_11, val.pad_12, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+mat4x2 load_u_inner_2_m() {
+  return mat4x2(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2, u.inner[2u].m_3);
+}
+
+void f() {
+  a(conv_arr4_S(u.inner));
+  b(conv_S(u.inner[2u]));
+  c(load_u_inner_2_m());
+  d(u.inner[0u].m_1.yx);
+  e(u.inner[0u].m_1.yx[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_fn.wgsl.expected.msl
new file mode 100644
index 0000000..e8c64c3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_fn.wgsl.expected.msl
@@ -0,0 +1,49 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0008 */ float4x2 m;
+  /* 0x0028 */ tint_array<int8_t, 24> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+void a(tint_array<S, 4> a_1) {
+}
+
+void b(S s) {
+}
+
+void c(float4x2 m) {
+}
+
+void d(float2 v) {
+}
+
+void e(float f_1) {
+}
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol [[buffer(0)]]) {
+  a(*(tint_symbol));
+  b((*(tint_symbol))[2]);
+  c((*(tint_symbol))[2].m);
+  d(float2((*(tint_symbol))[0].m[1]).yx);
+  e(float2((*(tint_symbol))[0].m[1]).yx[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_fn.wgsl.expected.spvasm
new file mode 100644
index 0000000..5136314
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_fn.wgsl.expected.spvasm
@@ -0,0 +1,211 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 128
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "m_2"
+               OpMemberName %S_std140 4 "m_3"
+               OpMemberName %S_std140 5 "after"
+               OpName %u "u"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %a "a"
+               OpName %a_1 "a_1"
+               OpName %b "b"
+               OpName %s "s"
+               OpName %c "c"
+               OpName %m "m"
+               OpName %d "d"
+               OpName %v "v"
+               OpName %e "e"
+               OpName %f_1 "f_1"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 8
+               OpMemberDecorate %S_std140 2 Offset 16
+               OpMemberDecorate %S_std140 3 Offset 24
+               OpMemberDecorate %S_std140 4 Offset 32
+               OpMemberDecorate %S_std140 5 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 8
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 8
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v2float = OpTypeVector %float 2
+   %S_std140 = OpTypeStruct %int %v2float %v2float %v2float %v2float %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+       %void = OpTypeVoid
+%mat4v2float = OpTypeMatrix %v2float 4
+          %S = OpTypeStruct %int %mat4v2float %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+         %11 = OpTypeFunction %void %_arr_S_uint_4
+         %19 = OpTypeFunction %void %S
+         %23 = OpTypeFunction %void %mat4v2float
+         %27 = OpTypeFunction %void %v2float
+         %31 = OpTypeFunction %void %float
+         %35 = OpTypeFunction %S %S_std140
+         %47 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+         %53 = OpConstantNull %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %56 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %69 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %82 = OpTypeFunction %mat4v2float
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
+     %uint_3 = OpConstant %uint 3
+        %105 = OpTypeFunction %void
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+          %a = OpFunction %void None %11
+        %a_1 = OpFunctionParameter %_arr_S_uint_4
+         %18 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %b = OpFunction %void None %19
+          %s = OpFunctionParameter %S
+         %22 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %c = OpFunction %void None %23
+          %m = OpFunctionParameter %mat4v2float
+         %26 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %d = OpFunction %void None %27
+          %v = OpFunctionParameter %v2float
+         %30 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %e = OpFunction %void None %31
+        %f_1 = OpFunctionParameter %float
+         %34 = OpLabel
+               OpReturn
+               OpFunctionEnd
+     %conv_S = OpFunction %S None %35
+        %val = OpFunctionParameter %S_std140
+         %38 = OpLabel
+         %39 = OpCompositeExtract %int %val 0
+         %40 = OpCompositeExtract %v2float %val 1
+         %41 = OpCompositeExtract %v2float %val 2
+         %42 = OpCompositeExtract %v2float %val 3
+         %43 = OpCompositeExtract %v2float %val 4
+         %44 = OpCompositeConstruct %mat4v2float %40 %41 %42 %43
+         %45 = OpCompositeExtract %int %val 5
+         %46 = OpCompositeConstruct %S %39 %44 %45
+               OpReturnValue %46
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %47
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %50 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %53
+          %i = OpVariable %_ptr_Function_uint Function %56
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %69
+               OpBranch %57
+         %57 = OpLabel
+               OpLoopMerge %58 %59 None
+               OpBranch %60
+         %60 = OpLabel
+         %62 = OpLoad %uint %i
+         %63 = OpULessThan %bool %62 %uint_4
+         %61 = OpLogicalNot %bool %63
+               OpSelectionMerge %65 None
+               OpBranchConditional %61 %66 %65
+         %66 = OpLabel
+               OpBranch %58
+         %65 = OpLabel
+               OpStore %var_for_index %val_0
+         %70 = OpLoad %uint %i
+         %72 = OpAccessChain %_ptr_Function_S %arr %70
+         %74 = OpLoad %uint %i
+         %76 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %74
+         %77 = OpLoad %S_std140 %76
+         %73 = OpFunctionCall %S %conv_S %77
+               OpStore %72 %73
+               OpBranch %59
+         %59 = OpLabel
+         %78 = OpLoad %uint %i
+         %80 = OpIAdd %uint %78 %uint_1
+               OpStore %i %80
+               OpBranch %57
+         %58 = OpLabel
+         %81 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %81
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat4v2float None %82
+         %84 = OpLabel
+         %89 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %92 = OpAccessChain %_ptr_Uniform_v2float %89 %uint_1
+         %93 = OpLoad %v2float %92
+         %95 = OpAccessChain %_ptr_Uniform_v2float %89 %uint_2
+         %96 = OpLoad %v2float %95
+         %99 = OpAccessChain %_ptr_Uniform_v2float %89 %uint_3
+        %100 = OpLoad %v2float %99
+        %102 = OpAccessChain %_ptr_Uniform_v2float %89 %uint_4
+        %103 = OpLoad %v2float %102
+        %104 = OpCompositeConstruct %mat4v2float %93 %96 %100 %103
+               OpReturnValue %104
+               OpFunctionEnd
+          %f = OpFunction %void None %105
+        %107 = OpLabel
+        %111 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+        %112 = OpLoad %_arr_S_std140_uint_4 %111
+        %109 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %112
+        %108 = OpFunctionCall %void %a %109
+        %115 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+        %116 = OpLoad %S_std140 %115
+        %114 = OpFunctionCall %S %conv_S %116
+        %113 = OpFunctionCall %void %b %114
+        %118 = OpFunctionCall %mat4v2float %load_u_inner_2_m
+        %117 = OpFunctionCall %void %c %118
+        %120 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %56 %uint_2
+        %121 = OpLoad %v2float %120
+        %122 = OpVectorShuffle %v2float %121 %121 1 0
+        %119 = OpFunctionCall %void %d %122
+        %124 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %56 %uint_2
+        %125 = OpLoad %v2float %124
+        %126 = OpVectorShuffle %v2float %125 %125 1 0
+        %127 = OpCompositeExtract %float %126 0
+        %123 = OpFunctionCall %void %e %127
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_fn.wgsl.expected.wgsl
new file mode 100644
index 0000000..9f3741e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_fn.wgsl.expected.wgsl
@@ -0,0 +1,32 @@
+struct S {
+  before : i32,
+  m : mat4x2<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+fn a(a : array<S, 4>) {
+}
+
+fn b(s : S) {
+}
+
+fn c(m : mat4x2<f32>) {
+}
+
+fn d(v : vec2<f32>) {
+}
+
+fn e(f : f32) {
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  a(u);
+  b(u[2]);
+  c(u[2].m);
+  d(u[0].m[1].yx);
+  e(u[0].m[1].yx.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_private.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_private.wgsl
new file mode 100644
index 0000000..d6ea0aa
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_private.wgsl
@@ -0,0 +1,17 @@
+struct S {
+  before : i32,
+  m : mat4x2<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+var<private> p : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[2];
+    p[3].m = u[2].m;
+    p[1].m[0] = u[0].m[1].yx;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_private.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..60c112b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_private.wgsl.expected.dxc.hlsl
@@ -0,0 +1,49 @@
+struct S {
+  int before;
+  float4x2 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+static S p[4] = (S[4])0;
+
+float4x2 tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_3 / 4];
+  return float4x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)), asfloat(((scalar_offset_3 & 2) ? ubo_load_3.zw : ubo_load_3.xy)));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 256u);
+  p[3].m = tint_symbol_3(u, 264u);
+  p[1].m[0] = asfloat(u[1].xy).yx;
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_private.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..60c112b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_private.wgsl.expected.fxc.hlsl
@@ -0,0 +1,49 @@
+struct S {
+  int before;
+  float4x2 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+static S p[4] = (S[4])0;
+
+float4x2 tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_3 / 4];
+  return float4x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)), asfloat(((scalar_offset_3 & 2) ? ubo_load_3.zw : ubo_load_3.xy)));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 256u);
+  p[3].m = tint_symbol_3(u, 264u);
+  p[1].m[0] = asfloat(u[1].xy).yx;
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..bdcf50b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_private.wgsl.expected.glsl
@@ -0,0 +1,96 @@
+#version 310 es
+
+struct S {
+  int before;
+  uint pad;
+  mat4x2 m;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  int after;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+};
+
+struct S_std140 {
+  int before;
+  uint pad;
+  vec2 m_0;
+  vec2 m_1;
+  vec2 m_2;
+  vec2 m_3;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  int after;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+S p[4] = S[4](S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+S conv_S(S_std140 val) {
+  return S(val.before, val.pad, mat4x2(val.m_0, val.m_1, val.m_2, val.m_3), val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.after, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.pad_11, val.pad_12, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+mat4x2 load_u_inner_2_m() {
+  return mat4x2(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2, u.inner[2u].m_3);
+}
+
+void f() {
+  p = conv_arr4_S(u.inner);
+  p[1] = conv_S(u.inner[2u]);
+  p[3].m = load_u_inner_2_m();
+  p[1].m[0] = u.inner[0u].m_1.yx;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..017641a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_private.wgsl.expected.msl
@@ -0,0 +1,34 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0008 */ float4x2 m;
+  /* 0x0028 */ tint_array<int8_t, 24> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol_1 [[buffer(0)]]) {
+  thread tint_array<S, 4> tint_symbol = {};
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[2];
+  tint_symbol[3].m = (*(tint_symbol_1))[2].m;
+  tint_symbol[1].m[0] = float2((*(tint_symbol_1))[0].m[1]).yx;
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_private.wgsl.expected.spvasm
new file mode 100644
index 0000000..9b3c6b0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_private.wgsl.expected.spvasm
@@ -0,0 +1,178 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 110
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "m_2"
+               OpMemberName %S_std140 4 "m_3"
+               OpMemberName %S_std140 5 "after"
+               OpName %u "u"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %p "p"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 8
+               OpMemberDecorate %S_std140 2 Offset 16
+               OpMemberDecorate %S_std140 3 Offset 24
+               OpMemberDecorate %S_std140 4 Offset 32
+               OpMemberDecorate %S_std140 5 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 8
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 8
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v2float = OpTypeVector %float 2
+   %S_std140 = OpTypeStruct %int %v2float %v2float %v2float %v2float %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+%mat4v2float = OpTypeMatrix %v2float 4
+          %S = OpTypeStruct %int %mat4v2float %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+%_ptr_Private__arr_S_uint_4 = OpTypePointer Private %_arr_S_uint_4
+         %16 = OpConstantNull %_arr_S_uint_4
+          %p = OpVariable %_ptr_Private__arr_S_uint_4 Private %16
+         %17 = OpTypeFunction %S %S_std140
+         %29 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %37 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %50 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %63 = OpTypeFunction %mat4v2float
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %86 = OpTypeFunction %void
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+      %int_1 = OpConstant %int 1
+%_ptr_Private_S = OpTypePointer Private %S
+      %int_3 = OpConstant %int 3
+%_ptr_Private_mat4v2float = OpTypePointer Private %mat4v2float
+        %104 = OpConstantNull %int
+%_ptr_Private_v2float = OpTypePointer Private %v2float
+     %conv_S = OpFunction %S None %17
+        %val = OpFunctionParameter %S_std140
+         %20 = OpLabel
+         %21 = OpCompositeExtract %int %val 0
+         %22 = OpCompositeExtract %v2float %val 1
+         %23 = OpCompositeExtract %v2float %val 2
+         %24 = OpCompositeExtract %v2float %val 3
+         %25 = OpCompositeExtract %v2float %val 4
+         %26 = OpCompositeConstruct %mat4v2float %22 %23 %24 %25
+         %27 = OpCompositeExtract %int %val 5
+         %28 = OpCompositeConstruct %S %21 %26 %27
+               OpReturnValue %28
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %29
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %32 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %16
+          %i = OpVariable %_ptr_Function_uint Function %37
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %50
+               OpBranch %38
+         %38 = OpLabel
+               OpLoopMerge %39 %40 None
+               OpBranch %41
+         %41 = OpLabel
+         %43 = OpLoad %uint %i
+         %44 = OpULessThan %bool %43 %uint_4
+         %42 = OpLogicalNot %bool %44
+               OpSelectionMerge %46 None
+               OpBranchConditional %42 %47 %46
+         %47 = OpLabel
+               OpBranch %39
+         %46 = OpLabel
+               OpStore %var_for_index %val_0
+         %51 = OpLoad %uint %i
+         %53 = OpAccessChain %_ptr_Function_S %arr %51
+         %55 = OpLoad %uint %i
+         %57 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %55
+         %58 = OpLoad %S_std140 %57
+         %54 = OpFunctionCall %S %conv_S %58
+               OpStore %53 %54
+               OpBranch %40
+         %40 = OpLabel
+         %59 = OpLoad %uint %i
+         %61 = OpIAdd %uint %59 %uint_1
+               OpStore %i %61
+               OpBranch %38
+         %39 = OpLabel
+         %62 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %62
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat4v2float None %63
+         %65 = OpLabel
+         %70 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %73 = OpAccessChain %_ptr_Uniform_v2float %70 %uint_1
+         %74 = OpLoad %v2float %73
+         %76 = OpAccessChain %_ptr_Uniform_v2float %70 %uint_2
+         %77 = OpLoad %v2float %76
+         %80 = OpAccessChain %_ptr_Uniform_v2float %70 %uint_3
+         %81 = OpLoad %v2float %80
+         %83 = OpAccessChain %_ptr_Uniform_v2float %70 %uint_4
+         %84 = OpLoad %v2float %83
+         %85 = OpCompositeConstruct %mat4v2float %74 %77 %81 %84
+               OpReturnValue %85
+               OpFunctionEnd
+          %f = OpFunction %void None %86
+         %89 = OpLabel
+         %92 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+         %93 = OpLoad %_arr_S_std140_uint_4 %92
+         %90 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %93
+               OpStore %p %90
+         %96 = OpAccessChain %_ptr_Private_S %p %int_1
+         %98 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %99 = OpLoad %S_std140 %98
+         %97 = OpFunctionCall %S %conv_S %99
+               OpStore %96 %97
+        %102 = OpAccessChain %_ptr_Private_mat4v2float %p %int_3 %uint_1
+        %103 = OpFunctionCall %mat4v2float %load_u_inner_2_m
+               OpStore %102 %103
+        %106 = OpAccessChain %_ptr_Private_v2float %p %int_1 %uint_1 %104
+        %107 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %37 %uint_2
+        %108 = OpLoad %v2float %107
+        %109 = OpVectorShuffle %v2float %108 %108 1 0
+               OpStore %106 %109
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..e2e9e62
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_private.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+struct S {
+  before : i32,
+  m : mat4x2<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+var<private> p : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[2];
+  p[3].m = u[2].m;
+  p[1].m[0] = u[0].m[1].yx;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_storage.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_storage.wgsl
new file mode 100644
index 0000000..df4ecdc
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_storage.wgsl
@@ -0,0 +1,17 @@
+struct S {
+  before : i32,
+  m : mat4x2<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+@group(0) @binding(1) var<storage, read_write> s : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[2];
+    s[3].m = u[2].m;
+    s[1].m[0] = u[0].m[1].yx;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_storage.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..5dc514f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_storage.wgsl.expected.dxc.hlsl
@@ -0,0 +1,71 @@
+struct S {
+  int before;
+  float4x2 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_3(RWByteAddressBuffer buffer, uint offset, float4x2 value) {
+  buffer.Store2((offset + 0u), asuint(value[0u]));
+  buffer.Store2((offset + 8u), asuint(value[1u]));
+  buffer.Store2((offset + 16u), asuint(value[2u]));
+  buffer.Store2((offset + 24u), asuint(value[3u]));
+}
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, S value) {
+  buffer.Store((offset + 0u), asuint(value.before));
+  tint_symbol_3(buffer, (offset + 8u), value.m);
+  buffer.Store((offset + 64u), asuint(value.after));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, S value[4]) {
+  S array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 128u)), array[i]);
+    }
+  }
+}
+
+float4x2 tint_symbol_8(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_3 / 4];
+  return float4x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)), asfloat(((scalar_offset_3 & 2) ? ubo_load_3.zw : ubo_load_3.xy)));
+}
+
+S tint_symbol_6(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 64u)) / 4;
+  const S tint_symbol_10 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_8(buffer, (offset + 8u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_10;
+}
+
+typedef S tint_symbol_5_ret[4];
+tint_symbol_5_ret tint_symbol_5(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_6(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_5(u, 0u));
+  tint_symbol_1(s, 128u, tint_symbol_6(u, 256u));
+  tint_symbol_3(s, 392u, tint_symbol_8(u, 264u));
+  s.Store2(136u, asuint(asfloat(u[1].xy).yx));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_storage.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..5dc514f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_storage.wgsl.expected.fxc.hlsl
@@ -0,0 +1,71 @@
+struct S {
+  int before;
+  float4x2 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_3(RWByteAddressBuffer buffer, uint offset, float4x2 value) {
+  buffer.Store2((offset + 0u), asuint(value[0u]));
+  buffer.Store2((offset + 8u), asuint(value[1u]));
+  buffer.Store2((offset + 16u), asuint(value[2u]));
+  buffer.Store2((offset + 24u), asuint(value[3u]));
+}
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, S value) {
+  buffer.Store((offset + 0u), asuint(value.before));
+  tint_symbol_3(buffer, (offset + 8u), value.m);
+  buffer.Store((offset + 64u), asuint(value.after));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, S value[4]) {
+  S array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 128u)), array[i]);
+    }
+  }
+}
+
+float4x2 tint_symbol_8(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_3 / 4];
+  return float4x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)), asfloat(((scalar_offset_3 & 2) ? ubo_load_3.zw : ubo_load_3.xy)));
+}
+
+S tint_symbol_6(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 64u)) / 4;
+  const S tint_symbol_10 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_8(buffer, (offset + 8u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_10;
+}
+
+typedef S tint_symbol_5_ret[4];
+tint_symbol_5_ret tint_symbol_5(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_6(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_5(u, 0u));
+  tint_symbol_1(s, 128u, tint_symbol_6(u, 256u));
+  tint_symbol_3(s, 392u, tint_symbol_8(u, 264u));
+  s.Store2(136u, asuint(asfloat(u[1].xy).yx));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..f0e1ba9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_storage.wgsl.expected.glsl
@@ -0,0 +1,99 @@
+#version 310 es
+
+struct S {
+  int before;
+  uint pad;
+  mat4x2 m;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  int after;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+};
+
+struct S_std140 {
+  int before;
+  uint pad;
+  vec2 m_0;
+  vec2 m_1;
+  vec2 m_2;
+  vec2 m_3;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  int after;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  S inner[4];
+} s;
+
+S conv_S(S_std140 val) {
+  return S(val.before, val.pad, mat4x2(val.m_0, val.m_1, val.m_2, val.m_3), val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.after, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.pad_11, val.pad_12, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+mat4x2 load_u_inner_2_m() {
+  return mat4x2(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2, u.inner[2u].m_3);
+}
+
+void f() {
+  s.inner = conv_arr4_S(u.inner);
+  s.inner[1] = conv_S(u.inner[2u]);
+  s.inner[3].m = load_u_inner_2_m();
+  s.inner[1].m[0] = u.inner[0u].m_1.yx;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..73076ac
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_storage.wgsl.expected.msl
@@ -0,0 +1,33 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0008 */ float4x2 m;
+  /* 0x0028 */ tint_array<int8_t, 24> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+kernel void f(device tint_array<S, 4>* tint_symbol [[buffer(1)]], const constant tint_array<S, 4>* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
+  (*(tint_symbol))[3].m = (*(tint_symbol_1))[2].m;
+  (*(tint_symbol))[1].m[0] = float2((*(tint_symbol_1))[0].m[1]).yx;
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_storage.wgsl.expected.spvasm
new file mode 100644
index 0000000..a640f22
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_storage.wgsl.expected.spvasm
@@ -0,0 +1,187 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 113
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "m_2"
+               OpMemberName %S_std140 4 "m_3"
+               OpMemberName %S_std140 5 "after"
+               OpName %u "u"
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %s "s"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 8
+               OpMemberDecorate %S_std140 2 Offset 16
+               OpMemberDecorate %S_std140 3 Offset 24
+               OpMemberDecorate %S_std140 4 Offset 32
+               OpMemberDecorate %S_std140 5 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 8
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 8
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+               OpDecorate %s DescriptorSet 0
+               OpDecorate %s Binding 1
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v2float = OpTypeVector %float 2
+   %S_std140 = OpTypeStruct %int %v2float %v2float %v2float %v2float %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+%mat4v2float = OpTypeMatrix %v2float 4
+          %S = OpTypeStruct %int %mat4v2float %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+    %u_block = OpTypeStruct %_arr_S_uint_4
+%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
+          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+         %17 = OpTypeFunction %S %S_std140
+         %29 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+         %35 = OpConstantNull %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %38 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %51 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %64 = OpTypeFunction %mat4v2float
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %87 = OpTypeFunction %void
+%_ptr_StorageBuffer__arr_S_uint_4 = OpTypePointer StorageBuffer %_arr_S_uint_4
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+      %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
+      %int_3 = OpConstant %int 3
+%_ptr_StorageBuffer_mat4v2float = OpTypePointer StorageBuffer %mat4v2float
+        %107 = OpConstantNull %int
+%_ptr_StorageBuffer_v2float = OpTypePointer StorageBuffer %v2float
+     %conv_S = OpFunction %S None %17
+        %val = OpFunctionParameter %S_std140
+         %20 = OpLabel
+         %21 = OpCompositeExtract %int %val 0
+         %22 = OpCompositeExtract %v2float %val 1
+         %23 = OpCompositeExtract %v2float %val 2
+         %24 = OpCompositeExtract %v2float %val 3
+         %25 = OpCompositeExtract %v2float %val 4
+         %26 = OpCompositeConstruct %mat4v2float %22 %23 %24 %25
+         %27 = OpCompositeExtract %int %val 5
+         %28 = OpCompositeConstruct %S %21 %26 %27
+               OpReturnValue %28
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %29
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %32 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %35
+          %i = OpVariable %_ptr_Function_uint Function %38
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %51
+               OpBranch %39
+         %39 = OpLabel
+               OpLoopMerge %40 %41 None
+               OpBranch %42
+         %42 = OpLabel
+         %44 = OpLoad %uint %i
+         %45 = OpULessThan %bool %44 %uint_4
+         %43 = OpLogicalNot %bool %45
+               OpSelectionMerge %47 None
+               OpBranchConditional %43 %48 %47
+         %48 = OpLabel
+               OpBranch %40
+         %47 = OpLabel
+               OpStore %var_for_index %val_0
+         %52 = OpLoad %uint %i
+         %54 = OpAccessChain %_ptr_Function_S %arr %52
+         %56 = OpLoad %uint %i
+         %58 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %56
+         %59 = OpLoad %S_std140 %58
+         %55 = OpFunctionCall %S %conv_S %59
+               OpStore %54 %55
+               OpBranch %41
+         %41 = OpLabel
+         %60 = OpLoad %uint %i
+         %62 = OpIAdd %uint %60 %uint_1
+               OpStore %i %62
+               OpBranch %39
+         %40 = OpLabel
+         %63 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %63
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat4v2float None %64
+         %66 = OpLabel
+         %71 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %74 = OpAccessChain %_ptr_Uniform_v2float %71 %uint_1
+         %75 = OpLoad %v2float %74
+         %77 = OpAccessChain %_ptr_Uniform_v2float %71 %uint_2
+         %78 = OpLoad %v2float %77
+         %81 = OpAccessChain %_ptr_Uniform_v2float %71 %uint_3
+         %82 = OpLoad %v2float %81
+         %84 = OpAccessChain %_ptr_Uniform_v2float %71 %uint_4
+         %85 = OpLoad %v2float %84
+         %86 = OpCompositeConstruct %mat4v2float %75 %78 %82 %85
+               OpReturnValue %86
+               OpFunctionEnd
+          %f = OpFunction %void None %87
+         %90 = OpLabel
+         %92 = OpAccessChain %_ptr_StorageBuffer__arr_S_uint_4 %s %uint_0
+         %95 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+         %96 = OpLoad %_arr_S_std140_uint_4 %95
+         %93 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %96
+               OpStore %92 %93
+         %99 = OpAccessChain %_ptr_StorageBuffer_S %s %uint_0 %int_1
+        %101 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+        %102 = OpLoad %S_std140 %101
+        %100 = OpFunctionCall %S %conv_S %102
+               OpStore %99 %100
+        %105 = OpAccessChain %_ptr_StorageBuffer_mat4v2float %s %uint_0 %int_3 %uint_1
+        %106 = OpFunctionCall %mat4v2float %load_u_inner_2_m
+               OpStore %105 %106
+        %109 = OpAccessChain %_ptr_StorageBuffer_v2float %s %uint_0 %int_1 %uint_1 %107
+        %110 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %38 %uint_2
+        %111 = OpLoad %v2float %110
+        %112 = OpVectorShuffle %v2float %111 %111 1 0
+               OpStore %109 %112
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..b32e1a4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+struct S {
+  before : i32,
+  m : mat4x2<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@group(0) @binding(1) var<storage, read_write> s : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[2];
+  s[3].m = u[2].m;
+  s[1].m[0] = u[0].m[1].yx;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_workgroup.wgsl
new file mode 100644
index 0000000..8e75a9b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_workgroup.wgsl
@@ -0,0 +1,17 @@
+struct S {
+  before : i32,
+  m : mat4x2<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+var<workgroup> w : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[2];
+    w[3].m = u[2].m;
+    w[1].m[0] = u[0].m[1].yx;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_workgroup.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..94f8f11
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_workgroup.wgsl.expected.dxc.hlsl
@@ -0,0 +1,65 @@
+struct S {
+  int before;
+  float4x2 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+groupshared S w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+float4x2 tint_symbol_5(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_3 / 4];
+  return float4x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)), asfloat(((scalar_offset_3 & 2) ? ubo_load_3.zw : ubo_load_3.xy)));
+}
+
+S tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 64u)) / 4;
+  const S tint_symbol_8 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_5(buffer, (offset + 8u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_8;
+}
+
+typedef S tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      const S tint_symbol_7 = (S)0;
+      w[i] = tint_symbol_7;
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 256u);
+  w[3].m = tint_symbol_5(u, 264u);
+  w[1].m[0] = asfloat(u[1].xy).yx;
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_workgroup.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..94f8f11
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_workgroup.wgsl.expected.fxc.hlsl
@@ -0,0 +1,65 @@
+struct S {
+  int before;
+  float4x2 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+groupshared S w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+float4x2 tint_symbol_5(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_3 / 4];
+  return float4x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)), asfloat(((scalar_offset_3 & 2) ? ubo_load_3.zw : ubo_load_3.xy)));
+}
+
+S tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 64u)) / 4;
+  const S tint_symbol_8 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_5(buffer, (offset + 8u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_8;
+}
+
+typedef S tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      const S tint_symbol_7 = (S)0;
+      w[i] = tint_symbol_7;
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 256u);
+  w[3].m = tint_symbol_5(u, 264u);
+  w[1].m[0] = asfloat(u[1].xy).yx;
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..05df402
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,104 @@
+#version 310 es
+
+struct S {
+  int before;
+  uint pad;
+  mat4x2 m;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  int after;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+};
+
+struct S_std140 {
+  int before;
+  uint pad;
+  vec2 m_0;
+  vec2 m_1;
+  vec2 m_2;
+  vec2 m_3;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  int after;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+shared S w[4];
+S conv_S(S_std140 val) {
+  return S(val.before, val.pad, mat4x2(val.m_0, val.m_1, val.m_2, val.m_3), val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.after, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.pad_11, val.pad_12, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, mat4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+mat4x2 load_u_inner_2_m() {
+  return mat4x2(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2, u.inner[2u].m_3);
+}
+
+void f(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      uint i = idx;
+      S tint_symbol = S(0, 0u, mat4x2(vec2(0.0f), vec2(0.0f), vec2(0.0f), vec2(0.0f)), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u);
+      w[i] = tint_symbol;
+    }
+  }
+  barrier();
+  w = conv_arr4_S(u.inner);
+  w[1] = conv_S(u.inner[2u]);
+  w[3].m = load_u_inner_2_m();
+  w[1].m[0] = u.inner[0u].m_1.yx;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..02501da
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,48 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0008 */ float4x2 m;
+  /* 0x0028 */ tint_array<int8_t, 24> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+struct tint_symbol_6 {
+  tint_array<S, 4> w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup tint_array<S, 4>* const tint_symbol_1, const constant tint_array<S, 4>* const tint_symbol_2) {
+  for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+    uint const i = idx;
+    S const tint_symbol = S{};
+    (*(tint_symbol_1))[i] = tint_symbol;
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol_1) = *(tint_symbol_2);
+  (*(tint_symbol_1))[1] = (*(tint_symbol_2))[2];
+  (*(tint_symbol_1))[3].m = (*(tint_symbol_2))[2].m;
+  (*(tint_symbol_1))[1].m[0] = float2((*(tint_symbol_2))[0].m[1]).yx;
+}
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol_5 [[buffer(0)]], threadgroup tint_symbol_6* tint_symbol_4 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup tint_array<S, 4>* const tint_symbol_3 = &((*(tint_symbol_4)).w);
+  f_inner(local_invocation_index, tint_symbol_3, tint_symbol_5);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_workgroup.wgsl.expected.spvasm
new file mode 100644
index 0000000..1a26894
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_workgroup.wgsl.expected.spvasm
@@ -0,0 +1,221 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 135
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %local_invocation_index_1 "local_invocation_index_1"
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "m_2"
+               OpMemberName %S_std140 4 "m_3"
+               OpMemberName %S_std140 5 "after"
+               OpName %u "u"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %w "w"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f_inner "f_inner"
+               OpName %local_invocation_index "local_invocation_index"
+               OpName %idx "idx"
+               OpName %f "f"
+               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 8
+               OpMemberDecorate %S_std140 2 Offset 16
+               OpMemberDecorate %S_std140 3 Offset 24
+               OpMemberDecorate %S_std140 4 Offset 32
+               OpMemberDecorate %S_std140 5 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 8
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 8
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v2float = OpTypeVector %float 2
+   %S_std140 = OpTypeStruct %int %v2float %v2float %v2float %v2float %int
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+%mat4v2float = OpTypeMatrix %v2float 4
+          %S = OpTypeStruct %int %mat4v2float %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+%_ptr_Workgroup__arr_S_uint_4 = OpTypePointer Workgroup %_arr_S_uint_4
+          %w = OpVariable %_ptr_Workgroup__arr_S_uint_4 Workgroup
+         %18 = OpTypeFunction %S %S_std140
+         %30 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+         %36 = OpConstantNull %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %39 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %52 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %65 = OpTypeFunction %mat4v2float
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %88 = OpTypeFunction %void %uint
+%_ptr_Workgroup_S = OpTypePointer Workgroup %S
+        %106 = OpConstantNull %S
+   %uint_264 = OpConstant %uint 264
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+      %int_1 = OpConstant %int 1
+      %int_3 = OpConstant %int 3
+%_ptr_Workgroup_mat4v2float = OpTypePointer Workgroup %mat4v2float
+        %124 = OpConstantNull %int
+%_ptr_Workgroup_v2float = OpTypePointer Workgroup %v2float
+        %130 = OpTypeFunction %void
+     %conv_S = OpFunction %S None %18
+        %val = OpFunctionParameter %S_std140
+         %21 = OpLabel
+         %22 = OpCompositeExtract %int %val 0
+         %23 = OpCompositeExtract %v2float %val 1
+         %24 = OpCompositeExtract %v2float %val 2
+         %25 = OpCompositeExtract %v2float %val 3
+         %26 = OpCompositeExtract %v2float %val 4
+         %27 = OpCompositeConstruct %mat4v2float %23 %24 %25 %26
+         %28 = OpCompositeExtract %int %val 5
+         %29 = OpCompositeConstruct %S %22 %27 %28
+               OpReturnValue %29
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %30
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %33 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %36
+          %i = OpVariable %_ptr_Function_uint Function %39
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %52
+               OpBranch %40
+         %40 = OpLabel
+               OpLoopMerge %41 %42 None
+               OpBranch %43
+         %43 = OpLabel
+         %45 = OpLoad %uint %i
+         %46 = OpULessThan %bool %45 %uint_4
+         %44 = OpLogicalNot %bool %46
+               OpSelectionMerge %48 None
+               OpBranchConditional %44 %49 %48
+         %49 = OpLabel
+               OpBranch %41
+         %48 = OpLabel
+               OpStore %var_for_index %val_0
+         %53 = OpLoad %uint %i
+         %55 = OpAccessChain %_ptr_Function_S %arr %53
+         %57 = OpLoad %uint %i
+         %59 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %57
+         %60 = OpLoad %S_std140 %59
+         %56 = OpFunctionCall %S %conv_S %60
+               OpStore %55 %56
+               OpBranch %42
+         %42 = OpLabel
+         %61 = OpLoad %uint %i
+         %63 = OpIAdd %uint %61 %uint_1
+               OpStore %i %63
+               OpBranch %40
+         %41 = OpLabel
+         %64 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %64
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat4v2float None %65
+         %67 = OpLabel
+         %72 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %75 = OpAccessChain %_ptr_Uniform_v2float %72 %uint_1
+         %76 = OpLoad %v2float %75
+         %78 = OpAccessChain %_ptr_Uniform_v2float %72 %uint_2
+         %79 = OpLoad %v2float %78
+         %82 = OpAccessChain %_ptr_Uniform_v2float %72 %uint_3
+         %83 = OpLoad %v2float %82
+         %85 = OpAccessChain %_ptr_Uniform_v2float %72 %uint_4
+         %86 = OpLoad %v2float %85
+         %87 = OpCompositeConstruct %mat4v2float %76 %79 %83 %86
+               OpReturnValue %87
+               OpFunctionEnd
+    %f_inner = OpFunction %void None %88
+%local_invocation_index = OpFunctionParameter %uint
+         %92 = OpLabel
+        %idx = OpVariable %_ptr_Function_uint Function %39
+               OpStore %idx %local_invocation_index
+               OpBranch %94
+         %94 = OpLabel
+               OpLoopMerge %95 %96 None
+               OpBranch %97
+         %97 = OpLabel
+         %99 = OpLoad %uint %idx
+        %100 = OpULessThan %bool %99 %uint_4
+         %98 = OpLogicalNot %bool %100
+               OpSelectionMerge %101 None
+               OpBranchConditional %98 %102 %101
+        %102 = OpLabel
+               OpBranch %95
+        %101 = OpLabel
+        %103 = OpLoad %uint %idx
+        %105 = OpAccessChain %_ptr_Workgroup_S %w %103
+               OpStore %105 %106
+               OpBranch %96
+         %96 = OpLabel
+        %107 = OpLoad %uint %idx
+        %108 = OpIAdd %uint %107 %uint_1
+               OpStore %idx %108
+               OpBranch %94
+         %95 = OpLabel
+               OpControlBarrier %uint_2 %uint_2 %uint_264
+        %113 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+        %114 = OpLoad %_arr_S_std140_uint_4 %113
+        %111 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %114
+               OpStore %w %111
+        %116 = OpAccessChain %_ptr_Workgroup_S %w %int_1
+        %118 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+        %119 = OpLoad %S_std140 %118
+        %117 = OpFunctionCall %S %conv_S %119
+               OpStore %116 %117
+        %122 = OpAccessChain %_ptr_Workgroup_mat4v2float %w %int_3 %uint_1
+        %123 = OpFunctionCall %mat4v2float %load_u_inner_2_m
+               OpStore %122 %123
+        %126 = OpAccessChain %_ptr_Workgroup_v2float %w %int_1 %uint_1 %124
+        %127 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0 %39 %uint_2
+        %128 = OpLoad %v2float %127
+        %129 = OpVectorShuffle %v2float %128 %128 1 0
+               OpStore %126 %129
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %130
+        %132 = OpLabel
+        %134 = OpLoad %uint %local_invocation_index_1
+        %133 = OpFunctionCall %void %f_inner %134
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..dd47e56
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x2_f32/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+struct S {
+  before : i32,
+  m : mat4x2<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+var<workgroup> w : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[2];
+  w[3].m = u[2].m;
+  w[1].m[0] = u[0].m[1].yx;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/dynamic_index_via_ptr.wgsl
new file mode 100644
index 0000000..d66d3ac
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/dynamic_index_via_ptr.wgsl
@@ -0,0 +1,34 @@
+enable f16;
+
+struct Inner {
+  @size(64)
+  m : mat4x3<f16>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a           = &a;
+  let p_a_i         = &((*p_a)[i()]);
+  let p_a_i_a       = &((*p_a_i).a);
+  let p_a_i_a_i     = &((*p_a_i_a)[i()]);
+  let p_a_i_a_i_m   = &((*p_a_i_a_i).m);
+  let p_a_i_a_i_m_i = &((*p_a_i_a_i_m)[i()]);
+
+
+  let l_a             : array<Outer, 4> =  *p_a;
+  let l_a_i           : Outer           =  *p_a_i;
+  let l_a_i_a         : array<Inner, 4> =  *p_a_i_a;
+  let l_a_i_a_i       : Inner           =  *p_a_i_a_i;
+  let l_a_i_a_i_m     : mat4x3<f16>     =  *p_a_i_a_i_m;
+  let l_a_i_a_i_m_i   : vec3<f16>       =  *p_a_i_a_i_m_i;
+  let l_a_i_a_i_m_i_i : f16             = (*p_a_i_a_i_m_i)[i()];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..96d9ebc
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,98 @@
+struct Inner {
+  matrix<float16_t, 4, 3> m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 4, 3> tint_symbol_8(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+}
+
+Inner tint_symbol_7(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_11 = {tint_symbol_8(buffer, (offset + 0u))};
+  return tint_symbol_11;
+}
+
+typedef Inner tint_symbol_6_ret[4];
+tint_symbol_6_ret tint_symbol_6(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_7(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_5(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_12 = {tint_symbol_6(buffer, (offset + 0u))};
+  return tint_symbol_12;
+}
+
+typedef Outer tint_symbol_4_ret[4];
+tint_symbol_4_ret tint_symbol_4(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
+      arr_1[i_2] = tint_symbol_5(buffer, (offset + (i_2 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_a_i_save = i();
+  const int p_a_i_a_i_m_i_save = i();
+  const Outer l_a[4] = tint_symbol_4(a, 0u);
+  const Outer l_a_i = tint_symbol_5(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a[4] = tint_symbol_6(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a_i = tint_symbol_7(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const matrix<float16_t, 4, 3> l_a_i_a_i_m = tint_symbol_8(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const uint scalar_offset_4 = ((((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))) + (8u * uint(p_a_i_a_i_m_i_save)))) / 4;
+  uint4 ubo_load_9 = a[scalar_offset_4 / 4];
+  uint2 ubo_load_8 = ((scalar_offset_4 & 2) ? ubo_load_9.zw : ubo_load_9.xy);
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  float16_t ubo_load_8_y = f16tof32(ubo_load_8[0] >> 16);
+  const vector<float16_t, 3> l_a_i_a_i_m_i = vector<float16_t, 3>(ubo_load_8_xz[0], ubo_load_8_y, ubo_load_8_xz[1]);
+  const int tint_symbol = p_a_i_save;
+  const int tint_symbol_1 = p_a_i_a_i_save;
+  const int tint_symbol_2 = p_a_i_a_i_m_i_save;
+  const int tint_symbol_3 = i();
+  const uint scalar_offset_bytes = (((((256u * uint(tint_symbol)) + (64u * uint(tint_symbol_1))) + (8u * uint(tint_symbol_2))) + (2u * uint(tint_symbol_3))));
+  const uint scalar_offset_index = scalar_offset_bytes / 4;
+  const float16_t l_a_i_a_i_m_i_i = float16_t(f16tof32(((a[scalar_offset_index / 4][scalar_offset_index % 4] >> (scalar_offset_bytes % 4 == 0 ? 0 : 16)) & 0xFFFF)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..ac36ddd
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,103 @@
+SKIP: FAILED
+
+struct Inner {
+  matrix<float16_t, 4, 3> m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 4, 3> tint_symbol_8(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+}
+
+Inner tint_symbol_7(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_11 = {tint_symbol_8(buffer, (offset + 0u))};
+  return tint_symbol_11;
+}
+
+typedef Inner tint_symbol_6_ret[4];
+tint_symbol_6_ret tint_symbol_6(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_7(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_5(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_12 = {tint_symbol_6(buffer, (offset + 0u))};
+  return tint_symbol_12;
+}
+
+typedef Outer tint_symbol_4_ret[4];
+tint_symbol_4_ret tint_symbol_4(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
+      arr_1[i_2] = tint_symbol_5(buffer, (offset + (i_2 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_a_i_save = i();
+  const int p_a_i_a_i_m_i_save = i();
+  const Outer l_a[4] = tint_symbol_4(a, 0u);
+  const Outer l_a_i = tint_symbol_5(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a[4] = tint_symbol_6(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a_i = tint_symbol_7(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const matrix<float16_t, 4, 3> l_a_i_a_i_m = tint_symbol_8(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const uint scalar_offset_4 = ((((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))) + (8u * uint(p_a_i_a_i_m_i_save)))) / 4;
+  uint4 ubo_load_9 = a[scalar_offset_4 / 4];
+  uint2 ubo_load_8 = ((scalar_offset_4 & 2) ? ubo_load_9.zw : ubo_load_9.xy);
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  float16_t ubo_load_8_y = f16tof32(ubo_load_8[0] >> 16);
+  const vector<float16_t, 3> l_a_i_a_i_m_i = vector<float16_t, 3>(ubo_load_8_xz[0], ubo_load_8_y, ubo_load_8_xz[1]);
+  const int tint_symbol = p_a_i_save;
+  const int tint_symbol_1 = p_a_i_a_i_save;
+  const int tint_symbol_2 = p_a_i_a_i_m_i_save;
+  const int tint_symbol_3 = i();
+  const uint scalar_offset_bytes = (((((256u * uint(tint_symbol)) + (64u * uint(tint_symbol_1))) + (8u * uint(tint_symbol_2))) + (2u * uint(tint_symbol_3))));
+  const uint scalar_offset_index = scalar_offset_bytes / 4;
+  const float16_t l_a_i_a_i_m_i_i = float16_t(f16tof32(((a[scalar_offset_index / 4][scalar_offset_index % 4] >> (scalar_offset_bytes % 4 == 0 ? 0 : 16)) & 0xFFFF)));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x00000236CB5C19B0(2,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..3a626b7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,157 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct Inner {
+  f16mat4x3 m;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+};
+
+struct Inner_std140 {
+  f16vec3 m_0;
+  f16vec3 m_1;
+  f16vec3 m_2;
+  f16vec3 m_3;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+};
+
+struct Outer {
+  Inner a[4];
+};
+
+struct Outer_std140 {
+  Inner_std140 a[4];
+};
+
+layout(binding = 0, std140) uniform a_block_std140_ubo {
+  Outer_std140 inner[4];
+} a;
+
+int counter = 0;
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+Inner conv_Inner(Inner_std140 val) {
+  return Inner(f16mat4x3(val.m_0, val.m_1, val.m_2, val.m_3), val.pad, val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7);
+}
+
+Inner[4] conv_arr4_Inner(Inner_std140 val[4]) {
+  Inner arr[4] = Inner[4](Inner(f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_Inner(val[i]);
+    }
+  }
+  return arr;
+}
+
+Outer conv_Outer(Outer_std140 val) {
+  return Outer(conv_arr4_Inner(val.a));
+}
+
+Outer[4] conv_arr4_Outer(Outer_std140 val[4]) {
+  Outer arr[4] = Outer[4](Outer(Inner[4](Inner(f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_Outer(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat4x3 load_a_inner_p0_a_p1_m(uint p0, uint p1) {
+  uint s_save = p0;
+  uint s_save_1 = p1;
+  return f16mat4x3(a.inner[s_save].a[s_save_1].m_0, a.inner[s_save].a[s_save_1].m_1, a.inner[s_save].a[s_save_1].m_2, a.inner[s_save].a[s_save_1].m_3);
+}
+
+f16vec3 load_a_inner_p0_a_p1_m_p2(uint p0, uint p1, uint p2) {
+  switch(p2) {
+    case 0u: {
+      return a.inner[p0].a[p1].m_0;
+      break;
+    }
+    case 1u: {
+      return a.inner[p0].a[p1].m_1;
+      break;
+    }
+    case 2u: {
+      return a.inner[p0].a[p1].m_2;
+      break;
+    }
+    case 3u: {
+      return a.inner[p0].a[p1].m_3;
+      break;
+    }
+    default: {
+      return f16vec3(0.0hf);
+      break;
+    }
+  }
+}
+
+float16_t load_a_inner_p0_a_p1_m_p2_p3(uint p0, uint p1, uint p2, uint p3) {
+  switch(p2) {
+    case 0u: {
+      return a.inner[p0].a[p1].m_0[p3];
+      break;
+    }
+    case 1u: {
+      return a.inner[p0].a[p1].m_1[p3];
+      break;
+    }
+    case 2u: {
+      return a.inner[p0].a[p1].m_2[p3];
+      break;
+    }
+    case 3u: {
+      return a.inner[p0].a[p1].m_3[p3];
+      break;
+    }
+    default: {
+      return 0.0hf;
+      break;
+    }
+  }
+}
+
+void f() {
+  Outer p_a[4] = conv_arr4_Outer(a.inner);
+  int tint_symbol = i();
+  Outer p_a_i = conv_Outer(a.inner[tint_symbol]);
+  Inner p_a_i_a[4] = conv_arr4_Inner(a.inner[tint_symbol].a);
+  int tint_symbol_1 = i();
+  Inner p_a_i_a_i = conv_Inner(a.inner[tint_symbol].a[tint_symbol_1]);
+  f16mat4x3 p_a_i_a_i_m = load_a_inner_p0_a_p1_m(uint(tint_symbol), uint(tint_symbol_1));
+  int tint_symbol_2 = i();
+  f16vec3 p_a_i_a_i_m_i = load_a_inner_p0_a_p1_m_p2(uint(tint_symbol), uint(tint_symbol_1), uint(tint_symbol_2));
+  Outer l_a[4] = conv_arr4_Outer(a.inner);
+  Outer l_a_i = conv_Outer(a.inner[tint_symbol]);
+  Inner l_a_i_a[4] = conv_arr4_Inner(a.inner[tint_symbol].a);
+  Inner l_a_i_a_i = conv_Inner(a.inner[tint_symbol].a[tint_symbol_1]);
+  f16mat4x3 l_a_i_a_i_m = load_a_inner_p0_a_p1_m(uint(tint_symbol), uint(tint_symbol_1));
+  f16vec3 l_a_i_a_i_m_i = load_a_inner_p0_a_p1_m_p2(uint(tint_symbol), uint(tint_symbol_1), uint(tint_symbol_2));
+  int tint_symbol_3 = i();
+  float16_t l_a_i_a_i_m_i_i = load_a_inner_p0_a_p1_m_p2_p3(uint(tint_symbol), uint(tint_symbol_1), uint(tint_symbol_2), uint(tint_symbol_3));
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..1369d42
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,49 @@
+#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 Inner {
+  /* 0x0000 */ half4x3 m;
+  /* 0x0020 */ tint_array<int8_t, 32> tint_pad;
+};
+
+struct Outer {
+  /* 0x0000 */ tint_array<Inner, 4> a;
+};
+
+int i() {
+  thread int tint_symbol_4 = 0;
+  tint_symbol_4 = as_type<int>((as_type<uint>(tint_symbol_4) + as_type<uint>(1)));
+  return tint_symbol_4;
+}
+
+kernel void f(const constant tint_array<Outer, 4>* tint_symbol_5 [[buffer(0)]]) {
+  int const tint_symbol = i();
+  int const p_a_i_save = tint_symbol;
+  int const tint_symbol_1 = i();
+  int const p_a_i_a_i_save = tint_symbol_1;
+  int const tint_symbol_2 = i();
+  int const p_a_i_a_i_m_i_save = tint_symbol_2;
+  tint_array<Outer, 4> const l_a = *(tint_symbol_5);
+  Outer const l_a_i = (*(tint_symbol_5))[p_a_i_save];
+  tint_array<Inner, 4> const l_a_i_a = (*(tint_symbol_5))[p_a_i_save].a;
+  Inner const l_a_i_a_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save];
+  half4x3 const l_a_i_a_i_m = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m;
+  half3 const l_a_i_a_i_m_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save];
+  int const tint_symbol_3 = i();
+  half const l_a_i_a_i_m_i_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save][tint_symbol_3];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..0b6a55d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,338 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 215
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block_std140 "a_block_std140"
+               OpMemberName %a_block_std140 0 "inner"
+               OpName %Outer_std140 "Outer_std140"
+               OpMemberName %Outer_std140 0 "a"
+               OpName %Inner_std140 "Inner_std140"
+               OpMemberName %Inner_std140 0 "m_0"
+               OpMemberName %Inner_std140 1 "m_1"
+               OpMemberName %Inner_std140 2 "m_2"
+               OpMemberName %Inner_std140 3 "m_3"
+               OpName %a "a"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %Inner "Inner"
+               OpMemberName %Inner 0 "m"
+               OpName %conv_Inner "conv_Inner"
+               OpName %val "val"
+               OpName %conv_arr4_Inner "conv_arr4_Inner"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i_0 "i"
+               OpName %var_for_index_1 "var_for_index_1"
+               OpName %Outer "Outer"
+               OpMemberName %Outer 0 "a"
+               OpName %conv_Outer "conv_Outer"
+               OpName %val_1 "val"
+               OpName %conv_arr4_Outer "conv_arr4_Outer"
+               OpName %val_2 "val"
+               OpName %arr_0 "arr"
+               OpName %i_1 "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_a_inner_p0_a_p1_m "load_a_inner_p0_a_p1_m"
+               OpName %p0 "p0"
+               OpName %p1 "p1"
+               OpName %load_a_inner_p0_a_p1_m_p2 "load_a_inner_p0_a_p1_m_p2"
+               OpName %p0_0 "p0"
+               OpName %p1_0 "p1"
+               OpName %p2 "p2"
+               OpName %load_a_inner_p0_a_p1_m_p2_p3 "load_a_inner_p0_a_p1_m_p2_p3"
+               OpName %p0_1 "p0"
+               OpName %p1_1 "p1"
+               OpName %p2_0 "p2"
+               OpName %p3 "p3"
+               OpName %f "f"
+               OpDecorate %a_block_std140 Block
+               OpMemberDecorate %a_block_std140 0 Offset 0
+               OpMemberDecorate %Outer_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 1 Offset 8
+               OpMemberDecorate %Inner_std140 2 Offset 16
+               OpMemberDecorate %Inner_std140 3 Offset 24
+               OpDecorate %_arr_Inner_std140_uint_4 ArrayStride 64
+               OpDecorate %_arr_Outer_std140_uint_4 ArrayStride 256
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+               OpMemberDecorate %Inner 0 Offset 0
+               OpMemberDecorate %Inner 0 ColMajor
+               OpMemberDecorate %Inner 0 MatrixStride 8
+               OpDecorate %_arr_Inner_uint_4 ArrayStride 64
+               OpMemberDecorate %Outer 0 Offset 0
+               OpDecorate %_arr_Outer_uint_4 ArrayStride 256
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+%Inner_std140 = OpTypeStruct %v3half %v3half %v3half %v3half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_Inner_std140_uint_4 = OpTypeArray %Inner_std140 %uint_4
+%Outer_std140 = OpTypeStruct %_arr_Inner_std140_uint_4
+%_arr_Outer_std140_uint_4 = OpTypeArray %Outer_std140 %uint_4
+%a_block_std140 = OpTypeStruct %_arr_Outer_std140_uint_4
+%_ptr_Uniform_a_block_std140 = OpTypePointer Uniform %a_block_std140
+          %a = OpVariable %_ptr_Uniform_a_block_std140 Uniform
+        %int = OpTypeInt 32 1
+         %13 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %13
+         %16 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+ %mat4v3half = OpTypeMatrix %v3half 4
+      %Inner = OpTypeStruct %mat4v3half
+         %23 = OpTypeFunction %Inner %Inner_std140
+%_arr_Inner_uint_4 = OpTypeArray %Inner %uint_4
+         %35 = OpTypeFunction %_arr_Inner_uint_4 %_arr_Inner_std140_uint_4
+%_ptr_Function__arr_Inner_uint_4 = OpTypePointer Function %_arr_Inner_uint_4
+         %42 = OpConstantNull %_arr_Inner_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %45 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_Inner_std140_uint_4 = OpTypePointer Function %_arr_Inner_std140_uint_4
+         %58 = OpConstantNull %_arr_Inner_std140_uint_4
+%_ptr_Function_Inner = OpTypePointer Function %Inner
+%_ptr_Function_Inner_std140 = OpTypePointer Function %Inner_std140
+     %uint_1 = OpConstant %uint 1
+      %Outer = OpTypeStruct %_arr_Inner_uint_4
+         %71 = OpTypeFunction %Outer %Outer_std140
+%_arr_Outer_uint_4 = OpTypeArray %Outer %uint_4
+         %79 = OpTypeFunction %_arr_Outer_uint_4 %_arr_Outer_std140_uint_4
+%_ptr_Function__arr_Outer_uint_4 = OpTypePointer Function %_arr_Outer_uint_4
+         %86 = OpConstantNull %_arr_Outer_uint_4
+%_ptr_Function__arr_Outer_std140_uint_4 = OpTypePointer Function %_arr_Outer_std140_uint_4
+         %99 = OpConstantNull %_arr_Outer_std140_uint_4
+%_ptr_Function_Outer = OpTypePointer Function %Outer
+%_ptr_Function_Outer_std140 = OpTypePointer Function %Outer_std140
+        %111 = OpTypeFunction %mat4v3half %uint %uint
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_Inner_std140 = OpTypePointer Uniform %Inner_std140
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+        %136 = OpTypeFunction %v3half %uint %uint %uint
+        %156 = OpConstantNull %v3half
+        %157 = OpTypeFunction %half %uint %uint %uint %uint
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+        %179 = OpConstantNull %half
+       %void = OpTypeVoid
+        %180 = OpTypeFunction %void
+%_ptr_Uniform__arr_Outer_std140_uint_4 = OpTypePointer Uniform %_arr_Outer_std140_uint_4
+%_ptr_Uniform_Outer_std140 = OpTypePointer Uniform %Outer_std140
+%_ptr_Uniform__arr_Inner_std140_uint_4 = OpTypePointer Uniform %_arr_Inner_std140_uint_4
+          %i = OpFunction %int None %16
+         %18 = OpLabel
+         %19 = OpLoad %int %counter
+         %21 = OpIAdd %int %19 %int_1
+               OpStore %counter %21
+         %22 = OpLoad %int %counter
+               OpReturnValue %22
+               OpFunctionEnd
+ %conv_Inner = OpFunction %Inner None %23
+        %val = OpFunctionParameter %Inner_std140
+         %28 = OpLabel
+         %29 = OpCompositeExtract %v3half %val 0
+         %30 = OpCompositeExtract %v3half %val 1
+         %31 = OpCompositeExtract %v3half %val 2
+         %32 = OpCompositeExtract %v3half %val 3
+         %33 = OpCompositeConstruct %mat4v3half %29 %30 %31 %32
+         %34 = OpCompositeConstruct %Inner %33
+               OpReturnValue %34
+               OpFunctionEnd
+%conv_arr4_Inner = OpFunction %_arr_Inner_uint_4 None %35
+      %val_0 = OpFunctionParameter %_arr_Inner_std140_uint_4
+         %39 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_Inner_uint_4 Function %42
+        %i_0 = OpVariable %_ptr_Function_uint Function %45
+%var_for_index_1 = OpVariable %_ptr_Function__arr_Inner_std140_uint_4 Function %58
+               OpBranch %46
+         %46 = OpLabel
+               OpLoopMerge %47 %48 None
+               OpBranch %49
+         %49 = OpLabel
+         %51 = OpLoad %uint %i_0
+         %52 = OpULessThan %bool %51 %uint_4
+         %50 = OpLogicalNot %bool %52
+               OpSelectionMerge %54 None
+               OpBranchConditional %50 %55 %54
+         %55 = OpLabel
+               OpBranch %47
+         %54 = OpLabel
+               OpStore %var_for_index_1 %val_0
+         %59 = OpLoad %uint %i_0
+         %61 = OpAccessChain %_ptr_Function_Inner %arr %59
+         %63 = OpLoad %uint %i_0
+         %65 = OpAccessChain %_ptr_Function_Inner_std140 %var_for_index_1 %63
+         %66 = OpLoad %Inner_std140 %65
+         %62 = OpFunctionCall %Inner %conv_Inner %66
+               OpStore %61 %62
+               OpBranch %48
+         %48 = OpLabel
+         %67 = OpLoad %uint %i_0
+         %69 = OpIAdd %uint %67 %uint_1
+               OpStore %i_0 %69
+               OpBranch %46
+         %47 = OpLabel
+         %70 = OpLoad %_arr_Inner_uint_4 %arr
+               OpReturnValue %70
+               OpFunctionEnd
+ %conv_Outer = OpFunction %Outer None %71
+      %val_1 = OpFunctionParameter %Outer_std140
+         %75 = OpLabel
+         %77 = OpCompositeExtract %_arr_Inner_std140_uint_4 %val_1 0
+         %76 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %77
+         %78 = OpCompositeConstruct %Outer %76
+               OpReturnValue %78
+               OpFunctionEnd
+%conv_arr4_Outer = OpFunction %_arr_Outer_uint_4 None %79
+      %val_2 = OpFunctionParameter %_arr_Outer_std140_uint_4
+         %83 = OpLabel
+      %arr_0 = OpVariable %_ptr_Function__arr_Outer_uint_4 Function %86
+        %i_1 = OpVariable %_ptr_Function_uint Function %45
+%var_for_index = OpVariable %_ptr_Function__arr_Outer_std140_uint_4 Function %99
+               OpBranch %88
+         %88 = OpLabel
+               OpLoopMerge %89 %90 None
+               OpBranch %91
+         %91 = OpLabel
+         %93 = OpLoad %uint %i_1
+         %94 = OpULessThan %bool %93 %uint_4
+         %92 = OpLogicalNot %bool %94
+               OpSelectionMerge %95 None
+               OpBranchConditional %92 %96 %95
+         %96 = OpLabel
+               OpBranch %89
+         %95 = OpLabel
+               OpStore %var_for_index %val_2
+        %100 = OpLoad %uint %i_1
+        %102 = OpAccessChain %_ptr_Function_Outer %arr_0 %100
+        %104 = OpLoad %uint %i_1
+        %106 = OpAccessChain %_ptr_Function_Outer_std140 %var_for_index %104
+        %107 = OpLoad %Outer_std140 %106
+        %103 = OpFunctionCall %Outer %conv_Outer %107
+               OpStore %102 %103
+               OpBranch %90
+         %90 = OpLabel
+        %108 = OpLoad %uint %i_1
+        %109 = OpIAdd %uint %108 %uint_1
+               OpStore %i_1 %109
+               OpBranch %88
+         %89 = OpLabel
+        %110 = OpLoad %_arr_Outer_uint_4 %arr_0
+               OpReturnValue %110
+               OpFunctionEnd
+%load_a_inner_p0_a_p1_m = OpFunction %mat4v3half None %111
+         %p0 = OpFunctionParameter %uint
+         %p1 = OpFunctionParameter %uint
+        %115 = OpLabel
+        %119 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %p0 %uint_0 %p1
+        %122 = OpAccessChain %_ptr_Uniform_v3half %119 %uint_0
+        %123 = OpLoad %v3half %122
+        %125 = OpAccessChain %_ptr_Uniform_v3half %119 %uint_1
+        %126 = OpLoad %v3half %125
+        %129 = OpAccessChain %_ptr_Uniform_v3half %119 %uint_2
+        %130 = OpLoad %v3half %129
+        %133 = OpAccessChain %_ptr_Uniform_v3half %119 %uint_3
+        %134 = OpLoad %v3half %133
+        %135 = OpCompositeConstruct %mat4v3half %123 %126 %130 %134
+               OpReturnValue %135
+               OpFunctionEnd
+%load_a_inner_p0_a_p1_m_p2 = OpFunction %v3half None %136
+       %p0_0 = OpFunctionParameter %uint
+       %p1_0 = OpFunctionParameter %uint
+         %p2 = OpFunctionParameter %uint
+        %141 = OpLabel
+               OpSelectionMerge %142 None
+               OpSwitch %p2 %143 0 %144 1 %145 2 %146 3 %147
+        %144 = OpLabel
+        %148 = OpAccessChain %_ptr_Uniform_v3half %a %uint_0 %p0_0 %uint_0 %p1_0 %uint_0
+        %149 = OpLoad %v3half %148
+               OpReturnValue %149
+        %145 = OpLabel
+        %150 = OpAccessChain %_ptr_Uniform_v3half %a %uint_0 %p0_0 %uint_0 %p1_0 %uint_1
+        %151 = OpLoad %v3half %150
+               OpReturnValue %151
+        %146 = OpLabel
+        %152 = OpAccessChain %_ptr_Uniform_v3half %a %uint_0 %p0_0 %uint_0 %p1_0 %uint_2
+        %153 = OpLoad %v3half %152
+               OpReturnValue %153
+        %147 = OpLabel
+        %154 = OpAccessChain %_ptr_Uniform_v3half %a %uint_0 %p0_0 %uint_0 %p1_0 %uint_3
+        %155 = OpLoad %v3half %154
+               OpReturnValue %155
+        %143 = OpLabel
+               OpReturnValue %156
+        %142 = OpLabel
+               OpReturnValue %156
+               OpFunctionEnd
+%load_a_inner_p0_a_p1_m_p2_p3 = OpFunction %half None %157
+       %p0_1 = OpFunctionParameter %uint
+       %p1_1 = OpFunctionParameter %uint
+       %p2_0 = OpFunctionParameter %uint
+         %p3 = OpFunctionParameter %uint
+        %163 = OpLabel
+               OpSelectionMerge %164 None
+               OpSwitch %p2_0 %165 0 %166 1 %167 2 %168 3 %169
+        %166 = OpLabel
+        %171 = OpAccessChain %_ptr_Uniform_half %a %uint_0 %p0_1 %uint_0 %p1_1 %uint_0 %p3
+        %172 = OpLoad %half %171
+               OpReturnValue %172
+        %167 = OpLabel
+        %173 = OpAccessChain %_ptr_Uniform_half %a %uint_0 %p0_1 %uint_0 %p1_1 %uint_1 %p3
+        %174 = OpLoad %half %173
+               OpReturnValue %174
+        %168 = OpLabel
+        %175 = OpAccessChain %_ptr_Uniform_half %a %uint_0 %p0_1 %uint_0 %p1_1 %uint_2 %p3
+        %176 = OpLoad %half %175
+               OpReturnValue %176
+        %169 = OpLabel
+        %177 = OpAccessChain %_ptr_Uniform_half %a %uint_0 %p0_1 %uint_0 %p1_1 %uint_3 %p3
+        %178 = OpLoad %half %177
+               OpReturnValue %178
+        %165 = OpLabel
+               OpReturnValue %179
+        %164 = OpLabel
+               OpReturnValue %179
+               OpFunctionEnd
+          %f = OpFunction %void None %180
+        %183 = OpLabel
+        %184 = OpFunctionCall %int %i
+        %185 = OpFunctionCall %int %i
+        %186 = OpFunctionCall %int %i
+        %189 = OpAccessChain %_ptr_Uniform__arr_Outer_std140_uint_4 %a %uint_0
+        %190 = OpLoad %_arr_Outer_std140_uint_4 %189
+        %187 = OpFunctionCall %_arr_Outer_uint_4 %conv_arr4_Outer %190
+        %193 = OpAccessChain %_ptr_Uniform_Outer_std140 %a %uint_0 %184
+        %194 = OpLoad %Outer_std140 %193
+        %191 = OpFunctionCall %Outer %conv_Outer %194
+        %197 = OpAccessChain %_ptr_Uniform__arr_Inner_std140_uint_4 %a %uint_0 %184 %uint_0
+        %198 = OpLoad %_arr_Inner_std140_uint_4 %197
+        %195 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %198
+        %200 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %184 %uint_0 %185
+        %201 = OpLoad %Inner_std140 %200
+        %199 = OpFunctionCall %Inner %conv_Inner %201
+        %203 = OpBitcast %uint %184
+        %204 = OpBitcast %uint %185
+        %202 = OpFunctionCall %mat4v3half %load_a_inner_p0_a_p1_m %203 %204
+        %206 = OpBitcast %uint %184
+        %207 = OpBitcast %uint %185
+        %208 = OpBitcast %uint %186
+        %205 = OpFunctionCall %v3half %load_a_inner_p0_a_p1_m_p2 %206 %207 %208
+        %209 = OpFunctionCall %int %i
+        %211 = OpBitcast %uint %184
+        %212 = OpBitcast %uint %185
+        %213 = OpBitcast %uint %186
+        %214 = OpBitcast %uint %209
+        %210 = OpFunctionCall %half %load_a_inner_p0_a_p1_m_p2_p3 %211 %212 %213 %214
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..4ac0990
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,36 @@
+enable f16;
+
+struct Inner {
+  @size(64)
+  m : mat4x3<f16>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_i = &((*(p_a))[i()]);
+  let p_a_i_a = &((*(p_a_i)).a);
+  let p_a_i_a_i = &((*(p_a_i_a))[i()]);
+  let p_a_i_a_i_m = &((*(p_a_i_a_i)).m);
+  let p_a_i_a_i_m_i = &((*(p_a_i_a_i_m))[i()]);
+  let l_a : array<Outer, 4> = *(p_a);
+  let l_a_i : Outer = *(p_a_i);
+  let l_a_i_a : array<Inner, 4> = *(p_a_i_a);
+  let l_a_i_a_i : Inner = *(p_a_i_a_i);
+  let l_a_i_a_i_m : mat4x3<f16> = *(p_a_i_a_i_m);
+  let l_a_i_a_i_m_i : vec3<f16> = *(p_a_i_a_i_m_i);
+  let l_a_i_a_i_m_i_i : f16 = (*(p_a_i_a_i_m_i))[i()];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/static_index_via_ptr.wgsl
new file mode 100644
index 0000000..efd61d8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/static_index_via_ptr.wgsl
@@ -0,0 +1,31 @@
+enable f16;
+
+struct Inner {
+  @size(64)
+  m : mat4x3<f16>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &a;
+  let p_a_3 = &((*p_a)[3]);
+  let p_a_3_a = &((*p_a_3).a);
+  let p_a_3_a_2 = &((*p_a_3_a)[2]);
+  let p_a_3_a_2_m = &((*p_a_3_a_2).m);
+  let p_a_3_a_2_m_1 = &((*p_a_3_a_2_m)[1]);
+
+
+  let l_a             : array<Outer, 4> = *p_a;
+  let l_a_3           : Outer           = *p_a_3;
+  let l_a_3_a         : array<Inner, 4> = *p_a_3_a;
+  let l_a_3_a_2       : Inner           = *p_a_3_a_2;
+  let l_a_3_a_2_m     : mat4x3<f16>     = *p_a_3_a_2_m;
+  let l_a_3_a_2_m_1   : vec3<f16>       = *p_a_3_a_2_m_1;
+  let l_a_3_a_2_m_1_0 : f16             = (*p_a_3_a_2_m_1)[0];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..7397fe3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,81 @@
+struct Inner {
+  matrix<float16_t, 4, 3> m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+
+matrix<float16_t, 4, 3> tint_symbol_4(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+}
+
+Inner tint_symbol_3(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_7 = {tint_symbol_4(buffer, (offset + 0u))};
+  return tint_symbol_7;
+}
+
+typedef Inner tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_3(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_1(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_8 = {tint_symbol_2(buffer, (offset + 0u))};
+  return tint_symbol_8;
+}
+
+typedef Outer tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr_1[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const Outer l_a[4] = tint_symbol(a, 0u);
+  const Outer l_a_3 = tint_symbol_1(a, 768u);
+  const Inner l_a_3_a[4] = tint_symbol_2(a, 768u);
+  const Inner l_a_3_a_2 = tint_symbol_3(a, 896u);
+  const matrix<float16_t, 4, 3> l_a_3_a_2_m = tint_symbol_4(a, 896u);
+  uint2 ubo_load_8 = a[56].zw;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  float16_t ubo_load_8_y = f16tof32(ubo_load_8[0] >> 16);
+  const vector<float16_t, 3> l_a_3_a_2_m_1 = vector<float16_t, 3>(ubo_load_8_xz[0], ubo_load_8_y, ubo_load_8_xz[1]);
+  const float16_t l_a_3_a_2_m_1_0 = float16_t(f16tof32(((a[56].z) & 0xFFFF)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..3cc9dd2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,86 @@
+SKIP: FAILED
+
+struct Inner {
+  matrix<float16_t, 4, 3> m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+
+matrix<float16_t, 4, 3> tint_symbol_4(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+}
+
+Inner tint_symbol_3(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_7 = {tint_symbol_4(buffer, (offset + 0u))};
+  return tint_symbol_7;
+}
+
+typedef Inner tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_3(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_1(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_8 = {tint_symbol_2(buffer, (offset + 0u))};
+  return tint_symbol_8;
+}
+
+typedef Outer tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr_1[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const Outer l_a[4] = tint_symbol(a, 0u);
+  const Outer l_a_3 = tint_symbol_1(a, 768u);
+  const Inner l_a_3_a[4] = tint_symbol_2(a, 768u);
+  const Inner l_a_3_a_2 = tint_symbol_3(a, 896u);
+  const matrix<float16_t, 4, 3> l_a_3_a_2_m = tint_symbol_4(a, 896u);
+  uint2 ubo_load_8 = a[56].zw;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  float16_t ubo_load_8_y = f16tof32(ubo_load_8[0] >> 16);
+  const vector<float16_t, 3> l_a_3_a_2_m_1 = vector<float16_t, 3>(ubo_load_8_xz[0], ubo_load_8_y, ubo_load_8_xz[1]);
+  const float16_t l_a_3_a_2_m_1_0 = float16_t(f16tof32(((a[56].z) & 0xFFFF)));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001CF48DE1160(2,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/static_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..bb6dc3e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/static_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,95 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct Inner {
+  f16mat4x3 m;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+};
+
+struct Inner_std140 {
+  f16vec3 m_0;
+  f16vec3 m_1;
+  f16vec3 m_2;
+  f16vec3 m_3;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+};
+
+struct Outer {
+  Inner a[4];
+};
+
+struct Outer_std140 {
+  Inner_std140 a[4];
+};
+
+layout(binding = 0, std140) uniform a_block_std140_ubo {
+  Outer_std140 inner[4];
+} a;
+
+Inner conv_Inner(Inner_std140 val) {
+  return Inner(f16mat4x3(val.m_0, val.m_1, val.m_2, val.m_3), val.pad, val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7);
+}
+
+Inner[4] conv_arr4_Inner(Inner_std140 val[4]) {
+  Inner arr[4] = Inner[4](Inner(f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_Inner(val[i]);
+    }
+  }
+  return arr;
+}
+
+Outer conv_Outer(Outer_std140 val) {
+  return Outer(conv_arr4_Inner(val.a));
+}
+
+Outer[4] conv_arr4_Outer(Outer_std140 val[4]) {
+  Outer arr[4] = Outer[4](Outer(Inner[4](Inner(f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_Outer(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat4x3 load_a_inner_3_a_2_m() {
+  return f16mat4x3(a.inner[3u].a[2u].m_0, a.inner[3u].a[2u].m_1, a.inner[3u].a[2u].m_2, a.inner[3u].a[2u].m_3);
+}
+
+void f() {
+  Outer p_a[4] = conv_arr4_Outer(a.inner);
+  Outer p_a_3 = conv_Outer(a.inner[3u]);
+  Inner p_a_3_a[4] = conv_arr4_Inner(a.inner[3u].a);
+  Inner p_a_3_a_2 = conv_Inner(a.inner[3u].a[2u]);
+  f16mat4x3 p_a_3_a_2_m = load_a_inner_3_a_2_m();
+  f16vec3 p_a_3_a_2_m_1 = a.inner[3u].a[2u].m_1;
+  Outer l_a[4] = conv_arr4_Outer(a.inner);
+  Outer l_a_3 = conv_Outer(a.inner[3u]);
+  Inner l_a_3_a[4] = conv_arr4_Inner(a.inner[3u].a);
+  Inner l_a_3_a_2 = conv_Inner(a.inner[3u].a[2u]);
+  f16mat4x3 l_a_3_a_2_m = load_a_inner_3_a_2_m();
+  f16vec3 l_a_3_a_2_m_1 = a.inner[3u].a[2u].m_1;
+  float16_t l_a_3_a_2_m_1_0 = a.inner[3u].a[2u].m_1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/static_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..ee0c952
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/static_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,36 @@
+#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 Inner {
+  /* 0x0000 */ half4x3 m;
+  /* 0x0020 */ tint_array<int8_t, 32> tint_pad;
+};
+
+struct Outer {
+  /* 0x0000 */ tint_array<Inner, 4> a;
+};
+
+kernel void f(const constant tint_array<Outer, 4>* tint_symbol [[buffer(0)]]) {
+  tint_array<Outer, 4> const l_a = *(tint_symbol);
+  Outer const l_a_3 = (*(tint_symbol))[3];
+  tint_array<Inner, 4> const l_a_3_a = (*(tint_symbol))[3].a;
+  Inner const l_a_3_a_2 = (*(tint_symbol))[3].a[2];
+  half4x3 const l_a_3_a_2_m = (*(tint_symbol))[3].a[2].m;
+  half3 const l_a_3_a_2_m_1 = (*(tint_symbol))[3].a[2].m[1];
+  half const l_a_3_a_2_m_1_0 = (*(tint_symbol))[3].a[2].m[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/static_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..507f1c0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/static_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,237 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 148
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block_std140 "a_block_std140"
+               OpMemberName %a_block_std140 0 "inner"
+               OpName %Outer_std140 "Outer_std140"
+               OpMemberName %Outer_std140 0 "a"
+               OpName %Inner_std140 "Inner_std140"
+               OpMemberName %Inner_std140 0 "m_0"
+               OpMemberName %Inner_std140 1 "m_1"
+               OpMemberName %Inner_std140 2 "m_2"
+               OpMemberName %Inner_std140 3 "m_3"
+               OpName %a "a"
+               OpName %Inner "Inner"
+               OpMemberName %Inner 0 "m"
+               OpName %conv_Inner "conv_Inner"
+               OpName %val "val"
+               OpName %conv_arr4_Inner "conv_arr4_Inner"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index_1 "var_for_index_1"
+               OpName %Outer "Outer"
+               OpMemberName %Outer 0 "a"
+               OpName %conv_Outer "conv_Outer"
+               OpName %val_1 "val"
+               OpName %conv_arr4_Outer "conv_arr4_Outer"
+               OpName %val_2 "val"
+               OpName %arr_0 "arr"
+               OpName %i_0 "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_a_inner_3_a_2_m "load_a_inner_3_a_2_m"
+               OpName %f "f"
+               OpDecorate %a_block_std140 Block
+               OpMemberDecorate %a_block_std140 0 Offset 0
+               OpMemberDecorate %Outer_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 1 Offset 8
+               OpMemberDecorate %Inner_std140 2 Offset 16
+               OpMemberDecorate %Inner_std140 3 Offset 24
+               OpDecorate %_arr_Inner_std140_uint_4 ArrayStride 64
+               OpDecorate %_arr_Outer_std140_uint_4 ArrayStride 256
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+               OpMemberDecorate %Inner 0 Offset 0
+               OpMemberDecorate %Inner 0 ColMajor
+               OpMemberDecorate %Inner 0 MatrixStride 8
+               OpDecorate %_arr_Inner_uint_4 ArrayStride 64
+               OpMemberDecorate %Outer 0 Offset 0
+               OpDecorate %_arr_Outer_uint_4 ArrayStride 256
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+%Inner_std140 = OpTypeStruct %v3half %v3half %v3half %v3half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_Inner_std140_uint_4 = OpTypeArray %Inner_std140 %uint_4
+%Outer_std140 = OpTypeStruct %_arr_Inner_std140_uint_4
+%_arr_Outer_std140_uint_4 = OpTypeArray %Outer_std140 %uint_4
+%a_block_std140 = OpTypeStruct %_arr_Outer_std140_uint_4
+%_ptr_Uniform_a_block_std140 = OpTypePointer Uniform %a_block_std140
+          %a = OpVariable %_ptr_Uniform_a_block_std140 Uniform
+ %mat4v3half = OpTypeMatrix %v3half 4
+      %Inner = OpTypeStruct %mat4v3half
+         %12 = OpTypeFunction %Inner %Inner_std140
+%_arr_Inner_uint_4 = OpTypeArray %Inner %uint_4
+         %24 = OpTypeFunction %_arr_Inner_uint_4 %_arr_Inner_std140_uint_4
+%_ptr_Function__arr_Inner_uint_4 = OpTypePointer Function %_arr_Inner_uint_4
+         %31 = OpConstantNull %_arr_Inner_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %34 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_Inner_std140_uint_4 = OpTypePointer Function %_arr_Inner_std140_uint_4
+         %47 = OpConstantNull %_arr_Inner_std140_uint_4
+%_ptr_Function_Inner = OpTypePointer Function %Inner
+%_ptr_Function_Inner_std140 = OpTypePointer Function %Inner_std140
+     %uint_1 = OpConstant %uint 1
+      %Outer = OpTypeStruct %_arr_Inner_uint_4
+         %60 = OpTypeFunction %Outer %Outer_std140
+%_arr_Outer_uint_4 = OpTypeArray %Outer %uint_4
+         %68 = OpTypeFunction %_arr_Outer_uint_4 %_arr_Outer_std140_uint_4
+%_ptr_Function__arr_Outer_uint_4 = OpTypePointer Function %_arr_Outer_uint_4
+         %75 = OpConstantNull %_arr_Outer_uint_4
+%_ptr_Function__arr_Outer_std140_uint_4 = OpTypePointer Function %_arr_Outer_std140_uint_4
+         %88 = OpConstantNull %_arr_Outer_std140_uint_4
+%_ptr_Function_Outer = OpTypePointer Function %Outer
+%_ptr_Function_Outer_std140 = OpTypePointer Function %Outer_std140
+        %100 = OpTypeFunction %mat4v3half
+     %uint_0 = OpConstant %uint 0
+     %uint_3 = OpConstant %uint 3
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_Inner_std140 = OpTypePointer Uniform %Inner_std140
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+       %void = OpTypeVoid
+        %123 = OpTypeFunction %void
+%_ptr_Uniform__arr_Outer_std140_uint_4 = OpTypePointer Uniform %_arr_Outer_std140_uint_4
+%_ptr_Uniform_Outer_std140 = OpTypePointer Uniform %Outer_std140
+%_ptr_Uniform__arr_Inner_std140_uint_4 = OpTypePointer Uniform %_arr_Inner_std140_uint_4
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+ %conv_Inner = OpFunction %Inner None %12
+        %val = OpFunctionParameter %Inner_std140
+         %17 = OpLabel
+         %18 = OpCompositeExtract %v3half %val 0
+         %19 = OpCompositeExtract %v3half %val 1
+         %20 = OpCompositeExtract %v3half %val 2
+         %21 = OpCompositeExtract %v3half %val 3
+         %22 = OpCompositeConstruct %mat4v3half %18 %19 %20 %21
+         %23 = OpCompositeConstruct %Inner %22
+               OpReturnValue %23
+               OpFunctionEnd
+%conv_arr4_Inner = OpFunction %_arr_Inner_uint_4 None %24
+      %val_0 = OpFunctionParameter %_arr_Inner_std140_uint_4
+         %28 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_Inner_uint_4 Function %31
+          %i = OpVariable %_ptr_Function_uint Function %34
+%var_for_index_1 = OpVariable %_ptr_Function__arr_Inner_std140_uint_4 Function %47
+               OpBranch %35
+         %35 = OpLabel
+               OpLoopMerge %36 %37 None
+               OpBranch %38
+         %38 = OpLabel
+         %40 = OpLoad %uint %i
+         %41 = OpULessThan %bool %40 %uint_4
+         %39 = OpLogicalNot %bool %41
+               OpSelectionMerge %43 None
+               OpBranchConditional %39 %44 %43
+         %44 = OpLabel
+               OpBranch %36
+         %43 = OpLabel
+               OpStore %var_for_index_1 %val_0
+         %48 = OpLoad %uint %i
+         %50 = OpAccessChain %_ptr_Function_Inner %arr %48
+         %52 = OpLoad %uint %i
+         %54 = OpAccessChain %_ptr_Function_Inner_std140 %var_for_index_1 %52
+         %55 = OpLoad %Inner_std140 %54
+         %51 = OpFunctionCall %Inner %conv_Inner %55
+               OpStore %50 %51
+               OpBranch %37
+         %37 = OpLabel
+         %56 = OpLoad %uint %i
+         %58 = OpIAdd %uint %56 %uint_1
+               OpStore %i %58
+               OpBranch %35
+         %36 = OpLabel
+         %59 = OpLoad %_arr_Inner_uint_4 %arr
+               OpReturnValue %59
+               OpFunctionEnd
+ %conv_Outer = OpFunction %Outer None %60
+      %val_1 = OpFunctionParameter %Outer_std140
+         %64 = OpLabel
+         %66 = OpCompositeExtract %_arr_Inner_std140_uint_4 %val_1 0
+         %65 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %66
+         %67 = OpCompositeConstruct %Outer %65
+               OpReturnValue %67
+               OpFunctionEnd
+%conv_arr4_Outer = OpFunction %_arr_Outer_uint_4 None %68
+      %val_2 = OpFunctionParameter %_arr_Outer_std140_uint_4
+         %72 = OpLabel
+      %arr_0 = OpVariable %_ptr_Function__arr_Outer_uint_4 Function %75
+        %i_0 = OpVariable %_ptr_Function_uint Function %34
+%var_for_index = OpVariable %_ptr_Function__arr_Outer_std140_uint_4 Function %88
+               OpBranch %77
+         %77 = OpLabel
+               OpLoopMerge %78 %79 None
+               OpBranch %80
+         %80 = OpLabel
+         %82 = OpLoad %uint %i_0
+         %83 = OpULessThan %bool %82 %uint_4
+         %81 = OpLogicalNot %bool %83
+               OpSelectionMerge %84 None
+               OpBranchConditional %81 %85 %84
+         %85 = OpLabel
+               OpBranch %78
+         %84 = OpLabel
+               OpStore %var_for_index %val_2
+         %89 = OpLoad %uint %i_0
+         %91 = OpAccessChain %_ptr_Function_Outer %arr_0 %89
+         %93 = OpLoad %uint %i_0
+         %95 = OpAccessChain %_ptr_Function_Outer_std140 %var_for_index %93
+         %96 = OpLoad %Outer_std140 %95
+         %92 = OpFunctionCall %Outer %conv_Outer %96
+               OpStore %91 %92
+               OpBranch %79
+         %79 = OpLabel
+         %97 = OpLoad %uint %i_0
+         %98 = OpIAdd %uint %97 %uint_1
+               OpStore %i_0 %98
+               OpBranch %77
+         %78 = OpLabel
+         %99 = OpLoad %_arr_Outer_uint_4 %arr_0
+               OpReturnValue %99
+               OpFunctionEnd
+%load_a_inner_3_a_2_m = OpFunction %mat4v3half None %100
+        %102 = OpLabel
+        %108 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %uint_3 %uint_0 %uint_2
+        %111 = OpAccessChain %_ptr_Uniform_v3half %108 %uint_0
+        %112 = OpLoad %v3half %111
+        %114 = OpAccessChain %_ptr_Uniform_v3half %108 %uint_1
+        %115 = OpLoad %v3half %114
+        %117 = OpAccessChain %_ptr_Uniform_v3half %108 %uint_2
+        %118 = OpLoad %v3half %117
+        %120 = OpAccessChain %_ptr_Uniform_v3half %108 %uint_3
+        %121 = OpLoad %v3half %120
+        %122 = OpCompositeConstruct %mat4v3half %112 %115 %118 %121
+               OpReturnValue %122
+               OpFunctionEnd
+          %f = OpFunction %void None %123
+        %126 = OpLabel
+        %129 = OpAccessChain %_ptr_Uniform__arr_Outer_std140_uint_4 %a %uint_0
+        %130 = OpLoad %_arr_Outer_std140_uint_4 %129
+        %127 = OpFunctionCall %_arr_Outer_uint_4 %conv_arr4_Outer %130
+        %133 = OpAccessChain %_ptr_Uniform_Outer_std140 %a %uint_0 %uint_3
+        %134 = OpLoad %Outer_std140 %133
+        %131 = OpFunctionCall %Outer %conv_Outer %134
+        %137 = OpAccessChain %_ptr_Uniform__arr_Inner_std140_uint_4 %a %uint_0 %uint_3 %uint_0
+        %138 = OpLoad %_arr_Inner_std140_uint_4 %137
+        %135 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %138
+        %140 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %uint_3 %uint_0 %uint_2
+        %141 = OpLoad %Inner_std140 %140
+        %139 = OpFunctionCall %Inner %conv_Inner %141
+        %142 = OpFunctionCall %mat4v3half %load_a_inner_3_a_2_m
+        %143 = OpAccessChain %_ptr_Uniform_v3half %a %uint_0 %uint_3 %uint_0 %uint_2 %uint_1
+        %144 = OpLoad %v3half %143
+        %146 = OpAccessChain %_ptr_Uniform_half %a %uint_0 %uint_3 %uint_0 %uint_2 %uint_1 %34
+        %147 = OpLoad %half %146
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/static_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..059ae45
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/static_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,29 @@
+enable f16;
+
+struct Inner {
+  @size(64)
+  m : mat4x3<f16>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_3 = &((*(p_a))[3]);
+  let p_a_3_a = &((*(p_a_3)).a);
+  let p_a_3_a_2 = &((*(p_a_3_a))[2]);
+  let p_a_3_a_2_m = &((*(p_a_3_a_2)).m);
+  let p_a_3_a_2_m_1 = &((*(p_a_3_a_2_m))[1]);
+  let l_a : array<Outer, 4> = *(p_a);
+  let l_a_3 : Outer = *(p_a_3);
+  let l_a_3_a : array<Inner, 4> = *(p_a_3_a);
+  let l_a_3_a_2 : Inner = *(p_a_3_a_2);
+  let l_a_3_a_2_m : mat4x3<f16> = *(p_a_3_a_2_m);
+  let l_a_3_a_2_m_1 : vec3<f16> = *(p_a_3_a_2_m_1);
+  let l_a_3_a_2_m_1_0 : f16 = (*(p_a_3_a_2_m_1))[0];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_builtin.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_builtin.wgsl
new file mode 100644
index 0000000..6bde739
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_builtin.wgsl
@@ -0,0 +1,17 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat4x3<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    let t = transpose(u[2].m);
+    let l = length(u[0].m[1].zxy);
+    let a = abs(u[0].m[1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_builtin.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..3123f10
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_builtin.wgsl.expected.dxc.hlsl
@@ -0,0 +1,41 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+matrix<float16_t, 4, 3> tint_symbol(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 3, 4> t = transpose(tint_symbol(u, 264u));
+  uint2 ubo_load_8 = u[1].xy;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  float16_t ubo_load_8_y = f16tof32(ubo_load_8[0] >> 16);
+  const float16_t l = length(vector<float16_t, 3>(ubo_load_8_xz[0], ubo_load_8_y, ubo_load_8_xz[1]).zxy);
+  uint2 ubo_load_9 = u[1].xy;
+  vector<float16_t, 2> ubo_load_9_xz = vector<float16_t, 2>(f16tof32(ubo_load_9 & 0xFFFF));
+  float16_t ubo_load_9_y = f16tof32(ubo_load_9[0] >> 16);
+  const float16_t a = abs(vector<float16_t, 3>(ubo_load_9_xz[0], ubo_load_9_y, ubo_load_9_xz[1]).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_builtin.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..1f18e46
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_builtin.wgsl.expected.fxc.hlsl
@@ -0,0 +1,46 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+matrix<float16_t, 4, 3> tint_symbol(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 3, 4> t = transpose(tint_symbol(u, 264u));
+  uint2 ubo_load_8 = u[1].xy;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  float16_t ubo_load_8_y = f16tof32(ubo_load_8[0] >> 16);
+  const float16_t l = length(vector<float16_t, 3>(ubo_load_8_xz[0], ubo_load_8_y, ubo_load_8_xz[1]).zxy);
+  uint2 ubo_load_9 = u[1].xy;
+  vector<float16_t, 2> ubo_load_9_xz = vector<float16_t, 2>(f16tof32(ubo_load_9 & 0xFFFF));
+  float16_t ubo_load_9_y = f16tof32(ubo_load_9[0] >> 16);
+  const float16_t a = abs(vector<float16_t, 3>(ubo_load_9_xz[0], ubo_load_9_y, ubo_load_9_xz[1]).zxy.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000023590C3D7E0(5,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_builtin.wgsl.expected.glsl
new file mode 100644
index 0000000..e8870bc
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_builtin.wgsl.expected.glsl
@@ -0,0 +1,81 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct S {
+  int before;
+  uint pad;
+  f16mat4x3 m;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  int after;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+};
+
+struct S_std140 {
+  int before;
+  uint pad;
+  f16vec3 m_0;
+  f16vec3 m_1;
+  f16vec3 m_2;
+  f16vec3 m_3;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  int after;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+f16mat4x3 load_u_inner_2_m() {
+  return f16mat4x3(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2, u.inner[2u].m_3);
+}
+
+void f() {
+  f16mat3x4 t = transpose(load_u_inner_2_m());
+  float16_t l = length(u.inner[0u].m_1.zxy);
+  float16_t a = abs(u.inner[0u].m_1.zxy[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_builtin.wgsl.expected.msl
new file mode 100644
index 0000000..3a831cd
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_builtin.wgsl.expected.msl
@@ -0,0 +1,32 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0008 */ half4x3 m;
+  /* 0x0028 */ tint_array<int8_t, 24> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol [[buffer(0)]]) {
+  half3x4 const t = transpose((*(tint_symbol))[2].m);
+  half const l = length(half3((*(tint_symbol))[0].m[1]).zxy);
+  half const a = fabs(half3((*(tint_symbol))[0].m[1]).zxy[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_builtin.wgsl.expected.spvasm
new file mode 100644
index 0000000..a5700e9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_builtin.wgsl.expected.spvasm
@@ -0,0 +1,90 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 55
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+         %45 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "m_2"
+               OpMemberName %S_std140 4 "m_3"
+               OpMemberName %S_std140 5 "after"
+               OpName %u "u"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 8
+               OpMemberDecorate %S_std140 2 Offset 16
+               OpMemberDecorate %S_std140 3 Offset 24
+               OpMemberDecorate %S_std140 4 Offset 32
+               OpMemberDecorate %S_std140 5 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+   %S_std140 = OpTypeStruct %int %v3half %v3half %v3half %v3half %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat4v3half = OpTypeMatrix %v3half 4
+         %11 = OpTypeFunction %mat4v3half
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+     %uint_1 = OpConstant %uint 1
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %36 = OpTypeFunction %void
+     %v4half = OpTypeVector %half 4
+ %mat3v4half = OpTypeMatrix %v4half 3
+         %46 = OpConstantNull %uint
+%load_u_inner_2_m = OpFunction %mat4v3half None %11
+         %14 = OpLabel
+         %19 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %23 = OpAccessChain %_ptr_Uniform_v3half %19 %uint_1
+         %24 = OpLoad %v3half %23
+         %26 = OpAccessChain %_ptr_Uniform_v3half %19 %uint_2
+         %27 = OpLoad %v3half %26
+         %30 = OpAccessChain %_ptr_Uniform_v3half %19 %uint_3
+         %31 = OpLoad %v3half %30
+         %33 = OpAccessChain %_ptr_Uniform_v3half %19 %uint_4
+         %34 = OpLoad %v3half %33
+         %35 = OpCompositeConstruct %mat4v3half %24 %27 %31 %34
+               OpReturnValue %35
+               OpFunctionEnd
+          %f = OpFunction %void None %36
+         %39 = OpLabel
+         %43 = OpFunctionCall %mat4v3half %load_u_inner_2_m
+         %40 = OpTranspose %mat3v4half %43
+         %47 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0 %46 %uint_2
+         %48 = OpLoad %v3half %47
+         %49 = OpVectorShuffle %v3half %48 %48 2 0 1
+         %44 = OpExtInst %half %45 Length %49
+         %51 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0 %46 %uint_2
+         %52 = OpLoad %v3half %51
+         %53 = OpVectorShuffle %v3half %52 %52 2 0 1
+         %54 = OpCompositeExtract %half %53 0
+         %50 = OpExtInst %half %45 FAbs %54
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_builtin.wgsl.expected.wgsl
new file mode 100644
index 0000000..6bd1807
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_builtin.wgsl.expected.wgsl
@@ -0,0 +1,17 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat4x3<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let t = transpose(u[2].m);
+  let l = length(u[0].m[1].zxy);
+  let a = abs(u[0].m[1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_fn.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_fn.wgsl
new file mode 100644
index 0000000..ab15ad4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_fn.wgsl
@@ -0,0 +1,25 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat4x3<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+fn a(a : array<S, 4>) {}
+fn b(s : S) {}
+fn c(m : mat4x3<f16>) {}
+fn d(v : vec3<f16>) {}
+fn e(f : f16) {}
+
+@compute @workgroup_size(1)
+fn f() {
+    a(u);
+    b(u[2]);
+    c(u[2].m);
+    d(u[0].m[1].zxy);
+    e(u[0].m[1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_fn.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..ef7574b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_fn.wgsl.expected.dxc.hlsl
@@ -0,0 +1,82 @@
+struct S {
+  int before;
+  matrix<float16_t, 4, 3> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(matrix<float16_t, 4, 3> m) {
+}
+
+void d(vector<float16_t, 3> v) {
+}
+
+void e(float16_t f_1) {
+}
+
+matrix<float16_t, 4, 3> tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 256u));
+  c(tint_symbol_3(u, 264u));
+  uint2 ubo_load_8 = u[1].xy;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  float16_t ubo_load_8_y = f16tof32(ubo_load_8[0] >> 16);
+  d(vector<float16_t, 3>(ubo_load_8_xz[0], ubo_load_8_y, ubo_load_8_xz[1]).zxy);
+  uint2 ubo_load_9 = u[1].xy;
+  vector<float16_t, 2> ubo_load_9_xz = vector<float16_t, 2>(f16tof32(ubo_load_9 & 0xFFFF));
+  float16_t ubo_load_9_y = f16tof32(ubo_load_9[0] >> 16);
+  e(vector<float16_t, 3>(ubo_load_9_xz[0], ubo_load_9_y, ubo_load_9_xz[1]).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_fn.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..ca1bbc5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_fn.wgsl.expected.fxc.hlsl
@@ -0,0 +1,87 @@
+SKIP: FAILED
+
+struct S {
+  int before;
+  matrix<float16_t, 4, 3> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(matrix<float16_t, 4, 3> m) {
+}
+
+void d(vector<float16_t, 3> v) {
+}
+
+void e(float16_t f_1) {
+}
+
+matrix<float16_t, 4, 3> tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 256u));
+  c(tint_symbol_3(u, 264u));
+  uint2 ubo_load_8 = u[1].xy;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  float16_t ubo_load_8_y = f16tof32(ubo_load_8[0] >> 16);
+  d(vector<float16_t, 3>(ubo_load_8_xz[0], ubo_load_8_y, ubo_load_8_xz[1]).zxy);
+  uint2 ubo_load_9 = u[1].xy;
+  vector<float16_t, 2> ubo_load_9_xz = vector<float16_t, 2>(f16tof32(ubo_load_9 & 0xFFFF));
+  float16_t ubo_load_9_y = f16tof32(ubo_load_9[0] >> 16);
+  e(vector<float16_t, 3>(ubo_load_9_xz[0], ubo_load_9_y, ubo_load_9_xz[1]).zxy.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001FF77F70B40(3,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_fn.wgsl.expected.glsl
new file mode 100644
index 0000000..bb2bc12
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_fn.wgsl.expected.glsl
@@ -0,0 +1,112 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct S {
+  int before;
+  uint pad;
+  f16mat4x3 m;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  int after;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+};
+
+struct S_std140 {
+  int before;
+  uint pad;
+  f16vec3 m_0;
+  f16vec3 m_1;
+  f16vec3 m_2;
+  f16vec3 m_3;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  int after;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(f16mat4x3 m) {
+}
+
+void d(f16vec3 v) {
+}
+
+void e(float16_t f_1) {
+}
+
+S conv_S(S_std140 val) {
+  return S(val.before, val.pad, f16mat4x3(val.m_0, val.m_1, val.m_2, val.m_3), val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.after, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.pad_11, val.pad_12, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, 0u, f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat4x3 load_u_inner_2_m() {
+  return f16mat4x3(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2, u.inner[2u].m_3);
+}
+
+void f() {
+  a(conv_arr4_S(u.inner));
+  b(conv_S(u.inner[2u]));
+  c(load_u_inner_2_m());
+  d(u.inner[0u].m_1.zxy);
+  e(u.inner[0u].m_1.zxy[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_fn.wgsl.expected.msl
new file mode 100644
index 0000000..821e522
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_fn.wgsl.expected.msl
@@ -0,0 +1,49 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0008 */ half4x3 m;
+  /* 0x0028 */ tint_array<int8_t, 24> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+void a(tint_array<S, 4> a_1) {
+}
+
+void b(S s) {
+}
+
+void c(half4x3 m) {
+}
+
+void d(half3 v) {
+}
+
+void e(half f_1) {
+}
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol [[buffer(0)]]) {
+  a(*(tint_symbol));
+  b((*(tint_symbol))[2]);
+  c((*(tint_symbol))[2].m);
+  d(half3((*(tint_symbol))[0].m[1]).zxy);
+  e(half3((*(tint_symbol))[0].m[1]).zxy[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_fn.wgsl.expected.spvasm
new file mode 100644
index 0000000..610fee7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_fn.wgsl.expected.spvasm
@@ -0,0 +1,215 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 128
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "m_2"
+               OpMemberName %S_std140 4 "m_3"
+               OpMemberName %S_std140 5 "after"
+               OpName %u "u"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %a "a"
+               OpName %a_1 "a_1"
+               OpName %b "b"
+               OpName %s "s"
+               OpName %c "c"
+               OpName %m "m"
+               OpName %d "d"
+               OpName %v "v"
+               OpName %e "e"
+               OpName %f_1 "f_1"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 8
+               OpMemberDecorate %S_std140 2 Offset 16
+               OpMemberDecorate %S_std140 3 Offset 24
+               OpMemberDecorate %S_std140 4 Offset 32
+               OpMemberDecorate %S_std140 5 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 8
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 8
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+   %S_std140 = OpTypeStruct %int %v3half %v3half %v3half %v3half %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+       %void = OpTypeVoid
+ %mat4v3half = OpTypeMatrix %v3half 4
+          %S = OpTypeStruct %int %mat4v3half %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+         %11 = OpTypeFunction %void %_arr_S_uint_4
+         %19 = OpTypeFunction %void %S
+         %23 = OpTypeFunction %void %mat4v3half
+         %27 = OpTypeFunction %void %v3half
+         %31 = OpTypeFunction %void %half
+         %35 = OpTypeFunction %S %S_std140
+         %47 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+         %53 = OpConstantNull %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %56 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %69 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %82 = OpTypeFunction %mat4v3half
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+     %uint_3 = OpConstant %uint 3
+        %105 = OpTypeFunction %void
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+          %a = OpFunction %void None %11
+        %a_1 = OpFunctionParameter %_arr_S_uint_4
+         %18 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %b = OpFunction %void None %19
+          %s = OpFunctionParameter %S
+         %22 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %c = OpFunction %void None %23
+          %m = OpFunctionParameter %mat4v3half
+         %26 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %d = OpFunction %void None %27
+          %v = OpFunctionParameter %v3half
+         %30 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %e = OpFunction %void None %31
+        %f_1 = OpFunctionParameter %half
+         %34 = OpLabel
+               OpReturn
+               OpFunctionEnd
+     %conv_S = OpFunction %S None %35
+        %val = OpFunctionParameter %S_std140
+         %38 = OpLabel
+         %39 = OpCompositeExtract %int %val 0
+         %40 = OpCompositeExtract %v3half %val 1
+         %41 = OpCompositeExtract %v3half %val 2
+         %42 = OpCompositeExtract %v3half %val 3
+         %43 = OpCompositeExtract %v3half %val 4
+         %44 = OpCompositeConstruct %mat4v3half %40 %41 %42 %43
+         %45 = OpCompositeExtract %int %val 5
+         %46 = OpCompositeConstruct %S %39 %44 %45
+               OpReturnValue %46
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %47
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %50 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %53
+          %i = OpVariable %_ptr_Function_uint Function %56
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %69
+               OpBranch %57
+         %57 = OpLabel
+               OpLoopMerge %58 %59 None
+               OpBranch %60
+         %60 = OpLabel
+         %62 = OpLoad %uint %i
+         %63 = OpULessThan %bool %62 %uint_4
+         %61 = OpLogicalNot %bool %63
+               OpSelectionMerge %65 None
+               OpBranchConditional %61 %66 %65
+         %66 = OpLabel
+               OpBranch %58
+         %65 = OpLabel
+               OpStore %var_for_index %val_0
+         %70 = OpLoad %uint %i
+         %72 = OpAccessChain %_ptr_Function_S %arr %70
+         %74 = OpLoad %uint %i
+         %76 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %74
+         %77 = OpLoad %S_std140 %76
+         %73 = OpFunctionCall %S %conv_S %77
+               OpStore %72 %73
+               OpBranch %59
+         %59 = OpLabel
+         %78 = OpLoad %uint %i
+         %80 = OpIAdd %uint %78 %uint_1
+               OpStore %i %80
+               OpBranch %57
+         %58 = OpLabel
+         %81 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %81
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat4v3half None %82
+         %84 = OpLabel
+         %89 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %92 = OpAccessChain %_ptr_Uniform_v3half %89 %uint_1
+         %93 = OpLoad %v3half %92
+         %95 = OpAccessChain %_ptr_Uniform_v3half %89 %uint_2
+         %96 = OpLoad %v3half %95
+         %99 = OpAccessChain %_ptr_Uniform_v3half %89 %uint_3
+        %100 = OpLoad %v3half %99
+        %102 = OpAccessChain %_ptr_Uniform_v3half %89 %uint_4
+        %103 = OpLoad %v3half %102
+        %104 = OpCompositeConstruct %mat4v3half %93 %96 %100 %103
+               OpReturnValue %104
+               OpFunctionEnd
+          %f = OpFunction %void None %105
+        %107 = OpLabel
+        %111 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+        %112 = OpLoad %_arr_S_std140_uint_4 %111
+        %109 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %112
+        %108 = OpFunctionCall %void %a %109
+        %115 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+        %116 = OpLoad %S_std140 %115
+        %114 = OpFunctionCall %S %conv_S %116
+        %113 = OpFunctionCall %void %b %114
+        %118 = OpFunctionCall %mat4v3half %load_u_inner_2_m
+        %117 = OpFunctionCall %void %c %118
+        %120 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0 %56 %uint_2
+        %121 = OpLoad %v3half %120
+        %122 = OpVectorShuffle %v3half %121 %121 2 0 1
+        %119 = OpFunctionCall %void %d %122
+        %124 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0 %56 %uint_2
+        %125 = OpLoad %v3half %124
+        %126 = OpVectorShuffle %v3half %125 %125 2 0 1
+        %127 = OpCompositeExtract %half %126 0
+        %123 = OpFunctionCall %void %e %127
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_fn.wgsl.expected.wgsl
new file mode 100644
index 0000000..a78087f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_fn.wgsl.expected.wgsl
@@ -0,0 +1,34 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat4x3<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+fn a(a : array<S, 4>) {
+}
+
+fn b(s : S) {
+}
+
+fn c(m : mat4x3<f16>) {
+}
+
+fn d(v : vec3<f16>) {
+}
+
+fn e(f : f16) {
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  a(u);
+  b(u[2]);
+  c(u[2].m);
+  d(u[0].m[1].zxy);
+  e(u[0].m[1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_private.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_private.wgsl
new file mode 100644
index 0000000..08f8f23
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_private.wgsl
@@ -0,0 +1,19 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat4x3<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+var<private> p : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[2];
+    p[3].m = u[2].m;
+    p[1].m[0] = u[0].m[1].zxy;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_private.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..d2aacee
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_private.wgsl.expected.dxc.hlsl
@@ -0,0 +1,64 @@
+struct S {
+  int before;
+  matrix<float16_t, 4, 3> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+static S p[4] = (S[4])0;
+
+matrix<float16_t, 4, 3> tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 256u);
+  p[3].m = tint_symbol_3(u, 264u);
+  uint2 ubo_load_8 = u[1].xy;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  float16_t ubo_load_8_y = f16tof32(ubo_load_8[0] >> 16);
+  p[1].m[0] = vector<float16_t, 3>(ubo_load_8_xz[0], ubo_load_8_y, ubo_load_8_xz[1]).zxy;
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_private.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..966dd5f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_private.wgsl.expected.fxc.hlsl
@@ -0,0 +1,69 @@
+SKIP: FAILED
+
+struct S {
+  int before;
+  matrix<float16_t, 4, 3> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+static S p[4] = (S[4])0;
+
+matrix<float16_t, 4, 3> tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 256u);
+  p[3].m = tint_symbol_3(u, 264u);
+  uint2 ubo_load_8 = u[1].xy;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  float16_t ubo_load_8_y = f16tof32(ubo_load_8[0] >> 16);
+  p[1].m[0] = vector<float16_t, 3>(ubo_load_8_xz[0], ubo_load_8_y, ubo_load_8_xz[1]).zxy;
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000019CC8F77C00(3,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..747a2c5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_private.wgsl.expected.glsl
@@ -0,0 +1,97 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct S {
+  int before;
+  uint pad;
+  f16mat4x3 m;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  int after;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+};
+
+struct S_std140 {
+  int before;
+  uint pad;
+  f16vec3 m_0;
+  f16vec3 m_1;
+  f16vec3 m_2;
+  f16vec3 m_3;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  int after;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+S p[4] = S[4](S(0, 0u, f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+S conv_S(S_std140 val) {
+  return S(val.before, val.pad, f16mat4x3(val.m_0, val.m_1, val.m_2, val.m_3), val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.after, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.pad_11, val.pad_12, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, 0u, f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat4x3 load_u_inner_2_m() {
+  return f16mat4x3(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2, u.inner[2u].m_3);
+}
+
+void f() {
+  p = conv_arr4_S(u.inner);
+  p[1] = conv_S(u.inner[2u]);
+  p[3].m = load_u_inner_2_m();
+  p[1].m[0] = u.inner[0u].m_1.zxy;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..175ed33
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_private.wgsl.expected.msl
@@ -0,0 +1,34 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0008 */ half4x3 m;
+  /* 0x0028 */ tint_array<int8_t, 24> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol_1 [[buffer(0)]]) {
+  thread tint_array<S, 4> tint_symbol = {};
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[2];
+  tint_symbol[3].m = (*(tint_symbol_1))[2].m;
+  tint_symbol[1].m[0] = half3((*(tint_symbol_1))[0].m[1]).zxy;
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_private.wgsl.expected.spvasm
new file mode 100644
index 0000000..1a8461b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_private.wgsl.expected.spvasm
@@ -0,0 +1,182 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 110
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "m_2"
+               OpMemberName %S_std140 4 "m_3"
+               OpMemberName %S_std140 5 "after"
+               OpName %u "u"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %p "p"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 8
+               OpMemberDecorate %S_std140 2 Offset 16
+               OpMemberDecorate %S_std140 3 Offset 24
+               OpMemberDecorate %S_std140 4 Offset 32
+               OpMemberDecorate %S_std140 5 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 8
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 8
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+   %S_std140 = OpTypeStruct %int %v3half %v3half %v3half %v3half %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat4v3half = OpTypeMatrix %v3half 4
+          %S = OpTypeStruct %int %mat4v3half %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+%_ptr_Private__arr_S_uint_4 = OpTypePointer Private %_arr_S_uint_4
+         %16 = OpConstantNull %_arr_S_uint_4
+          %p = OpVariable %_ptr_Private__arr_S_uint_4 Private %16
+         %17 = OpTypeFunction %S %S_std140
+         %29 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %37 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %50 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %63 = OpTypeFunction %mat4v3half
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %86 = OpTypeFunction %void
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+      %int_1 = OpConstant %int 1
+%_ptr_Private_S = OpTypePointer Private %S
+      %int_3 = OpConstant %int 3
+%_ptr_Private_mat4v3half = OpTypePointer Private %mat4v3half
+        %104 = OpConstantNull %int
+%_ptr_Private_v3half = OpTypePointer Private %v3half
+     %conv_S = OpFunction %S None %17
+        %val = OpFunctionParameter %S_std140
+         %20 = OpLabel
+         %21 = OpCompositeExtract %int %val 0
+         %22 = OpCompositeExtract %v3half %val 1
+         %23 = OpCompositeExtract %v3half %val 2
+         %24 = OpCompositeExtract %v3half %val 3
+         %25 = OpCompositeExtract %v3half %val 4
+         %26 = OpCompositeConstruct %mat4v3half %22 %23 %24 %25
+         %27 = OpCompositeExtract %int %val 5
+         %28 = OpCompositeConstruct %S %21 %26 %27
+               OpReturnValue %28
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %29
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %32 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %16
+          %i = OpVariable %_ptr_Function_uint Function %37
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %50
+               OpBranch %38
+         %38 = OpLabel
+               OpLoopMerge %39 %40 None
+               OpBranch %41
+         %41 = OpLabel
+         %43 = OpLoad %uint %i
+         %44 = OpULessThan %bool %43 %uint_4
+         %42 = OpLogicalNot %bool %44
+               OpSelectionMerge %46 None
+               OpBranchConditional %42 %47 %46
+         %47 = OpLabel
+               OpBranch %39
+         %46 = OpLabel
+               OpStore %var_for_index %val_0
+         %51 = OpLoad %uint %i
+         %53 = OpAccessChain %_ptr_Function_S %arr %51
+         %55 = OpLoad %uint %i
+         %57 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %55
+         %58 = OpLoad %S_std140 %57
+         %54 = OpFunctionCall %S %conv_S %58
+               OpStore %53 %54
+               OpBranch %40
+         %40 = OpLabel
+         %59 = OpLoad %uint %i
+         %61 = OpIAdd %uint %59 %uint_1
+               OpStore %i %61
+               OpBranch %38
+         %39 = OpLabel
+         %62 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %62
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat4v3half None %63
+         %65 = OpLabel
+         %70 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %73 = OpAccessChain %_ptr_Uniform_v3half %70 %uint_1
+         %74 = OpLoad %v3half %73
+         %76 = OpAccessChain %_ptr_Uniform_v3half %70 %uint_2
+         %77 = OpLoad %v3half %76
+         %80 = OpAccessChain %_ptr_Uniform_v3half %70 %uint_3
+         %81 = OpLoad %v3half %80
+         %83 = OpAccessChain %_ptr_Uniform_v3half %70 %uint_4
+         %84 = OpLoad %v3half %83
+         %85 = OpCompositeConstruct %mat4v3half %74 %77 %81 %84
+               OpReturnValue %85
+               OpFunctionEnd
+          %f = OpFunction %void None %86
+         %89 = OpLabel
+         %92 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+         %93 = OpLoad %_arr_S_std140_uint_4 %92
+         %90 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %93
+               OpStore %p %90
+         %96 = OpAccessChain %_ptr_Private_S %p %int_1
+         %98 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %99 = OpLoad %S_std140 %98
+         %97 = OpFunctionCall %S %conv_S %99
+               OpStore %96 %97
+        %102 = OpAccessChain %_ptr_Private_mat4v3half %p %int_3 %uint_1
+        %103 = OpFunctionCall %mat4v3half %load_u_inner_2_m
+               OpStore %102 %103
+        %106 = OpAccessChain %_ptr_Private_v3half %p %int_1 %uint_1 %104
+        %107 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0 %37 %uint_2
+        %108 = OpLoad %v3half %107
+        %109 = OpVectorShuffle %v3half %108 %108 2 0 1
+               OpStore %106 %109
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..988ba24
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_private.wgsl.expected.wgsl
@@ -0,0 +1,20 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat4x3<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+var<private> p : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[2];
+  p[3].m = u[2].m;
+  p[1].m[0] = u[0].m[1].zxy;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_storage.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_storage.wgsl
new file mode 100644
index 0000000..3d34c0c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_storage.wgsl
@@ -0,0 +1,19 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat4x3<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+@group(0) @binding(1) var<storage, read_write> s : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[2];
+    s[3].m = u[2].m;
+    s[1].m[0] = u[0].m[1].zxy;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_storage.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..5b9dfa8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_storage.wgsl.expected.dxc.hlsl
@@ -0,0 +1,86 @@
+struct S {
+  int before;
+  matrix<float16_t, 4, 3> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_3(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 3> value) {
+  buffer.Store<vector<float16_t, 3> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 8u), value[1u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 16u), value[2u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 24u), value[3u]);
+}
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, S value) {
+  buffer.Store((offset + 0u), asuint(value.before));
+  tint_symbol_3(buffer, (offset + 8u), value.m);
+  buffer.Store((offset + 64u), asuint(value.after));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, S value[4]) {
+  S array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 128u)), array[i]);
+    }
+  }
+}
+
+matrix<float16_t, 4, 3> tint_symbol_8(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+}
+
+S tint_symbol_6(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 64u)) / 4;
+  const S tint_symbol_10 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_8(buffer, (offset + 8u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_10;
+}
+
+typedef S tint_symbol_5_ret[4];
+tint_symbol_5_ret tint_symbol_5(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_6(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_5(u, 0u));
+  tint_symbol_1(s, 128u, tint_symbol_6(u, 256u));
+  tint_symbol_3(s, 392u, tint_symbol_8(u, 264u));
+  uint2 ubo_load_8 = u[1].xy;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  float16_t ubo_load_8_y = f16tof32(ubo_load_8[0] >> 16);
+  s.Store<vector<float16_t, 3> >(136u, vector<float16_t, 3>(ubo_load_8_xz[0], ubo_load_8_y, ubo_load_8_xz[1]).zxy);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_storage.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..c440a1c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_storage.wgsl.expected.fxc.hlsl
@@ -0,0 +1,91 @@
+SKIP: FAILED
+
+struct S {
+  int before;
+  matrix<float16_t, 4, 3> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_3(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 3> value) {
+  buffer.Store<vector<float16_t, 3> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 8u), value[1u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 16u), value[2u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 24u), value[3u]);
+}
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, S value) {
+  buffer.Store((offset + 0u), asuint(value.before));
+  tint_symbol_3(buffer, (offset + 8u), value.m);
+  buffer.Store((offset + 64u), asuint(value.after));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, S value[4]) {
+  S array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 128u)), array[i]);
+    }
+  }
+}
+
+matrix<float16_t, 4, 3> tint_symbol_8(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+}
+
+S tint_symbol_6(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 64u)) / 4;
+  const S tint_symbol_10 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_8(buffer, (offset + 8u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_10;
+}
+
+typedef S tint_symbol_5_ret[4];
+tint_symbol_5_ret tint_symbol_5(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_6(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_5(u, 0u));
+  tint_symbol_1(s, 128u, tint_symbol_6(u, 256u));
+  tint_symbol_3(s, 392u, tint_symbol_8(u, 264u));
+  uint2 ubo_load_8 = u[1].xy;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  float16_t ubo_load_8_y = f16tof32(ubo_load_8[0] >> 16);
+  s.Store<vector<float16_t, 3> >(136u, vector<float16_t, 3>(ubo_load_8_xz[0], ubo_load_8_y, ubo_load_8_xz[1]).zxy);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x00000168827ABEC0(3,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..d07a67c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_storage.wgsl.expected.glsl
@@ -0,0 +1,100 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct S {
+  int before;
+  uint pad;
+  f16mat4x3 m;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  int after;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+};
+
+struct S_std140 {
+  int before;
+  uint pad;
+  f16vec3 m_0;
+  f16vec3 m_1;
+  f16vec3 m_2;
+  f16vec3 m_3;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  int after;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  S inner[4];
+} s;
+
+S conv_S(S_std140 val) {
+  return S(val.before, val.pad, f16mat4x3(val.m_0, val.m_1, val.m_2, val.m_3), val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.after, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.pad_11, val.pad_12, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, 0u, f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat4x3 load_u_inner_2_m() {
+  return f16mat4x3(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2, u.inner[2u].m_3);
+}
+
+void f() {
+  s.inner = conv_arr4_S(u.inner);
+  s.inner[1] = conv_S(u.inner[2u]);
+  s.inner[3].m = load_u_inner_2_m();
+  s.inner[1].m[0] = u.inner[0u].m_1.zxy;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..92723db
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_storage.wgsl.expected.msl
@@ -0,0 +1,33 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0008 */ half4x3 m;
+  /* 0x0028 */ tint_array<int8_t, 24> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+kernel void f(device tint_array<S, 4>* tint_symbol [[buffer(1)]], const constant tint_array<S, 4>* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
+  (*(tint_symbol))[3].m = (*(tint_symbol_1))[2].m;
+  (*(tint_symbol))[1].m[0] = half3((*(tint_symbol_1))[0].m[1]).zxy;
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_storage.wgsl.expected.spvasm
new file mode 100644
index 0000000..8105d9e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_storage.wgsl.expected.spvasm
@@ -0,0 +1,191 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 113
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "m_2"
+               OpMemberName %S_std140 4 "m_3"
+               OpMemberName %S_std140 5 "after"
+               OpName %u "u"
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %s "s"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 8
+               OpMemberDecorate %S_std140 2 Offset 16
+               OpMemberDecorate %S_std140 3 Offset 24
+               OpMemberDecorate %S_std140 4 Offset 32
+               OpMemberDecorate %S_std140 5 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 8
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 8
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+               OpDecorate %s DescriptorSet 0
+               OpDecorate %s Binding 1
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+   %S_std140 = OpTypeStruct %int %v3half %v3half %v3half %v3half %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat4v3half = OpTypeMatrix %v3half 4
+          %S = OpTypeStruct %int %mat4v3half %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+    %u_block = OpTypeStruct %_arr_S_uint_4
+%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
+          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+         %17 = OpTypeFunction %S %S_std140
+         %29 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+         %35 = OpConstantNull %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %38 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %51 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %64 = OpTypeFunction %mat4v3half
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %87 = OpTypeFunction %void
+%_ptr_StorageBuffer__arr_S_uint_4 = OpTypePointer StorageBuffer %_arr_S_uint_4
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+      %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
+      %int_3 = OpConstant %int 3
+%_ptr_StorageBuffer_mat4v3half = OpTypePointer StorageBuffer %mat4v3half
+        %107 = OpConstantNull %int
+%_ptr_StorageBuffer_v3half = OpTypePointer StorageBuffer %v3half
+     %conv_S = OpFunction %S None %17
+        %val = OpFunctionParameter %S_std140
+         %20 = OpLabel
+         %21 = OpCompositeExtract %int %val 0
+         %22 = OpCompositeExtract %v3half %val 1
+         %23 = OpCompositeExtract %v3half %val 2
+         %24 = OpCompositeExtract %v3half %val 3
+         %25 = OpCompositeExtract %v3half %val 4
+         %26 = OpCompositeConstruct %mat4v3half %22 %23 %24 %25
+         %27 = OpCompositeExtract %int %val 5
+         %28 = OpCompositeConstruct %S %21 %26 %27
+               OpReturnValue %28
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %29
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %32 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %35
+          %i = OpVariable %_ptr_Function_uint Function %38
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %51
+               OpBranch %39
+         %39 = OpLabel
+               OpLoopMerge %40 %41 None
+               OpBranch %42
+         %42 = OpLabel
+         %44 = OpLoad %uint %i
+         %45 = OpULessThan %bool %44 %uint_4
+         %43 = OpLogicalNot %bool %45
+               OpSelectionMerge %47 None
+               OpBranchConditional %43 %48 %47
+         %48 = OpLabel
+               OpBranch %40
+         %47 = OpLabel
+               OpStore %var_for_index %val_0
+         %52 = OpLoad %uint %i
+         %54 = OpAccessChain %_ptr_Function_S %arr %52
+         %56 = OpLoad %uint %i
+         %58 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %56
+         %59 = OpLoad %S_std140 %58
+         %55 = OpFunctionCall %S %conv_S %59
+               OpStore %54 %55
+               OpBranch %41
+         %41 = OpLabel
+         %60 = OpLoad %uint %i
+         %62 = OpIAdd %uint %60 %uint_1
+               OpStore %i %62
+               OpBranch %39
+         %40 = OpLabel
+         %63 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %63
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat4v3half None %64
+         %66 = OpLabel
+         %71 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %74 = OpAccessChain %_ptr_Uniform_v3half %71 %uint_1
+         %75 = OpLoad %v3half %74
+         %77 = OpAccessChain %_ptr_Uniform_v3half %71 %uint_2
+         %78 = OpLoad %v3half %77
+         %81 = OpAccessChain %_ptr_Uniform_v3half %71 %uint_3
+         %82 = OpLoad %v3half %81
+         %84 = OpAccessChain %_ptr_Uniform_v3half %71 %uint_4
+         %85 = OpLoad %v3half %84
+         %86 = OpCompositeConstruct %mat4v3half %75 %78 %82 %85
+               OpReturnValue %86
+               OpFunctionEnd
+          %f = OpFunction %void None %87
+         %90 = OpLabel
+         %92 = OpAccessChain %_ptr_StorageBuffer__arr_S_uint_4 %s %uint_0
+         %95 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+         %96 = OpLoad %_arr_S_std140_uint_4 %95
+         %93 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %96
+               OpStore %92 %93
+         %99 = OpAccessChain %_ptr_StorageBuffer_S %s %uint_0 %int_1
+        %101 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+        %102 = OpLoad %S_std140 %101
+        %100 = OpFunctionCall %S %conv_S %102
+               OpStore %99 %100
+        %105 = OpAccessChain %_ptr_StorageBuffer_mat4v3half %s %uint_0 %int_3 %uint_1
+        %106 = OpFunctionCall %mat4v3half %load_u_inner_2_m
+               OpStore %105 %106
+        %109 = OpAccessChain %_ptr_StorageBuffer_v3half %s %uint_0 %int_1 %uint_1 %107
+        %110 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0 %38 %uint_2
+        %111 = OpLoad %v3half %110
+        %112 = OpVectorShuffle %v3half %111 %111 2 0 1
+               OpStore %109 %112
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..0320160
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,20 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat4x3<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@group(0) @binding(1) var<storage, read_write> s : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[2];
+  s[3].m = u[2].m;
+  s[1].m[0] = u[0].m[1].zxy;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_workgroup.wgsl
new file mode 100644
index 0000000..a4c2043
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_workgroup.wgsl
@@ -0,0 +1,19 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat4x3<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+var<workgroup> w : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[2];
+    w[3].m = u[2].m;
+    w[1].m[0] = u[0].m[1].zxy;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_workgroup.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..c660740
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_workgroup.wgsl.expected.dxc.hlsl
@@ -0,0 +1,80 @@
+struct S {
+  int before;
+  matrix<float16_t, 4, 3> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+groupshared S w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 4, 3> tint_symbol_5(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+}
+
+S tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 64u)) / 4;
+  const S tint_symbol_8 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_5(buffer, (offset + 8u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_8;
+}
+
+typedef S tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      const S tint_symbol_7 = (S)0;
+      w[i] = tint_symbol_7;
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 256u);
+  w[3].m = tint_symbol_5(u, 264u);
+  uint2 ubo_load_8 = u[1].xy;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  float16_t ubo_load_8_y = f16tof32(ubo_load_8[0] >> 16);
+  w[1].m[0] = vector<float16_t, 3>(ubo_load_8_xz[0], ubo_load_8_y, ubo_load_8_xz[1]).zxy;
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_workgroup.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..a9b0792
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_workgroup.wgsl.expected.fxc.hlsl
@@ -0,0 +1,85 @@
+SKIP: FAILED
+
+struct S {
+  int before;
+  matrix<float16_t, 4, 3> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+groupshared S w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 4, 3> tint_symbol_5(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+}
+
+S tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 64u)) / 4;
+  const S tint_symbol_8 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_5(buffer, (offset + 8u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_8;
+}
+
+typedef S tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      const S tint_symbol_7 = (S)0;
+      w[i] = tint_symbol_7;
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 256u);
+  w[3].m = tint_symbol_5(u, 264u);
+  uint2 ubo_load_8 = u[1].xy;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  float16_t ubo_load_8_y = f16tof32(ubo_load_8[0] >> 16);
+  w[1].m[0] = vector<float16_t, 3>(ubo_load_8_xz[0], ubo_load_8_y, ubo_load_8_xz[1]).zxy;
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000002136A44CFC0(3,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..06b3e5e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,105 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct S {
+  int before;
+  uint pad;
+  f16mat4x3 m;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  int after;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+};
+
+struct S_std140 {
+  int before;
+  uint pad;
+  f16vec3 m_0;
+  f16vec3 m_1;
+  f16vec3 m_2;
+  f16vec3 m_3;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  int after;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+shared S w[4];
+S conv_S(S_std140 val) {
+  return S(val.before, val.pad, f16mat4x3(val.m_0, val.m_1, val.m_2, val.m_3), val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.after, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.pad_11, val.pad_12, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, 0u, f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat4x3 load_u_inner_2_m() {
+  return f16mat4x3(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2, u.inner[2u].m_3);
+}
+
+void f(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      uint i = idx;
+      S tint_symbol = S(0, 0u, f16mat4x3(f16vec3(0.0hf), f16vec3(0.0hf), f16vec3(0.0hf), f16vec3(0.0hf)), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u);
+      w[i] = tint_symbol;
+    }
+  }
+  barrier();
+  w = conv_arr4_S(u.inner);
+  w[1] = conv_S(u.inner[2u]);
+  w[3].m = load_u_inner_2_m();
+  w[1].m[0] = u.inner[0u].m_1.zxy;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..eedfd26
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,48 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0008 */ half4x3 m;
+  /* 0x0028 */ tint_array<int8_t, 24> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+struct tint_symbol_6 {
+  tint_array<S, 4> w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup tint_array<S, 4>* const tint_symbol_1, const constant tint_array<S, 4>* const tint_symbol_2) {
+  for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+    uint const i = idx;
+    S const tint_symbol = S{};
+    (*(tint_symbol_1))[i] = tint_symbol;
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol_1) = *(tint_symbol_2);
+  (*(tint_symbol_1))[1] = (*(tint_symbol_2))[2];
+  (*(tint_symbol_1))[3].m = (*(tint_symbol_2))[2].m;
+  (*(tint_symbol_1))[1].m[0] = half3((*(tint_symbol_2))[0].m[1]).zxy;
+}
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol_5 [[buffer(0)]], threadgroup tint_symbol_6* tint_symbol_4 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup tint_array<S, 4>* const tint_symbol_3 = &((*(tint_symbol_4)).w);
+  f_inner(local_invocation_index, tint_symbol_3, tint_symbol_5);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_workgroup.wgsl.expected.spvasm
new file mode 100644
index 0000000..7249176
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_workgroup.wgsl.expected.spvasm
@@ -0,0 +1,225 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 135
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %local_invocation_index_1 "local_invocation_index_1"
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "m_2"
+               OpMemberName %S_std140 4 "m_3"
+               OpMemberName %S_std140 5 "after"
+               OpName %u "u"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %w "w"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f_inner "f_inner"
+               OpName %local_invocation_index "local_invocation_index"
+               OpName %idx "idx"
+               OpName %f "f"
+               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 8
+               OpMemberDecorate %S_std140 2 Offset 16
+               OpMemberDecorate %S_std140 3 Offset 24
+               OpMemberDecorate %S_std140 4 Offset 32
+               OpMemberDecorate %S_std140 5 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 8
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 8
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+   %S_std140 = OpTypeStruct %int %v3half %v3half %v3half %v3half %int
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat4v3half = OpTypeMatrix %v3half 4
+          %S = OpTypeStruct %int %mat4v3half %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+%_ptr_Workgroup__arr_S_uint_4 = OpTypePointer Workgroup %_arr_S_uint_4
+          %w = OpVariable %_ptr_Workgroup__arr_S_uint_4 Workgroup
+         %18 = OpTypeFunction %S %S_std140
+         %30 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+         %36 = OpConstantNull %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %39 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %52 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %65 = OpTypeFunction %mat4v3half
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %88 = OpTypeFunction %void %uint
+%_ptr_Workgroup_S = OpTypePointer Workgroup %S
+        %106 = OpConstantNull %S
+   %uint_264 = OpConstant %uint 264
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+      %int_1 = OpConstant %int 1
+      %int_3 = OpConstant %int 3
+%_ptr_Workgroup_mat4v3half = OpTypePointer Workgroup %mat4v3half
+        %124 = OpConstantNull %int
+%_ptr_Workgroup_v3half = OpTypePointer Workgroup %v3half
+        %130 = OpTypeFunction %void
+     %conv_S = OpFunction %S None %18
+        %val = OpFunctionParameter %S_std140
+         %21 = OpLabel
+         %22 = OpCompositeExtract %int %val 0
+         %23 = OpCompositeExtract %v3half %val 1
+         %24 = OpCompositeExtract %v3half %val 2
+         %25 = OpCompositeExtract %v3half %val 3
+         %26 = OpCompositeExtract %v3half %val 4
+         %27 = OpCompositeConstruct %mat4v3half %23 %24 %25 %26
+         %28 = OpCompositeExtract %int %val 5
+         %29 = OpCompositeConstruct %S %22 %27 %28
+               OpReturnValue %29
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %30
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %33 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %36
+          %i = OpVariable %_ptr_Function_uint Function %39
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %52
+               OpBranch %40
+         %40 = OpLabel
+               OpLoopMerge %41 %42 None
+               OpBranch %43
+         %43 = OpLabel
+         %45 = OpLoad %uint %i
+         %46 = OpULessThan %bool %45 %uint_4
+         %44 = OpLogicalNot %bool %46
+               OpSelectionMerge %48 None
+               OpBranchConditional %44 %49 %48
+         %49 = OpLabel
+               OpBranch %41
+         %48 = OpLabel
+               OpStore %var_for_index %val_0
+         %53 = OpLoad %uint %i
+         %55 = OpAccessChain %_ptr_Function_S %arr %53
+         %57 = OpLoad %uint %i
+         %59 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %57
+         %60 = OpLoad %S_std140 %59
+         %56 = OpFunctionCall %S %conv_S %60
+               OpStore %55 %56
+               OpBranch %42
+         %42 = OpLabel
+         %61 = OpLoad %uint %i
+         %63 = OpIAdd %uint %61 %uint_1
+               OpStore %i %63
+               OpBranch %40
+         %41 = OpLabel
+         %64 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %64
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat4v3half None %65
+         %67 = OpLabel
+         %72 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %75 = OpAccessChain %_ptr_Uniform_v3half %72 %uint_1
+         %76 = OpLoad %v3half %75
+         %78 = OpAccessChain %_ptr_Uniform_v3half %72 %uint_2
+         %79 = OpLoad %v3half %78
+         %82 = OpAccessChain %_ptr_Uniform_v3half %72 %uint_3
+         %83 = OpLoad %v3half %82
+         %85 = OpAccessChain %_ptr_Uniform_v3half %72 %uint_4
+         %86 = OpLoad %v3half %85
+         %87 = OpCompositeConstruct %mat4v3half %76 %79 %83 %86
+               OpReturnValue %87
+               OpFunctionEnd
+    %f_inner = OpFunction %void None %88
+%local_invocation_index = OpFunctionParameter %uint
+         %92 = OpLabel
+        %idx = OpVariable %_ptr_Function_uint Function %39
+               OpStore %idx %local_invocation_index
+               OpBranch %94
+         %94 = OpLabel
+               OpLoopMerge %95 %96 None
+               OpBranch %97
+         %97 = OpLabel
+         %99 = OpLoad %uint %idx
+        %100 = OpULessThan %bool %99 %uint_4
+         %98 = OpLogicalNot %bool %100
+               OpSelectionMerge %101 None
+               OpBranchConditional %98 %102 %101
+        %102 = OpLabel
+               OpBranch %95
+        %101 = OpLabel
+        %103 = OpLoad %uint %idx
+        %105 = OpAccessChain %_ptr_Workgroup_S %w %103
+               OpStore %105 %106
+               OpBranch %96
+         %96 = OpLabel
+        %107 = OpLoad %uint %idx
+        %108 = OpIAdd %uint %107 %uint_1
+               OpStore %idx %108
+               OpBranch %94
+         %95 = OpLabel
+               OpControlBarrier %uint_2 %uint_2 %uint_264
+        %113 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+        %114 = OpLoad %_arr_S_std140_uint_4 %113
+        %111 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %114
+               OpStore %w %111
+        %116 = OpAccessChain %_ptr_Workgroup_S %w %int_1
+        %118 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+        %119 = OpLoad %S_std140 %118
+        %117 = OpFunctionCall %S %conv_S %119
+               OpStore %116 %117
+        %122 = OpAccessChain %_ptr_Workgroup_mat4v3half %w %int_3 %uint_1
+        %123 = OpFunctionCall %mat4v3half %load_u_inner_2_m
+               OpStore %122 %123
+        %126 = OpAccessChain %_ptr_Workgroup_v3half %w %int_1 %uint_1 %124
+        %127 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0 %39 %uint_2
+        %128 = OpLoad %v3half %127
+        %129 = OpVectorShuffle %v3half %128 %128 2 0 1
+               OpStore %126 %129
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %130
+        %132 = OpLabel
+        %134 = OpLoad %uint %local_invocation_index_1
+        %133 = OpFunctionCall %void %f_inner %134
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..0e99164
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f16/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,20 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat4x3<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+var<workgroup> w : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[2];
+  w[3].m = u[2].m;
+  w[1].m[0] = u[0].m[1].zxy;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/dynamic_index_via_ptr.wgsl
new file mode 100644
index 0000000..73048bf
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/dynamic_index_via_ptr.wgsl
@@ -0,0 +1,32 @@
+struct Inner {
+  @size(64)
+  m : mat4x3<f32>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a           = &a;
+  let p_a_i         = &((*p_a)[i()]);
+  let p_a_i_a       = &((*p_a_i).a);
+  let p_a_i_a_i     = &((*p_a_i_a)[i()]);
+  let p_a_i_a_i_m   = &((*p_a_i_a_i).m);
+  let p_a_i_a_i_m_i = &((*p_a_i_a_i_m)[i()]);
+
+
+  let l_a             : array<Outer, 4> =  *p_a;
+  let l_a_i           : Outer           =  *p_a_i;
+  let l_a_i_a         : array<Inner, 4> =  *p_a_i_a;
+  let l_a_i_a_i       : Inner           =  *p_a_i_a_i;
+  let l_a_i_a_i_m     : mat4x3<f32>     =  *p_a_i_a_i_m;
+  let l_a_i_a_i_m_i   : vec3<f32>       =  *p_a_i_a_i_m_i;
+  let l_a_i_a_i_m_i_i : f32             = (*p_a_i_a_i_m_i)[i()];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..907314e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,77 @@
+struct Inner {
+  float4x3 m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float4x3 tint_symbol_8(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+Inner tint_symbol_7(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_11 = {tint_symbol_8(buffer, (offset + 0u))};
+  return tint_symbol_11;
+}
+
+typedef Inner tint_symbol_6_ret[4];
+tint_symbol_6_ret tint_symbol_6(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_7(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_5(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_12 = {tint_symbol_6(buffer, (offset + 0u))};
+  return tint_symbol_12;
+}
+
+typedef Outer tint_symbol_4_ret[4];
+tint_symbol_4_ret tint_symbol_4(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
+      arr_1[i_2] = tint_symbol_5(buffer, (offset + (i_2 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_a_i_save = i();
+  const int p_a_i_a_i_m_i_save = i();
+  const Outer l_a[4] = tint_symbol_4(a, 0u);
+  const Outer l_a_i = tint_symbol_5(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a[4] = tint_symbol_6(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a_i = tint_symbol_7(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const float4x3 l_a_i_a_i_m = tint_symbol_8(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const uint scalar_offset_4 = ((((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))) + (16u * uint(p_a_i_a_i_m_i_save)))) / 4;
+  const float3 l_a_i_a_i_m_i = asfloat(a[scalar_offset_4 / 4].xyz);
+  const int tint_symbol = p_a_i_save;
+  const int tint_symbol_1 = p_a_i_a_i_save;
+  const int tint_symbol_2 = p_a_i_a_i_m_i_save;
+  const int tint_symbol_3 = i();
+  const uint scalar_offset_5 = (((((256u * uint(tint_symbol)) + (64u * uint(tint_symbol_1))) + (16u * uint(tint_symbol_2))) + (4u * uint(tint_symbol_3)))) / 4;
+  const float l_a_i_a_i_m_i_i = asfloat(a[scalar_offset_5 / 4][scalar_offset_5 % 4]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..907314e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,77 @@
+struct Inner {
+  float4x3 m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float4x3 tint_symbol_8(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+Inner tint_symbol_7(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_11 = {tint_symbol_8(buffer, (offset + 0u))};
+  return tint_symbol_11;
+}
+
+typedef Inner tint_symbol_6_ret[4];
+tint_symbol_6_ret tint_symbol_6(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_7(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_5(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_12 = {tint_symbol_6(buffer, (offset + 0u))};
+  return tint_symbol_12;
+}
+
+typedef Outer tint_symbol_4_ret[4];
+tint_symbol_4_ret tint_symbol_4(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
+      arr_1[i_2] = tint_symbol_5(buffer, (offset + (i_2 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_a_i_save = i();
+  const int p_a_i_a_i_m_i_save = i();
+  const Outer l_a[4] = tint_symbol_4(a, 0u);
+  const Outer l_a_i = tint_symbol_5(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a[4] = tint_symbol_6(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a_i = tint_symbol_7(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const float4x3 l_a_i_a_i_m = tint_symbol_8(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const uint scalar_offset_4 = ((((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))) + (16u * uint(p_a_i_a_i_m_i_save)))) / 4;
+  const float3 l_a_i_a_i_m_i = asfloat(a[scalar_offset_4 / 4].xyz);
+  const int tint_symbol = p_a_i_save;
+  const int tint_symbol_1 = p_a_i_a_i_save;
+  const int tint_symbol_2 = p_a_i_a_i_m_i_save;
+  const int tint_symbol_3 = i();
+  const uint scalar_offset_5 = (((((256u * uint(tint_symbol)) + (64u * uint(tint_symbol_1))) + (16u * uint(tint_symbol_2))) + (4u * uint(tint_symbol_3)))) / 4;
+  const float l_a_i_a_i_m_i_i = asfloat(a[scalar_offset_5 / 4][scalar_offset_5 % 4]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..9f05f1e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,42 @@
+#version 310 es
+
+struct Inner {
+  mat4x3 m;
+};
+
+struct Outer {
+  Inner a[4];
+};
+
+layout(binding = 0, std140) uniform a_block_ubo {
+  Outer inner[4];
+} a;
+
+int counter = 0;
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+void f() {
+  int tint_symbol = i();
+  int p_a_i_save = tint_symbol;
+  int tint_symbol_1 = i();
+  int p_a_i_a_i_save = tint_symbol_1;
+  int tint_symbol_2 = i();
+  int p_a_i_a_i_m_i_save = tint_symbol_2;
+  Outer l_a[4] = a.inner;
+  Outer l_a_i = a.inner[p_a_i_save];
+  Inner l_a_i_a[4] = a.inner[p_a_i_save].a;
+  Inner l_a_i_a_i = a.inner[p_a_i_save].a[p_a_i_a_i_save];
+  mat4x3 l_a_i_a_i_m = a.inner[p_a_i_save].a[p_a_i_a_i_save].m;
+  vec3 l_a_i_a_i_m_i = a.inner[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save];
+  int tint_symbol_3 = i();
+  float l_a_i_a_i_m_i_i = a.inner[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save][tint_symbol_3];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..ea70250
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,48 @@
+#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 Inner {
+  /* 0x0000 */ float4x3 m;
+};
+
+struct Outer {
+  /* 0x0000 */ tint_array<Inner, 4> a;
+};
+
+int i() {
+  thread int tint_symbol_4 = 0;
+  tint_symbol_4 = as_type<int>((as_type<uint>(tint_symbol_4) + as_type<uint>(1)));
+  return tint_symbol_4;
+}
+
+kernel void f(const constant tint_array<Outer, 4>* tint_symbol_5 [[buffer(0)]]) {
+  int const tint_symbol = i();
+  int const p_a_i_save = tint_symbol;
+  int const tint_symbol_1 = i();
+  int const p_a_i_a_i_save = tint_symbol_1;
+  int const tint_symbol_2 = i();
+  int const p_a_i_a_i_m_i_save = tint_symbol_2;
+  tint_array<Outer, 4> const l_a = *(tint_symbol_5);
+  Outer const l_a_i = (*(tint_symbol_5))[p_a_i_save];
+  tint_array<Inner, 4> const l_a_i_a = (*(tint_symbol_5))[p_a_i_save].a;
+  Inner const l_a_i_a_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save];
+  float4x3 const l_a_i_a_i_m = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m;
+  float3 const l_a_i_a_i_m_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save];
+  int const tint_symbol_3 = i();
+  float const l_a_i_a_i_m_i_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save][tint_symbol_3];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..83ed200
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,88 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 54
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block "a_block"
+               OpMemberName %a_block 0 "inner"
+               OpName %Outer "Outer"
+               OpMemberName %Outer 0 "a"
+               OpName %Inner "Inner"
+               OpMemberName %Inner 0 "m"
+               OpName %a "a"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %f "f"
+               OpDecorate %a_block Block
+               OpMemberDecorate %a_block 0 Offset 0
+               OpMemberDecorate %Outer 0 Offset 0
+               OpMemberDecorate %Inner 0 Offset 0
+               OpMemberDecorate %Inner 0 ColMajor
+               OpMemberDecorate %Inner 0 MatrixStride 16
+               OpDecorate %_arr_Inner_uint_4 ArrayStride 64
+               OpDecorate %_arr_Outer_uint_4 ArrayStride 256
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat4v3float = OpTypeMatrix %v3float 4
+      %Inner = OpTypeStruct %mat4v3float
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_Inner_uint_4 = OpTypeArray %Inner %uint_4
+      %Outer = OpTypeStruct %_arr_Inner_uint_4
+%_arr_Outer_uint_4 = OpTypeArray %Outer %uint_4
+    %a_block = OpTypeStruct %_arr_Outer_uint_4
+%_ptr_Uniform_a_block = OpTypePointer Uniform %a_block
+          %a = OpVariable %_ptr_Uniform_a_block Uniform
+        %int = OpTypeInt 32 1
+         %14 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %14
+         %17 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+       %void = OpTypeVoid
+         %24 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_Outer_uint_4 = OpTypePointer Uniform %_arr_Outer_uint_4
+%_ptr_Uniform_Outer = OpTypePointer Uniform %Outer
+%_ptr_Uniform__arr_Inner_uint_4 = OpTypePointer Uniform %_arr_Inner_uint_4
+%_ptr_Uniform_Inner = OpTypePointer Uniform %Inner
+%_ptr_Uniform_mat4v3float = OpTypePointer Uniform %mat4v3float
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+          %i = OpFunction %int None %17
+         %19 = OpLabel
+         %20 = OpLoad %int %counter
+         %22 = OpIAdd %int %20 %int_1
+               OpStore %counter %22
+         %23 = OpLoad %int %counter
+               OpReturnValue %23
+               OpFunctionEnd
+          %f = OpFunction %void None %24
+         %27 = OpLabel
+         %28 = OpFunctionCall %int %i
+         %29 = OpFunctionCall %int %i
+         %30 = OpFunctionCall %int %i
+         %33 = OpAccessChain %_ptr_Uniform__arr_Outer_uint_4 %a %uint_0
+         %34 = OpLoad %_arr_Outer_uint_4 %33
+         %36 = OpAccessChain %_ptr_Uniform_Outer %a %uint_0 %28
+         %37 = OpLoad %Outer %36
+         %39 = OpAccessChain %_ptr_Uniform__arr_Inner_uint_4 %a %uint_0 %28 %uint_0
+         %40 = OpLoad %_arr_Inner_uint_4 %39
+         %42 = OpAccessChain %_ptr_Uniform_Inner %a %uint_0 %28 %uint_0 %29
+         %43 = OpLoad %Inner %42
+         %45 = OpAccessChain %_ptr_Uniform_mat4v3float %a %uint_0 %28 %uint_0 %29 %uint_0
+         %46 = OpLoad %mat4v3float %45
+         %48 = OpAccessChain %_ptr_Uniform_v3float %a %uint_0 %28 %uint_0 %29 %uint_0 %30
+         %49 = OpLoad %v3float %48
+         %50 = OpFunctionCall %int %i
+         %52 = OpAccessChain %_ptr_Uniform_float %a %uint_0 %28 %uint_0 %29 %uint_0 %30 %50
+         %53 = OpLoad %float %52
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..206ba53
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,34 @@
+struct Inner {
+  @size(64)
+  m : mat4x3<f32>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_i = &((*(p_a))[i()]);
+  let p_a_i_a = &((*(p_a_i)).a);
+  let p_a_i_a_i = &((*(p_a_i_a))[i()]);
+  let p_a_i_a_i_m = &((*(p_a_i_a_i)).m);
+  let p_a_i_a_i_m_i = &((*(p_a_i_a_i_m))[i()]);
+  let l_a : array<Outer, 4> = *(p_a);
+  let l_a_i : Outer = *(p_a_i);
+  let l_a_i_a : array<Inner, 4> = *(p_a_i_a);
+  let l_a_i_a_i : Inner = *(p_a_i_a_i);
+  let l_a_i_a_i_m : mat4x3<f32> = *(p_a_i_a_i_m);
+  let l_a_i_a_i_m_i : vec3<f32> = *(p_a_i_a_i_m_i);
+  let l_a_i_a_i_m_i_i : f32 = (*(p_a_i_a_i_m_i))[i()];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/static_index_via_ptr.wgsl
new file mode 100644
index 0000000..a985f02
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/static_index_via_ptr.wgsl
@@ -0,0 +1,29 @@
+struct Inner {
+  @size(64)
+  m : mat4x3<f32>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &a;
+  let p_a_3 = &((*p_a)[3]);
+  let p_a_3_a = &((*p_a_3).a);
+  let p_a_3_a_2 = &((*p_a_3_a)[2]);
+  let p_a_3_a_2_m = &((*p_a_3_a_2).m);
+  let p_a_3_a_2_m_1 = &((*p_a_3_a_2_m)[1]);
+
+
+  let l_a             : array<Outer, 4> = *p_a;
+  let l_a_3           : Outer           = *p_a_3;
+  let l_a_3_a         : array<Inner, 4> = *p_a_3_a;
+  let l_a_3_a_2       : Inner           = *p_a_3_a_2;
+  let l_a_3_a_2_m     : mat4x3<f32>     = *p_a_3_a_2_m;
+  let l_a_3_a_2_m_1   : vec3<f32>       = *p_a_3_a_2_m_1;
+  let l_a_3_a_2_m_1_0 : f32             = (*p_a_3_a_2_m_1)[0];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..a678c85
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,62 @@
+struct Inner {
+  float4x3 m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+
+float4x3 tint_symbol_4(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+Inner tint_symbol_3(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_7 = {tint_symbol_4(buffer, (offset + 0u))};
+  return tint_symbol_7;
+}
+
+typedef Inner tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_3(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_1(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_8 = {tint_symbol_2(buffer, (offset + 0u))};
+  return tint_symbol_8;
+}
+
+typedef Outer tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr_1[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const Outer l_a[4] = tint_symbol(a, 0u);
+  const Outer l_a_3 = tint_symbol_1(a, 768u);
+  const Inner l_a_3_a[4] = tint_symbol_2(a, 768u);
+  const Inner l_a_3_a_2 = tint_symbol_3(a, 896u);
+  const float4x3 l_a_3_a_2_m = tint_symbol_4(a, 896u);
+  const float3 l_a_3_a_2_m_1 = asfloat(a[57].xyz);
+  const float l_a_3_a_2_m_1_0 = asfloat(a[57].x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..a678c85
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,62 @@
+struct Inner {
+  float4x3 m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+
+float4x3 tint_symbol_4(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+Inner tint_symbol_3(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_7 = {tint_symbol_4(buffer, (offset + 0u))};
+  return tint_symbol_7;
+}
+
+typedef Inner tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_3(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_1(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_8 = {tint_symbol_2(buffer, (offset + 0u))};
+  return tint_symbol_8;
+}
+
+typedef Outer tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr_1[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const Outer l_a[4] = tint_symbol(a, 0u);
+  const Outer l_a_3 = tint_symbol_1(a, 768u);
+  const Inner l_a_3_a[4] = tint_symbol_2(a, 768u);
+  const Inner l_a_3_a_2 = tint_symbol_3(a, 896u);
+  const float4x3 l_a_3_a_2_m = tint_symbol_4(a, 896u);
+  const float3 l_a_3_a_2_m_1 = asfloat(a[57].xyz);
+  const float l_a_3_a_2_m_1_0 = asfloat(a[57].x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/static_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..63ae890
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/static_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,29 @@
+#version 310 es
+
+struct Inner {
+  mat4x3 m;
+};
+
+struct Outer {
+  Inner a[4];
+};
+
+layout(binding = 0, std140) uniform a_block_ubo {
+  Outer inner[4];
+} a;
+
+void f() {
+  Outer l_a[4] = a.inner;
+  Outer l_a_3 = a.inner[3];
+  Inner l_a_3_a[4] = a.inner[3].a;
+  Inner l_a_3_a_2 = a.inner[3].a[2];
+  mat4x3 l_a_3_a_2_m = a.inner[3].a[2].m;
+  vec3 l_a_3_a_2_m_1 = a.inner[3].a[2].m[1];
+  float l_a_3_a_2_m_1_0 = a.inner[3].a[2].m[1][0];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/static_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..a7fb219
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/static_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,35 @@
+#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 Inner {
+  /* 0x0000 */ float4x3 m;
+};
+
+struct Outer {
+  /* 0x0000 */ tint_array<Inner, 4> a;
+};
+
+kernel void f(const constant tint_array<Outer, 4>* tint_symbol [[buffer(0)]]) {
+  tint_array<Outer, 4> const l_a = *(tint_symbol);
+  Outer const l_a_3 = (*(tint_symbol))[3];
+  tint_array<Inner, 4> const l_a_3_a = (*(tint_symbol))[3].a;
+  Inner const l_a_3_a_2 = (*(tint_symbol))[3].a[2];
+  float4x3 const l_a_3_a_2_m = (*(tint_symbol))[3].a[2].m;
+  float3 const l_a_3_a_2_m_1 = (*(tint_symbol))[3].a[2].m[1];
+  float const l_a_3_a_2_m_1_0 = (*(tint_symbol))[3].a[2].m[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/static_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..310cfbc
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/static_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,73 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 44
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block "a_block"
+               OpMemberName %a_block 0 "inner"
+               OpName %Outer "Outer"
+               OpMemberName %Outer 0 "a"
+               OpName %Inner "Inner"
+               OpMemberName %Inner 0 "m"
+               OpName %a "a"
+               OpName %f "f"
+               OpDecorate %a_block Block
+               OpMemberDecorate %a_block 0 Offset 0
+               OpMemberDecorate %Outer 0 Offset 0
+               OpMemberDecorate %Inner 0 Offset 0
+               OpMemberDecorate %Inner 0 ColMajor
+               OpMemberDecorate %Inner 0 MatrixStride 16
+               OpDecorate %_arr_Inner_uint_4 ArrayStride 64
+               OpDecorate %_arr_Outer_uint_4 ArrayStride 256
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat4v3float = OpTypeMatrix %v3float 4
+      %Inner = OpTypeStruct %mat4v3float
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_Inner_uint_4 = OpTypeArray %Inner %uint_4
+      %Outer = OpTypeStruct %_arr_Inner_uint_4
+%_arr_Outer_uint_4 = OpTypeArray %Outer %uint_4
+    %a_block = OpTypeStruct %_arr_Outer_uint_4
+%_ptr_Uniform_a_block = OpTypePointer Uniform %a_block
+          %a = OpVariable %_ptr_Uniform_a_block Uniform
+       %void = OpTypeVoid
+         %13 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_Outer_uint_4 = OpTypePointer Uniform %_arr_Outer_uint_4
+        %int = OpTypeInt 32 1
+      %int_3 = OpConstant %int 3
+%_ptr_Uniform_Outer = OpTypePointer Uniform %Outer
+%_ptr_Uniform__arr_Inner_uint_4 = OpTypePointer Uniform %_arr_Inner_uint_4
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_Inner = OpTypePointer Uniform %Inner
+%_ptr_Uniform_mat4v3float = OpTypePointer Uniform %mat4v3float
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+         %40 = OpConstantNull %int
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+          %f = OpFunction %void None %13
+         %16 = OpLabel
+         %19 = OpAccessChain %_ptr_Uniform__arr_Outer_uint_4 %a %uint_0
+         %20 = OpLoad %_arr_Outer_uint_4 %19
+         %24 = OpAccessChain %_ptr_Uniform_Outer %a %uint_0 %int_3
+         %25 = OpLoad %Outer %24
+         %27 = OpAccessChain %_ptr_Uniform__arr_Inner_uint_4 %a %uint_0 %int_3 %uint_0
+         %28 = OpLoad %_arr_Inner_uint_4 %27
+         %31 = OpAccessChain %_ptr_Uniform_Inner %a %uint_0 %int_3 %uint_0 %int_2
+         %32 = OpLoad %Inner %31
+         %34 = OpAccessChain %_ptr_Uniform_mat4v3float %a %uint_0 %int_3 %uint_0 %int_2 %uint_0
+         %35 = OpLoad %mat4v3float %34
+         %38 = OpAccessChain %_ptr_Uniform_v3float %a %uint_0 %int_3 %uint_0 %int_2 %uint_0 %int_1
+         %39 = OpLoad %v3float %38
+         %42 = OpAccessChain %_ptr_Uniform_float %a %uint_0 %int_3 %uint_0 %int_2 %uint_0 %int_1 %40
+         %43 = OpLoad %float %42
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/static_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..90b476f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/static_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,27 @@
+struct Inner {
+  @size(64)
+  m : mat4x3<f32>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_3 = &((*(p_a))[3]);
+  let p_a_3_a = &((*(p_a_3)).a);
+  let p_a_3_a_2 = &((*(p_a_3_a))[2]);
+  let p_a_3_a_2_m = &((*(p_a_3_a_2)).m);
+  let p_a_3_a_2_m_1 = &((*(p_a_3_a_2_m))[1]);
+  let l_a : array<Outer, 4> = *(p_a);
+  let l_a_3 : Outer = *(p_a_3);
+  let l_a_3_a : array<Inner, 4> = *(p_a_3_a);
+  let l_a_3_a_2 : Inner = *(p_a_3_a_2);
+  let l_a_3_a_2_m : mat4x3<f32> = *(p_a_3_a_2_m);
+  let l_a_3_a_2_m_1 : vec3<f32> = *(p_a_3_a_2_m_1);
+  let l_a_3_a_2_m_1_0 : f32 = (*(p_a_3_a_2_m_1))[0];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_builtin.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_builtin.wgsl
new file mode 100644
index 0000000..127d8ef
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_builtin.wgsl
@@ -0,0 +1,15 @@
+struct S {
+  before : i32,
+  m : mat4x3<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    let t = transpose(u[2].m);
+    let l = length(u[0].m[1].zxy);
+    let a = abs(u[0].m[1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_builtin.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..37cf503
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_builtin.wgsl.expected.dxc.hlsl
@@ -0,0 +1,19 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[48];
+};
+
+float4x3 tint_symbol(uint4 buffer[48], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float3x4 t = transpose(tint_symbol(u, 400u));
+  const float l = length(asfloat(u[2].xyz).zxy);
+  const float a = abs(asfloat(u[2].xyz).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_builtin.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..37cf503
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_builtin.wgsl.expected.fxc.hlsl
@@ -0,0 +1,19 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[48];
+};
+
+float4x3 tint_symbol(uint4 buffer[48], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float3x4 t = transpose(tint_symbol(u, 400u));
+  const float l = length(asfloat(u[2].xyz).zxy);
+  const float a = abs(asfloat(u[2].xyz).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_builtin.wgsl.expected.glsl
new file mode 100644
index 0000000..4e77e60
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_builtin.wgsl.expected.glsl
@@ -0,0 +1,53 @@
+#version 310 es
+
+struct S {
+  int before;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  mat4x3 m;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  int after;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+  uint pad_26;
+  uint pad_27;
+  uint pad_28;
+  uint pad_29;
+};
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  S inner[4];
+} u;
+
+void f() {
+  mat3x4 t = transpose(u.inner[2].m);
+  float l = length(u.inner[0].m[1].zxy);
+  float a = abs(u.inner[0].m[1].zxy.x);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_builtin.wgsl.expected.msl
new file mode 100644
index 0000000..90364fc
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_builtin.wgsl.expected.msl
@@ -0,0 +1,32 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 12> tint_pad;
+  /* 0x0010 */ float4x3 m;
+  /* 0x0050 */ tint_array<int8_t, 48> tint_pad_1;
+  /* 0x0080 */ int after;
+  /* 0x0084 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol [[buffer(0)]]) {
+  float3x4 const t = transpose((*(tint_symbol))[2].m);
+  float const l = length(float3((*(tint_symbol))[0].m[1]).zxy);
+  float const a = fabs(float3((*(tint_symbol))[0].m[1]).zxy[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_builtin.wgsl.expected.spvasm
new file mode 100644
index 0000000..1ce238f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_builtin.wgsl.expected.spvasm
@@ -0,0 +1,67 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 38
+; Schema: 0
+               OpCapability Shader
+         %26 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %u "u"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 16
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 16
+               OpMemberDecorate %S 2 Offset 128
+               OpDecorate %_arr_S_uint_4 ArrayStride 192
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat4v3float = OpTypeMatrix %v3float 4
+          %S = OpTypeStruct %int %mat4v3float %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+    %u_block = OpTypeStruct %_arr_S_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+         %12 = OpTypeFunction %void
+    %v4float = OpTypeVector %float 4
+%mat3v4float = OpTypeMatrix %v4float 3
+     %uint_0 = OpConstant %uint 0
+      %int_2 = OpConstant %int 2
+     %uint_1 = OpConstant %uint 1
+%_ptr_Uniform_mat4v3float = OpTypePointer Uniform %mat4v3float
+         %27 = OpConstantNull %int
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+          %f = OpFunction %void None %12
+         %15 = OpLabel
+         %23 = OpAccessChain %_ptr_Uniform_mat4v3float %u %uint_0 %int_2 %uint_1
+         %24 = OpLoad %mat4v3float %23
+         %16 = OpTranspose %mat3v4float %24
+         %30 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %27 %uint_1 %int_1
+         %31 = OpLoad %v3float %30
+         %32 = OpVectorShuffle %v3float %31 %31 2 0 1
+         %25 = OpExtInst %float %26 Length %32
+         %34 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %27 %uint_1 %int_1
+         %35 = OpLoad %v3float %34
+         %36 = OpVectorShuffle %v3float %35 %35 2 0 1
+         %37 = OpCompositeExtract %float %36 0
+         %33 = OpExtInst %float %26 FAbs %37
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_builtin.wgsl.expected.wgsl
new file mode 100644
index 0000000..59ed8c5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_builtin.wgsl.expected.wgsl
@@ -0,0 +1,15 @@
+struct S {
+  before : i32,
+  m : mat4x3<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let t = transpose(u[2].m);
+  let l = length(u[0].m[1].zxy);
+  let a = abs(u[0].m[1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_fn.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_fn.wgsl
new file mode 100644
index 0000000..37a0425
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_fn.wgsl
@@ -0,0 +1,23 @@
+struct S {
+  before : i32,
+  m : mat4x3<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+fn a(a : array<S, 4>) {}
+fn b(s : S) {}
+fn c(m : mat4x3<f32>) {}
+fn d(v : vec3<f32>) {}
+fn e(f : f32) {}
+
+@compute @workgroup_size(1)
+fn f() {
+    a(u);
+    b(u[2]);
+    c(u[2].m);
+    d(u[0].m[1].zxy);
+    e(u[0].m[1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_fn.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..2fadcff
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_fn.wgsl.expected.dxc.hlsl
@@ -0,0 +1,60 @@
+struct S {
+  int before;
+  float4x3 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[48];
+};
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(float4x3 m) {
+}
+
+void d(float3 v) {
+}
+
+void e(float f_1) {
+}
+
+float4x3 tint_symbol_3(uint4 buffer[48], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+S tint_symbol_1(uint4 buffer[48], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 128u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_3(buffer, (offset + 16u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[48], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 192u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 384u));
+  c(tint_symbol_3(u, 400u));
+  d(asfloat(u[2].xyz).zxy);
+  e(asfloat(u[2].xyz).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_fn.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..2fadcff
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_fn.wgsl.expected.fxc.hlsl
@@ -0,0 +1,60 @@
+struct S {
+  int before;
+  float4x3 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[48];
+};
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(float4x3 m) {
+}
+
+void d(float3 v) {
+}
+
+void e(float f_1) {
+}
+
+float4x3 tint_symbol_3(uint4 buffer[48], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+S tint_symbol_1(uint4 buffer[48], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 128u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_3(buffer, (offset + 16u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[48], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 192u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 384u));
+  c(tint_symbol_3(u, 400u));
+  d(asfloat(u[2].xyz).zxy);
+  e(asfloat(u[2].xyz).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_fn.wgsl.expected.glsl
new file mode 100644
index 0000000..e2289e9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_fn.wgsl.expected.glsl
@@ -0,0 +1,70 @@
+#version 310 es
+
+struct S {
+  int before;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  mat4x3 m;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  int after;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+  uint pad_26;
+  uint pad_27;
+  uint pad_28;
+  uint pad_29;
+};
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  S inner[4];
+} u;
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(mat4x3 m) {
+}
+
+void d(vec3 v) {
+}
+
+void e(float f_1) {
+}
+
+void f() {
+  a(u.inner);
+  b(u.inner[2]);
+  c(u.inner[2].m);
+  d(u.inner[0].m[1].zxy);
+  e(u.inner[0].m[1].zxy.x);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_fn.wgsl.expected.msl
new file mode 100644
index 0000000..2406d51
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_fn.wgsl.expected.msl
@@ -0,0 +1,49 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 12> tint_pad;
+  /* 0x0010 */ float4x3 m;
+  /* 0x0050 */ tint_array<int8_t, 48> tint_pad_1;
+  /* 0x0080 */ int after;
+  /* 0x0084 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+void a(tint_array<S, 4> a_1) {
+}
+
+void b(S s) {
+}
+
+void c(float4x3 m) {
+}
+
+void d(float3 v) {
+}
+
+void e(float f_1) {
+}
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol [[buffer(0)]]) {
+  a(*(tint_symbol));
+  b((*(tint_symbol))[2]);
+  c((*(tint_symbol))[2].m);
+  d(float3((*(tint_symbol))[0].m[1]).zxy);
+  e(float3((*(tint_symbol))[0].m[1]).zxy[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_fn.wgsl.expected.spvasm
new file mode 100644
index 0000000..1679e28
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_fn.wgsl.expected.spvasm
@@ -0,0 +1,112 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 63
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %u "u"
+               OpName %a "a"
+               OpName %a_1 "a_1"
+               OpName %b "b"
+               OpName %s "s"
+               OpName %c "c"
+               OpName %m "m"
+               OpName %d "d"
+               OpName %v "v"
+               OpName %e "e"
+               OpName %f_1 "f_1"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 16
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 16
+               OpMemberDecorate %S 2 Offset 128
+               OpDecorate %_arr_S_uint_4 ArrayStride 192
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat4v3float = OpTypeMatrix %v3float 4
+          %S = OpTypeStruct %int %mat4v3float %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+    %u_block = OpTypeStruct %_arr_S_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+         %12 = OpTypeFunction %void %_arr_S_uint_4
+         %17 = OpTypeFunction %void %S
+         %21 = OpTypeFunction %void %mat4v3float
+         %25 = OpTypeFunction %void %v3float
+         %29 = OpTypeFunction %void %float
+         %33 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_S_uint_4 = OpTypePointer Uniform %_arr_S_uint_4
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_S = OpTypePointer Uniform %S
+     %uint_1 = OpConstant %uint 1
+%_ptr_Uniform_mat4v3float = OpTypePointer Uniform %mat4v3float
+         %52 = OpConstantNull %int
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+          %a = OpFunction %void None %12
+        %a_1 = OpFunctionParameter %_arr_S_uint_4
+         %16 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %b = OpFunction %void None %17
+          %s = OpFunctionParameter %S
+         %20 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %c = OpFunction %void None %21
+          %m = OpFunctionParameter %mat4v3float
+         %24 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %d = OpFunction %void None %25
+          %v = OpFunctionParameter %v3float
+         %28 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %e = OpFunction %void None %29
+        %f_1 = OpFunctionParameter %float
+         %32 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %33
+         %35 = OpLabel
+         %39 = OpAccessChain %_ptr_Uniform__arr_S_uint_4 %u %uint_0
+         %40 = OpLoad %_arr_S_uint_4 %39
+         %36 = OpFunctionCall %void %a %40
+         %44 = OpAccessChain %_ptr_Uniform_S %u %uint_0 %int_2
+         %45 = OpLoad %S %44
+         %41 = OpFunctionCall %void %b %45
+         %49 = OpAccessChain %_ptr_Uniform_mat4v3float %u %uint_0 %int_2 %uint_1
+         %50 = OpLoad %mat4v3float %49
+         %46 = OpFunctionCall %void %c %50
+         %55 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %52 %uint_1 %int_1
+         %56 = OpLoad %v3float %55
+         %57 = OpVectorShuffle %v3float %56 %56 2 0 1
+         %51 = OpFunctionCall %void %d %57
+         %59 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %52 %uint_1 %int_1
+         %60 = OpLoad %v3float %59
+         %61 = OpVectorShuffle %v3float %60 %60 2 0 1
+         %62 = OpCompositeExtract %float %61 0
+         %58 = OpFunctionCall %void %e %62
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_fn.wgsl.expected.wgsl
new file mode 100644
index 0000000..934c242
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_fn.wgsl.expected.wgsl
@@ -0,0 +1,32 @@
+struct S {
+  before : i32,
+  m : mat4x3<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+fn a(a : array<S, 4>) {
+}
+
+fn b(s : S) {
+}
+
+fn c(m : mat4x3<f32>) {
+}
+
+fn d(v : vec3<f32>) {
+}
+
+fn e(f : f32) {
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  a(u);
+  b(u[2]);
+  c(u[2].m);
+  d(u[0].m[1].zxy);
+  e(u[0].m[1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_private.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_private.wgsl
new file mode 100644
index 0000000..591c9ae
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_private.wgsl
@@ -0,0 +1,17 @@
+struct S {
+  before : i32,
+  m : mat4x3<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+var<private> p : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[2];
+    p[3].m = u[2].m;
+    p[1].m[0] = u[0].m[1].zxy;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_private.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..5426bb4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_private.wgsl.expected.dxc.hlsl
@@ -0,0 +1,45 @@
+struct S {
+  int before;
+  float4x3 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[48];
+};
+static S p[4] = (S[4])0;
+
+float4x3 tint_symbol_3(uint4 buffer[48], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+S tint_symbol_1(uint4 buffer[48], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 128u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_3(buffer, (offset + 16u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[48], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 192u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 384u);
+  p[3].m = tint_symbol_3(u, 400u);
+  p[1].m[0] = asfloat(u[2].xyz).zxy;
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_private.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..5426bb4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_private.wgsl.expected.fxc.hlsl
@@ -0,0 +1,45 @@
+struct S {
+  int before;
+  float4x3 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[48];
+};
+static S p[4] = (S[4])0;
+
+float4x3 tint_symbol_3(uint4 buffer[48], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+S tint_symbol_1(uint4 buffer[48], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 128u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_3(buffer, (offset + 16u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[48], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 192u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 384u);
+  p[3].m = tint_symbol_3(u, 400u);
+  p[1].m[0] = asfloat(u[2].xyz).zxy;
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..80b3c35
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_private.wgsl.expected.glsl
@@ -0,0 +1,55 @@
+#version 310 es
+
+struct S {
+  int before;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  mat4x3 m;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  int after;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+  uint pad_26;
+  uint pad_27;
+  uint pad_28;
+  uint pad_29;
+};
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  S inner[4];
+} u;
+
+S p[4] = S[4](S(0, 0u, 0u, 0u, mat4x3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, 0u, 0u, mat4x3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, 0u, 0u, mat4x3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, 0u, 0u, mat4x3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+void f() {
+  p = u.inner;
+  p[1] = u.inner[2];
+  p[3].m = u.inner[2].m;
+  p[1].m[0] = u.inner[0].m[1].zxy;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..2392000
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_private.wgsl.expected.msl
@@ -0,0 +1,34 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 12> tint_pad;
+  /* 0x0010 */ float4x3 m;
+  /* 0x0050 */ tint_array<int8_t, 48> tint_pad_1;
+  /* 0x0080 */ int after;
+  /* 0x0084 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol_1 [[buffer(0)]]) {
+  thread tint_array<S, 4> tint_symbol = {};
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[2];
+  tint_symbol[3].m = (*(tint_symbol_1))[2].m;
+  tint_symbol[1].m[0] = float3((*(tint_symbol_1))[0].m[1]).zxy;
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_private.wgsl.expected.spvasm
new file mode 100644
index 0000000..7152135
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_private.wgsl.expected.spvasm
@@ -0,0 +1,78 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 44
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %u "u"
+               OpName %p "p"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 16
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 16
+               OpMemberDecorate %S 2 Offset 128
+               OpDecorate %_arr_S_uint_4 ArrayStride 192
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat4v3float = OpTypeMatrix %v3float 4
+          %S = OpTypeStruct %int %mat4v3float %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+    %u_block = OpTypeStruct %_arr_S_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_Private__arr_S_uint_4 = OpTypePointer Private %_arr_S_uint_4
+         %14 = OpConstantNull %_arr_S_uint_4
+          %p = OpVariable %_ptr_Private__arr_S_uint_4 Private %14
+       %void = OpTypeVoid
+         %15 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_S_uint_4 = OpTypePointer Uniform %_arr_S_uint_4
+      %int_1 = OpConstant %int 1
+%_ptr_Private_S = OpTypePointer Private %S
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_S = OpTypePointer Uniform %S
+      %int_3 = OpConstant %int 3
+     %uint_1 = OpConstant %uint 1
+%_ptr_Private_mat4v3float = OpTypePointer Private %mat4v3float
+%_ptr_Uniform_mat4v3float = OpTypePointer Uniform %mat4v3float
+         %37 = OpConstantNull %int
+%_ptr_Private_v3float = OpTypePointer Private %v3float
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+          %f = OpFunction %void None %15
+         %18 = OpLabel
+         %21 = OpAccessChain %_ptr_Uniform__arr_S_uint_4 %u %uint_0
+         %22 = OpLoad %_arr_S_uint_4 %21
+               OpStore %p %22
+         %25 = OpAccessChain %_ptr_Private_S %p %int_1
+         %28 = OpAccessChain %_ptr_Uniform_S %u %uint_0 %int_2
+         %29 = OpLoad %S %28
+               OpStore %25 %29
+         %33 = OpAccessChain %_ptr_Private_mat4v3float %p %int_3 %uint_1
+         %35 = OpAccessChain %_ptr_Uniform_mat4v3float %u %uint_0 %int_2 %uint_1
+         %36 = OpLoad %mat4v3float %35
+               OpStore %33 %36
+         %39 = OpAccessChain %_ptr_Private_v3float %p %int_1 %uint_1 %37
+         %41 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %37 %uint_1 %int_1
+         %42 = OpLoad %v3float %41
+         %43 = OpVectorShuffle %v3float %42 %42 2 0 1
+               OpStore %39 %43
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..fc15a1c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_private.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+struct S {
+  before : i32,
+  m : mat4x3<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+var<private> p : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[2];
+  p[3].m = u[2].m;
+  p[1].m[0] = u[0].m[1].zxy;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_storage.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_storage.wgsl
new file mode 100644
index 0000000..a46bb45
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_storage.wgsl
@@ -0,0 +1,17 @@
+struct S {
+  before : i32,
+  m : mat4x3<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+@group(0) @binding(1) var<storage, read_write> s : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[2];
+    s[3].m = u[2].m;
+    s[1].m[0] = u[0].m[1].zxy;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_storage.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..f910578
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_storage.wgsl.expected.dxc.hlsl
@@ -0,0 +1,67 @@
+struct S {
+  int before;
+  float4x3 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[48];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_3(RWByteAddressBuffer buffer, uint offset, float4x3 value) {
+  buffer.Store3((offset + 0u), asuint(value[0u]));
+  buffer.Store3((offset + 16u), asuint(value[1u]));
+  buffer.Store3((offset + 32u), asuint(value[2u]));
+  buffer.Store3((offset + 48u), asuint(value[3u]));
+}
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, S value) {
+  buffer.Store((offset + 0u), asuint(value.before));
+  tint_symbol_3(buffer, (offset + 16u), value.m);
+  buffer.Store((offset + 128u), asuint(value.after));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, S value[4]) {
+  S array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 192u)), array[i]);
+    }
+  }
+}
+
+float4x3 tint_symbol_8(uint4 buffer[48], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+S tint_symbol_6(uint4 buffer[48], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 128u)) / 4;
+  const S tint_symbol_10 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_8(buffer, (offset + 16u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_10;
+}
+
+typedef S tint_symbol_5_ret[4];
+tint_symbol_5_ret tint_symbol_5(uint4 buffer[48], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_6(buffer, (offset + (i_1 * 192u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_5(u, 0u));
+  tint_symbol_1(s, 192u, tint_symbol_6(u, 384u));
+  tint_symbol_3(s, 592u, tint_symbol_8(u, 400u));
+  s.Store3(208u, asuint(asfloat(u[2].xyz).zxy));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_storage.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..f910578
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_storage.wgsl.expected.fxc.hlsl
@@ -0,0 +1,67 @@
+struct S {
+  int before;
+  float4x3 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[48];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_3(RWByteAddressBuffer buffer, uint offset, float4x3 value) {
+  buffer.Store3((offset + 0u), asuint(value[0u]));
+  buffer.Store3((offset + 16u), asuint(value[1u]));
+  buffer.Store3((offset + 32u), asuint(value[2u]));
+  buffer.Store3((offset + 48u), asuint(value[3u]));
+}
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, S value) {
+  buffer.Store((offset + 0u), asuint(value.before));
+  tint_symbol_3(buffer, (offset + 16u), value.m);
+  buffer.Store((offset + 128u), asuint(value.after));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, S value[4]) {
+  S array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 192u)), array[i]);
+    }
+  }
+}
+
+float4x3 tint_symbol_8(uint4 buffer[48], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+S tint_symbol_6(uint4 buffer[48], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 128u)) / 4;
+  const S tint_symbol_10 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_8(buffer, (offset + 16u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_10;
+}
+
+typedef S tint_symbol_5_ret[4];
+tint_symbol_5_ret tint_symbol_5(uint4 buffer[48], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_6(buffer, (offset + (i_1 * 192u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_5(u, 0u));
+  tint_symbol_1(s, 192u, tint_symbol_6(u, 384u));
+  tint_symbol_3(s, 592u, tint_symbol_8(u, 400u));
+  s.Store3(208u, asuint(asfloat(u[2].xyz).zxy));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..d852f0c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_storage.wgsl.expected.glsl
@@ -0,0 +1,58 @@
+#version 310 es
+
+struct S {
+  int before;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  mat4x3 m;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  int after;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+  uint pad_26;
+  uint pad_27;
+  uint pad_28;
+  uint pad_29;
+};
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  S inner[4];
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  S inner[4];
+} s;
+
+void f() {
+  s.inner = u.inner;
+  s.inner[1] = u.inner[2];
+  s.inner[3].m = u.inner[2].m;
+  s.inner[1].m[0] = u.inner[0].m[1].zxy;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..19fab81
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_storage.wgsl.expected.msl
@@ -0,0 +1,33 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 12> tint_pad;
+  /* 0x0010 */ float4x3 m;
+  /* 0x0050 */ tint_array<int8_t, 48> tint_pad_1;
+  /* 0x0080 */ int after;
+  /* 0x0084 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+kernel void f(device tint_array<S, 4>* tint_symbol [[buffer(1)]], const constant tint_array<S, 4>* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
+  (*(tint_symbol))[3].m = (*(tint_symbol_1))[2].m;
+  (*(tint_symbol))[1].m[0] = float3((*(tint_symbol_1))[0].m[1]).zxy;
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_storage.wgsl.expected.spvasm
new file mode 100644
index 0000000..54a79a4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_storage.wgsl.expected.spvasm
@@ -0,0 +1,81 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 45
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %u "u"
+               OpName %s "s"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 16
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 16
+               OpMemberDecorate %S 2 Offset 128
+               OpDecorate %_arr_S_uint_4 ArrayStride 192
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %s DescriptorSet 0
+               OpDecorate %s Binding 1
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat4v3float = OpTypeMatrix %v3float 4
+          %S = OpTypeStruct %int %mat4v3float %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+    %u_block = OpTypeStruct %_arr_S_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
+          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+       %void = OpTypeVoid
+         %14 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer__arr_S_uint_4 = OpTypePointer StorageBuffer %_arr_S_uint_4
+%_ptr_Uniform__arr_S_uint_4 = OpTypePointer Uniform %_arr_S_uint_4
+      %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_S = OpTypePointer Uniform %S
+      %int_3 = OpConstant %int 3
+     %uint_1 = OpConstant %uint 1
+%_ptr_StorageBuffer_mat4v3float = OpTypePointer StorageBuffer %mat4v3float
+%_ptr_Uniform_mat4v3float = OpTypePointer Uniform %mat4v3float
+         %38 = OpConstantNull %int
+%_ptr_StorageBuffer_v3float = OpTypePointer StorageBuffer %v3float
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+          %f = OpFunction %void None %14
+         %17 = OpLabel
+         %20 = OpAccessChain %_ptr_StorageBuffer__arr_S_uint_4 %s %uint_0
+         %22 = OpAccessChain %_ptr_Uniform__arr_S_uint_4 %u %uint_0
+         %23 = OpLoad %_arr_S_uint_4 %22
+               OpStore %20 %23
+         %26 = OpAccessChain %_ptr_StorageBuffer_S %s %uint_0 %int_1
+         %29 = OpAccessChain %_ptr_Uniform_S %u %uint_0 %int_2
+         %30 = OpLoad %S %29
+               OpStore %26 %30
+         %34 = OpAccessChain %_ptr_StorageBuffer_mat4v3float %s %uint_0 %int_3 %uint_1
+         %36 = OpAccessChain %_ptr_Uniform_mat4v3float %u %uint_0 %int_2 %uint_1
+         %37 = OpLoad %mat4v3float %36
+               OpStore %34 %37
+         %40 = OpAccessChain %_ptr_StorageBuffer_v3float %s %uint_0 %int_1 %uint_1 %38
+         %42 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %38 %uint_1 %int_1
+         %43 = OpLoad %v3float %42
+         %44 = OpVectorShuffle %v3float %43 %43 2 0 1
+               OpStore %40 %44
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..6219423
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+struct S {
+  before : i32,
+  m : mat4x3<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@group(0) @binding(1) var<storage, read_write> s : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[2];
+  s[3].m = u[2].m;
+  s[1].m[0] = u[0].m[1].zxy;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_workgroup.wgsl
new file mode 100644
index 0000000..eea6519
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_workgroup.wgsl
@@ -0,0 +1,17 @@
+struct S {
+  before : i32,
+  m : mat4x3<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+var<workgroup> w : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[2];
+    w[3].m = u[2].m;
+    w[1].m[0] = u[0].m[1].zxy;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_workgroup.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..11ebf40
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_workgroup.wgsl.expected.dxc.hlsl
@@ -0,0 +1,61 @@
+struct S {
+  int before;
+  float4x3 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[48];
+};
+groupshared S w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+float4x3 tint_symbol_5(uint4 buffer[48], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+S tint_symbol_3(uint4 buffer[48], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 128u)) / 4;
+  const S tint_symbol_8 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_5(buffer, (offset + 16u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_8;
+}
+
+typedef S tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[48], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 192u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      const S tint_symbol_7 = (S)0;
+      w[i] = tint_symbol_7;
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 384u);
+  w[3].m = tint_symbol_5(u, 400u);
+  w[1].m[0] = asfloat(u[2].xyz).zxy;
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_workgroup.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..11ebf40
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_workgroup.wgsl.expected.fxc.hlsl
@@ -0,0 +1,61 @@
+struct S {
+  int before;
+  float4x3 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[48];
+};
+groupshared S w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+float4x3 tint_symbol_5(uint4 buffer[48], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+S tint_symbol_3(uint4 buffer[48], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 128u)) / 4;
+  const S tint_symbol_8 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_5(buffer, (offset + 16u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_8;
+}
+
+typedef S tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[48], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 192u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      const S tint_symbol_7 = (S)0;
+      w[i] = tint_symbol_7;
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 384u);
+  w[3].m = tint_symbol_5(u, 400u);
+  w[1].m[0] = asfloat(u[2].xyz).zxy;
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..a5f912f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,63 @@
+#version 310 es
+
+struct S {
+  int before;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  mat4x3 m;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  int after;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+  uint pad_26;
+  uint pad_27;
+  uint pad_28;
+  uint pad_29;
+};
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  S inner[4];
+} u;
+
+shared S w[4];
+void f(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      uint i = idx;
+      S tint_symbol = S(0, 0u, 0u, 0u, mat4x3(vec3(0.0f), vec3(0.0f), vec3(0.0f), vec3(0.0f)), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u);
+      w[i] = tint_symbol;
+    }
+  }
+  barrier();
+  w = u.inner;
+  w[1] = u.inner[2];
+  w[3].m = u.inner[2].m;
+  w[1].m[0] = u.inner[0].m[1].zxy;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..17fa37d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,48 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 12> tint_pad;
+  /* 0x0010 */ float4x3 m;
+  /* 0x0050 */ tint_array<int8_t, 48> tint_pad_1;
+  /* 0x0080 */ int after;
+  /* 0x0084 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+struct tint_symbol_6 {
+  tint_array<S, 4> w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup tint_array<S, 4>* const tint_symbol_1, const constant tint_array<S, 4>* const tint_symbol_2) {
+  for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+    uint const i = idx;
+    S const tint_symbol = S{};
+    (*(tint_symbol_1))[i] = tint_symbol;
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol_1) = *(tint_symbol_2);
+  (*(tint_symbol_1))[1] = (*(tint_symbol_2))[2];
+  (*(tint_symbol_1))[3].m = (*(tint_symbol_2))[2].m;
+  (*(tint_symbol_1))[1].m[0] = float3((*(tint_symbol_2))[0].m[1]).zxy;
+}
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol_5 [[buffer(0)]], threadgroup tint_symbol_6* tint_symbol_4 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup tint_array<S, 4>* const tint_symbol_3 = &((*(tint_symbol_4)).w);
+  f_inner(local_invocation_index, tint_symbol_3, tint_symbol_5);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_workgroup.wgsl.expected.spvasm
new file mode 100644
index 0000000..27c9f46
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_workgroup.wgsl.expected.spvasm
@@ -0,0 +1,124 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 72
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %local_invocation_index_1 "local_invocation_index_1"
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %u "u"
+               OpName %w "w"
+               OpName %f_inner "f_inner"
+               OpName %local_invocation_index "local_invocation_index"
+               OpName %idx "idx"
+               OpName %f "f"
+               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 16
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 16
+               OpMemberDecorate %S 2 Offset 128
+               OpDecorate %_arr_S_uint_4 ArrayStride 192
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat4v3float = OpTypeMatrix %v3float 4
+          %S = OpTypeStruct %int %mat4v3float %int
+     %uint_4 = OpConstant %uint 4
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+    %u_block = OpTypeStruct %_arr_S_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_Workgroup__arr_S_uint_4 = OpTypePointer Workgroup %_arr_S_uint_4
+          %w = OpVariable %_ptr_Workgroup__arr_S_uint_4 Workgroup
+       %void = OpTypeVoid
+         %16 = OpTypeFunction %void %uint
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %23 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Workgroup_S = OpTypePointer Workgroup %S
+         %37 = OpConstantNull %S
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+   %uint_264 = OpConstant %uint 264
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_S_uint_4 = OpTypePointer Uniform %_arr_S_uint_4
+      %int_1 = OpConstant %int 1
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_S = OpTypePointer Uniform %S
+      %int_3 = OpConstant %int 3
+%_ptr_Workgroup_mat4v3float = OpTypePointer Workgroup %mat4v3float
+%_ptr_Uniform_mat4v3float = OpTypePointer Uniform %mat4v3float
+         %60 = OpConstantNull %int
+%_ptr_Workgroup_v3float = OpTypePointer Workgroup %v3float
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+         %67 = OpTypeFunction %void
+    %f_inner = OpFunction %void None %16
+%local_invocation_index = OpFunctionParameter %uint
+         %20 = OpLabel
+        %idx = OpVariable %_ptr_Function_uint Function %23
+               OpStore %idx %local_invocation_index
+               OpBranch %24
+         %24 = OpLabel
+               OpLoopMerge %25 %26 None
+               OpBranch %27
+         %27 = OpLabel
+         %29 = OpLoad %uint %idx
+         %30 = OpULessThan %bool %29 %uint_4
+         %28 = OpLogicalNot %bool %30
+               OpSelectionMerge %32 None
+               OpBranchConditional %28 %33 %32
+         %33 = OpLabel
+               OpBranch %25
+         %32 = OpLabel
+         %34 = OpLoad %uint %idx
+         %36 = OpAccessChain %_ptr_Workgroup_S %w %34
+               OpStore %36 %37
+               OpBranch %26
+         %26 = OpLabel
+         %38 = OpLoad %uint %idx
+         %40 = OpIAdd %uint %38 %uint_1
+               OpStore %idx %40
+               OpBranch %24
+         %25 = OpLabel
+               OpControlBarrier %uint_2 %uint_2 %uint_264
+         %46 = OpAccessChain %_ptr_Uniform__arr_S_uint_4 %u %uint_0
+         %47 = OpLoad %_arr_S_uint_4 %46
+               OpStore %w %47
+         %49 = OpAccessChain %_ptr_Workgroup_S %w %int_1
+         %52 = OpAccessChain %_ptr_Uniform_S %u %uint_0 %int_2
+         %53 = OpLoad %S %52
+               OpStore %49 %53
+         %56 = OpAccessChain %_ptr_Workgroup_mat4v3float %w %int_3 %uint_1
+         %58 = OpAccessChain %_ptr_Uniform_mat4v3float %u %uint_0 %int_2 %uint_1
+         %59 = OpLoad %mat4v3float %58
+               OpStore %56 %59
+         %62 = OpAccessChain %_ptr_Workgroup_v3float %w %int_1 %uint_1 %60
+         %64 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %60 %uint_1 %int_1
+         %65 = OpLoad %v3float %64
+         %66 = OpVectorShuffle %v3float %65 %65 2 0 1
+               OpStore %62 %66
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %67
+         %69 = OpLabel
+         %71 = OpLoad %uint %local_invocation_index_1
+         %70 = OpFunctionCall %void %f_inner %71
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..4b7ef2b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x3_f32/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+struct S {
+  before : i32,
+  m : mat4x3<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+var<workgroup> w : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[2];
+  w[3].m = u[2].m;
+  w[1].m[0] = u[0].m[1].zxy;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/dynamic_index_via_ptr.wgsl
new file mode 100644
index 0000000..688558a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/dynamic_index_via_ptr.wgsl
@@ -0,0 +1,34 @@
+enable f16;
+
+struct Inner {
+  @size(64)
+  m : mat4x4<f16>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a           = &a;
+  let p_a_i         = &((*p_a)[i()]);
+  let p_a_i_a       = &((*p_a_i).a);
+  let p_a_i_a_i     = &((*p_a_i_a)[i()]);
+  let p_a_i_a_i_m   = &((*p_a_i_a_i).m);
+  let p_a_i_a_i_m_i = &((*p_a_i_a_i_m)[i()]);
+
+
+  let l_a             : array<Outer, 4> =  *p_a;
+  let l_a_i           : Outer           =  *p_a_i;
+  let l_a_i_a         : array<Inner, 4> =  *p_a_i_a;
+  let l_a_i_a_i       : Inner           =  *p_a_i_a_i;
+  let l_a_i_a_i_m     : mat4x4<f16>     =  *p_a_i_a_i_m;
+  let l_a_i_a_i_m_i   : vec4<f16>       =  *p_a_i_a_i_m_i;
+  let l_a_i_a_i_m_i_i : f16             = (*p_a_i_a_i_m_i)[i()];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..c0fa0aa
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,98 @@
+struct Inner {
+  matrix<float16_t, 4, 4> m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 4, 4> tint_symbol_8(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+}
+
+Inner tint_symbol_7(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_11 = {tint_symbol_8(buffer, (offset + 0u))};
+  return tint_symbol_11;
+}
+
+typedef Inner tint_symbol_6_ret[4];
+tint_symbol_6_ret tint_symbol_6(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_7(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_5(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_12 = {tint_symbol_6(buffer, (offset + 0u))};
+  return tint_symbol_12;
+}
+
+typedef Outer tint_symbol_4_ret[4];
+tint_symbol_4_ret tint_symbol_4(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
+      arr_1[i_2] = tint_symbol_5(buffer, (offset + (i_2 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_a_i_save = i();
+  const int p_a_i_a_i_m_i_save = i();
+  const Outer l_a[4] = tint_symbol_4(a, 0u);
+  const Outer l_a_i = tint_symbol_5(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a[4] = tint_symbol_6(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a_i = tint_symbol_7(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const matrix<float16_t, 4, 4> l_a_i_a_i_m = tint_symbol_8(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const uint scalar_offset_4 = ((((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))) + (8u * uint(p_a_i_a_i_m_i_save)))) / 4;
+  uint4 ubo_load_9 = a[scalar_offset_4 / 4];
+  uint2 ubo_load_8 = ((scalar_offset_4 & 2) ? ubo_load_9.zw : ubo_load_9.xy);
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_8_yw = vector<float16_t, 2>(f16tof32(ubo_load_8 >> 16));
+  const vector<float16_t, 4> l_a_i_a_i_m_i = vector<float16_t, 4>(ubo_load_8_xz[0], ubo_load_8_yw[0], ubo_load_8_xz[1], ubo_load_8_yw[1]);
+  const int tint_symbol = p_a_i_save;
+  const int tint_symbol_1 = p_a_i_a_i_save;
+  const int tint_symbol_2 = p_a_i_a_i_m_i_save;
+  const int tint_symbol_3 = i();
+  const uint scalar_offset_bytes = (((((256u * uint(tint_symbol)) + (64u * uint(tint_symbol_1))) + (8u * uint(tint_symbol_2))) + (2u * uint(tint_symbol_3))));
+  const uint scalar_offset_index = scalar_offset_bytes / 4;
+  const float16_t l_a_i_a_i_m_i_i = float16_t(f16tof32(((a[scalar_offset_index / 4][scalar_offset_index % 4] >> (scalar_offset_bytes % 4 == 0 ? 0 : 16)) & 0xFFFF)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..835df5d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,103 @@
+SKIP: FAILED
+
+struct Inner {
+  matrix<float16_t, 4, 4> m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 4, 4> tint_symbol_8(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+}
+
+Inner tint_symbol_7(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_11 = {tint_symbol_8(buffer, (offset + 0u))};
+  return tint_symbol_11;
+}
+
+typedef Inner tint_symbol_6_ret[4];
+tint_symbol_6_ret tint_symbol_6(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_7(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_5(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_12 = {tint_symbol_6(buffer, (offset + 0u))};
+  return tint_symbol_12;
+}
+
+typedef Outer tint_symbol_4_ret[4];
+tint_symbol_4_ret tint_symbol_4(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
+      arr_1[i_2] = tint_symbol_5(buffer, (offset + (i_2 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_a_i_save = i();
+  const int p_a_i_a_i_m_i_save = i();
+  const Outer l_a[4] = tint_symbol_4(a, 0u);
+  const Outer l_a_i = tint_symbol_5(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a[4] = tint_symbol_6(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a_i = tint_symbol_7(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const matrix<float16_t, 4, 4> l_a_i_a_i_m = tint_symbol_8(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const uint scalar_offset_4 = ((((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))) + (8u * uint(p_a_i_a_i_m_i_save)))) / 4;
+  uint4 ubo_load_9 = a[scalar_offset_4 / 4];
+  uint2 ubo_load_8 = ((scalar_offset_4 & 2) ? ubo_load_9.zw : ubo_load_9.xy);
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_8_yw = vector<float16_t, 2>(f16tof32(ubo_load_8 >> 16));
+  const vector<float16_t, 4> l_a_i_a_i_m_i = vector<float16_t, 4>(ubo_load_8_xz[0], ubo_load_8_yw[0], ubo_load_8_xz[1], ubo_load_8_yw[1]);
+  const int tint_symbol = p_a_i_save;
+  const int tint_symbol_1 = p_a_i_a_i_save;
+  const int tint_symbol_2 = p_a_i_a_i_m_i_save;
+  const int tint_symbol_3 = i();
+  const uint scalar_offset_bytes = (((((256u * uint(tint_symbol)) + (64u * uint(tint_symbol_1))) + (8u * uint(tint_symbol_2))) + (2u * uint(tint_symbol_3))));
+  const uint scalar_offset_index = scalar_offset_bytes / 4;
+  const float16_t l_a_i_a_i_m_i_i = float16_t(f16tof32(((a[scalar_offset_index / 4][scalar_offset_index % 4] >> (scalar_offset_bytes % 4 == 0 ? 0 : 16)) & 0xFFFF)));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000022FAD9FCD80(2,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..5578dfd
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,157 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct Inner {
+  f16mat4 m;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+};
+
+struct Inner_std140 {
+  f16vec4 m_0;
+  f16vec4 m_1;
+  f16vec4 m_2;
+  f16vec4 m_3;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+};
+
+struct Outer {
+  Inner a[4];
+};
+
+struct Outer_std140 {
+  Inner_std140 a[4];
+};
+
+layout(binding = 0, std140) uniform a_block_std140_ubo {
+  Outer_std140 inner[4];
+} a;
+
+int counter = 0;
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+Inner conv_Inner(Inner_std140 val) {
+  return Inner(f16mat4(val.m_0, val.m_1, val.m_2, val.m_3), val.pad, val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7);
+}
+
+Inner[4] conv_arr4_Inner(Inner_std140 val[4]) {
+  Inner arr[4] = Inner[4](Inner(f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_Inner(val[i]);
+    }
+  }
+  return arr;
+}
+
+Outer conv_Outer(Outer_std140 val) {
+  return Outer(conv_arr4_Inner(val.a));
+}
+
+Outer[4] conv_arr4_Outer(Outer_std140 val[4]) {
+  Outer arr[4] = Outer[4](Outer(Inner[4](Inner(f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_Outer(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat4 load_a_inner_p0_a_p1_m(uint p0, uint p1) {
+  uint s_save = p0;
+  uint s_save_1 = p1;
+  return f16mat4(a.inner[s_save].a[s_save_1].m_0, a.inner[s_save].a[s_save_1].m_1, a.inner[s_save].a[s_save_1].m_2, a.inner[s_save].a[s_save_1].m_3);
+}
+
+f16vec4 load_a_inner_p0_a_p1_m_p2(uint p0, uint p1, uint p2) {
+  switch(p2) {
+    case 0u: {
+      return a.inner[p0].a[p1].m_0;
+      break;
+    }
+    case 1u: {
+      return a.inner[p0].a[p1].m_1;
+      break;
+    }
+    case 2u: {
+      return a.inner[p0].a[p1].m_2;
+      break;
+    }
+    case 3u: {
+      return a.inner[p0].a[p1].m_3;
+      break;
+    }
+    default: {
+      return f16vec4(0.0hf);
+      break;
+    }
+  }
+}
+
+float16_t load_a_inner_p0_a_p1_m_p2_p3(uint p0, uint p1, uint p2, uint p3) {
+  switch(p2) {
+    case 0u: {
+      return a.inner[p0].a[p1].m_0[p3];
+      break;
+    }
+    case 1u: {
+      return a.inner[p0].a[p1].m_1[p3];
+      break;
+    }
+    case 2u: {
+      return a.inner[p0].a[p1].m_2[p3];
+      break;
+    }
+    case 3u: {
+      return a.inner[p0].a[p1].m_3[p3];
+      break;
+    }
+    default: {
+      return 0.0hf;
+      break;
+    }
+  }
+}
+
+void f() {
+  Outer p_a[4] = conv_arr4_Outer(a.inner);
+  int tint_symbol = i();
+  Outer p_a_i = conv_Outer(a.inner[tint_symbol]);
+  Inner p_a_i_a[4] = conv_arr4_Inner(a.inner[tint_symbol].a);
+  int tint_symbol_1 = i();
+  Inner p_a_i_a_i = conv_Inner(a.inner[tint_symbol].a[tint_symbol_1]);
+  f16mat4 p_a_i_a_i_m = load_a_inner_p0_a_p1_m(uint(tint_symbol), uint(tint_symbol_1));
+  int tint_symbol_2 = i();
+  f16vec4 p_a_i_a_i_m_i = load_a_inner_p0_a_p1_m_p2(uint(tint_symbol), uint(tint_symbol_1), uint(tint_symbol_2));
+  Outer l_a[4] = conv_arr4_Outer(a.inner);
+  Outer l_a_i = conv_Outer(a.inner[tint_symbol]);
+  Inner l_a_i_a[4] = conv_arr4_Inner(a.inner[tint_symbol].a);
+  Inner l_a_i_a_i = conv_Inner(a.inner[tint_symbol].a[tint_symbol_1]);
+  f16mat4 l_a_i_a_i_m = load_a_inner_p0_a_p1_m(uint(tint_symbol), uint(tint_symbol_1));
+  f16vec4 l_a_i_a_i_m_i = load_a_inner_p0_a_p1_m_p2(uint(tint_symbol), uint(tint_symbol_1), uint(tint_symbol_2));
+  int tint_symbol_3 = i();
+  float16_t l_a_i_a_i_m_i_i = load_a_inner_p0_a_p1_m_p2_p3(uint(tint_symbol), uint(tint_symbol_1), uint(tint_symbol_2), uint(tint_symbol_3));
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..31fbf6a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,49 @@
+#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 Inner {
+  /* 0x0000 */ half4x4 m;
+  /* 0x0020 */ tint_array<int8_t, 32> tint_pad;
+};
+
+struct Outer {
+  /* 0x0000 */ tint_array<Inner, 4> a;
+};
+
+int i() {
+  thread int tint_symbol_4 = 0;
+  tint_symbol_4 = as_type<int>((as_type<uint>(tint_symbol_4) + as_type<uint>(1)));
+  return tint_symbol_4;
+}
+
+kernel void f(const constant tint_array<Outer, 4>* tint_symbol_5 [[buffer(0)]]) {
+  int const tint_symbol = i();
+  int const p_a_i_save = tint_symbol;
+  int const tint_symbol_1 = i();
+  int const p_a_i_a_i_save = tint_symbol_1;
+  int const tint_symbol_2 = i();
+  int const p_a_i_a_i_m_i_save = tint_symbol_2;
+  tint_array<Outer, 4> const l_a = *(tint_symbol_5);
+  Outer const l_a_i = (*(tint_symbol_5))[p_a_i_save];
+  tint_array<Inner, 4> const l_a_i_a = (*(tint_symbol_5))[p_a_i_save].a;
+  Inner const l_a_i_a_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save];
+  half4x4 const l_a_i_a_i_m = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m;
+  half4 const l_a_i_a_i_m_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save];
+  int const tint_symbol_3 = i();
+  half const l_a_i_a_i_m_i_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save][tint_symbol_3];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..14536fe
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,338 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 215
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block_std140 "a_block_std140"
+               OpMemberName %a_block_std140 0 "inner"
+               OpName %Outer_std140 "Outer_std140"
+               OpMemberName %Outer_std140 0 "a"
+               OpName %Inner_std140 "Inner_std140"
+               OpMemberName %Inner_std140 0 "m_0"
+               OpMemberName %Inner_std140 1 "m_1"
+               OpMemberName %Inner_std140 2 "m_2"
+               OpMemberName %Inner_std140 3 "m_3"
+               OpName %a "a"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %Inner "Inner"
+               OpMemberName %Inner 0 "m"
+               OpName %conv_Inner "conv_Inner"
+               OpName %val "val"
+               OpName %conv_arr4_Inner "conv_arr4_Inner"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i_0 "i"
+               OpName %var_for_index_1 "var_for_index_1"
+               OpName %Outer "Outer"
+               OpMemberName %Outer 0 "a"
+               OpName %conv_Outer "conv_Outer"
+               OpName %val_1 "val"
+               OpName %conv_arr4_Outer "conv_arr4_Outer"
+               OpName %val_2 "val"
+               OpName %arr_0 "arr"
+               OpName %i_1 "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_a_inner_p0_a_p1_m "load_a_inner_p0_a_p1_m"
+               OpName %p0 "p0"
+               OpName %p1 "p1"
+               OpName %load_a_inner_p0_a_p1_m_p2 "load_a_inner_p0_a_p1_m_p2"
+               OpName %p0_0 "p0"
+               OpName %p1_0 "p1"
+               OpName %p2 "p2"
+               OpName %load_a_inner_p0_a_p1_m_p2_p3 "load_a_inner_p0_a_p1_m_p2_p3"
+               OpName %p0_1 "p0"
+               OpName %p1_1 "p1"
+               OpName %p2_0 "p2"
+               OpName %p3 "p3"
+               OpName %f "f"
+               OpDecorate %a_block_std140 Block
+               OpMemberDecorate %a_block_std140 0 Offset 0
+               OpMemberDecorate %Outer_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 1 Offset 8
+               OpMemberDecorate %Inner_std140 2 Offset 16
+               OpMemberDecorate %Inner_std140 3 Offset 24
+               OpDecorate %_arr_Inner_std140_uint_4 ArrayStride 64
+               OpDecorate %_arr_Outer_std140_uint_4 ArrayStride 256
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+               OpMemberDecorate %Inner 0 Offset 0
+               OpMemberDecorate %Inner 0 ColMajor
+               OpMemberDecorate %Inner 0 MatrixStride 8
+               OpDecorate %_arr_Inner_uint_4 ArrayStride 64
+               OpMemberDecorate %Outer 0 Offset 0
+               OpDecorate %_arr_Outer_uint_4 ArrayStride 256
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+%Inner_std140 = OpTypeStruct %v4half %v4half %v4half %v4half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_Inner_std140_uint_4 = OpTypeArray %Inner_std140 %uint_4
+%Outer_std140 = OpTypeStruct %_arr_Inner_std140_uint_4
+%_arr_Outer_std140_uint_4 = OpTypeArray %Outer_std140 %uint_4
+%a_block_std140 = OpTypeStruct %_arr_Outer_std140_uint_4
+%_ptr_Uniform_a_block_std140 = OpTypePointer Uniform %a_block_std140
+          %a = OpVariable %_ptr_Uniform_a_block_std140 Uniform
+        %int = OpTypeInt 32 1
+         %13 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %13
+         %16 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+ %mat4v4half = OpTypeMatrix %v4half 4
+      %Inner = OpTypeStruct %mat4v4half
+         %23 = OpTypeFunction %Inner %Inner_std140
+%_arr_Inner_uint_4 = OpTypeArray %Inner %uint_4
+         %35 = OpTypeFunction %_arr_Inner_uint_4 %_arr_Inner_std140_uint_4
+%_ptr_Function__arr_Inner_uint_4 = OpTypePointer Function %_arr_Inner_uint_4
+         %42 = OpConstantNull %_arr_Inner_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %45 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_Inner_std140_uint_4 = OpTypePointer Function %_arr_Inner_std140_uint_4
+         %58 = OpConstantNull %_arr_Inner_std140_uint_4
+%_ptr_Function_Inner = OpTypePointer Function %Inner
+%_ptr_Function_Inner_std140 = OpTypePointer Function %Inner_std140
+     %uint_1 = OpConstant %uint 1
+      %Outer = OpTypeStruct %_arr_Inner_uint_4
+         %71 = OpTypeFunction %Outer %Outer_std140
+%_arr_Outer_uint_4 = OpTypeArray %Outer %uint_4
+         %79 = OpTypeFunction %_arr_Outer_uint_4 %_arr_Outer_std140_uint_4
+%_ptr_Function__arr_Outer_uint_4 = OpTypePointer Function %_arr_Outer_uint_4
+         %86 = OpConstantNull %_arr_Outer_uint_4
+%_ptr_Function__arr_Outer_std140_uint_4 = OpTypePointer Function %_arr_Outer_std140_uint_4
+         %99 = OpConstantNull %_arr_Outer_std140_uint_4
+%_ptr_Function_Outer = OpTypePointer Function %Outer
+%_ptr_Function_Outer_std140 = OpTypePointer Function %Outer_std140
+        %111 = OpTypeFunction %mat4v4half %uint %uint
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_Inner_std140 = OpTypePointer Uniform %Inner_std140
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+        %136 = OpTypeFunction %v4half %uint %uint %uint
+        %156 = OpConstantNull %v4half
+        %157 = OpTypeFunction %half %uint %uint %uint %uint
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+        %179 = OpConstantNull %half
+       %void = OpTypeVoid
+        %180 = OpTypeFunction %void
+%_ptr_Uniform__arr_Outer_std140_uint_4 = OpTypePointer Uniform %_arr_Outer_std140_uint_4
+%_ptr_Uniform_Outer_std140 = OpTypePointer Uniform %Outer_std140
+%_ptr_Uniform__arr_Inner_std140_uint_4 = OpTypePointer Uniform %_arr_Inner_std140_uint_4
+          %i = OpFunction %int None %16
+         %18 = OpLabel
+         %19 = OpLoad %int %counter
+         %21 = OpIAdd %int %19 %int_1
+               OpStore %counter %21
+         %22 = OpLoad %int %counter
+               OpReturnValue %22
+               OpFunctionEnd
+ %conv_Inner = OpFunction %Inner None %23
+        %val = OpFunctionParameter %Inner_std140
+         %28 = OpLabel
+         %29 = OpCompositeExtract %v4half %val 0
+         %30 = OpCompositeExtract %v4half %val 1
+         %31 = OpCompositeExtract %v4half %val 2
+         %32 = OpCompositeExtract %v4half %val 3
+         %33 = OpCompositeConstruct %mat4v4half %29 %30 %31 %32
+         %34 = OpCompositeConstruct %Inner %33
+               OpReturnValue %34
+               OpFunctionEnd
+%conv_arr4_Inner = OpFunction %_arr_Inner_uint_4 None %35
+      %val_0 = OpFunctionParameter %_arr_Inner_std140_uint_4
+         %39 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_Inner_uint_4 Function %42
+        %i_0 = OpVariable %_ptr_Function_uint Function %45
+%var_for_index_1 = OpVariable %_ptr_Function__arr_Inner_std140_uint_4 Function %58
+               OpBranch %46
+         %46 = OpLabel
+               OpLoopMerge %47 %48 None
+               OpBranch %49
+         %49 = OpLabel
+         %51 = OpLoad %uint %i_0
+         %52 = OpULessThan %bool %51 %uint_4
+         %50 = OpLogicalNot %bool %52
+               OpSelectionMerge %54 None
+               OpBranchConditional %50 %55 %54
+         %55 = OpLabel
+               OpBranch %47
+         %54 = OpLabel
+               OpStore %var_for_index_1 %val_0
+         %59 = OpLoad %uint %i_0
+         %61 = OpAccessChain %_ptr_Function_Inner %arr %59
+         %63 = OpLoad %uint %i_0
+         %65 = OpAccessChain %_ptr_Function_Inner_std140 %var_for_index_1 %63
+         %66 = OpLoad %Inner_std140 %65
+         %62 = OpFunctionCall %Inner %conv_Inner %66
+               OpStore %61 %62
+               OpBranch %48
+         %48 = OpLabel
+         %67 = OpLoad %uint %i_0
+         %69 = OpIAdd %uint %67 %uint_1
+               OpStore %i_0 %69
+               OpBranch %46
+         %47 = OpLabel
+         %70 = OpLoad %_arr_Inner_uint_4 %arr
+               OpReturnValue %70
+               OpFunctionEnd
+ %conv_Outer = OpFunction %Outer None %71
+      %val_1 = OpFunctionParameter %Outer_std140
+         %75 = OpLabel
+         %77 = OpCompositeExtract %_arr_Inner_std140_uint_4 %val_1 0
+         %76 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %77
+         %78 = OpCompositeConstruct %Outer %76
+               OpReturnValue %78
+               OpFunctionEnd
+%conv_arr4_Outer = OpFunction %_arr_Outer_uint_4 None %79
+      %val_2 = OpFunctionParameter %_arr_Outer_std140_uint_4
+         %83 = OpLabel
+      %arr_0 = OpVariable %_ptr_Function__arr_Outer_uint_4 Function %86
+        %i_1 = OpVariable %_ptr_Function_uint Function %45
+%var_for_index = OpVariable %_ptr_Function__arr_Outer_std140_uint_4 Function %99
+               OpBranch %88
+         %88 = OpLabel
+               OpLoopMerge %89 %90 None
+               OpBranch %91
+         %91 = OpLabel
+         %93 = OpLoad %uint %i_1
+         %94 = OpULessThan %bool %93 %uint_4
+         %92 = OpLogicalNot %bool %94
+               OpSelectionMerge %95 None
+               OpBranchConditional %92 %96 %95
+         %96 = OpLabel
+               OpBranch %89
+         %95 = OpLabel
+               OpStore %var_for_index %val_2
+        %100 = OpLoad %uint %i_1
+        %102 = OpAccessChain %_ptr_Function_Outer %arr_0 %100
+        %104 = OpLoad %uint %i_1
+        %106 = OpAccessChain %_ptr_Function_Outer_std140 %var_for_index %104
+        %107 = OpLoad %Outer_std140 %106
+        %103 = OpFunctionCall %Outer %conv_Outer %107
+               OpStore %102 %103
+               OpBranch %90
+         %90 = OpLabel
+        %108 = OpLoad %uint %i_1
+        %109 = OpIAdd %uint %108 %uint_1
+               OpStore %i_1 %109
+               OpBranch %88
+         %89 = OpLabel
+        %110 = OpLoad %_arr_Outer_uint_4 %arr_0
+               OpReturnValue %110
+               OpFunctionEnd
+%load_a_inner_p0_a_p1_m = OpFunction %mat4v4half None %111
+         %p0 = OpFunctionParameter %uint
+         %p1 = OpFunctionParameter %uint
+        %115 = OpLabel
+        %119 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %p0 %uint_0 %p1
+        %122 = OpAccessChain %_ptr_Uniform_v4half %119 %uint_0
+        %123 = OpLoad %v4half %122
+        %125 = OpAccessChain %_ptr_Uniform_v4half %119 %uint_1
+        %126 = OpLoad %v4half %125
+        %129 = OpAccessChain %_ptr_Uniform_v4half %119 %uint_2
+        %130 = OpLoad %v4half %129
+        %133 = OpAccessChain %_ptr_Uniform_v4half %119 %uint_3
+        %134 = OpLoad %v4half %133
+        %135 = OpCompositeConstruct %mat4v4half %123 %126 %130 %134
+               OpReturnValue %135
+               OpFunctionEnd
+%load_a_inner_p0_a_p1_m_p2 = OpFunction %v4half None %136
+       %p0_0 = OpFunctionParameter %uint
+       %p1_0 = OpFunctionParameter %uint
+         %p2 = OpFunctionParameter %uint
+        %141 = OpLabel
+               OpSelectionMerge %142 None
+               OpSwitch %p2 %143 0 %144 1 %145 2 %146 3 %147
+        %144 = OpLabel
+        %148 = OpAccessChain %_ptr_Uniform_v4half %a %uint_0 %p0_0 %uint_0 %p1_0 %uint_0
+        %149 = OpLoad %v4half %148
+               OpReturnValue %149
+        %145 = OpLabel
+        %150 = OpAccessChain %_ptr_Uniform_v4half %a %uint_0 %p0_0 %uint_0 %p1_0 %uint_1
+        %151 = OpLoad %v4half %150
+               OpReturnValue %151
+        %146 = OpLabel
+        %152 = OpAccessChain %_ptr_Uniform_v4half %a %uint_0 %p0_0 %uint_0 %p1_0 %uint_2
+        %153 = OpLoad %v4half %152
+               OpReturnValue %153
+        %147 = OpLabel
+        %154 = OpAccessChain %_ptr_Uniform_v4half %a %uint_0 %p0_0 %uint_0 %p1_0 %uint_3
+        %155 = OpLoad %v4half %154
+               OpReturnValue %155
+        %143 = OpLabel
+               OpReturnValue %156
+        %142 = OpLabel
+               OpReturnValue %156
+               OpFunctionEnd
+%load_a_inner_p0_a_p1_m_p2_p3 = OpFunction %half None %157
+       %p0_1 = OpFunctionParameter %uint
+       %p1_1 = OpFunctionParameter %uint
+       %p2_0 = OpFunctionParameter %uint
+         %p3 = OpFunctionParameter %uint
+        %163 = OpLabel
+               OpSelectionMerge %164 None
+               OpSwitch %p2_0 %165 0 %166 1 %167 2 %168 3 %169
+        %166 = OpLabel
+        %171 = OpAccessChain %_ptr_Uniform_half %a %uint_0 %p0_1 %uint_0 %p1_1 %uint_0 %p3
+        %172 = OpLoad %half %171
+               OpReturnValue %172
+        %167 = OpLabel
+        %173 = OpAccessChain %_ptr_Uniform_half %a %uint_0 %p0_1 %uint_0 %p1_1 %uint_1 %p3
+        %174 = OpLoad %half %173
+               OpReturnValue %174
+        %168 = OpLabel
+        %175 = OpAccessChain %_ptr_Uniform_half %a %uint_0 %p0_1 %uint_0 %p1_1 %uint_2 %p3
+        %176 = OpLoad %half %175
+               OpReturnValue %176
+        %169 = OpLabel
+        %177 = OpAccessChain %_ptr_Uniform_half %a %uint_0 %p0_1 %uint_0 %p1_1 %uint_3 %p3
+        %178 = OpLoad %half %177
+               OpReturnValue %178
+        %165 = OpLabel
+               OpReturnValue %179
+        %164 = OpLabel
+               OpReturnValue %179
+               OpFunctionEnd
+          %f = OpFunction %void None %180
+        %183 = OpLabel
+        %184 = OpFunctionCall %int %i
+        %185 = OpFunctionCall %int %i
+        %186 = OpFunctionCall %int %i
+        %189 = OpAccessChain %_ptr_Uniform__arr_Outer_std140_uint_4 %a %uint_0
+        %190 = OpLoad %_arr_Outer_std140_uint_4 %189
+        %187 = OpFunctionCall %_arr_Outer_uint_4 %conv_arr4_Outer %190
+        %193 = OpAccessChain %_ptr_Uniform_Outer_std140 %a %uint_0 %184
+        %194 = OpLoad %Outer_std140 %193
+        %191 = OpFunctionCall %Outer %conv_Outer %194
+        %197 = OpAccessChain %_ptr_Uniform__arr_Inner_std140_uint_4 %a %uint_0 %184 %uint_0
+        %198 = OpLoad %_arr_Inner_std140_uint_4 %197
+        %195 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %198
+        %200 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %184 %uint_0 %185
+        %201 = OpLoad %Inner_std140 %200
+        %199 = OpFunctionCall %Inner %conv_Inner %201
+        %203 = OpBitcast %uint %184
+        %204 = OpBitcast %uint %185
+        %202 = OpFunctionCall %mat4v4half %load_a_inner_p0_a_p1_m %203 %204
+        %206 = OpBitcast %uint %184
+        %207 = OpBitcast %uint %185
+        %208 = OpBitcast %uint %186
+        %205 = OpFunctionCall %v4half %load_a_inner_p0_a_p1_m_p2 %206 %207 %208
+        %209 = OpFunctionCall %int %i
+        %211 = OpBitcast %uint %184
+        %212 = OpBitcast %uint %185
+        %213 = OpBitcast %uint %186
+        %214 = OpBitcast %uint %209
+        %210 = OpFunctionCall %half %load_a_inner_p0_a_p1_m_p2_p3 %211 %212 %213 %214
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..181af9f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,36 @@
+enable f16;
+
+struct Inner {
+  @size(64)
+  m : mat4x4<f16>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_i = &((*(p_a))[i()]);
+  let p_a_i_a = &((*(p_a_i)).a);
+  let p_a_i_a_i = &((*(p_a_i_a))[i()]);
+  let p_a_i_a_i_m = &((*(p_a_i_a_i)).m);
+  let p_a_i_a_i_m_i = &((*(p_a_i_a_i_m))[i()]);
+  let l_a : array<Outer, 4> = *(p_a);
+  let l_a_i : Outer = *(p_a_i);
+  let l_a_i_a : array<Inner, 4> = *(p_a_i_a);
+  let l_a_i_a_i : Inner = *(p_a_i_a_i);
+  let l_a_i_a_i_m : mat4x4<f16> = *(p_a_i_a_i_m);
+  let l_a_i_a_i_m_i : vec4<f16> = *(p_a_i_a_i_m_i);
+  let l_a_i_a_i_m_i_i : f16 = (*(p_a_i_a_i_m_i))[i()];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/static_index_via_ptr.wgsl
new file mode 100644
index 0000000..d8ec543
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/static_index_via_ptr.wgsl
@@ -0,0 +1,31 @@
+enable f16;
+
+struct Inner {
+  @size(64)
+  m : mat4x4<f16>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &a;
+  let p_a_3 = &((*p_a)[3]);
+  let p_a_3_a = &((*p_a_3).a);
+  let p_a_3_a_2 = &((*p_a_3_a)[2]);
+  let p_a_3_a_2_m = &((*p_a_3_a_2).m);
+  let p_a_3_a_2_m_1 = &((*p_a_3_a_2_m)[1]);
+
+
+  let l_a             : array<Outer, 4> = *p_a;
+  let l_a_3           : Outer           = *p_a_3;
+  let l_a_3_a         : array<Inner, 4> = *p_a_3_a;
+  let l_a_3_a_2       : Inner           = *p_a_3_a_2;
+  let l_a_3_a_2_m     : mat4x4<f16>     = *p_a_3_a_2_m;
+  let l_a_3_a_2_m_1   : vec4<f16>       = *p_a_3_a_2_m_1;
+  let l_a_3_a_2_m_1_0 : f16             = (*p_a_3_a_2_m_1)[0];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..5af54cf
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,81 @@
+struct Inner {
+  matrix<float16_t, 4, 4> m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+
+matrix<float16_t, 4, 4> tint_symbol_4(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+}
+
+Inner tint_symbol_3(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_7 = {tint_symbol_4(buffer, (offset + 0u))};
+  return tint_symbol_7;
+}
+
+typedef Inner tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_3(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_1(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_8 = {tint_symbol_2(buffer, (offset + 0u))};
+  return tint_symbol_8;
+}
+
+typedef Outer tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr_1[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const Outer l_a[4] = tint_symbol(a, 0u);
+  const Outer l_a_3 = tint_symbol_1(a, 768u);
+  const Inner l_a_3_a[4] = tint_symbol_2(a, 768u);
+  const Inner l_a_3_a_2 = tint_symbol_3(a, 896u);
+  const matrix<float16_t, 4, 4> l_a_3_a_2_m = tint_symbol_4(a, 896u);
+  uint2 ubo_load_8 = a[56].zw;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_8_yw = vector<float16_t, 2>(f16tof32(ubo_load_8 >> 16));
+  const vector<float16_t, 4> l_a_3_a_2_m_1 = vector<float16_t, 4>(ubo_load_8_xz[0], ubo_load_8_yw[0], ubo_load_8_xz[1], ubo_load_8_yw[1]);
+  const float16_t l_a_3_a_2_m_1_0 = float16_t(f16tof32(((a[56].z) & 0xFFFF)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..cb11b50
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,86 @@
+SKIP: FAILED
+
+struct Inner {
+  matrix<float16_t, 4, 4> m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+
+matrix<float16_t, 4, 4> tint_symbol_4(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+}
+
+Inner tint_symbol_3(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_7 = {tint_symbol_4(buffer, (offset + 0u))};
+  return tint_symbol_7;
+}
+
+typedef Inner tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_3(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_1(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_8 = {tint_symbol_2(buffer, (offset + 0u))};
+  return tint_symbol_8;
+}
+
+typedef Outer tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr_1[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const Outer l_a[4] = tint_symbol(a, 0u);
+  const Outer l_a_3 = tint_symbol_1(a, 768u);
+  const Inner l_a_3_a[4] = tint_symbol_2(a, 768u);
+  const Inner l_a_3_a_2 = tint_symbol_3(a, 896u);
+  const matrix<float16_t, 4, 4> l_a_3_a_2_m = tint_symbol_4(a, 896u);
+  uint2 ubo_load_8 = a[56].zw;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_8_yw = vector<float16_t, 2>(f16tof32(ubo_load_8 >> 16));
+  const vector<float16_t, 4> l_a_3_a_2_m_1 = vector<float16_t, 4>(ubo_load_8_xz[0], ubo_load_8_yw[0], ubo_load_8_xz[1], ubo_load_8_yw[1]);
+  const float16_t l_a_3_a_2_m_1_0 = float16_t(f16tof32(((a[56].z) & 0xFFFF)));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000015C09593480(2,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/static_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..c87dc31
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/static_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,95 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct Inner {
+  f16mat4 m;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+};
+
+struct Inner_std140 {
+  f16vec4 m_0;
+  f16vec4 m_1;
+  f16vec4 m_2;
+  f16vec4 m_3;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+};
+
+struct Outer {
+  Inner a[4];
+};
+
+struct Outer_std140 {
+  Inner_std140 a[4];
+};
+
+layout(binding = 0, std140) uniform a_block_std140_ubo {
+  Outer_std140 inner[4];
+} a;
+
+Inner conv_Inner(Inner_std140 val) {
+  return Inner(f16mat4(val.m_0, val.m_1, val.m_2, val.m_3), val.pad, val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.pad_7);
+}
+
+Inner[4] conv_arr4_Inner(Inner_std140 val[4]) {
+  Inner arr[4] = Inner[4](Inner(f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_Inner(val[i]);
+    }
+  }
+  return arr;
+}
+
+Outer conv_Outer(Outer_std140 val) {
+  return Outer(conv_arr4_Inner(val.a));
+}
+
+Outer[4] conv_arr4_Outer(Outer_std140 val[4]) {
+  Outer arr[4] = Outer[4](Outer(Inner[4](Inner(f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))), Outer(Inner[4](Inner(f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), Inner(f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u))));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_Outer(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat4 load_a_inner_3_a_2_m() {
+  return f16mat4(a.inner[3u].a[2u].m_0, a.inner[3u].a[2u].m_1, a.inner[3u].a[2u].m_2, a.inner[3u].a[2u].m_3);
+}
+
+void f() {
+  Outer p_a[4] = conv_arr4_Outer(a.inner);
+  Outer p_a_3 = conv_Outer(a.inner[3u]);
+  Inner p_a_3_a[4] = conv_arr4_Inner(a.inner[3u].a);
+  Inner p_a_3_a_2 = conv_Inner(a.inner[3u].a[2u]);
+  f16mat4 p_a_3_a_2_m = load_a_inner_3_a_2_m();
+  f16vec4 p_a_3_a_2_m_1 = a.inner[3u].a[2u].m_1;
+  Outer l_a[4] = conv_arr4_Outer(a.inner);
+  Outer l_a_3 = conv_Outer(a.inner[3u]);
+  Inner l_a_3_a[4] = conv_arr4_Inner(a.inner[3u].a);
+  Inner l_a_3_a_2 = conv_Inner(a.inner[3u].a[2u]);
+  f16mat4 l_a_3_a_2_m = load_a_inner_3_a_2_m();
+  f16vec4 l_a_3_a_2_m_1 = a.inner[3u].a[2u].m_1;
+  float16_t l_a_3_a_2_m_1_0 = a.inner[3u].a[2u].m_1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/static_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..1f4ea61
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/static_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,36 @@
+#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 Inner {
+  /* 0x0000 */ half4x4 m;
+  /* 0x0020 */ tint_array<int8_t, 32> tint_pad;
+};
+
+struct Outer {
+  /* 0x0000 */ tint_array<Inner, 4> a;
+};
+
+kernel void f(const constant tint_array<Outer, 4>* tint_symbol [[buffer(0)]]) {
+  tint_array<Outer, 4> const l_a = *(tint_symbol);
+  Outer const l_a_3 = (*(tint_symbol))[3];
+  tint_array<Inner, 4> const l_a_3_a = (*(tint_symbol))[3].a;
+  Inner const l_a_3_a_2 = (*(tint_symbol))[3].a[2];
+  half4x4 const l_a_3_a_2_m = (*(tint_symbol))[3].a[2].m;
+  half4 const l_a_3_a_2_m_1 = (*(tint_symbol))[3].a[2].m[1];
+  half const l_a_3_a_2_m_1_0 = (*(tint_symbol))[3].a[2].m[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/static_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..e9f2926
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/static_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,237 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 148
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block_std140 "a_block_std140"
+               OpMemberName %a_block_std140 0 "inner"
+               OpName %Outer_std140 "Outer_std140"
+               OpMemberName %Outer_std140 0 "a"
+               OpName %Inner_std140 "Inner_std140"
+               OpMemberName %Inner_std140 0 "m_0"
+               OpMemberName %Inner_std140 1 "m_1"
+               OpMemberName %Inner_std140 2 "m_2"
+               OpMemberName %Inner_std140 3 "m_3"
+               OpName %a "a"
+               OpName %Inner "Inner"
+               OpMemberName %Inner 0 "m"
+               OpName %conv_Inner "conv_Inner"
+               OpName %val "val"
+               OpName %conv_arr4_Inner "conv_arr4_Inner"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index_1 "var_for_index_1"
+               OpName %Outer "Outer"
+               OpMemberName %Outer 0 "a"
+               OpName %conv_Outer "conv_Outer"
+               OpName %val_1 "val"
+               OpName %conv_arr4_Outer "conv_arr4_Outer"
+               OpName %val_2 "val"
+               OpName %arr_0 "arr"
+               OpName %i_0 "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_a_inner_3_a_2_m "load_a_inner_3_a_2_m"
+               OpName %f "f"
+               OpDecorate %a_block_std140 Block
+               OpMemberDecorate %a_block_std140 0 Offset 0
+               OpMemberDecorate %Outer_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 1 Offset 8
+               OpMemberDecorate %Inner_std140 2 Offset 16
+               OpMemberDecorate %Inner_std140 3 Offset 24
+               OpDecorate %_arr_Inner_std140_uint_4 ArrayStride 64
+               OpDecorate %_arr_Outer_std140_uint_4 ArrayStride 256
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+               OpMemberDecorate %Inner 0 Offset 0
+               OpMemberDecorate %Inner 0 ColMajor
+               OpMemberDecorate %Inner 0 MatrixStride 8
+               OpDecorate %_arr_Inner_uint_4 ArrayStride 64
+               OpMemberDecorate %Outer 0 Offset 0
+               OpDecorate %_arr_Outer_uint_4 ArrayStride 256
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+%Inner_std140 = OpTypeStruct %v4half %v4half %v4half %v4half
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_Inner_std140_uint_4 = OpTypeArray %Inner_std140 %uint_4
+%Outer_std140 = OpTypeStruct %_arr_Inner_std140_uint_4
+%_arr_Outer_std140_uint_4 = OpTypeArray %Outer_std140 %uint_4
+%a_block_std140 = OpTypeStruct %_arr_Outer_std140_uint_4
+%_ptr_Uniform_a_block_std140 = OpTypePointer Uniform %a_block_std140
+          %a = OpVariable %_ptr_Uniform_a_block_std140 Uniform
+ %mat4v4half = OpTypeMatrix %v4half 4
+      %Inner = OpTypeStruct %mat4v4half
+         %12 = OpTypeFunction %Inner %Inner_std140
+%_arr_Inner_uint_4 = OpTypeArray %Inner %uint_4
+         %24 = OpTypeFunction %_arr_Inner_uint_4 %_arr_Inner_std140_uint_4
+%_ptr_Function__arr_Inner_uint_4 = OpTypePointer Function %_arr_Inner_uint_4
+         %31 = OpConstantNull %_arr_Inner_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %34 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_Inner_std140_uint_4 = OpTypePointer Function %_arr_Inner_std140_uint_4
+         %47 = OpConstantNull %_arr_Inner_std140_uint_4
+%_ptr_Function_Inner = OpTypePointer Function %Inner
+%_ptr_Function_Inner_std140 = OpTypePointer Function %Inner_std140
+     %uint_1 = OpConstant %uint 1
+      %Outer = OpTypeStruct %_arr_Inner_uint_4
+         %60 = OpTypeFunction %Outer %Outer_std140
+%_arr_Outer_uint_4 = OpTypeArray %Outer %uint_4
+         %68 = OpTypeFunction %_arr_Outer_uint_4 %_arr_Outer_std140_uint_4
+%_ptr_Function__arr_Outer_uint_4 = OpTypePointer Function %_arr_Outer_uint_4
+         %75 = OpConstantNull %_arr_Outer_uint_4
+%_ptr_Function__arr_Outer_std140_uint_4 = OpTypePointer Function %_arr_Outer_std140_uint_4
+         %88 = OpConstantNull %_arr_Outer_std140_uint_4
+%_ptr_Function_Outer = OpTypePointer Function %Outer
+%_ptr_Function_Outer_std140 = OpTypePointer Function %Outer_std140
+        %100 = OpTypeFunction %mat4v4half
+     %uint_0 = OpConstant %uint 0
+     %uint_3 = OpConstant %uint 3
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_Inner_std140 = OpTypePointer Uniform %Inner_std140
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+       %void = OpTypeVoid
+        %123 = OpTypeFunction %void
+%_ptr_Uniform__arr_Outer_std140_uint_4 = OpTypePointer Uniform %_arr_Outer_std140_uint_4
+%_ptr_Uniform_Outer_std140 = OpTypePointer Uniform %Outer_std140
+%_ptr_Uniform__arr_Inner_std140_uint_4 = OpTypePointer Uniform %_arr_Inner_std140_uint_4
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+ %conv_Inner = OpFunction %Inner None %12
+        %val = OpFunctionParameter %Inner_std140
+         %17 = OpLabel
+         %18 = OpCompositeExtract %v4half %val 0
+         %19 = OpCompositeExtract %v4half %val 1
+         %20 = OpCompositeExtract %v4half %val 2
+         %21 = OpCompositeExtract %v4half %val 3
+         %22 = OpCompositeConstruct %mat4v4half %18 %19 %20 %21
+         %23 = OpCompositeConstruct %Inner %22
+               OpReturnValue %23
+               OpFunctionEnd
+%conv_arr4_Inner = OpFunction %_arr_Inner_uint_4 None %24
+      %val_0 = OpFunctionParameter %_arr_Inner_std140_uint_4
+         %28 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_Inner_uint_4 Function %31
+          %i = OpVariable %_ptr_Function_uint Function %34
+%var_for_index_1 = OpVariable %_ptr_Function__arr_Inner_std140_uint_4 Function %47
+               OpBranch %35
+         %35 = OpLabel
+               OpLoopMerge %36 %37 None
+               OpBranch %38
+         %38 = OpLabel
+         %40 = OpLoad %uint %i
+         %41 = OpULessThan %bool %40 %uint_4
+         %39 = OpLogicalNot %bool %41
+               OpSelectionMerge %43 None
+               OpBranchConditional %39 %44 %43
+         %44 = OpLabel
+               OpBranch %36
+         %43 = OpLabel
+               OpStore %var_for_index_1 %val_0
+         %48 = OpLoad %uint %i
+         %50 = OpAccessChain %_ptr_Function_Inner %arr %48
+         %52 = OpLoad %uint %i
+         %54 = OpAccessChain %_ptr_Function_Inner_std140 %var_for_index_1 %52
+         %55 = OpLoad %Inner_std140 %54
+         %51 = OpFunctionCall %Inner %conv_Inner %55
+               OpStore %50 %51
+               OpBranch %37
+         %37 = OpLabel
+         %56 = OpLoad %uint %i
+         %58 = OpIAdd %uint %56 %uint_1
+               OpStore %i %58
+               OpBranch %35
+         %36 = OpLabel
+         %59 = OpLoad %_arr_Inner_uint_4 %arr
+               OpReturnValue %59
+               OpFunctionEnd
+ %conv_Outer = OpFunction %Outer None %60
+      %val_1 = OpFunctionParameter %Outer_std140
+         %64 = OpLabel
+         %66 = OpCompositeExtract %_arr_Inner_std140_uint_4 %val_1 0
+         %65 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %66
+         %67 = OpCompositeConstruct %Outer %65
+               OpReturnValue %67
+               OpFunctionEnd
+%conv_arr4_Outer = OpFunction %_arr_Outer_uint_4 None %68
+      %val_2 = OpFunctionParameter %_arr_Outer_std140_uint_4
+         %72 = OpLabel
+      %arr_0 = OpVariable %_ptr_Function__arr_Outer_uint_4 Function %75
+        %i_0 = OpVariable %_ptr_Function_uint Function %34
+%var_for_index = OpVariable %_ptr_Function__arr_Outer_std140_uint_4 Function %88
+               OpBranch %77
+         %77 = OpLabel
+               OpLoopMerge %78 %79 None
+               OpBranch %80
+         %80 = OpLabel
+         %82 = OpLoad %uint %i_0
+         %83 = OpULessThan %bool %82 %uint_4
+         %81 = OpLogicalNot %bool %83
+               OpSelectionMerge %84 None
+               OpBranchConditional %81 %85 %84
+         %85 = OpLabel
+               OpBranch %78
+         %84 = OpLabel
+               OpStore %var_for_index %val_2
+         %89 = OpLoad %uint %i_0
+         %91 = OpAccessChain %_ptr_Function_Outer %arr_0 %89
+         %93 = OpLoad %uint %i_0
+         %95 = OpAccessChain %_ptr_Function_Outer_std140 %var_for_index %93
+         %96 = OpLoad %Outer_std140 %95
+         %92 = OpFunctionCall %Outer %conv_Outer %96
+               OpStore %91 %92
+               OpBranch %79
+         %79 = OpLabel
+         %97 = OpLoad %uint %i_0
+         %98 = OpIAdd %uint %97 %uint_1
+               OpStore %i_0 %98
+               OpBranch %77
+         %78 = OpLabel
+         %99 = OpLoad %_arr_Outer_uint_4 %arr_0
+               OpReturnValue %99
+               OpFunctionEnd
+%load_a_inner_3_a_2_m = OpFunction %mat4v4half None %100
+        %102 = OpLabel
+        %108 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %uint_3 %uint_0 %uint_2
+        %111 = OpAccessChain %_ptr_Uniform_v4half %108 %uint_0
+        %112 = OpLoad %v4half %111
+        %114 = OpAccessChain %_ptr_Uniform_v4half %108 %uint_1
+        %115 = OpLoad %v4half %114
+        %117 = OpAccessChain %_ptr_Uniform_v4half %108 %uint_2
+        %118 = OpLoad %v4half %117
+        %120 = OpAccessChain %_ptr_Uniform_v4half %108 %uint_3
+        %121 = OpLoad %v4half %120
+        %122 = OpCompositeConstruct %mat4v4half %112 %115 %118 %121
+               OpReturnValue %122
+               OpFunctionEnd
+          %f = OpFunction %void None %123
+        %126 = OpLabel
+        %129 = OpAccessChain %_ptr_Uniform__arr_Outer_std140_uint_4 %a %uint_0
+        %130 = OpLoad %_arr_Outer_std140_uint_4 %129
+        %127 = OpFunctionCall %_arr_Outer_uint_4 %conv_arr4_Outer %130
+        %133 = OpAccessChain %_ptr_Uniform_Outer_std140 %a %uint_0 %uint_3
+        %134 = OpLoad %Outer_std140 %133
+        %131 = OpFunctionCall %Outer %conv_Outer %134
+        %137 = OpAccessChain %_ptr_Uniform__arr_Inner_std140_uint_4 %a %uint_0 %uint_3 %uint_0
+        %138 = OpLoad %_arr_Inner_std140_uint_4 %137
+        %135 = OpFunctionCall %_arr_Inner_uint_4 %conv_arr4_Inner %138
+        %140 = OpAccessChain %_ptr_Uniform_Inner_std140 %a %uint_0 %uint_3 %uint_0 %uint_2
+        %141 = OpLoad %Inner_std140 %140
+        %139 = OpFunctionCall %Inner %conv_Inner %141
+        %142 = OpFunctionCall %mat4v4half %load_a_inner_3_a_2_m
+        %143 = OpAccessChain %_ptr_Uniform_v4half %a %uint_0 %uint_3 %uint_0 %uint_2 %uint_1
+        %144 = OpLoad %v4half %143
+        %146 = OpAccessChain %_ptr_Uniform_half %a %uint_0 %uint_3 %uint_0 %uint_2 %uint_1 %34
+        %147 = OpLoad %half %146
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/static_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..152ccef
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/static_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,29 @@
+enable f16;
+
+struct Inner {
+  @size(64)
+  m : mat4x4<f16>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_3 = &((*(p_a))[3]);
+  let p_a_3_a = &((*(p_a_3)).a);
+  let p_a_3_a_2 = &((*(p_a_3_a))[2]);
+  let p_a_3_a_2_m = &((*(p_a_3_a_2)).m);
+  let p_a_3_a_2_m_1 = &((*(p_a_3_a_2_m))[1]);
+  let l_a : array<Outer, 4> = *(p_a);
+  let l_a_3 : Outer = *(p_a_3);
+  let l_a_3_a : array<Inner, 4> = *(p_a_3_a);
+  let l_a_3_a_2 : Inner = *(p_a_3_a_2);
+  let l_a_3_a_2_m : mat4x4<f16> = *(p_a_3_a_2_m);
+  let l_a_3_a_2_m_1 : vec4<f16> = *(p_a_3_a_2_m_1);
+  let l_a_3_a_2_m_1_0 : f16 = (*(p_a_3_a_2_m_1))[0];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_builtin.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_builtin.wgsl
new file mode 100644
index 0000000..3157732
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_builtin.wgsl
@@ -0,0 +1,17 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat4x4<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    let t = transpose(u[2].m);
+    let l = length(u[0].m[1].ywxz);
+    let a = abs(u[0].m[1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_builtin.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..fdce8e0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_builtin.wgsl.expected.dxc.hlsl
@@ -0,0 +1,41 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+matrix<float16_t, 4, 4> tint_symbol(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 4, 4> t = transpose(tint_symbol(u, 264u));
+  uint2 ubo_load_8 = u[1].xy;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_8_yw = vector<float16_t, 2>(f16tof32(ubo_load_8 >> 16));
+  const float16_t l = length(vector<float16_t, 4>(ubo_load_8_xz[0], ubo_load_8_yw[0], ubo_load_8_xz[1], ubo_load_8_yw[1]).ywxz);
+  uint2 ubo_load_9 = u[1].xy;
+  vector<float16_t, 2> ubo_load_9_xz = vector<float16_t, 2>(f16tof32(ubo_load_9 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_9_yw = vector<float16_t, 2>(f16tof32(ubo_load_9 >> 16));
+  const float16_t a = abs(vector<float16_t, 4>(ubo_load_9_xz[0], ubo_load_9_yw[0], ubo_load_9_xz[1], ubo_load_9_yw[1]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_builtin.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..05b1dfe
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_builtin.wgsl.expected.fxc.hlsl
@@ -0,0 +1,46 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+matrix<float16_t, 4, 4> tint_symbol(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 4, 4> t = transpose(tint_symbol(u, 264u));
+  uint2 ubo_load_8 = u[1].xy;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_8_yw = vector<float16_t, 2>(f16tof32(ubo_load_8 >> 16));
+  const float16_t l = length(vector<float16_t, 4>(ubo_load_8_xz[0], ubo_load_8_yw[0], ubo_load_8_xz[1], ubo_load_8_yw[1]).ywxz);
+  uint2 ubo_load_9 = u[1].xy;
+  vector<float16_t, 2> ubo_load_9_xz = vector<float16_t, 2>(f16tof32(ubo_load_9 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_9_yw = vector<float16_t, 2>(f16tof32(ubo_load_9 >> 16));
+  const float16_t a = abs(vector<float16_t, 4>(ubo_load_9_xz[0], ubo_load_9_yw[0], ubo_load_9_xz[1], ubo_load_9_yw[1]).ywxz.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000025F14CDF3D0(5,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_builtin.wgsl.expected.glsl
new file mode 100644
index 0000000..cb628a8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_builtin.wgsl.expected.glsl
@@ -0,0 +1,81 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct S {
+  int before;
+  uint pad;
+  f16mat4 m;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  int after;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+};
+
+struct S_std140 {
+  int before;
+  uint pad;
+  f16vec4 m_0;
+  f16vec4 m_1;
+  f16vec4 m_2;
+  f16vec4 m_3;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  int after;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+f16mat4 load_u_inner_2_m() {
+  return f16mat4(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2, u.inner[2u].m_3);
+}
+
+void f() {
+  f16mat4 t = transpose(load_u_inner_2_m());
+  float16_t l = length(u.inner[0u].m_1.ywxz);
+  float16_t a = abs(u.inner[0u].m_1.ywxz[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_builtin.wgsl.expected.msl
new file mode 100644
index 0000000..7f59502
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_builtin.wgsl.expected.msl
@@ -0,0 +1,32 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0008 */ half4x4 m;
+  /* 0x0028 */ tint_array<int8_t, 24> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol [[buffer(0)]]) {
+  half4x4 const t = transpose((*(tint_symbol))[2].m);
+  half const l = length(half4((*(tint_symbol))[0].m[1]).ywxz);
+  half const a = fabs(half4((*(tint_symbol))[0].m[1]).ywxz[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_builtin.wgsl.expected.spvasm
new file mode 100644
index 0000000..03b661d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_builtin.wgsl.expected.spvasm
@@ -0,0 +1,88 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 53
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+         %43 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "m_2"
+               OpMemberName %S_std140 4 "m_3"
+               OpMemberName %S_std140 5 "after"
+               OpName %u "u"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 8
+               OpMemberDecorate %S_std140 2 Offset 16
+               OpMemberDecorate %S_std140 3 Offset 24
+               OpMemberDecorate %S_std140 4 Offset 32
+               OpMemberDecorate %S_std140 5 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+   %S_std140 = OpTypeStruct %int %v4half %v4half %v4half %v4half %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat4v4half = OpTypeMatrix %v4half 4
+         %11 = OpTypeFunction %mat4v4half
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+     %uint_1 = OpConstant %uint 1
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %36 = OpTypeFunction %void
+         %44 = OpConstantNull %uint
+%load_u_inner_2_m = OpFunction %mat4v4half None %11
+         %14 = OpLabel
+         %19 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %23 = OpAccessChain %_ptr_Uniform_v4half %19 %uint_1
+         %24 = OpLoad %v4half %23
+         %26 = OpAccessChain %_ptr_Uniform_v4half %19 %uint_2
+         %27 = OpLoad %v4half %26
+         %30 = OpAccessChain %_ptr_Uniform_v4half %19 %uint_3
+         %31 = OpLoad %v4half %30
+         %33 = OpAccessChain %_ptr_Uniform_v4half %19 %uint_4
+         %34 = OpLoad %v4half %33
+         %35 = OpCompositeConstruct %mat4v4half %24 %27 %31 %34
+               OpReturnValue %35
+               OpFunctionEnd
+          %f = OpFunction %void None %36
+         %39 = OpLabel
+         %41 = OpFunctionCall %mat4v4half %load_u_inner_2_m
+         %40 = OpTranspose %mat4v4half %41
+         %45 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0 %44 %uint_2
+         %46 = OpLoad %v4half %45
+         %47 = OpVectorShuffle %v4half %46 %46 1 3 0 2
+         %42 = OpExtInst %half %43 Length %47
+         %49 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0 %44 %uint_2
+         %50 = OpLoad %v4half %49
+         %51 = OpVectorShuffle %v4half %50 %50 1 3 0 2
+         %52 = OpCompositeExtract %half %51 0
+         %48 = OpExtInst %half %43 FAbs %52
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_builtin.wgsl.expected.wgsl
new file mode 100644
index 0000000..125c5e3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_builtin.wgsl.expected.wgsl
@@ -0,0 +1,17 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat4x4<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let t = transpose(u[2].m);
+  let l = length(u[0].m[1].ywxz);
+  let a = abs(u[0].m[1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_fn.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_fn.wgsl
new file mode 100644
index 0000000..8842fbe
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_fn.wgsl
@@ -0,0 +1,25 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat4x4<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+fn a(a : array<S, 4>) {}
+fn b(s : S) {}
+fn c(m : mat4x4<f16>) {}
+fn d(v : vec4<f16>) {}
+fn e(f : f16) {}
+
+@compute @workgroup_size(1)
+fn f() {
+    a(u);
+    b(u[2]);
+    c(u[2].m);
+    d(u[0].m[1].ywxz);
+    e(u[0].m[1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_fn.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..9b871b4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_fn.wgsl.expected.dxc.hlsl
@@ -0,0 +1,82 @@
+struct S {
+  int before;
+  matrix<float16_t, 4, 4> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(matrix<float16_t, 4, 4> m) {
+}
+
+void d(vector<float16_t, 4> v) {
+}
+
+void e(float16_t f_1) {
+}
+
+matrix<float16_t, 4, 4> tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 256u));
+  c(tint_symbol_3(u, 264u));
+  uint2 ubo_load_8 = u[1].xy;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_8_yw = vector<float16_t, 2>(f16tof32(ubo_load_8 >> 16));
+  d(vector<float16_t, 4>(ubo_load_8_xz[0], ubo_load_8_yw[0], ubo_load_8_xz[1], ubo_load_8_yw[1]).ywxz);
+  uint2 ubo_load_9 = u[1].xy;
+  vector<float16_t, 2> ubo_load_9_xz = vector<float16_t, 2>(f16tof32(ubo_load_9 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_9_yw = vector<float16_t, 2>(f16tof32(ubo_load_9 >> 16));
+  e(vector<float16_t, 4>(ubo_load_9_xz[0], ubo_load_9_yw[0], ubo_load_9_xz[1], ubo_load_9_yw[1]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_fn.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..e6dbe02
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_fn.wgsl.expected.fxc.hlsl
@@ -0,0 +1,87 @@
+SKIP: FAILED
+
+struct S {
+  int before;
+  matrix<float16_t, 4, 4> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(matrix<float16_t, 4, 4> m) {
+}
+
+void d(vector<float16_t, 4> v) {
+}
+
+void e(float16_t f_1) {
+}
+
+matrix<float16_t, 4, 4> tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 256u));
+  c(tint_symbol_3(u, 264u));
+  uint2 ubo_load_8 = u[1].xy;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_8_yw = vector<float16_t, 2>(f16tof32(ubo_load_8 >> 16));
+  d(vector<float16_t, 4>(ubo_load_8_xz[0], ubo_load_8_yw[0], ubo_load_8_xz[1], ubo_load_8_yw[1]).ywxz);
+  uint2 ubo_load_9 = u[1].xy;
+  vector<float16_t, 2> ubo_load_9_xz = vector<float16_t, 2>(f16tof32(ubo_load_9 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_9_yw = vector<float16_t, 2>(f16tof32(ubo_load_9 >> 16));
+  e(vector<float16_t, 4>(ubo_load_9_xz[0], ubo_load_9_yw[0], ubo_load_9_xz[1], ubo_load_9_yw[1]).ywxz.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x00000151DEE459C0(3,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_fn.wgsl.expected.glsl
new file mode 100644
index 0000000..21ad3bf
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_fn.wgsl.expected.glsl
@@ -0,0 +1,112 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct S {
+  int before;
+  uint pad;
+  f16mat4 m;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  int after;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+};
+
+struct S_std140 {
+  int before;
+  uint pad;
+  f16vec4 m_0;
+  f16vec4 m_1;
+  f16vec4 m_2;
+  f16vec4 m_3;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  int after;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(f16mat4 m) {
+}
+
+void d(f16vec4 v) {
+}
+
+void e(float16_t f_1) {
+}
+
+S conv_S(S_std140 val) {
+  return S(val.before, val.pad, f16mat4(val.m_0, val.m_1, val.m_2, val.m_3), val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.after, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.pad_11, val.pad_12, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, 0u, f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat4 load_u_inner_2_m() {
+  return f16mat4(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2, u.inner[2u].m_3);
+}
+
+void f() {
+  a(conv_arr4_S(u.inner));
+  b(conv_S(u.inner[2u]));
+  c(load_u_inner_2_m());
+  d(u.inner[0u].m_1.ywxz);
+  e(u.inner[0u].m_1.ywxz[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_fn.wgsl.expected.msl
new file mode 100644
index 0000000..7524e8b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_fn.wgsl.expected.msl
@@ -0,0 +1,49 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0008 */ half4x4 m;
+  /* 0x0028 */ tint_array<int8_t, 24> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+void a(tint_array<S, 4> a_1) {
+}
+
+void b(S s) {
+}
+
+void c(half4x4 m) {
+}
+
+void d(half4 v) {
+}
+
+void e(half f_1) {
+}
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol [[buffer(0)]]) {
+  a(*(tint_symbol));
+  b((*(tint_symbol))[2]);
+  c((*(tint_symbol))[2].m);
+  d(half4((*(tint_symbol))[0].m[1]).ywxz);
+  e(half4((*(tint_symbol))[0].m[1]).ywxz[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_fn.wgsl.expected.spvasm
new file mode 100644
index 0000000..c830e91
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_fn.wgsl.expected.spvasm
@@ -0,0 +1,215 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 128
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "m_2"
+               OpMemberName %S_std140 4 "m_3"
+               OpMemberName %S_std140 5 "after"
+               OpName %u "u"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %a "a"
+               OpName %a_1 "a_1"
+               OpName %b "b"
+               OpName %s "s"
+               OpName %c "c"
+               OpName %m "m"
+               OpName %d "d"
+               OpName %v "v"
+               OpName %e "e"
+               OpName %f_1 "f_1"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 8
+               OpMemberDecorate %S_std140 2 Offset 16
+               OpMemberDecorate %S_std140 3 Offset 24
+               OpMemberDecorate %S_std140 4 Offset 32
+               OpMemberDecorate %S_std140 5 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 8
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 8
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+   %S_std140 = OpTypeStruct %int %v4half %v4half %v4half %v4half %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+       %void = OpTypeVoid
+ %mat4v4half = OpTypeMatrix %v4half 4
+          %S = OpTypeStruct %int %mat4v4half %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+         %11 = OpTypeFunction %void %_arr_S_uint_4
+         %19 = OpTypeFunction %void %S
+         %23 = OpTypeFunction %void %mat4v4half
+         %27 = OpTypeFunction %void %v4half
+         %31 = OpTypeFunction %void %half
+         %35 = OpTypeFunction %S %S_std140
+         %47 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+         %53 = OpConstantNull %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %56 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %69 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %82 = OpTypeFunction %mat4v4half
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+     %uint_3 = OpConstant %uint 3
+        %105 = OpTypeFunction %void
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+          %a = OpFunction %void None %11
+        %a_1 = OpFunctionParameter %_arr_S_uint_4
+         %18 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %b = OpFunction %void None %19
+          %s = OpFunctionParameter %S
+         %22 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %c = OpFunction %void None %23
+          %m = OpFunctionParameter %mat4v4half
+         %26 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %d = OpFunction %void None %27
+          %v = OpFunctionParameter %v4half
+         %30 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %e = OpFunction %void None %31
+        %f_1 = OpFunctionParameter %half
+         %34 = OpLabel
+               OpReturn
+               OpFunctionEnd
+     %conv_S = OpFunction %S None %35
+        %val = OpFunctionParameter %S_std140
+         %38 = OpLabel
+         %39 = OpCompositeExtract %int %val 0
+         %40 = OpCompositeExtract %v4half %val 1
+         %41 = OpCompositeExtract %v4half %val 2
+         %42 = OpCompositeExtract %v4half %val 3
+         %43 = OpCompositeExtract %v4half %val 4
+         %44 = OpCompositeConstruct %mat4v4half %40 %41 %42 %43
+         %45 = OpCompositeExtract %int %val 5
+         %46 = OpCompositeConstruct %S %39 %44 %45
+               OpReturnValue %46
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %47
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %50 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %53
+          %i = OpVariable %_ptr_Function_uint Function %56
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %69
+               OpBranch %57
+         %57 = OpLabel
+               OpLoopMerge %58 %59 None
+               OpBranch %60
+         %60 = OpLabel
+         %62 = OpLoad %uint %i
+         %63 = OpULessThan %bool %62 %uint_4
+         %61 = OpLogicalNot %bool %63
+               OpSelectionMerge %65 None
+               OpBranchConditional %61 %66 %65
+         %66 = OpLabel
+               OpBranch %58
+         %65 = OpLabel
+               OpStore %var_for_index %val_0
+         %70 = OpLoad %uint %i
+         %72 = OpAccessChain %_ptr_Function_S %arr %70
+         %74 = OpLoad %uint %i
+         %76 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %74
+         %77 = OpLoad %S_std140 %76
+         %73 = OpFunctionCall %S %conv_S %77
+               OpStore %72 %73
+               OpBranch %59
+         %59 = OpLabel
+         %78 = OpLoad %uint %i
+         %80 = OpIAdd %uint %78 %uint_1
+               OpStore %i %80
+               OpBranch %57
+         %58 = OpLabel
+         %81 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %81
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat4v4half None %82
+         %84 = OpLabel
+         %89 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %92 = OpAccessChain %_ptr_Uniform_v4half %89 %uint_1
+         %93 = OpLoad %v4half %92
+         %95 = OpAccessChain %_ptr_Uniform_v4half %89 %uint_2
+         %96 = OpLoad %v4half %95
+         %99 = OpAccessChain %_ptr_Uniform_v4half %89 %uint_3
+        %100 = OpLoad %v4half %99
+        %102 = OpAccessChain %_ptr_Uniform_v4half %89 %uint_4
+        %103 = OpLoad %v4half %102
+        %104 = OpCompositeConstruct %mat4v4half %93 %96 %100 %103
+               OpReturnValue %104
+               OpFunctionEnd
+          %f = OpFunction %void None %105
+        %107 = OpLabel
+        %111 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+        %112 = OpLoad %_arr_S_std140_uint_4 %111
+        %109 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %112
+        %108 = OpFunctionCall %void %a %109
+        %115 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+        %116 = OpLoad %S_std140 %115
+        %114 = OpFunctionCall %S %conv_S %116
+        %113 = OpFunctionCall %void %b %114
+        %118 = OpFunctionCall %mat4v4half %load_u_inner_2_m
+        %117 = OpFunctionCall %void %c %118
+        %120 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0 %56 %uint_2
+        %121 = OpLoad %v4half %120
+        %122 = OpVectorShuffle %v4half %121 %121 1 3 0 2
+        %119 = OpFunctionCall %void %d %122
+        %124 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0 %56 %uint_2
+        %125 = OpLoad %v4half %124
+        %126 = OpVectorShuffle %v4half %125 %125 1 3 0 2
+        %127 = OpCompositeExtract %half %126 0
+        %123 = OpFunctionCall %void %e %127
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_fn.wgsl.expected.wgsl
new file mode 100644
index 0000000..828eca7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_fn.wgsl.expected.wgsl
@@ -0,0 +1,34 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat4x4<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+fn a(a : array<S, 4>) {
+}
+
+fn b(s : S) {
+}
+
+fn c(m : mat4x4<f16>) {
+}
+
+fn d(v : vec4<f16>) {
+}
+
+fn e(f : f16) {
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  a(u);
+  b(u[2]);
+  c(u[2].m);
+  d(u[0].m[1].ywxz);
+  e(u[0].m[1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_private.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_private.wgsl
new file mode 100644
index 0000000..d9bcd28
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_private.wgsl
@@ -0,0 +1,19 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat4x4<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+var<private> p : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[2];
+    p[3].m = u[2].m;
+    p[1].m[0] = u[0].m[1].ywxz;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_private.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..8b11bb5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_private.wgsl.expected.dxc.hlsl
@@ -0,0 +1,64 @@
+struct S {
+  int before;
+  matrix<float16_t, 4, 4> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+static S p[4] = (S[4])0;
+
+matrix<float16_t, 4, 4> tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 256u);
+  p[3].m = tint_symbol_3(u, 264u);
+  uint2 ubo_load_8 = u[1].xy;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_8_yw = vector<float16_t, 2>(f16tof32(ubo_load_8 >> 16));
+  p[1].m[0] = vector<float16_t, 4>(ubo_load_8_xz[0], ubo_load_8_yw[0], ubo_load_8_xz[1], ubo_load_8_yw[1]).ywxz;
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_private.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..a642960
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_private.wgsl.expected.fxc.hlsl
@@ -0,0 +1,69 @@
+SKIP: FAILED
+
+struct S {
+  int before;
+  matrix<float16_t, 4, 4> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+static S p[4] = (S[4])0;
+
+matrix<float16_t, 4, 4> tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+}
+
+S tint_symbol_1(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 64u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_3(buffer, (offset + 8u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 256u);
+  p[3].m = tint_symbol_3(u, 264u);
+  uint2 ubo_load_8 = u[1].xy;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_8_yw = vector<float16_t, 2>(f16tof32(ubo_load_8 >> 16));
+  p[1].m[0] = vector<float16_t, 4>(ubo_load_8_xz[0], ubo_load_8_yw[0], ubo_load_8_xz[1], ubo_load_8_yw[1]).ywxz;
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001D8880F79A0(3,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..c026bc2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_private.wgsl.expected.glsl
@@ -0,0 +1,97 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct S {
+  int before;
+  uint pad;
+  f16mat4 m;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  int after;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+};
+
+struct S_std140 {
+  int before;
+  uint pad;
+  f16vec4 m_0;
+  f16vec4 m_1;
+  f16vec4 m_2;
+  f16vec4 m_3;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  int after;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+S p[4] = S[4](S(0, 0u, f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+S conv_S(S_std140 val) {
+  return S(val.before, val.pad, f16mat4(val.m_0, val.m_1, val.m_2, val.m_3), val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.after, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.pad_11, val.pad_12, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, 0u, f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat4 load_u_inner_2_m() {
+  return f16mat4(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2, u.inner[2u].m_3);
+}
+
+void f() {
+  p = conv_arr4_S(u.inner);
+  p[1] = conv_S(u.inner[2u]);
+  p[3].m = load_u_inner_2_m();
+  p[1].m[0] = u.inner[0u].m_1.ywxz;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..4b6869d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_private.wgsl.expected.msl
@@ -0,0 +1,34 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0008 */ half4x4 m;
+  /* 0x0028 */ tint_array<int8_t, 24> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol_1 [[buffer(0)]]) {
+  thread tint_array<S, 4> tint_symbol = {};
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[2];
+  tint_symbol[3].m = (*(tint_symbol_1))[2].m;
+  tint_symbol[1].m[0] = half4((*(tint_symbol_1))[0].m[1]).ywxz;
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_private.wgsl.expected.spvasm
new file mode 100644
index 0000000..5e02a14
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_private.wgsl.expected.spvasm
@@ -0,0 +1,182 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 110
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "m_2"
+               OpMemberName %S_std140 4 "m_3"
+               OpMemberName %S_std140 5 "after"
+               OpName %u "u"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %p "p"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 8
+               OpMemberDecorate %S_std140 2 Offset 16
+               OpMemberDecorate %S_std140 3 Offset 24
+               OpMemberDecorate %S_std140 4 Offset 32
+               OpMemberDecorate %S_std140 5 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 8
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 8
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+   %S_std140 = OpTypeStruct %int %v4half %v4half %v4half %v4half %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat4v4half = OpTypeMatrix %v4half 4
+          %S = OpTypeStruct %int %mat4v4half %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+%_ptr_Private__arr_S_uint_4 = OpTypePointer Private %_arr_S_uint_4
+         %16 = OpConstantNull %_arr_S_uint_4
+          %p = OpVariable %_ptr_Private__arr_S_uint_4 Private %16
+         %17 = OpTypeFunction %S %S_std140
+         %29 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %37 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %50 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %63 = OpTypeFunction %mat4v4half
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %86 = OpTypeFunction %void
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+      %int_1 = OpConstant %int 1
+%_ptr_Private_S = OpTypePointer Private %S
+      %int_3 = OpConstant %int 3
+%_ptr_Private_mat4v4half = OpTypePointer Private %mat4v4half
+        %104 = OpConstantNull %int
+%_ptr_Private_v4half = OpTypePointer Private %v4half
+     %conv_S = OpFunction %S None %17
+        %val = OpFunctionParameter %S_std140
+         %20 = OpLabel
+         %21 = OpCompositeExtract %int %val 0
+         %22 = OpCompositeExtract %v4half %val 1
+         %23 = OpCompositeExtract %v4half %val 2
+         %24 = OpCompositeExtract %v4half %val 3
+         %25 = OpCompositeExtract %v4half %val 4
+         %26 = OpCompositeConstruct %mat4v4half %22 %23 %24 %25
+         %27 = OpCompositeExtract %int %val 5
+         %28 = OpCompositeConstruct %S %21 %26 %27
+               OpReturnValue %28
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %29
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %32 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %16
+          %i = OpVariable %_ptr_Function_uint Function %37
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %50
+               OpBranch %38
+         %38 = OpLabel
+               OpLoopMerge %39 %40 None
+               OpBranch %41
+         %41 = OpLabel
+         %43 = OpLoad %uint %i
+         %44 = OpULessThan %bool %43 %uint_4
+         %42 = OpLogicalNot %bool %44
+               OpSelectionMerge %46 None
+               OpBranchConditional %42 %47 %46
+         %47 = OpLabel
+               OpBranch %39
+         %46 = OpLabel
+               OpStore %var_for_index %val_0
+         %51 = OpLoad %uint %i
+         %53 = OpAccessChain %_ptr_Function_S %arr %51
+         %55 = OpLoad %uint %i
+         %57 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %55
+         %58 = OpLoad %S_std140 %57
+         %54 = OpFunctionCall %S %conv_S %58
+               OpStore %53 %54
+               OpBranch %40
+         %40 = OpLabel
+         %59 = OpLoad %uint %i
+         %61 = OpIAdd %uint %59 %uint_1
+               OpStore %i %61
+               OpBranch %38
+         %39 = OpLabel
+         %62 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %62
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat4v4half None %63
+         %65 = OpLabel
+         %70 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %73 = OpAccessChain %_ptr_Uniform_v4half %70 %uint_1
+         %74 = OpLoad %v4half %73
+         %76 = OpAccessChain %_ptr_Uniform_v4half %70 %uint_2
+         %77 = OpLoad %v4half %76
+         %80 = OpAccessChain %_ptr_Uniform_v4half %70 %uint_3
+         %81 = OpLoad %v4half %80
+         %83 = OpAccessChain %_ptr_Uniform_v4half %70 %uint_4
+         %84 = OpLoad %v4half %83
+         %85 = OpCompositeConstruct %mat4v4half %74 %77 %81 %84
+               OpReturnValue %85
+               OpFunctionEnd
+          %f = OpFunction %void None %86
+         %89 = OpLabel
+         %92 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+         %93 = OpLoad %_arr_S_std140_uint_4 %92
+         %90 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %93
+               OpStore %p %90
+         %96 = OpAccessChain %_ptr_Private_S %p %int_1
+         %98 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %99 = OpLoad %S_std140 %98
+         %97 = OpFunctionCall %S %conv_S %99
+               OpStore %96 %97
+        %102 = OpAccessChain %_ptr_Private_mat4v4half %p %int_3 %uint_1
+        %103 = OpFunctionCall %mat4v4half %load_u_inner_2_m
+               OpStore %102 %103
+        %106 = OpAccessChain %_ptr_Private_v4half %p %int_1 %uint_1 %104
+        %107 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0 %37 %uint_2
+        %108 = OpLoad %v4half %107
+        %109 = OpVectorShuffle %v4half %108 %108 1 3 0 2
+               OpStore %106 %109
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..6bf5854
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_private.wgsl.expected.wgsl
@@ -0,0 +1,20 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat4x4<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+var<private> p : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[2];
+  p[3].m = u[2].m;
+  p[1].m[0] = u[0].m[1].ywxz;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_storage.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_storage.wgsl
new file mode 100644
index 0000000..6d8ea1a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_storage.wgsl
@@ -0,0 +1,19 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat4x4<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+@group(0) @binding(1) var<storage, read_write> s : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[2];
+    s[3].m = u[2].m;
+    s[1].m[0] = u[0].m[1].ywxz;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_storage.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..212b921
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_storage.wgsl.expected.dxc.hlsl
@@ -0,0 +1,86 @@
+struct S {
+  int before;
+  matrix<float16_t, 4, 4> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_3(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 4> value) {
+  buffer.Store<vector<float16_t, 4> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 8u), value[1u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 16u), value[2u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 24u), value[3u]);
+}
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, S value) {
+  buffer.Store((offset + 0u), asuint(value.before));
+  tint_symbol_3(buffer, (offset + 8u), value.m);
+  buffer.Store((offset + 64u), asuint(value.after));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, S value[4]) {
+  S array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 128u)), array[i]);
+    }
+  }
+}
+
+matrix<float16_t, 4, 4> tint_symbol_8(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+}
+
+S tint_symbol_6(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 64u)) / 4;
+  const S tint_symbol_10 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_8(buffer, (offset + 8u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_10;
+}
+
+typedef S tint_symbol_5_ret[4];
+tint_symbol_5_ret tint_symbol_5(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_6(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_5(u, 0u));
+  tint_symbol_1(s, 128u, tint_symbol_6(u, 256u));
+  tint_symbol_3(s, 392u, tint_symbol_8(u, 264u));
+  uint2 ubo_load_8 = u[1].xy;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_8_yw = vector<float16_t, 2>(f16tof32(ubo_load_8 >> 16));
+  s.Store<vector<float16_t, 4> >(136u, vector<float16_t, 4>(ubo_load_8_xz[0], ubo_load_8_yw[0], ubo_load_8_xz[1], ubo_load_8_yw[1]).ywxz);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_storage.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..a426c30
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_storage.wgsl.expected.fxc.hlsl
@@ -0,0 +1,91 @@
+SKIP: FAILED
+
+struct S {
+  int before;
+  matrix<float16_t, 4, 4> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_3(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 4> value) {
+  buffer.Store<vector<float16_t, 4> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 8u), value[1u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 16u), value[2u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 24u), value[3u]);
+}
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, S value) {
+  buffer.Store((offset + 0u), asuint(value.before));
+  tint_symbol_3(buffer, (offset + 8u), value.m);
+  buffer.Store((offset + 64u), asuint(value.after));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, S value[4]) {
+  S array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 128u)), array[i]);
+    }
+  }
+}
+
+matrix<float16_t, 4, 4> tint_symbol_8(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+}
+
+S tint_symbol_6(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 64u)) / 4;
+  const S tint_symbol_10 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_8(buffer, (offset + 8u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_10;
+}
+
+typedef S tint_symbol_5_ret[4];
+tint_symbol_5_ret tint_symbol_5(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_6(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_5(u, 0u));
+  tint_symbol_1(s, 128u, tint_symbol_6(u, 256u));
+  tint_symbol_3(s, 392u, tint_symbol_8(u, 264u));
+  uint2 ubo_load_8 = u[1].xy;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_8_yw = vector<float16_t, 2>(f16tof32(ubo_load_8 >> 16));
+  s.Store<vector<float16_t, 4> >(136u, vector<float16_t, 4>(ubo_load_8_xz[0], ubo_load_8_yw[0], ubo_load_8_xz[1], ubo_load_8_yw[1]).ywxz);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000013BAAFBAEB0(3,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..0a061cd
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_storage.wgsl.expected.glsl
@@ -0,0 +1,100 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct S {
+  int before;
+  uint pad;
+  f16mat4 m;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  int after;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+};
+
+struct S_std140 {
+  int before;
+  uint pad;
+  f16vec4 m_0;
+  f16vec4 m_1;
+  f16vec4 m_2;
+  f16vec4 m_3;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  int after;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  S inner[4];
+} s;
+
+S conv_S(S_std140 val) {
+  return S(val.before, val.pad, f16mat4(val.m_0, val.m_1, val.m_2, val.m_3), val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.after, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.pad_11, val.pad_12, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, 0u, f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat4 load_u_inner_2_m() {
+  return f16mat4(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2, u.inner[2u].m_3);
+}
+
+void f() {
+  s.inner = conv_arr4_S(u.inner);
+  s.inner[1] = conv_S(u.inner[2u]);
+  s.inner[3].m = load_u_inner_2_m();
+  s.inner[1].m[0] = u.inner[0u].m_1.ywxz;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..1573001
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_storage.wgsl.expected.msl
@@ -0,0 +1,33 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0008 */ half4x4 m;
+  /* 0x0028 */ tint_array<int8_t, 24> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+kernel void f(device tint_array<S, 4>* tint_symbol [[buffer(1)]], const constant tint_array<S, 4>* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
+  (*(tint_symbol))[3].m = (*(tint_symbol_1))[2].m;
+  (*(tint_symbol))[1].m[0] = half4((*(tint_symbol_1))[0].m[1]).ywxz;
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_storage.wgsl.expected.spvasm
new file mode 100644
index 0000000..93a467a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_storage.wgsl.expected.spvasm
@@ -0,0 +1,191 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 113
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "m_2"
+               OpMemberName %S_std140 4 "m_3"
+               OpMemberName %S_std140 5 "after"
+               OpName %u "u"
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %s "s"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 8
+               OpMemberDecorate %S_std140 2 Offset 16
+               OpMemberDecorate %S_std140 3 Offset 24
+               OpMemberDecorate %S_std140 4 Offset 32
+               OpMemberDecorate %S_std140 5 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 8
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 8
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+               OpDecorate %s DescriptorSet 0
+               OpDecorate %s Binding 1
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+   %S_std140 = OpTypeStruct %int %v4half %v4half %v4half %v4half %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat4v4half = OpTypeMatrix %v4half 4
+          %S = OpTypeStruct %int %mat4v4half %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+    %u_block = OpTypeStruct %_arr_S_uint_4
+%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
+          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+         %17 = OpTypeFunction %S %S_std140
+         %29 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+         %35 = OpConstantNull %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %38 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %51 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %64 = OpTypeFunction %mat4v4half
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %87 = OpTypeFunction %void
+%_ptr_StorageBuffer__arr_S_uint_4 = OpTypePointer StorageBuffer %_arr_S_uint_4
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+      %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
+      %int_3 = OpConstant %int 3
+%_ptr_StorageBuffer_mat4v4half = OpTypePointer StorageBuffer %mat4v4half
+        %107 = OpConstantNull %int
+%_ptr_StorageBuffer_v4half = OpTypePointer StorageBuffer %v4half
+     %conv_S = OpFunction %S None %17
+        %val = OpFunctionParameter %S_std140
+         %20 = OpLabel
+         %21 = OpCompositeExtract %int %val 0
+         %22 = OpCompositeExtract %v4half %val 1
+         %23 = OpCompositeExtract %v4half %val 2
+         %24 = OpCompositeExtract %v4half %val 3
+         %25 = OpCompositeExtract %v4half %val 4
+         %26 = OpCompositeConstruct %mat4v4half %22 %23 %24 %25
+         %27 = OpCompositeExtract %int %val 5
+         %28 = OpCompositeConstruct %S %21 %26 %27
+               OpReturnValue %28
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %29
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %32 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %35
+          %i = OpVariable %_ptr_Function_uint Function %38
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %51
+               OpBranch %39
+         %39 = OpLabel
+               OpLoopMerge %40 %41 None
+               OpBranch %42
+         %42 = OpLabel
+         %44 = OpLoad %uint %i
+         %45 = OpULessThan %bool %44 %uint_4
+         %43 = OpLogicalNot %bool %45
+               OpSelectionMerge %47 None
+               OpBranchConditional %43 %48 %47
+         %48 = OpLabel
+               OpBranch %40
+         %47 = OpLabel
+               OpStore %var_for_index %val_0
+         %52 = OpLoad %uint %i
+         %54 = OpAccessChain %_ptr_Function_S %arr %52
+         %56 = OpLoad %uint %i
+         %58 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %56
+         %59 = OpLoad %S_std140 %58
+         %55 = OpFunctionCall %S %conv_S %59
+               OpStore %54 %55
+               OpBranch %41
+         %41 = OpLabel
+         %60 = OpLoad %uint %i
+         %62 = OpIAdd %uint %60 %uint_1
+               OpStore %i %62
+               OpBranch %39
+         %40 = OpLabel
+         %63 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %63
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat4v4half None %64
+         %66 = OpLabel
+         %71 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %74 = OpAccessChain %_ptr_Uniform_v4half %71 %uint_1
+         %75 = OpLoad %v4half %74
+         %77 = OpAccessChain %_ptr_Uniform_v4half %71 %uint_2
+         %78 = OpLoad %v4half %77
+         %81 = OpAccessChain %_ptr_Uniform_v4half %71 %uint_3
+         %82 = OpLoad %v4half %81
+         %84 = OpAccessChain %_ptr_Uniform_v4half %71 %uint_4
+         %85 = OpLoad %v4half %84
+         %86 = OpCompositeConstruct %mat4v4half %75 %78 %82 %85
+               OpReturnValue %86
+               OpFunctionEnd
+          %f = OpFunction %void None %87
+         %90 = OpLabel
+         %92 = OpAccessChain %_ptr_StorageBuffer__arr_S_uint_4 %s %uint_0
+         %95 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+         %96 = OpLoad %_arr_S_std140_uint_4 %95
+         %93 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %96
+               OpStore %92 %93
+         %99 = OpAccessChain %_ptr_StorageBuffer_S %s %uint_0 %int_1
+        %101 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+        %102 = OpLoad %S_std140 %101
+        %100 = OpFunctionCall %S %conv_S %102
+               OpStore %99 %100
+        %105 = OpAccessChain %_ptr_StorageBuffer_mat4v4half %s %uint_0 %int_3 %uint_1
+        %106 = OpFunctionCall %mat4v4half %load_u_inner_2_m
+               OpStore %105 %106
+        %109 = OpAccessChain %_ptr_StorageBuffer_v4half %s %uint_0 %int_1 %uint_1 %107
+        %110 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0 %38 %uint_2
+        %111 = OpLoad %v4half %110
+        %112 = OpVectorShuffle %v4half %111 %111 1 3 0 2
+               OpStore %109 %112
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..d07f7c3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,20 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat4x4<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@group(0) @binding(1) var<storage, read_write> s : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[2];
+  s[3].m = u[2].m;
+  s[1].m[0] = u[0].m[1].ywxz;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_workgroup.wgsl
new file mode 100644
index 0000000..b794ec8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_workgroup.wgsl
@@ -0,0 +1,19 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat4x4<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+var<workgroup> w : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[2];
+    w[3].m = u[2].m;
+    w[1].m[0] = u[0].m[1].ywxz;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_workgroup.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..45f86b8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_workgroup.wgsl.expected.dxc.hlsl
@@ -0,0 +1,80 @@
+struct S {
+  int before;
+  matrix<float16_t, 4, 4> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+groupshared S w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 4, 4> tint_symbol_5(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+}
+
+S tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 64u)) / 4;
+  const S tint_symbol_8 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_5(buffer, (offset + 8u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_8;
+}
+
+typedef S tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      const S tint_symbol_7 = (S)0;
+      w[i] = tint_symbol_7;
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 256u);
+  w[3].m = tint_symbol_5(u, 264u);
+  uint2 ubo_load_8 = u[1].xy;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_8_yw = vector<float16_t, 2>(f16tof32(ubo_load_8 >> 16));
+  w[1].m[0] = vector<float16_t, 4>(ubo_load_8_xz[0], ubo_load_8_yw[0], ubo_load_8_xz[1], ubo_load_8_yw[1]).ywxz;
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_workgroup.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..a09f876
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_workgroup.wgsl.expected.fxc.hlsl
@@ -0,0 +1,85 @@
+SKIP: FAILED
+
+struct S {
+  int before;
+  matrix<float16_t, 4, 4> m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[32];
+};
+groupshared S w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 4, 4> tint_symbol_5(uint4 buffer[32], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+}
+
+S tint_symbol_3(uint4 buffer[32], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 64u)) / 4;
+  const S tint_symbol_8 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_5(buffer, (offset + 8u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_8;
+}
+
+typedef S tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[32], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 128u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      const S tint_symbol_7 = (S)0;
+      w[i] = tint_symbol_7;
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 256u);
+  w[3].m = tint_symbol_5(u, 264u);
+  uint2 ubo_load_8 = u[1].xy;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_8_yw = vector<float16_t, 2>(f16tof32(ubo_load_8 >> 16));
+  w[1].m[0] = vector<float16_t, 4>(ubo_load_8_xz[0], ubo_load_8_yw[0], ubo_load_8_xz[1], ubo_load_8_yw[1]).ywxz;
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001355D73AE70(3,10-18): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..644ea81
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,105 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct S {
+  int before;
+  uint pad;
+  f16mat4 m;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  int after;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+};
+
+struct S_std140 {
+  int before;
+  uint pad;
+  f16vec4 m_0;
+  f16vec4 m_1;
+  f16vec4 m_2;
+  f16vec4 m_3;
+  uint pad_1;
+  uint pad_2;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  int after;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner[4];
+} u;
+
+shared S w[4];
+S conv_S(S_std140 val) {
+  return S(val.before, val.pad, f16mat4(val.m_0, val.m_1, val.m_2, val.m_3), val.pad_1, val.pad_2, val.pad_3, val.pad_4, val.pad_5, val.pad_6, val.after, val.pad_7, val.pad_8, val.pad_9, val.pad_10, val.pad_11, val.pad_12, val.pad_13, val.pad_14, val.pad_15, val.pad_16, val.pad_17, val.pad_18, val.pad_19, val.pad_20, val.pad_21);
+}
+
+S[4] conv_arr4_S(S_std140 val[4]) {
+  S arr[4] = S[4](S(0, 0u, f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = conv_S(val[i]);
+    }
+  }
+  return arr;
+}
+
+f16mat4 load_u_inner_2_m() {
+  return f16mat4(u.inner[2u].m_0, u.inner[2u].m_1, u.inner[2u].m_2, u.inner[2u].m_3);
+}
+
+void f(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      uint i = idx;
+      S tint_symbol = S(0, 0u, f16mat4(f16vec4(0.0hf), f16vec4(0.0hf), f16vec4(0.0hf), f16vec4(0.0hf)), 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u);
+      w[i] = tint_symbol;
+    }
+  }
+  barrier();
+  w = conv_arr4_S(u.inner);
+  w[1] = conv_S(u.inner[2u]);
+  w[3].m = load_u_inner_2_m();
+  w[1].m[0] = u.inner[0u].m_1.ywxz;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..f1d4c32
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,48 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 4> tint_pad;
+  /* 0x0008 */ half4x4 m;
+  /* 0x0028 */ tint_array<int8_t, 24> tint_pad_1;
+  /* 0x0040 */ int after;
+  /* 0x0044 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+struct tint_symbol_6 {
+  tint_array<S, 4> w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup tint_array<S, 4>* const tint_symbol_1, const constant tint_array<S, 4>* const tint_symbol_2) {
+  for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+    uint const i = idx;
+    S const tint_symbol = S{};
+    (*(tint_symbol_1))[i] = tint_symbol;
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol_1) = *(tint_symbol_2);
+  (*(tint_symbol_1))[1] = (*(tint_symbol_2))[2];
+  (*(tint_symbol_1))[3].m = (*(tint_symbol_2))[2].m;
+  (*(tint_symbol_1))[1].m[0] = half4((*(tint_symbol_2))[0].m[1]).ywxz;
+}
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol_5 [[buffer(0)]], threadgroup tint_symbol_6* tint_symbol_4 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup tint_array<S, 4>* const tint_symbol_3 = &((*(tint_symbol_4)).w);
+  f_inner(local_invocation_index, tint_symbol_3, tint_symbol_5);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_workgroup.wgsl.expected.spvasm
new file mode 100644
index 0000000..23c6874
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_workgroup.wgsl.expected.spvasm
@@ -0,0 +1,225 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 135
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %local_invocation_index_1 "local_invocation_index_1"
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "before"
+               OpMemberName %S_std140 1 "m_0"
+               OpMemberName %S_std140 2 "m_1"
+               OpMemberName %S_std140 3 "m_2"
+               OpMemberName %S_std140 4 "m_3"
+               OpMemberName %S_std140 5 "after"
+               OpName %u "u"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %w "w"
+               OpName %conv_S "conv_S"
+               OpName %val "val"
+               OpName %conv_arr4_S "conv_arr4_S"
+               OpName %val_0 "val"
+               OpName %arr "arr"
+               OpName %i "i"
+               OpName %var_for_index "var_for_index"
+               OpName %load_u_inner_2_m "load_u_inner_2_m"
+               OpName %f_inner "f_inner"
+               OpName %local_invocation_index "local_invocation_index"
+               OpName %idx "idx"
+               OpName %f "f"
+               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %S_std140 1 Offset 8
+               OpMemberDecorate %S_std140 2 Offset 16
+               OpMemberDecorate %S_std140 3 Offset 24
+               OpMemberDecorate %S_std140 4 Offset 32
+               OpMemberDecorate %S_std140 5 Offset 64
+               OpDecorate %_arr_S_std140_uint_4 ArrayStride 128
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 8
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 8
+               OpMemberDecorate %S 2 Offset 64
+               OpDecorate %_arr_S_uint_4 ArrayStride 128
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+        %int = OpTypeInt 32 1
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+   %S_std140 = OpTypeStruct %int %v4half %v4half %v4half %v4half %int
+     %uint_4 = OpConstant %uint 4
+%_arr_S_std140_uint_4 = OpTypeArray %S_std140 %uint_4
+%u_block_std140 = OpTypeStruct %_arr_S_std140_uint_4
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat4v4half = OpTypeMatrix %v4half 4
+          %S = OpTypeStruct %int %mat4v4half %int
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+%_ptr_Workgroup__arr_S_uint_4 = OpTypePointer Workgroup %_arr_S_uint_4
+          %w = OpVariable %_ptr_Workgroup__arr_S_uint_4 Workgroup
+         %18 = OpTypeFunction %S %S_std140
+         %30 = OpTypeFunction %_arr_S_uint_4 %_arr_S_std140_uint_4
+%_ptr_Function__arr_S_uint_4 = OpTypePointer Function %_arr_S_uint_4
+         %36 = OpConstantNull %_arr_S_uint_4
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %39 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Function__arr_S_std140_uint_4 = OpTypePointer Function %_arr_S_std140_uint_4
+         %52 = OpConstantNull %_arr_S_std140_uint_4
+%_ptr_Function_S = OpTypePointer Function %S
+%_ptr_Function_S_std140 = OpTypePointer Function %S_std140
+     %uint_1 = OpConstant %uint 1
+         %65 = OpTypeFunction %mat4v4half
+     %uint_0 = OpConstant %uint 0
+     %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %88 = OpTypeFunction %void %uint
+%_ptr_Workgroup_S = OpTypePointer Workgroup %S
+        %106 = OpConstantNull %S
+   %uint_264 = OpConstant %uint 264
+%_ptr_Uniform__arr_S_std140_uint_4 = OpTypePointer Uniform %_arr_S_std140_uint_4
+      %int_1 = OpConstant %int 1
+      %int_3 = OpConstant %int 3
+%_ptr_Workgroup_mat4v4half = OpTypePointer Workgroup %mat4v4half
+        %124 = OpConstantNull %int
+%_ptr_Workgroup_v4half = OpTypePointer Workgroup %v4half
+        %130 = OpTypeFunction %void
+     %conv_S = OpFunction %S None %18
+        %val = OpFunctionParameter %S_std140
+         %21 = OpLabel
+         %22 = OpCompositeExtract %int %val 0
+         %23 = OpCompositeExtract %v4half %val 1
+         %24 = OpCompositeExtract %v4half %val 2
+         %25 = OpCompositeExtract %v4half %val 3
+         %26 = OpCompositeExtract %v4half %val 4
+         %27 = OpCompositeConstruct %mat4v4half %23 %24 %25 %26
+         %28 = OpCompositeExtract %int %val 5
+         %29 = OpCompositeConstruct %S %22 %27 %28
+               OpReturnValue %29
+               OpFunctionEnd
+%conv_arr4_S = OpFunction %_arr_S_uint_4 None %30
+      %val_0 = OpFunctionParameter %_arr_S_std140_uint_4
+         %33 = OpLabel
+        %arr = OpVariable %_ptr_Function__arr_S_uint_4 Function %36
+          %i = OpVariable %_ptr_Function_uint Function %39
+%var_for_index = OpVariable %_ptr_Function__arr_S_std140_uint_4 Function %52
+               OpBranch %40
+         %40 = OpLabel
+               OpLoopMerge %41 %42 None
+               OpBranch %43
+         %43 = OpLabel
+         %45 = OpLoad %uint %i
+         %46 = OpULessThan %bool %45 %uint_4
+         %44 = OpLogicalNot %bool %46
+               OpSelectionMerge %48 None
+               OpBranchConditional %44 %49 %48
+         %49 = OpLabel
+               OpBranch %41
+         %48 = OpLabel
+               OpStore %var_for_index %val_0
+         %53 = OpLoad %uint %i
+         %55 = OpAccessChain %_ptr_Function_S %arr %53
+         %57 = OpLoad %uint %i
+         %59 = OpAccessChain %_ptr_Function_S_std140 %var_for_index %57
+         %60 = OpLoad %S_std140 %59
+         %56 = OpFunctionCall %S %conv_S %60
+               OpStore %55 %56
+               OpBranch %42
+         %42 = OpLabel
+         %61 = OpLoad %uint %i
+         %63 = OpIAdd %uint %61 %uint_1
+               OpStore %i %63
+               OpBranch %40
+         %41 = OpLabel
+         %64 = OpLoad %_arr_S_uint_4 %arr
+               OpReturnValue %64
+               OpFunctionEnd
+%load_u_inner_2_m = OpFunction %mat4v4half None %65
+         %67 = OpLabel
+         %72 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+         %75 = OpAccessChain %_ptr_Uniform_v4half %72 %uint_1
+         %76 = OpLoad %v4half %75
+         %78 = OpAccessChain %_ptr_Uniform_v4half %72 %uint_2
+         %79 = OpLoad %v4half %78
+         %82 = OpAccessChain %_ptr_Uniform_v4half %72 %uint_3
+         %83 = OpLoad %v4half %82
+         %85 = OpAccessChain %_ptr_Uniform_v4half %72 %uint_4
+         %86 = OpLoad %v4half %85
+         %87 = OpCompositeConstruct %mat4v4half %76 %79 %83 %86
+               OpReturnValue %87
+               OpFunctionEnd
+    %f_inner = OpFunction %void None %88
+%local_invocation_index = OpFunctionParameter %uint
+         %92 = OpLabel
+        %idx = OpVariable %_ptr_Function_uint Function %39
+               OpStore %idx %local_invocation_index
+               OpBranch %94
+         %94 = OpLabel
+               OpLoopMerge %95 %96 None
+               OpBranch %97
+         %97 = OpLabel
+         %99 = OpLoad %uint %idx
+        %100 = OpULessThan %bool %99 %uint_4
+         %98 = OpLogicalNot %bool %100
+               OpSelectionMerge %101 None
+               OpBranchConditional %98 %102 %101
+        %102 = OpLabel
+               OpBranch %95
+        %101 = OpLabel
+        %103 = OpLoad %uint %idx
+        %105 = OpAccessChain %_ptr_Workgroup_S %w %103
+               OpStore %105 %106
+               OpBranch %96
+         %96 = OpLabel
+        %107 = OpLoad %uint %idx
+        %108 = OpIAdd %uint %107 %uint_1
+               OpStore %idx %108
+               OpBranch %94
+         %95 = OpLabel
+               OpControlBarrier %uint_2 %uint_2 %uint_264
+        %113 = OpAccessChain %_ptr_Uniform__arr_S_std140_uint_4 %u %uint_0
+        %114 = OpLoad %_arr_S_std140_uint_4 %113
+        %111 = OpFunctionCall %_arr_S_uint_4 %conv_arr4_S %114
+               OpStore %w %111
+        %116 = OpAccessChain %_ptr_Workgroup_S %w %int_1
+        %118 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0 %uint_2
+        %119 = OpLoad %S_std140 %118
+        %117 = OpFunctionCall %S %conv_S %119
+               OpStore %116 %117
+        %122 = OpAccessChain %_ptr_Workgroup_mat4v4half %w %int_3 %uint_1
+        %123 = OpFunctionCall %mat4v4half %load_u_inner_2_m
+               OpStore %122 %123
+        %126 = OpAccessChain %_ptr_Workgroup_v4half %w %int_1 %uint_1 %124
+        %127 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0 %39 %uint_2
+        %128 = OpLoad %v4half %127
+        %129 = OpVectorShuffle %v4half %128 %128 1 3 0 2
+               OpStore %126 %129
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %130
+        %132 = OpLabel
+        %134 = OpLoad %uint %local_invocation_index_1
+        %133 = OpFunctionCall %void %f_inner %134
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..7788484
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f16/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,20 @@
+enable f16;
+
+struct S {
+  before : i32,
+  m : mat4x4<f16>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+var<workgroup> w : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[2];
+  w[3].m = u[2].m;
+  w[1].m[0] = u[0].m[1].ywxz;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/dynamic_index_via_ptr.wgsl
new file mode 100644
index 0000000..aee7c0c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/dynamic_index_via_ptr.wgsl
@@ -0,0 +1,32 @@
+struct Inner {
+  @size(64)
+  m : mat4x4<f32>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a           = &a;
+  let p_a_i         = &((*p_a)[i()]);
+  let p_a_i_a       = &((*p_a_i).a);
+  let p_a_i_a_i     = &((*p_a_i_a)[i()]);
+  let p_a_i_a_i_m   = &((*p_a_i_a_i).m);
+  let p_a_i_a_i_m_i = &((*p_a_i_a_i_m)[i()]);
+
+
+  let l_a             : array<Outer, 4> =  *p_a;
+  let l_a_i           : Outer           =  *p_a_i;
+  let l_a_i_a         : array<Inner, 4> =  *p_a_i_a;
+  let l_a_i_a_i       : Inner           =  *p_a_i_a_i;
+  let l_a_i_a_i_m     : mat4x4<f32>     =  *p_a_i_a_i_m;
+  let l_a_i_a_i_m_i   : vec4<f32>       =  *p_a_i_a_i_m_i;
+  let l_a_i_a_i_m_i_i : f32             = (*p_a_i_a_i_m_i)[i()];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..0029647
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,77 @@
+struct Inner {
+  float4x4 m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float4x4 tint_symbol_8(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]), asfloat(buffer[scalar_offset_3 / 4]));
+}
+
+Inner tint_symbol_7(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_11 = {tint_symbol_8(buffer, (offset + 0u))};
+  return tint_symbol_11;
+}
+
+typedef Inner tint_symbol_6_ret[4];
+tint_symbol_6_ret tint_symbol_6(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_7(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_5(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_12 = {tint_symbol_6(buffer, (offset + 0u))};
+  return tint_symbol_12;
+}
+
+typedef Outer tint_symbol_4_ret[4];
+tint_symbol_4_ret tint_symbol_4(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
+      arr_1[i_2] = tint_symbol_5(buffer, (offset + (i_2 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_a_i_save = i();
+  const int p_a_i_a_i_m_i_save = i();
+  const Outer l_a[4] = tint_symbol_4(a, 0u);
+  const Outer l_a_i = tint_symbol_5(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a[4] = tint_symbol_6(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a_i = tint_symbol_7(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const float4x4 l_a_i_a_i_m = tint_symbol_8(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const uint scalar_offset_4 = ((((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))) + (16u * uint(p_a_i_a_i_m_i_save)))) / 4;
+  const float4 l_a_i_a_i_m_i = asfloat(a[scalar_offset_4 / 4]);
+  const int tint_symbol = p_a_i_save;
+  const int tint_symbol_1 = p_a_i_a_i_save;
+  const int tint_symbol_2 = p_a_i_a_i_m_i_save;
+  const int tint_symbol_3 = i();
+  const uint scalar_offset_5 = (((((256u * uint(tint_symbol)) + (64u * uint(tint_symbol_1))) + (16u * uint(tint_symbol_2))) + (4u * uint(tint_symbol_3)))) / 4;
+  const float l_a_i_a_i_m_i_i = asfloat(a[scalar_offset_5 / 4][scalar_offset_5 % 4]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..0029647
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,77 @@
+struct Inner {
+  float4x4 m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float4x4 tint_symbol_8(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]), asfloat(buffer[scalar_offset_3 / 4]));
+}
+
+Inner tint_symbol_7(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_11 = {tint_symbol_8(buffer, (offset + 0u))};
+  return tint_symbol_11;
+}
+
+typedef Inner tint_symbol_6_ret[4];
+tint_symbol_6_ret tint_symbol_6(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_7(buffer, (offset + (i_1 * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_5(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_12 = {tint_symbol_6(buffer, (offset + 0u))};
+  return tint_symbol_12;
+}
+
+typedef Outer tint_symbol_4_ret[4];
+tint_symbol_4_ret tint_symbol_4(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_2 = 0u; (i_2 < 4u); i_2 = (i_2 + 1u)) {
+      arr_1[i_2] = tint_symbol_5(buffer, (offset + (i_2 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_a_i_save = i();
+  const int p_a_i_a_i_save = i();
+  const int p_a_i_a_i_m_i_save = i();
+  const Outer l_a[4] = tint_symbol_4(a, 0u);
+  const Outer l_a_i = tint_symbol_5(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a[4] = tint_symbol_6(a, (256u * uint(p_a_i_save)));
+  const Inner l_a_i_a_i = tint_symbol_7(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const float4x4 l_a_i_a_i_m = tint_symbol_8(a, ((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))));
+  const uint scalar_offset_4 = ((((256u * uint(p_a_i_save)) + (64u * uint(p_a_i_a_i_save))) + (16u * uint(p_a_i_a_i_m_i_save)))) / 4;
+  const float4 l_a_i_a_i_m_i = asfloat(a[scalar_offset_4 / 4]);
+  const int tint_symbol = p_a_i_save;
+  const int tint_symbol_1 = p_a_i_a_i_save;
+  const int tint_symbol_2 = p_a_i_a_i_m_i_save;
+  const int tint_symbol_3 = i();
+  const uint scalar_offset_5 = (((((256u * uint(tint_symbol)) + (64u * uint(tint_symbol_1))) + (16u * uint(tint_symbol_2))) + (4u * uint(tint_symbol_3)))) / 4;
+  const float l_a_i_a_i_m_i_i = asfloat(a[scalar_offset_5 / 4][scalar_offset_5 % 4]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..0ca086c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,42 @@
+#version 310 es
+
+struct Inner {
+  mat4 m;
+};
+
+struct Outer {
+  Inner a[4];
+};
+
+layout(binding = 0, std140) uniform a_block_ubo {
+  Outer inner[4];
+} a;
+
+int counter = 0;
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+void f() {
+  int tint_symbol = i();
+  int p_a_i_save = tint_symbol;
+  int tint_symbol_1 = i();
+  int p_a_i_a_i_save = tint_symbol_1;
+  int tint_symbol_2 = i();
+  int p_a_i_a_i_m_i_save = tint_symbol_2;
+  Outer l_a[4] = a.inner;
+  Outer l_a_i = a.inner[p_a_i_save];
+  Inner l_a_i_a[4] = a.inner[p_a_i_save].a;
+  Inner l_a_i_a_i = a.inner[p_a_i_save].a[p_a_i_a_i_save];
+  mat4 l_a_i_a_i_m = a.inner[p_a_i_save].a[p_a_i_a_i_save].m;
+  vec4 l_a_i_a_i_m_i = a.inner[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save];
+  int tint_symbol_3 = i();
+  float l_a_i_a_i_m_i_i = a.inner[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save][tint_symbol_3];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..5fc5475
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,48 @@
+#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 Inner {
+  /* 0x0000 */ float4x4 m;
+};
+
+struct Outer {
+  /* 0x0000 */ tint_array<Inner, 4> a;
+};
+
+int i() {
+  thread int tint_symbol_4 = 0;
+  tint_symbol_4 = as_type<int>((as_type<uint>(tint_symbol_4) + as_type<uint>(1)));
+  return tint_symbol_4;
+}
+
+kernel void f(const constant tint_array<Outer, 4>* tint_symbol_5 [[buffer(0)]]) {
+  int const tint_symbol = i();
+  int const p_a_i_save = tint_symbol;
+  int const tint_symbol_1 = i();
+  int const p_a_i_a_i_save = tint_symbol_1;
+  int const tint_symbol_2 = i();
+  int const p_a_i_a_i_m_i_save = tint_symbol_2;
+  tint_array<Outer, 4> const l_a = *(tint_symbol_5);
+  Outer const l_a_i = (*(tint_symbol_5))[p_a_i_save];
+  tint_array<Inner, 4> const l_a_i_a = (*(tint_symbol_5))[p_a_i_save].a;
+  Inner const l_a_i_a_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save];
+  float4x4 const l_a_i_a_i_m = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m;
+  float4 const l_a_i_a_i_m_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save];
+  int const tint_symbol_3 = i();
+  float const l_a_i_a_i_m_i_i = (*(tint_symbol_5))[p_a_i_save].a[p_a_i_a_i_save].m[p_a_i_a_i_m_i_save][tint_symbol_3];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..fb735a0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,88 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 54
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block "a_block"
+               OpMemberName %a_block 0 "inner"
+               OpName %Outer "Outer"
+               OpMemberName %Outer 0 "a"
+               OpName %Inner "Inner"
+               OpMemberName %Inner 0 "m"
+               OpName %a "a"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %f "f"
+               OpDecorate %a_block Block
+               OpMemberDecorate %a_block 0 Offset 0
+               OpMemberDecorate %Outer 0 Offset 0
+               OpMemberDecorate %Inner 0 Offset 0
+               OpMemberDecorate %Inner 0 ColMajor
+               OpMemberDecorate %Inner 0 MatrixStride 16
+               OpDecorate %_arr_Inner_uint_4 ArrayStride 64
+               OpDecorate %_arr_Outer_uint_4 ArrayStride 256
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat4v4float = OpTypeMatrix %v4float 4
+      %Inner = OpTypeStruct %mat4v4float
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_Inner_uint_4 = OpTypeArray %Inner %uint_4
+      %Outer = OpTypeStruct %_arr_Inner_uint_4
+%_arr_Outer_uint_4 = OpTypeArray %Outer %uint_4
+    %a_block = OpTypeStruct %_arr_Outer_uint_4
+%_ptr_Uniform_a_block = OpTypePointer Uniform %a_block
+          %a = OpVariable %_ptr_Uniform_a_block Uniform
+        %int = OpTypeInt 32 1
+         %14 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %14
+         %17 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+       %void = OpTypeVoid
+         %24 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_Outer_uint_4 = OpTypePointer Uniform %_arr_Outer_uint_4
+%_ptr_Uniform_Outer = OpTypePointer Uniform %Outer
+%_ptr_Uniform__arr_Inner_uint_4 = OpTypePointer Uniform %_arr_Inner_uint_4
+%_ptr_Uniform_Inner = OpTypePointer Uniform %Inner
+%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+          %i = OpFunction %int None %17
+         %19 = OpLabel
+         %20 = OpLoad %int %counter
+         %22 = OpIAdd %int %20 %int_1
+               OpStore %counter %22
+         %23 = OpLoad %int %counter
+               OpReturnValue %23
+               OpFunctionEnd
+          %f = OpFunction %void None %24
+         %27 = OpLabel
+         %28 = OpFunctionCall %int %i
+         %29 = OpFunctionCall %int %i
+         %30 = OpFunctionCall %int %i
+         %33 = OpAccessChain %_ptr_Uniform__arr_Outer_uint_4 %a %uint_0
+         %34 = OpLoad %_arr_Outer_uint_4 %33
+         %36 = OpAccessChain %_ptr_Uniform_Outer %a %uint_0 %28
+         %37 = OpLoad %Outer %36
+         %39 = OpAccessChain %_ptr_Uniform__arr_Inner_uint_4 %a %uint_0 %28 %uint_0
+         %40 = OpLoad %_arr_Inner_uint_4 %39
+         %42 = OpAccessChain %_ptr_Uniform_Inner %a %uint_0 %28 %uint_0 %29
+         %43 = OpLoad %Inner %42
+         %45 = OpAccessChain %_ptr_Uniform_mat4v4float %a %uint_0 %28 %uint_0 %29 %uint_0
+         %46 = OpLoad %mat4v4float %45
+         %48 = OpAccessChain %_ptr_Uniform_v4float %a %uint_0 %28 %uint_0 %29 %uint_0 %30
+         %49 = OpLoad %v4float %48
+         %50 = OpFunctionCall %int %i
+         %52 = OpAccessChain %_ptr_Uniform_float %a %uint_0 %28 %uint_0 %29 %uint_0 %30 %50
+         %53 = OpLoad %float %52
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..06d520a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,34 @@
+struct Inner {
+  @size(64)
+  m : mat4x4<f32>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_i = &((*(p_a))[i()]);
+  let p_a_i_a = &((*(p_a_i)).a);
+  let p_a_i_a_i = &((*(p_a_i_a))[i()]);
+  let p_a_i_a_i_m = &((*(p_a_i_a_i)).m);
+  let p_a_i_a_i_m_i = &((*(p_a_i_a_i_m))[i()]);
+  let l_a : array<Outer, 4> = *(p_a);
+  let l_a_i : Outer = *(p_a_i);
+  let l_a_i_a : array<Inner, 4> = *(p_a_i_a);
+  let l_a_i_a_i : Inner = *(p_a_i_a_i);
+  let l_a_i_a_i_m : mat4x4<f32> = *(p_a_i_a_i_m);
+  let l_a_i_a_i_m_i : vec4<f32> = *(p_a_i_a_i_m_i);
+  let l_a_i_a_i_m_i_i : f32 = (*(p_a_i_a_i_m_i))[i()];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/static_index_via_ptr.wgsl
new file mode 100644
index 0000000..a50e0e3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/static_index_via_ptr.wgsl
@@ -0,0 +1,29 @@
+struct Inner {
+  @size(64)
+  m : mat4x4<f32>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &a;
+  let p_a_3 = &((*p_a)[3]);
+  let p_a_3_a = &((*p_a_3).a);
+  let p_a_3_a_2 = &((*p_a_3_a)[2]);
+  let p_a_3_a_2_m = &((*p_a_3_a_2).m);
+  let p_a_3_a_2_m_1 = &((*p_a_3_a_2_m)[1]);
+
+
+  let l_a             : array<Outer, 4> = *p_a;
+  let l_a_3           : Outer           = *p_a_3;
+  let l_a_3_a         : array<Inner, 4> = *p_a_3_a;
+  let l_a_3_a_2       : Inner           = *p_a_3_a_2;
+  let l_a_3_a_2_m     : mat4x4<f32>     = *p_a_3_a_2_m;
+  let l_a_3_a_2_m_1   : vec4<f32>       = *p_a_3_a_2_m_1;
+  let l_a_3_a_2_m_1_0 : f32             = (*p_a_3_a_2_m_1)[0];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..045c9d3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,62 @@
+struct Inner {
+  float4x4 m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+
+float4x4 tint_symbol_4(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]), asfloat(buffer[scalar_offset_3 / 4]));
+}
+
+Inner tint_symbol_3(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_7 = {tint_symbol_4(buffer, (offset + 0u))};
+  return tint_symbol_7;
+}
+
+typedef Inner tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_3(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_1(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_8 = {tint_symbol_2(buffer, (offset + 0u))};
+  return tint_symbol_8;
+}
+
+typedef Outer tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr_1[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const Outer l_a[4] = tint_symbol(a, 0u);
+  const Outer l_a_3 = tint_symbol_1(a, 768u);
+  const Inner l_a_3_a[4] = tint_symbol_2(a, 768u);
+  const Inner l_a_3_a_2 = tint_symbol_3(a, 896u);
+  const float4x4 l_a_3_a_2_m = tint_symbol_4(a, 896u);
+  const float4 l_a_3_a_2_m_1 = asfloat(a[57]);
+  const float l_a_3_a_2_m_1_0 = asfloat(a[57].x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..045c9d3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,62 @@
+struct Inner {
+  float4x4 m;
+};
+struct Outer {
+  Inner a[4];
+};
+
+cbuffer cbuffer_a : register(b0, space0) {
+  uint4 a[64];
+};
+
+float4x4 tint_symbol_4(uint4 buffer[64], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]), asfloat(buffer[scalar_offset_3 / 4]));
+}
+
+Inner tint_symbol_3(uint4 buffer[64], uint offset) {
+  const Inner tint_symbol_7 = {tint_symbol_4(buffer, (offset + 0u))};
+  return tint_symbol_7;
+}
+
+typedef Inner tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[64], uint offset) {
+  Inner arr[4] = (Inner[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_3(buffer, (offset + (i * 64u)));
+    }
+  }
+  return arr;
+}
+
+Outer tint_symbol_1(uint4 buffer[64], uint offset) {
+  const Outer tint_symbol_8 = {tint_symbol_2(buffer, (offset + 0u))};
+  return tint_symbol_8;
+}
+
+typedef Outer tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[64], uint offset) {
+  Outer arr_1[4] = (Outer[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr_1[i_1] = tint_symbol_1(buffer, (offset + (i_1 * 256u)));
+    }
+  }
+  return arr_1;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const Outer l_a[4] = tint_symbol(a, 0u);
+  const Outer l_a_3 = tint_symbol_1(a, 768u);
+  const Inner l_a_3_a[4] = tint_symbol_2(a, 768u);
+  const Inner l_a_3_a_2 = tint_symbol_3(a, 896u);
+  const float4x4 l_a_3_a_2_m = tint_symbol_4(a, 896u);
+  const float4 l_a_3_a_2_m_1 = asfloat(a[57]);
+  const float l_a_3_a_2_m_1_0 = asfloat(a[57].x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/static_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..e0dae3c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/static_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,29 @@
+#version 310 es
+
+struct Inner {
+  mat4 m;
+};
+
+struct Outer {
+  Inner a[4];
+};
+
+layout(binding = 0, std140) uniform a_block_ubo {
+  Outer inner[4];
+} a;
+
+void f() {
+  Outer l_a[4] = a.inner;
+  Outer l_a_3 = a.inner[3];
+  Inner l_a_3_a[4] = a.inner[3].a;
+  Inner l_a_3_a_2 = a.inner[3].a[2];
+  mat4 l_a_3_a_2_m = a.inner[3].a[2].m;
+  vec4 l_a_3_a_2_m_1 = a.inner[3].a[2].m[1];
+  float l_a_3_a_2_m_1_0 = a.inner[3].a[2].m[1][0];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/static_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..4c1c3cc
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/static_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,35 @@
+#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 Inner {
+  /* 0x0000 */ float4x4 m;
+};
+
+struct Outer {
+  /* 0x0000 */ tint_array<Inner, 4> a;
+};
+
+kernel void f(const constant tint_array<Outer, 4>* tint_symbol [[buffer(0)]]) {
+  tint_array<Outer, 4> const l_a = *(tint_symbol);
+  Outer const l_a_3 = (*(tint_symbol))[3];
+  tint_array<Inner, 4> const l_a_3_a = (*(tint_symbol))[3].a;
+  Inner const l_a_3_a_2 = (*(tint_symbol))[3].a[2];
+  float4x4 const l_a_3_a_2_m = (*(tint_symbol))[3].a[2].m;
+  float4 const l_a_3_a_2_m_1 = (*(tint_symbol))[3].a[2].m[1];
+  float const l_a_3_a_2_m_1_0 = (*(tint_symbol))[3].a[2].m[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/static_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..2ed9260
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/static_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,73 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 44
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %a_block "a_block"
+               OpMemberName %a_block 0 "inner"
+               OpName %Outer "Outer"
+               OpMemberName %Outer 0 "a"
+               OpName %Inner "Inner"
+               OpMemberName %Inner 0 "m"
+               OpName %a "a"
+               OpName %f "f"
+               OpDecorate %a_block Block
+               OpMemberDecorate %a_block 0 Offset 0
+               OpMemberDecorate %Outer 0 Offset 0
+               OpMemberDecorate %Inner 0 Offset 0
+               OpMemberDecorate %Inner 0 ColMajor
+               OpMemberDecorate %Inner 0 MatrixStride 16
+               OpDecorate %_arr_Inner_uint_4 ArrayStride 64
+               OpDecorate %_arr_Outer_uint_4 ArrayStride 256
+               OpDecorate %a NonWritable
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat4v4float = OpTypeMatrix %v4float 4
+      %Inner = OpTypeStruct %mat4v4float
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_Inner_uint_4 = OpTypeArray %Inner %uint_4
+      %Outer = OpTypeStruct %_arr_Inner_uint_4
+%_arr_Outer_uint_4 = OpTypeArray %Outer %uint_4
+    %a_block = OpTypeStruct %_arr_Outer_uint_4
+%_ptr_Uniform_a_block = OpTypePointer Uniform %a_block
+          %a = OpVariable %_ptr_Uniform_a_block Uniform
+       %void = OpTypeVoid
+         %13 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_Outer_uint_4 = OpTypePointer Uniform %_arr_Outer_uint_4
+        %int = OpTypeInt 32 1
+      %int_3 = OpConstant %int 3
+%_ptr_Uniform_Outer = OpTypePointer Uniform %Outer
+%_ptr_Uniform__arr_Inner_uint_4 = OpTypePointer Uniform %_arr_Inner_uint_4
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_Inner = OpTypePointer Uniform %Inner
+%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+         %40 = OpConstantNull %int
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+          %f = OpFunction %void None %13
+         %16 = OpLabel
+         %19 = OpAccessChain %_ptr_Uniform__arr_Outer_uint_4 %a %uint_0
+         %20 = OpLoad %_arr_Outer_uint_4 %19
+         %24 = OpAccessChain %_ptr_Uniform_Outer %a %uint_0 %int_3
+         %25 = OpLoad %Outer %24
+         %27 = OpAccessChain %_ptr_Uniform__arr_Inner_uint_4 %a %uint_0 %int_3 %uint_0
+         %28 = OpLoad %_arr_Inner_uint_4 %27
+         %31 = OpAccessChain %_ptr_Uniform_Inner %a %uint_0 %int_3 %uint_0 %int_2
+         %32 = OpLoad %Inner %31
+         %34 = OpAccessChain %_ptr_Uniform_mat4v4float %a %uint_0 %int_3 %uint_0 %int_2 %uint_0
+         %35 = OpLoad %mat4v4float %34
+         %38 = OpAccessChain %_ptr_Uniform_v4float %a %uint_0 %int_3 %uint_0 %int_2 %uint_0 %int_1
+         %39 = OpLoad %v4float %38
+         %42 = OpAccessChain %_ptr_Uniform_float %a %uint_0 %int_3 %uint_0 %int_2 %uint_0 %int_1 %40
+         %43 = OpLoad %float %42
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/static_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..5377dfc
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/static_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,27 @@
+struct Inner {
+  @size(64)
+  m : mat4x4<f32>,
+}
+
+struct Outer {
+  a : array<Inner, 4>,
+}
+
+@group(0) @binding(0) var<uniform> a : array<Outer, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_a = &(a);
+  let p_a_3 = &((*(p_a))[3]);
+  let p_a_3_a = &((*(p_a_3)).a);
+  let p_a_3_a_2 = &((*(p_a_3_a))[2]);
+  let p_a_3_a_2_m = &((*(p_a_3_a_2)).m);
+  let p_a_3_a_2_m_1 = &((*(p_a_3_a_2_m))[1]);
+  let l_a : array<Outer, 4> = *(p_a);
+  let l_a_3 : Outer = *(p_a_3);
+  let l_a_3_a : array<Inner, 4> = *(p_a_3_a);
+  let l_a_3_a_2 : Inner = *(p_a_3_a_2);
+  let l_a_3_a_2_m : mat4x4<f32> = *(p_a_3_a_2_m);
+  let l_a_3_a_2_m_1 : vec4<f32> = *(p_a_3_a_2_m_1);
+  let l_a_3_a_2_m_1_0 : f32 = (*(p_a_3_a_2_m_1))[0];
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_builtin.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_builtin.wgsl
new file mode 100644
index 0000000..d7bf513
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_builtin.wgsl
@@ -0,0 +1,15 @@
+struct S {
+  before : i32,
+  m : mat4x4<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    let t = transpose(u[2].m);
+    let l = length(u[0].m[1].ywxz);
+    let a = abs(u[0].m[1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_builtin.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..8748244
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_builtin.wgsl.expected.dxc.hlsl
@@ -0,0 +1,19 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[48];
+};
+
+float4x4 tint_symbol(uint4 buffer[48], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]), asfloat(buffer[scalar_offset_3 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float4x4 t = transpose(tint_symbol(u, 400u));
+  const float l = length(asfloat(u[2]).ywxz);
+  const float a = abs(asfloat(u[2]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_builtin.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..8748244
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_builtin.wgsl.expected.fxc.hlsl
@@ -0,0 +1,19 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[48];
+};
+
+float4x4 tint_symbol(uint4 buffer[48], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]), asfloat(buffer[scalar_offset_3 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float4x4 t = transpose(tint_symbol(u, 400u));
+  const float l = length(asfloat(u[2]).ywxz);
+  const float a = abs(asfloat(u[2]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_builtin.wgsl.expected.glsl
new file mode 100644
index 0000000..2fb59ea
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_builtin.wgsl.expected.glsl
@@ -0,0 +1,53 @@
+#version 310 es
+
+struct S {
+  int before;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  mat4 m;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  int after;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+  uint pad_26;
+  uint pad_27;
+  uint pad_28;
+  uint pad_29;
+};
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  S inner[4];
+} u;
+
+void f() {
+  mat4 t = transpose(u.inner[2].m);
+  float l = length(u.inner[0].m[1].ywxz);
+  float a = abs(u.inner[0].m[1].ywxz.x);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_builtin.wgsl.expected.msl
new file mode 100644
index 0000000..e7981db
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_builtin.wgsl.expected.msl
@@ -0,0 +1,32 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 12> tint_pad;
+  /* 0x0010 */ float4x4 m;
+  /* 0x0050 */ tint_array<int8_t, 48> tint_pad_1;
+  /* 0x0080 */ int after;
+  /* 0x0084 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol [[buffer(0)]]) {
+  float4x4 const t = transpose((*(tint_symbol))[2].m);
+  float const l = length(float4((*(tint_symbol))[0].m[1]).ywxz);
+  float const a = fabs(float4((*(tint_symbol))[0].m[1]).ywxz[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_builtin.wgsl.expected.spvasm
new file mode 100644
index 0000000..b239797
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_builtin.wgsl.expected.spvasm
@@ -0,0 +1,65 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 36
+; Schema: 0
+               OpCapability Shader
+         %24 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %u "u"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 16
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 16
+               OpMemberDecorate %S 2 Offset 128
+               OpDecorate %_arr_S_uint_4 ArrayStride 192
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat4v4float = OpTypeMatrix %v4float 4
+          %S = OpTypeStruct %int %mat4v4float %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+    %u_block = OpTypeStruct %_arr_S_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+         %12 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+      %int_2 = OpConstant %int 2
+     %uint_1 = OpConstant %uint 1
+%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float
+         %25 = OpConstantNull %int
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+          %f = OpFunction %void None %12
+         %15 = OpLabel
+         %21 = OpAccessChain %_ptr_Uniform_mat4v4float %u %uint_0 %int_2 %uint_1
+         %22 = OpLoad %mat4v4float %21
+         %16 = OpTranspose %mat4v4float %22
+         %28 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %25 %uint_1 %int_1
+         %29 = OpLoad %v4float %28
+         %30 = OpVectorShuffle %v4float %29 %29 1 3 0 2
+         %23 = OpExtInst %float %24 Length %30
+         %32 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %25 %uint_1 %int_1
+         %33 = OpLoad %v4float %32
+         %34 = OpVectorShuffle %v4float %33 %33 1 3 0 2
+         %35 = OpCompositeExtract %float %34 0
+         %31 = OpExtInst %float %24 FAbs %35
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_builtin.wgsl.expected.wgsl
new file mode 100644
index 0000000..0a0e872
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_builtin.wgsl.expected.wgsl
@@ -0,0 +1,15 @@
+struct S {
+  before : i32,
+  m : mat4x4<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let t = transpose(u[2].m);
+  let l = length(u[0].m[1].ywxz);
+  let a = abs(u[0].m[1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_fn.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_fn.wgsl
new file mode 100644
index 0000000..0de96f6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_fn.wgsl
@@ -0,0 +1,23 @@
+struct S {
+  before : i32,
+  m : mat4x4<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+fn a(a : array<S, 4>) {}
+fn b(s : S) {}
+fn c(m : mat4x4<f32>) {}
+fn d(v : vec4<f32>) {}
+fn e(f : f32) {}
+
+@compute @workgroup_size(1)
+fn f() {
+    a(u);
+    b(u[2]);
+    c(u[2].m);
+    d(u[0].m[1].ywxz);
+    e(u[0].m[1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_fn.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..4aaff71
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_fn.wgsl.expected.dxc.hlsl
@@ -0,0 +1,60 @@
+struct S {
+  int before;
+  float4x4 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[48];
+};
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(float4x4 m) {
+}
+
+void d(float4 v) {
+}
+
+void e(float f_1) {
+}
+
+float4x4 tint_symbol_3(uint4 buffer[48], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]), asfloat(buffer[scalar_offset_3 / 4]));
+}
+
+S tint_symbol_1(uint4 buffer[48], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 128u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_3(buffer, (offset + 16u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[48], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 192u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 384u));
+  c(tint_symbol_3(u, 400u));
+  d(asfloat(u[2]).ywxz);
+  e(asfloat(u[2]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_fn.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..4aaff71
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_fn.wgsl.expected.fxc.hlsl
@@ -0,0 +1,60 @@
+struct S {
+  int before;
+  float4x4 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[48];
+};
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(float4x4 m) {
+}
+
+void d(float4 v) {
+}
+
+void e(float f_1) {
+}
+
+float4x4 tint_symbol_3(uint4 buffer[48], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]), asfloat(buffer[scalar_offset_3 / 4]));
+}
+
+S tint_symbol_1(uint4 buffer[48], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 128u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_3(buffer, (offset + 16u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[48], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 192u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(tint_symbol_1(u, 384u));
+  c(tint_symbol_3(u, 400u));
+  d(asfloat(u[2]).ywxz);
+  e(asfloat(u[2]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_fn.wgsl.expected.glsl
new file mode 100644
index 0000000..25c9615
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_fn.wgsl.expected.glsl
@@ -0,0 +1,70 @@
+#version 310 es
+
+struct S {
+  int before;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  mat4 m;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  int after;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+  uint pad_26;
+  uint pad_27;
+  uint pad_28;
+  uint pad_29;
+};
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  S inner[4];
+} u;
+
+void a(S a_1[4]) {
+}
+
+void b(S s) {
+}
+
+void c(mat4 m) {
+}
+
+void d(vec4 v) {
+}
+
+void e(float f_1) {
+}
+
+void f() {
+  a(u.inner);
+  b(u.inner[2]);
+  c(u.inner[2].m);
+  d(u.inner[0].m[1].ywxz);
+  e(u.inner[0].m[1].ywxz.x);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_fn.wgsl.expected.msl
new file mode 100644
index 0000000..032931f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_fn.wgsl.expected.msl
@@ -0,0 +1,49 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 12> tint_pad;
+  /* 0x0010 */ float4x4 m;
+  /* 0x0050 */ tint_array<int8_t, 48> tint_pad_1;
+  /* 0x0080 */ int after;
+  /* 0x0084 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+void a(tint_array<S, 4> a_1) {
+}
+
+void b(S s) {
+}
+
+void c(float4x4 m) {
+}
+
+void d(float4 v) {
+}
+
+void e(float f_1) {
+}
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol [[buffer(0)]]) {
+  a(*(tint_symbol));
+  b((*(tint_symbol))[2]);
+  c((*(tint_symbol))[2].m);
+  d(float4((*(tint_symbol))[0].m[1]).ywxz);
+  e(float4((*(tint_symbol))[0].m[1]).ywxz[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_fn.wgsl.expected.spvasm
new file mode 100644
index 0000000..ca7c033
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_fn.wgsl.expected.spvasm
@@ -0,0 +1,112 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 63
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %u "u"
+               OpName %a "a"
+               OpName %a_1 "a_1"
+               OpName %b "b"
+               OpName %s "s"
+               OpName %c "c"
+               OpName %m "m"
+               OpName %d "d"
+               OpName %v "v"
+               OpName %e "e"
+               OpName %f_1 "f_1"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 16
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 16
+               OpMemberDecorate %S 2 Offset 128
+               OpDecorate %_arr_S_uint_4 ArrayStride 192
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat4v4float = OpTypeMatrix %v4float 4
+          %S = OpTypeStruct %int %mat4v4float %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+    %u_block = OpTypeStruct %_arr_S_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+         %12 = OpTypeFunction %void %_arr_S_uint_4
+         %17 = OpTypeFunction %void %S
+         %21 = OpTypeFunction %void %mat4v4float
+         %25 = OpTypeFunction %void %v4float
+         %29 = OpTypeFunction %void %float
+         %33 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_S_uint_4 = OpTypePointer Uniform %_arr_S_uint_4
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_S = OpTypePointer Uniform %S
+     %uint_1 = OpConstant %uint 1
+%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float
+         %52 = OpConstantNull %int
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+          %a = OpFunction %void None %12
+        %a_1 = OpFunctionParameter %_arr_S_uint_4
+         %16 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %b = OpFunction %void None %17
+          %s = OpFunctionParameter %S
+         %20 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %c = OpFunction %void None %21
+          %m = OpFunctionParameter %mat4v4float
+         %24 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %d = OpFunction %void None %25
+          %v = OpFunctionParameter %v4float
+         %28 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %e = OpFunction %void None %29
+        %f_1 = OpFunctionParameter %float
+         %32 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %33
+         %35 = OpLabel
+         %39 = OpAccessChain %_ptr_Uniform__arr_S_uint_4 %u %uint_0
+         %40 = OpLoad %_arr_S_uint_4 %39
+         %36 = OpFunctionCall %void %a %40
+         %44 = OpAccessChain %_ptr_Uniform_S %u %uint_0 %int_2
+         %45 = OpLoad %S %44
+         %41 = OpFunctionCall %void %b %45
+         %49 = OpAccessChain %_ptr_Uniform_mat4v4float %u %uint_0 %int_2 %uint_1
+         %50 = OpLoad %mat4v4float %49
+         %46 = OpFunctionCall %void %c %50
+         %55 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %52 %uint_1 %int_1
+         %56 = OpLoad %v4float %55
+         %57 = OpVectorShuffle %v4float %56 %56 1 3 0 2
+         %51 = OpFunctionCall %void %d %57
+         %59 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %52 %uint_1 %int_1
+         %60 = OpLoad %v4float %59
+         %61 = OpVectorShuffle %v4float %60 %60 1 3 0 2
+         %62 = OpCompositeExtract %float %61 0
+         %58 = OpFunctionCall %void %e %62
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_fn.wgsl.expected.wgsl
new file mode 100644
index 0000000..614b495
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_fn.wgsl.expected.wgsl
@@ -0,0 +1,32 @@
+struct S {
+  before : i32,
+  m : mat4x4<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+fn a(a : array<S, 4>) {
+}
+
+fn b(s : S) {
+}
+
+fn c(m : mat4x4<f32>) {
+}
+
+fn d(v : vec4<f32>) {
+}
+
+fn e(f : f32) {
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  a(u);
+  b(u[2]);
+  c(u[2].m);
+  d(u[0].m[1].ywxz);
+  e(u[0].m[1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_private.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_private.wgsl
new file mode 100644
index 0000000..aeb7b5e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_private.wgsl
@@ -0,0 +1,17 @@
+struct S {
+  before : i32,
+  m : mat4x4<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+var<private> p : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[2];
+    p[3].m = u[2].m;
+    p[1].m[0] = u[0].m[1].ywxz;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_private.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..be13120
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_private.wgsl.expected.dxc.hlsl
@@ -0,0 +1,45 @@
+struct S {
+  int before;
+  float4x4 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[48];
+};
+static S p[4] = (S[4])0;
+
+float4x4 tint_symbol_3(uint4 buffer[48], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]), asfloat(buffer[scalar_offset_3 / 4]));
+}
+
+S tint_symbol_1(uint4 buffer[48], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 128u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_3(buffer, (offset + 16u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[48], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 192u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 384u);
+  p[3].m = tint_symbol_3(u, 400u);
+  p[1].m[0] = asfloat(u[2]).ywxz;
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_private.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..be13120
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_private.wgsl.expected.fxc.hlsl
@@ -0,0 +1,45 @@
+struct S {
+  int before;
+  float4x4 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[48];
+};
+static S p[4] = (S[4])0;
+
+float4x4 tint_symbol_3(uint4 buffer[48], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]), asfloat(buffer[scalar_offset_3 / 4]));
+}
+
+S tint_symbol_1(uint4 buffer[48], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 128u)) / 4;
+  const S tint_symbol_5 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_3(buffer, (offset + 16u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_5;
+}
+
+typedef S tint_symbol_ret[4];
+tint_symbol_ret tint_symbol(uint4 buffer[48], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      arr[i] = tint_symbol_1(buffer, (offset + (i * 192u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = tint_symbol_1(u, 384u);
+  p[3].m = tint_symbol_3(u, 400u);
+  p[1].m[0] = asfloat(u[2]).ywxz;
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..3f9ed3c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_private.wgsl.expected.glsl
@@ -0,0 +1,55 @@
+#version 310 es
+
+struct S {
+  int before;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  mat4 m;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  int after;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+  uint pad_26;
+  uint pad_27;
+  uint pad_28;
+  uint pad_29;
+};
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  S inner[4];
+} u;
+
+S p[4] = S[4](S(0, 0u, 0u, 0u, mat4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, 0u, 0u, mat4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, 0u, 0u, mat4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u), S(0, 0u, 0u, 0u, mat4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u));
+void f() {
+  p = u.inner;
+  p[1] = u.inner[2];
+  p[3].m = u.inner[2].m;
+  p[1].m[0] = u.inner[0].m[1].ywxz;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..ebaafb7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_private.wgsl.expected.msl
@@ -0,0 +1,34 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 12> tint_pad;
+  /* 0x0010 */ float4x4 m;
+  /* 0x0050 */ tint_array<int8_t, 48> tint_pad_1;
+  /* 0x0080 */ int after;
+  /* 0x0084 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol_1 [[buffer(0)]]) {
+  thread tint_array<S, 4> tint_symbol = {};
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[2];
+  tint_symbol[3].m = (*(tint_symbol_1))[2].m;
+  tint_symbol[1].m[0] = float4((*(tint_symbol_1))[0].m[1]).ywxz;
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_private.wgsl.expected.spvasm
new file mode 100644
index 0000000..6f1b407
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_private.wgsl.expected.spvasm
@@ -0,0 +1,78 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 44
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %u "u"
+               OpName %p "p"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 16
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 16
+               OpMemberDecorate %S 2 Offset 128
+               OpDecorate %_arr_S_uint_4 ArrayStride 192
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat4v4float = OpTypeMatrix %v4float 4
+          %S = OpTypeStruct %int %mat4v4float %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+    %u_block = OpTypeStruct %_arr_S_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_Private__arr_S_uint_4 = OpTypePointer Private %_arr_S_uint_4
+         %14 = OpConstantNull %_arr_S_uint_4
+          %p = OpVariable %_ptr_Private__arr_S_uint_4 Private %14
+       %void = OpTypeVoid
+         %15 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_S_uint_4 = OpTypePointer Uniform %_arr_S_uint_4
+      %int_1 = OpConstant %int 1
+%_ptr_Private_S = OpTypePointer Private %S
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_S = OpTypePointer Uniform %S
+      %int_3 = OpConstant %int 3
+     %uint_1 = OpConstant %uint 1
+%_ptr_Private_mat4v4float = OpTypePointer Private %mat4v4float
+%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float
+         %37 = OpConstantNull %int
+%_ptr_Private_v4float = OpTypePointer Private %v4float
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+          %f = OpFunction %void None %15
+         %18 = OpLabel
+         %21 = OpAccessChain %_ptr_Uniform__arr_S_uint_4 %u %uint_0
+         %22 = OpLoad %_arr_S_uint_4 %21
+               OpStore %p %22
+         %25 = OpAccessChain %_ptr_Private_S %p %int_1
+         %28 = OpAccessChain %_ptr_Uniform_S %u %uint_0 %int_2
+         %29 = OpLoad %S %28
+               OpStore %25 %29
+         %33 = OpAccessChain %_ptr_Private_mat4v4float %p %int_3 %uint_1
+         %35 = OpAccessChain %_ptr_Uniform_mat4v4float %u %uint_0 %int_2 %uint_1
+         %36 = OpLoad %mat4v4float %35
+               OpStore %33 %36
+         %39 = OpAccessChain %_ptr_Private_v4float %p %int_1 %uint_1 %37
+         %41 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %37 %uint_1 %int_1
+         %42 = OpLoad %v4float %41
+         %43 = OpVectorShuffle %v4float %42 %42 1 3 0 2
+               OpStore %39 %43
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..7c8565d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_private.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+struct S {
+  before : i32,
+  m : mat4x4<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+var<private> p : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[2];
+  p[3].m = u[2].m;
+  p[1].m[0] = u[0].m[1].ywxz;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_storage.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_storage.wgsl
new file mode 100644
index 0000000..0dbde254
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_storage.wgsl
@@ -0,0 +1,17 @@
+struct S {
+  before : i32,
+  m : mat4x4<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+@group(0) @binding(1) var<storage, read_write> s : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[2];
+    s[3].m = u[2].m;
+    s[1].m[0] = u[0].m[1].ywxz;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_storage.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..cc21007
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_storage.wgsl.expected.dxc.hlsl
@@ -0,0 +1,67 @@
+struct S {
+  int before;
+  float4x4 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[48];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_3(RWByteAddressBuffer buffer, uint offset, float4x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+  buffer.Store4((offset + 32u), asuint(value[2u]));
+  buffer.Store4((offset + 48u), asuint(value[3u]));
+}
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, S value) {
+  buffer.Store((offset + 0u), asuint(value.before));
+  tint_symbol_3(buffer, (offset + 16u), value.m);
+  buffer.Store((offset + 128u), asuint(value.after));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, S value[4]) {
+  S array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 192u)), array[i]);
+    }
+  }
+}
+
+float4x4 tint_symbol_8(uint4 buffer[48], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]), asfloat(buffer[scalar_offset_3 / 4]));
+}
+
+S tint_symbol_6(uint4 buffer[48], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 128u)) / 4;
+  const S tint_symbol_10 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_8(buffer, (offset + 16u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_10;
+}
+
+typedef S tint_symbol_5_ret[4];
+tint_symbol_5_ret tint_symbol_5(uint4 buffer[48], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_6(buffer, (offset + (i_1 * 192u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_5(u, 0u));
+  tint_symbol_1(s, 192u, tint_symbol_6(u, 384u));
+  tint_symbol_3(s, 592u, tint_symbol_8(u, 400u));
+  s.Store4(208u, asuint(asfloat(u[2]).ywxz));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_storage.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..cc21007
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_storage.wgsl.expected.fxc.hlsl
@@ -0,0 +1,67 @@
+struct S {
+  int before;
+  float4x4 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[48];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol_3(RWByteAddressBuffer buffer, uint offset, float4x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+  buffer.Store4((offset + 32u), asuint(value[2u]));
+  buffer.Store4((offset + 48u), asuint(value[3u]));
+}
+
+void tint_symbol_1(RWByteAddressBuffer buffer, uint offset, S value) {
+  buffer.Store((offset + 0u), asuint(value.before));
+  tint_symbol_3(buffer, (offset + 16u), value.m);
+  buffer.Store((offset + 128u), asuint(value.after));
+}
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, S value[4]) {
+  S array[4] = value;
+  {
+    for(uint i = 0u; (i < 4u); i = (i + 1u)) {
+      tint_symbol_1(buffer, (offset + (i * 192u)), array[i]);
+    }
+  }
+}
+
+float4x4 tint_symbol_8(uint4 buffer[48], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]), asfloat(buffer[scalar_offset_3 / 4]));
+}
+
+S tint_symbol_6(uint4 buffer[48], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 128u)) / 4;
+  const S tint_symbol_10 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_8(buffer, (offset + 16u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_10;
+}
+
+typedef S tint_symbol_5_ret[4];
+tint_symbol_5_ret tint_symbol_5(uint4 buffer[48], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_6(buffer, (offset + (i_1 * 192u)));
+    }
+  }
+  return arr;
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_5(u, 0u));
+  tint_symbol_1(s, 192u, tint_symbol_6(u, 384u));
+  tint_symbol_3(s, 592u, tint_symbol_8(u, 400u));
+  s.Store4(208u, asuint(asfloat(u[2]).ywxz));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..012d60c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_storage.wgsl.expected.glsl
@@ -0,0 +1,58 @@
+#version 310 es
+
+struct S {
+  int before;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  mat4 m;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  int after;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+  uint pad_26;
+  uint pad_27;
+  uint pad_28;
+  uint pad_29;
+};
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  S inner[4];
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  S inner[4];
+} s;
+
+void f() {
+  s.inner = u.inner;
+  s.inner[1] = u.inner[2];
+  s.inner[3].m = u.inner[2].m;
+  s.inner[1].m[0] = u.inner[0].m[1].ywxz;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..b049b86
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_storage.wgsl.expected.msl
@@ -0,0 +1,33 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 12> tint_pad;
+  /* 0x0010 */ float4x4 m;
+  /* 0x0050 */ tint_array<int8_t, 48> tint_pad_1;
+  /* 0x0080 */ int after;
+  /* 0x0084 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+kernel void f(device tint_array<S, 4>* tint_symbol [[buffer(1)]], const constant tint_array<S, 4>* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[2];
+  (*(tint_symbol))[3].m = (*(tint_symbol_1))[2].m;
+  (*(tint_symbol))[1].m[0] = float4((*(tint_symbol_1))[0].m[1]).ywxz;
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_storage.wgsl.expected.spvasm
new file mode 100644
index 0000000..899c29c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_storage.wgsl.expected.spvasm
@@ -0,0 +1,81 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 45
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %u "u"
+               OpName %s "s"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 16
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 16
+               OpMemberDecorate %S 2 Offset 128
+               OpDecorate %_arr_S_uint_4 ArrayStride 192
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %s DescriptorSet 0
+               OpDecorate %s Binding 1
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat4v4float = OpTypeMatrix %v4float 4
+          %S = OpTypeStruct %int %mat4v4float %int
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+    %u_block = OpTypeStruct %_arr_S_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
+          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+       %void = OpTypeVoid
+         %14 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer__arr_S_uint_4 = OpTypePointer StorageBuffer %_arr_S_uint_4
+%_ptr_Uniform__arr_S_uint_4 = OpTypePointer Uniform %_arr_S_uint_4
+      %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_S = OpTypePointer Uniform %S
+      %int_3 = OpConstant %int 3
+     %uint_1 = OpConstant %uint 1
+%_ptr_StorageBuffer_mat4v4float = OpTypePointer StorageBuffer %mat4v4float
+%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float
+         %38 = OpConstantNull %int
+%_ptr_StorageBuffer_v4float = OpTypePointer StorageBuffer %v4float
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+          %f = OpFunction %void None %14
+         %17 = OpLabel
+         %20 = OpAccessChain %_ptr_StorageBuffer__arr_S_uint_4 %s %uint_0
+         %22 = OpAccessChain %_ptr_Uniform__arr_S_uint_4 %u %uint_0
+         %23 = OpLoad %_arr_S_uint_4 %22
+               OpStore %20 %23
+         %26 = OpAccessChain %_ptr_StorageBuffer_S %s %uint_0 %int_1
+         %29 = OpAccessChain %_ptr_Uniform_S %u %uint_0 %int_2
+         %30 = OpLoad %S %29
+               OpStore %26 %30
+         %34 = OpAccessChain %_ptr_StorageBuffer_mat4v4float %s %uint_0 %int_3 %uint_1
+         %36 = OpAccessChain %_ptr_Uniform_mat4v4float %u %uint_0 %int_2 %uint_1
+         %37 = OpLoad %mat4v4float %36
+               OpStore %34 %37
+         %40 = OpAccessChain %_ptr_StorageBuffer_v4float %s %uint_0 %int_1 %uint_1 %38
+         %42 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %38 %uint_1 %int_1
+         %43 = OpLoad %v4float %42
+         %44 = OpVectorShuffle %v4float %43 %43 1 3 0 2
+               OpStore %40 %44
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..8b33398
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+struct S {
+  before : i32,
+  m : mat4x4<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+@group(0) @binding(1) var<storage, read_write> s : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[2];
+  s[3].m = u[2].m;
+  s[1].m[0] = u[0].m[1].ywxz;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_workgroup.wgsl
new file mode 100644
index 0000000..c952bdf
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_workgroup.wgsl
@@ -0,0 +1,17 @@
+struct S {
+  before : i32,
+  m : mat4x4<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+var<workgroup> w : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[2];
+    w[3].m = u[2].m;
+    w[1].m[0] = u[0].m[1].ywxz;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_workgroup.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..5bf6274
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_workgroup.wgsl.expected.dxc.hlsl
@@ -0,0 +1,61 @@
+struct S {
+  int before;
+  float4x4 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[48];
+};
+groupshared S w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+float4x4 tint_symbol_5(uint4 buffer[48], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]), asfloat(buffer[scalar_offset_3 / 4]));
+}
+
+S tint_symbol_3(uint4 buffer[48], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 128u)) / 4;
+  const S tint_symbol_8 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_5(buffer, (offset + 16u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_8;
+}
+
+typedef S tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[48], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 192u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      const S tint_symbol_7 = (S)0;
+      w[i] = tint_symbol_7;
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 384u);
+  w[3].m = tint_symbol_5(u, 400u);
+  w[1].m[0] = asfloat(u[2]).ywxz;
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_workgroup.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..5bf6274
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_workgroup.wgsl.expected.fxc.hlsl
@@ -0,0 +1,61 @@
+struct S {
+  int before;
+  float4x4 m;
+  int after;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[48];
+};
+groupshared S w[4];
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+float4x4 tint_symbol_5(uint4 buffer[48], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]), asfloat(buffer[scalar_offset_3 / 4]));
+}
+
+S tint_symbol_3(uint4 buffer[48], uint offset) {
+  const uint scalar_offset_4 = ((offset + 0u)) / 4;
+  const uint scalar_offset_5 = ((offset + 128u)) / 4;
+  const S tint_symbol_8 = {asint(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), tint_symbol_5(buffer, (offset + 16u)), asint(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4])};
+  return tint_symbol_8;
+}
+
+typedef S tint_symbol_2_ret[4];
+tint_symbol_2_ret tint_symbol_2(uint4 buffer[48], uint offset) {
+  S arr[4] = (S[4])0;
+  {
+    for(uint i_1 = 0u; (i_1 < 4u); i_1 = (i_1 + 1u)) {
+      arr[i_1] = tint_symbol_3(buffer, (offset + (i_1 * 192u)));
+    }
+  }
+  return arr;
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      const uint i = idx;
+      const S tint_symbol_7 = (S)0;
+      w[i] = tint_symbol_7;
+    }
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = tint_symbol_3(u, 384u);
+  w[3].m = tint_symbol_5(u, 400u);
+  w[1].m[0] = asfloat(u[2]).ywxz;
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..327158d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,63 @@
+#version 310 es
+
+struct S {
+  int before;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  mat4 m;
+  uint pad_3;
+  uint pad_4;
+  uint pad_5;
+  uint pad_6;
+  uint pad_7;
+  uint pad_8;
+  uint pad_9;
+  uint pad_10;
+  uint pad_11;
+  uint pad_12;
+  uint pad_13;
+  uint pad_14;
+  int after;
+  uint pad_15;
+  uint pad_16;
+  uint pad_17;
+  uint pad_18;
+  uint pad_19;
+  uint pad_20;
+  uint pad_21;
+  uint pad_22;
+  uint pad_23;
+  uint pad_24;
+  uint pad_25;
+  uint pad_26;
+  uint pad_27;
+  uint pad_28;
+  uint pad_29;
+};
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  S inner[4];
+} u;
+
+shared S w[4];
+void f(uint local_invocation_index) {
+  {
+    for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+      uint i = idx;
+      S tint_symbol = S(0, 0u, 0u, 0u, mat4(vec4(0.0f), vec4(0.0f), vec4(0.0f), vec4(0.0f)), 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u);
+      w[i] = tint_symbol;
+    }
+  }
+  barrier();
+  w = u.inner;
+  w[1] = u.inner[2];
+  w[3].m = u.inner[2].m;
+  w[1].m[0] = u.inner[0].m[1].ywxz;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..302c388
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,48 @@
+#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 S {
+  /* 0x0000 */ int before;
+  /* 0x0004 */ tint_array<int8_t, 12> tint_pad;
+  /* 0x0010 */ float4x4 m;
+  /* 0x0050 */ tint_array<int8_t, 48> tint_pad_1;
+  /* 0x0080 */ int after;
+  /* 0x0084 */ tint_array<int8_t, 60> tint_pad_2;
+};
+
+struct tint_symbol_6 {
+  tint_array<S, 4> w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup tint_array<S, 4>* const tint_symbol_1, const constant tint_array<S, 4>* const tint_symbol_2) {
+  for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+    uint const i = idx;
+    S const tint_symbol = S{};
+    (*(tint_symbol_1))[i] = tint_symbol;
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol_1) = *(tint_symbol_2);
+  (*(tint_symbol_1))[1] = (*(tint_symbol_2))[2];
+  (*(tint_symbol_1))[3].m = (*(tint_symbol_2))[2].m;
+  (*(tint_symbol_1))[1].m[0] = float4((*(tint_symbol_2))[0].m[1]).ywxz;
+}
+
+kernel void f(const constant tint_array<S, 4>* tint_symbol_5 [[buffer(0)]], threadgroup tint_symbol_6* tint_symbol_4 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup tint_array<S, 4>* const tint_symbol_3 = &((*(tint_symbol_4)).w);
+  f_inner(local_invocation_index, tint_symbol_3, tint_symbol_5);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_workgroup.wgsl.expected.spvasm
new file mode 100644
index 0000000..220cd9b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_workgroup.wgsl.expected.spvasm
@@ -0,0 +1,124 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 72
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %local_invocation_index_1 "local_invocation_index_1"
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "before"
+               OpMemberName %S 1 "m"
+               OpMemberName %S 2 "after"
+               OpName %u "u"
+               OpName %w "w"
+               OpName %f_inner "f_inner"
+               OpName %local_invocation_index "local_invocation_index"
+               OpName %idx "idx"
+               OpName %f "f"
+               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %S 1 Offset 16
+               OpMemberDecorate %S 1 ColMajor
+               OpMemberDecorate %S 1 MatrixStride 16
+               OpMemberDecorate %S 2 Offset 128
+               OpDecorate %_arr_S_uint_4 ArrayStride 192
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat4v4float = OpTypeMatrix %v4float 4
+          %S = OpTypeStruct %int %mat4v4float %int
+     %uint_4 = OpConstant %uint 4
+%_arr_S_uint_4 = OpTypeArray %S %uint_4
+    %u_block = OpTypeStruct %_arr_S_uint_4
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_Workgroup__arr_S_uint_4 = OpTypePointer Workgroup %_arr_S_uint_4
+          %w = OpVariable %_ptr_Workgroup__arr_S_uint_4 Workgroup
+       %void = OpTypeVoid
+         %16 = OpTypeFunction %void %uint
+%_ptr_Function_uint = OpTypePointer Function %uint
+         %23 = OpConstantNull %uint
+       %bool = OpTypeBool
+%_ptr_Workgroup_S = OpTypePointer Workgroup %S
+         %37 = OpConstantNull %S
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+   %uint_264 = OpConstant %uint 264
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform__arr_S_uint_4 = OpTypePointer Uniform %_arr_S_uint_4
+      %int_1 = OpConstant %int 1
+      %int_2 = OpConstant %int 2
+%_ptr_Uniform_S = OpTypePointer Uniform %S
+      %int_3 = OpConstant %int 3
+%_ptr_Workgroup_mat4v4float = OpTypePointer Workgroup %mat4v4float
+%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float
+         %60 = OpConstantNull %int
+%_ptr_Workgroup_v4float = OpTypePointer Workgroup %v4float
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+         %67 = OpTypeFunction %void
+    %f_inner = OpFunction %void None %16
+%local_invocation_index = OpFunctionParameter %uint
+         %20 = OpLabel
+        %idx = OpVariable %_ptr_Function_uint Function %23
+               OpStore %idx %local_invocation_index
+               OpBranch %24
+         %24 = OpLabel
+               OpLoopMerge %25 %26 None
+               OpBranch %27
+         %27 = OpLabel
+         %29 = OpLoad %uint %idx
+         %30 = OpULessThan %bool %29 %uint_4
+         %28 = OpLogicalNot %bool %30
+               OpSelectionMerge %32 None
+               OpBranchConditional %28 %33 %32
+         %33 = OpLabel
+               OpBranch %25
+         %32 = OpLabel
+         %34 = OpLoad %uint %idx
+         %36 = OpAccessChain %_ptr_Workgroup_S %w %34
+               OpStore %36 %37
+               OpBranch %26
+         %26 = OpLabel
+         %38 = OpLoad %uint %idx
+         %40 = OpIAdd %uint %38 %uint_1
+               OpStore %idx %40
+               OpBranch %24
+         %25 = OpLabel
+               OpControlBarrier %uint_2 %uint_2 %uint_264
+         %46 = OpAccessChain %_ptr_Uniform__arr_S_uint_4 %u %uint_0
+         %47 = OpLoad %_arr_S_uint_4 %46
+               OpStore %w %47
+         %49 = OpAccessChain %_ptr_Workgroup_S %w %int_1
+         %52 = OpAccessChain %_ptr_Uniform_S %u %uint_0 %int_2
+         %53 = OpLoad %S %52
+               OpStore %49 %53
+         %56 = OpAccessChain %_ptr_Workgroup_mat4v4float %w %int_3 %uint_1
+         %58 = OpAccessChain %_ptr_Uniform_mat4v4float %u %uint_0 %int_2 %uint_1
+         %59 = OpLoad %mat4v4float %58
+               OpStore %56 %59
+         %62 = OpAccessChain %_ptr_Workgroup_v4float %w %int_1 %uint_1 %60
+         %64 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %60 %uint_1 %int_1
+         %65 = OpLoad %v4float %64
+         %66 = OpVectorShuffle %v4float %65 %65 1 3 0 2
+               OpStore %62 %66
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %67
+         %69 = OpLabel
+         %71 = OpLoad %uint %local_invocation_index_1
+         %70 = OpFunctionCall %void %f_inner %71
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..c618743
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/struct/mat4x4_f32/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+struct S {
+  before : i32,
+  m : mat4x4<f32>,
+  @align(64) @size(16)
+  after : i32,
+}
+
+@group(0) @binding(0) var<uniform> u : array<S, 4>;
+
+var<workgroup> w : array<S, 4>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[2];
+  w[3].m = u[2].m;
+  w[1].m[0] = u[0].m[1].ywxz;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/dynamic_index_via_ptr.wgsl
new file mode 100644
index 0000000..8f28ad3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/dynamic_index_via_ptr.wgsl
@@ -0,0 +1,15 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> m : mat2x2<f16>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m   = &m;
+  let p_m_i = &((*p_m)[i()]);
+
+  let l_m   : mat2x2<f16> = *p_m;
+  let l_m_i : vec2<f16>   = *p_m_i;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..5dc66f6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,27 @@
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[1];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 2, 2> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  return matrix<float16_t, 2, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_m_i_save = i();
+  const matrix<float16_t, 2, 2> l_m = tint_symbol(m, 0u);
+  const uint scalar_offset_2 = ((4u * uint(p_m_i_save))) / 4;
+  uint ubo_load_2 = m[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const vector<float16_t, 2> l_m_i = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..02ff823
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,32 @@
+SKIP: FAILED
+
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[1];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 2, 2> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  return matrix<float16_t, 2, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_m_i_save = i();
+  const matrix<float16_t, 2, 2> l_m = tint_symbol(m, 0u);
+  const uint scalar_offset_2 = ((4u * uint(p_m_i_save))) / 4;
+  uint ubo_load_2 = m[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const vector<float16_t, 2> l_m_i = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16)));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000021290B9AF00(11,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/dynamic_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..72425b7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,48 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform m_block_std140_ubo {
+  f16vec2 inner_0;
+  f16vec2 inner_1;
+} m;
+
+int counter = 0;
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+f16mat2 load_m_inner() {
+  return f16mat2(m.inner_0, m.inner_1);
+}
+
+f16vec2 load_m_inner_p0(uint p0) {
+  switch(p0) {
+    case 0u: {
+      return m.inner_0;
+      break;
+    }
+    case 1u: {
+      return m.inner_1;
+      break;
+    }
+    default: {
+      return f16vec2(0.0hf);
+      break;
+    }
+  }
+}
+
+void f() {
+  f16mat2 p_m = load_m_inner();
+  int tint_symbol = i();
+  f16vec2 p_m_i = load_m_inner_p0(uint(tint_symbol));
+  f16mat2 l_m = load_m_inner();
+  f16vec2 l_m_i = load_m_inner_p0(uint(tint_symbol));
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/dynamic_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..f9562f6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/dynamic_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,17 @@
+#include <metal_stdlib>
+
+using namespace metal;
+int i() {
+  thread int tint_symbol_1 = 0;
+  tint_symbol_1 = as_type<int>((as_type<uint>(tint_symbol_1) + as_type<uint>(1)));
+  return tint_symbol_1;
+}
+
+kernel void f(const constant half2x2* tint_symbol_2 [[buffer(0)]]) {
+  int const tint_symbol = i();
+  int const p_m_i_save = tint_symbol;
+  half2x2 const l_m = *(tint_symbol_2);
+  half2 const l_m_i = (*(tint_symbol_2))[p_m_i_save];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..4270e43
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,93 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 54
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %m_block_std140 "m_block_std140"
+               OpMemberName %m_block_std140 0 "inner_0"
+               OpMemberName %m_block_std140 1 "inner_1"
+               OpName %m "m"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %load_m_inner "load_m_inner"
+               OpName %load_m_inner_p0 "load_m_inner_p0"
+               OpName %p0 "p0"
+               OpName %f "f"
+               OpDecorate %m_block_std140 Block
+               OpMemberDecorate %m_block_std140 0 Offset 0
+               OpMemberDecorate %m_block_std140 1 Offset 4
+               OpDecorate %m NonWritable
+               OpDecorate %m DescriptorSet 0
+               OpDecorate %m Binding 0
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+%m_block_std140 = OpTypeStruct %v2half %v2half
+%_ptr_Uniform_m_block_std140 = OpTypePointer Uniform %m_block_std140
+          %m = OpVariable %_ptr_Uniform_m_block_std140 Uniform
+        %int = OpTypeInt 32 1
+          %7 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %7
+         %10 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+ %mat2v2half = OpTypeMatrix %v2half 2
+         %17 = OpTypeFunction %mat2v2half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+     %uint_1 = OpConstant %uint 1
+         %33 = OpTypeFunction %v2half %uint
+         %45 = OpConstantNull %v2half
+       %void = OpTypeVoid
+         %46 = OpTypeFunction %void
+          %i = OpFunction %int None %10
+         %12 = OpLabel
+         %13 = OpLoad %int %counter
+         %15 = OpIAdd %int %13 %int_1
+               OpStore %counter %15
+         %16 = OpLoad %int %counter
+               OpReturnValue %16
+               OpFunctionEnd
+%load_m_inner = OpFunction %mat2v2half None %17
+         %20 = OpLabel
+         %26 = OpAccessChain %_ptr_Uniform_v2half %m %uint_0
+         %27 = OpLoad %v2half %26
+         %30 = OpAccessChain %_ptr_Uniform_v2half %m %uint_1
+         %31 = OpLoad %v2half %30
+         %32 = OpCompositeConstruct %mat2v2half %27 %31
+               OpReturnValue %32
+               OpFunctionEnd
+%load_m_inner_p0 = OpFunction %v2half None %33
+         %p0 = OpFunctionParameter %uint
+         %36 = OpLabel
+               OpSelectionMerge %37 None
+               OpSwitch %p0 %38 0 %39 1 %40
+         %39 = OpLabel
+         %41 = OpAccessChain %_ptr_Uniform_v2half %m %uint_0
+         %42 = OpLoad %v2half %41
+               OpReturnValue %42
+         %40 = OpLabel
+         %43 = OpAccessChain %_ptr_Uniform_v2half %m %uint_1
+         %44 = OpLoad %v2half %43
+               OpReturnValue %44
+         %38 = OpLabel
+               OpReturnValue %45
+         %37 = OpLabel
+               OpReturnValue %45
+               OpFunctionEnd
+          %f = OpFunction %void None %46
+         %49 = OpLabel
+         %50 = OpFunctionCall %int %i
+         %51 = OpFunctionCall %mat2v2half %load_m_inner
+         %53 = OpBitcast %uint %50
+         %52 = OpFunctionCall %v2half %load_m_inner_p0 %53
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..2ba6a33
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> m : mat2x2<f16>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m = &(m);
+  let p_m_i = &((*(p_m))[i()]);
+  let l_m : mat2x2<f16> = *(p_m);
+  let l_m_i : vec2<f16> = *(p_m_i);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/static_index_via_ptr.wgsl
new file mode 100644
index 0000000..62c686f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/static_index_via_ptr.wgsl
@@ -0,0 +1,15 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> m : mat2x2<f16>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m   = &m;
+  let p_m_1 = &((*p_m)[1]);
+
+  let l_m   : mat2x2<f16> = *p_m;
+  let l_m_1 : vec2<f16>   = *p_m_1;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..b381bd2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,25 @@
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[1];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 2, 2> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  return matrix<float16_t, 2, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 2, 2> l_m = tint_symbol(m, 0u);
+  uint ubo_load_2 = m[0].y;
+  const vector<float16_t, 2> l_m_1 = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..d28f04f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,30 @@
+SKIP: FAILED
+
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[1];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 2, 2> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  return matrix<float16_t, 2, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 2, 2> l_m = tint_symbol(m, 0u);
+  uint ubo_load_2 = m[0].y;
+  const vector<float16_t, 2> l_m_1 = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16)));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001899F313180(11,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/static_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..c17ae4c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/static_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,24 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform m_block_std140_ubo {
+  f16vec2 inner_0;
+  f16vec2 inner_1;
+} m;
+
+f16mat2 load_m_inner() {
+  return f16mat2(m.inner_0, m.inner_1);
+}
+
+void f() {
+  f16mat2 p_m = load_m_inner();
+  f16vec2 p_m_1 = m.inner_1;
+  f16mat2 l_m = load_m_inner();
+  f16vec2 l_m_1 = m.inner_1;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/static_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..59df3ba
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/static_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,15 @@
+#include <metal_stdlib>
+
+using namespace metal;
+int i() {
+  thread int tint_symbol = 0;
+  tint_symbol = as_type<int>((as_type<uint>(tint_symbol) + as_type<uint>(1)));
+  return tint_symbol;
+}
+
+kernel void f(const constant half2x2* tint_symbol_1 [[buffer(0)]]) {
+  half2x2 const l_m = *(tint_symbol_1);
+  half2 const l_m_1 = (*(tint_symbol_1))[1];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/static_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..7ec1f84
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/static_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,70 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 40
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %m_block_std140 "m_block_std140"
+               OpMemberName %m_block_std140 0 "inner_0"
+               OpMemberName %m_block_std140 1 "inner_1"
+               OpName %m "m"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %load_m_inner "load_m_inner"
+               OpName %f "f"
+               OpDecorate %m_block_std140 Block
+               OpMemberDecorate %m_block_std140 0 Offset 0
+               OpMemberDecorate %m_block_std140 1 Offset 4
+               OpDecorate %m NonWritable
+               OpDecorate %m DescriptorSet 0
+               OpDecorate %m Binding 0
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+%m_block_std140 = OpTypeStruct %v2half %v2half
+%_ptr_Uniform_m_block_std140 = OpTypePointer Uniform %m_block_std140
+          %m = OpVariable %_ptr_Uniform_m_block_std140 Uniform
+        %int = OpTypeInt 32 1
+          %7 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %7
+         %10 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+ %mat2v2half = OpTypeMatrix %v2half 2
+         %17 = OpTypeFunction %mat2v2half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+     %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %33 = OpTypeFunction %void
+          %i = OpFunction %int None %10
+         %12 = OpLabel
+         %13 = OpLoad %int %counter
+         %15 = OpIAdd %int %13 %int_1
+               OpStore %counter %15
+         %16 = OpLoad %int %counter
+               OpReturnValue %16
+               OpFunctionEnd
+%load_m_inner = OpFunction %mat2v2half None %17
+         %20 = OpLabel
+         %26 = OpAccessChain %_ptr_Uniform_v2half %m %uint_0
+         %27 = OpLoad %v2half %26
+         %30 = OpAccessChain %_ptr_Uniform_v2half %m %uint_1
+         %31 = OpLoad %v2half %30
+         %32 = OpCompositeConstruct %mat2v2half %27 %31
+               OpReturnValue %32
+               OpFunctionEnd
+          %f = OpFunction %void None %33
+         %36 = OpLabel
+         %37 = OpFunctionCall %mat2v2half %load_m_inner
+         %38 = OpAccessChain %_ptr_Uniform_v2half %m %uint_1
+         %39 = OpLoad %v2half %38
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/static_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..5f02f84
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/static_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> m : mat2x2<f16>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m = &(m);
+  let p_m_1 = &((*(p_m))[1]);
+  let l_m : mat2x2<f16> = *(p_m);
+  let l_m_1 : vec2<f16> = *(p_m_1);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_builtin.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_builtin.wgsl
new file mode 100644
index 0000000..ac0adc1
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_builtin.wgsl
@@ -0,0 +1,10 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat2x2<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+    let t = transpose(u);
+    let l = length(u[1]);
+    let a = abs(u[0].yx.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_builtin.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..7946311
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_builtin.wgsl.expected.dxc.hlsl
@@ -0,0 +1,21 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+matrix<float16_t, 2, 2> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  return matrix<float16_t, 2, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 2, 2> t = transpose(tint_symbol(u, 0u));
+  uint ubo_load_2 = u[0].y;
+  const float16_t l = length(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))));
+  uint ubo_load_3 = u[0].x;
+  const float16_t a = abs(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))).yx.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_builtin.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..aedd56c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_builtin.wgsl.expected.fxc.hlsl
@@ -0,0 +1,26 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+matrix<float16_t, 2, 2> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  return matrix<float16_t, 2, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 2, 2> t = transpose(tint_symbol(u, 0u));
+  uint ubo_load_2 = u[0].y;
+  const float16_t l = length(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))));
+  uint ubo_load_3 = u[0].x;
+  const float16_t a = abs(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))).yx.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001C84DC29980(5,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_builtin.wgsl.expected.glsl
new file mode 100644
index 0000000..50c298f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_builtin.wgsl.expected.glsl
@@ -0,0 +1,23 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec2 inner_0;
+  f16vec2 inner_1;
+} u;
+
+f16mat2 load_u_inner() {
+  return f16mat2(u.inner_0, u.inner_1);
+}
+
+void f() {
+  f16mat2 t = transpose(load_u_inner());
+  float16_t l = length(u.inner_1);
+  float16_t a = abs(u.inner_0.yx[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_builtin.wgsl.expected.msl
new file mode 100644
index 0000000..2b5e676
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_builtin.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f(const constant half2x2* tint_symbol [[buffer(0)]]) {
+  half2x2 const t = transpose(*(tint_symbol));
+  half const l = length((*(tint_symbol))[1]);
+  half const a = fabs(half2((*(tint_symbol))[0]).yx[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_builtin.wgsl.expected.spvasm
new file mode 100644
index 0000000..783d7a5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_builtin.wgsl.expected.spvasm
@@ -0,0 +1,63 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 38
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+         %29 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpName %u "u"
+               OpName %load_u_inner "load_u_inner"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 4
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+%u_block_std140 = OpTypeStruct %v2half %v2half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat2v2half = OpTypeMatrix %v2half 2
+          %6 = OpTypeFunction %mat2v2half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+     %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %22 = OpTypeFunction %void
+         %36 = OpConstantNull %uint
+%load_u_inner = OpFunction %mat2v2half None %6
+          %9 = OpLabel
+         %15 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0
+         %16 = OpLoad %v2half %15
+         %19 = OpAccessChain %_ptr_Uniform_v2half %u %uint_1
+         %20 = OpLoad %v2half %19
+         %21 = OpCompositeConstruct %mat2v2half %16 %20
+               OpReturnValue %21
+               OpFunctionEnd
+          %f = OpFunction %void None %22
+         %25 = OpLabel
+         %27 = OpFunctionCall %mat2v2half %load_u_inner
+         %26 = OpTranspose %mat2v2half %27
+         %30 = OpAccessChain %_ptr_Uniform_v2half %u %uint_1
+         %31 = OpLoad %v2half %30
+         %28 = OpExtInst %half %29 Length %31
+         %33 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0
+         %34 = OpLoad %v2half %33
+         %35 = OpVectorShuffle %v2half %34 %34 1 0
+         %37 = OpCompositeExtract %half %35 0
+         %32 = OpExtInst %half %29 FAbs %37
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_builtin.wgsl.expected.wgsl
new file mode 100644
index 0000000..85c4b9e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_builtin.wgsl.expected.wgsl
@@ -0,0 +1,10 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat2x2<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let t = transpose(u);
+  let l = length(u[1]);
+  let a = abs(u[0].yx.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_fn.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_fn.wgsl
new file mode 100644
index 0000000..6a59efb
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_fn.wgsl
@@ -0,0 +1,16 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat2x2<f16>;
+
+fn a(m : mat2x2<f16>) {}
+fn b(v : vec2<f16>) {}
+fn c(f : f16) {}
+
+@compute @workgroup_size(1)
+fn f() {
+    a(u);
+    b(u[1]);
+    b(u[1].yx);
+    c(u[1].x);
+    c(u[1].yx.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_fn.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..6e0c6f2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_fn.wgsl.expected.dxc.hlsl
@@ -0,0 +1,33 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+void a(matrix<float16_t, 2, 2> m) {
+}
+
+void b(vector<float16_t, 2> v) {
+}
+
+void c(float16_t f_1) {
+}
+
+matrix<float16_t, 2, 2> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  return matrix<float16_t, 2, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  uint ubo_load_2 = u[0].y;
+  b(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))));
+  uint ubo_load_3 = u[0].y;
+  b(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))).yx);
+  c(float16_t(f16tof32(((u[0].y) & 0xFFFF))));
+  uint ubo_load_4 = u[0].y;
+  c(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16))).yx.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_fn.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..a5b412f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_fn.wgsl.expected.fxc.hlsl
@@ -0,0 +1,40 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+void a(matrix<float16_t, 2, 2> m) {
+}
+
+void b(vector<float16_t, 2> v) {
+}
+
+void c(float16_t f_1) {
+}
+
+matrix<float16_t, 2, 2> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  return matrix<float16_t, 2, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  uint ubo_load_2 = u[0].y;
+  b(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))));
+  uint ubo_load_3 = u[0].y;
+  b(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))).yx);
+  c(float16_t(f16tof32(((u[0].y) & 0xFFFF))));
+  uint ubo_load_4 = u[0].y;
+  c(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16))).yx.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000020E82D03620(5,15-23): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000020E82D03620(8,15-23): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000020E82D03620(11,8-16): error X3000: unrecognized identifier 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_fn.wgsl.expected.glsl
new file mode 100644
index 0000000..a4cd27f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_fn.wgsl.expected.glsl
@@ -0,0 +1,34 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec2 inner_0;
+  f16vec2 inner_1;
+} u;
+
+void a(f16mat2 m) {
+}
+
+void b(f16vec2 v) {
+}
+
+void c(float16_t f_1) {
+}
+
+f16mat2 load_u_inner() {
+  return f16mat2(u.inner_0, u.inner_1);
+}
+
+void f() {
+  a(load_u_inner());
+  b(u.inner_1);
+  b(u.inner_1.yx);
+  c(u.inner_1[0u]);
+  c(u.inner_1.yx[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_fn.wgsl.expected.msl
new file mode 100644
index 0000000..8c3ff4f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_fn.wgsl.expected.msl
@@ -0,0 +1,21 @@
+#include <metal_stdlib>
+
+using namespace metal;
+void a(half2x2 m) {
+}
+
+void b(half2 v) {
+}
+
+void c(half f_1) {
+}
+
+kernel void f(const constant half2x2* tint_symbol [[buffer(0)]]) {
+  a(*(tint_symbol));
+  b((*(tint_symbol))[1]);
+  b(half2((*(tint_symbol))[1]).yx);
+  c((*(tint_symbol))[1][0]);
+  c(half2((*(tint_symbol))[1]).yx[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_fn.wgsl.expected.spvasm
new file mode 100644
index 0000000..e5673eb
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_fn.wgsl.expected.spvasm
@@ -0,0 +1,94 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 57
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpName %u "u"
+               OpName %a "a"
+               OpName %m "m"
+               OpName %b "b"
+               OpName %v "v"
+               OpName %c "c"
+               OpName %f_1 "f_1"
+               OpName %load_u_inner "load_u_inner"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 4
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+%u_block_std140 = OpTypeStruct %v2half %v2half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+       %void = OpTypeVoid
+ %mat2v2half = OpTypeMatrix %v2half 2
+          %6 = OpTypeFunction %void %mat2v2half
+         %12 = OpTypeFunction %void %v2half
+         %16 = OpTypeFunction %void %half
+         %20 = OpTypeFunction %mat2v2half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+     %uint_1 = OpConstant %uint 1
+         %35 = OpTypeFunction %void
+         %48 = OpConstantNull %uint
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+          %a = OpFunction %void None %6
+          %m = OpFunctionParameter %mat2v2half
+         %11 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %b = OpFunction %void None %12
+          %v = OpFunctionParameter %v2half
+         %15 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %c = OpFunction %void None %16
+        %f_1 = OpFunctionParameter %half
+         %19 = OpLabel
+               OpReturn
+               OpFunctionEnd
+%load_u_inner = OpFunction %mat2v2half None %20
+         %22 = OpLabel
+         %28 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0
+         %29 = OpLoad %v2half %28
+         %32 = OpAccessChain %_ptr_Uniform_v2half %u %uint_1
+         %33 = OpLoad %v2half %32
+         %34 = OpCompositeConstruct %mat2v2half %29 %33
+               OpReturnValue %34
+               OpFunctionEnd
+          %f = OpFunction %void None %35
+         %37 = OpLabel
+         %39 = OpFunctionCall %mat2v2half %load_u_inner
+         %38 = OpFunctionCall %void %a %39
+         %41 = OpAccessChain %_ptr_Uniform_v2half %u %uint_1
+         %42 = OpLoad %v2half %41
+         %40 = OpFunctionCall %void %b %42
+         %44 = OpAccessChain %_ptr_Uniform_v2half %u %uint_1
+         %45 = OpLoad %v2half %44
+         %46 = OpVectorShuffle %v2half %45 %45 1 0
+         %43 = OpFunctionCall %void %b %46
+         %50 = OpAccessChain %_ptr_Uniform_half %u %uint_1 %48
+         %51 = OpLoad %half %50
+         %47 = OpFunctionCall %void %c %51
+         %53 = OpAccessChain %_ptr_Uniform_v2half %u %uint_1
+         %54 = OpLoad %v2half %53
+         %55 = OpVectorShuffle %v2half %54 %54 1 0
+         %56 = OpCompositeExtract %half %55 0
+         %52 = OpFunctionCall %void %c %56
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_fn.wgsl.expected.wgsl
new file mode 100644
index 0000000..0a1e56c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_fn.wgsl.expected.wgsl
@@ -0,0 +1,21 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat2x2<f16>;
+
+fn a(m : mat2x2<f16>) {
+}
+
+fn b(v : vec2<f16>) {
+}
+
+fn c(f : f16) {
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  a(u);
+  b(u[1]);
+  b(u[1].yx);
+  c(u[1].x);
+  c(u[1].yx.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_private.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_private.wgsl
new file mode 100644
index 0000000..14cee66
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_private.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat2x2<f16>;
+var<private> p : mat2x2<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[0];
+    p[1] = u[0].yx;
+    p[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_private.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..649090f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_private.wgsl.expected.dxc.hlsl
@@ -0,0 +1,23 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+static matrix<float16_t, 2, 2> p = matrix<float16_t, 2, 2>(float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h));
+
+matrix<float16_t, 2, 2> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  return matrix<float16_t, 2, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  uint ubo_load_2 = u[0].x;
+  p[1] = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16)));
+  uint ubo_load_3 = u[0].x;
+  p[1] = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))).yx;
+  p[0][1] = float16_t(f16tof32(((u[0].y) & 0xFFFF)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_private.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..56e9dbe
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_private.wgsl.expected.fxc.hlsl
@@ -0,0 +1,28 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+static matrix<float16_t, 2, 2> p = matrix<float16_t, 2, 2>(float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h));
+
+matrix<float16_t, 2, 2> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  return matrix<float16_t, 2, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  uint ubo_load_2 = u[0].x;
+  p[1] = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16)));
+  uint ubo_load_3 = u[0].x;
+  p[1] = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))).yx;
+  p[0][1] = float16_t(f16tof32(((u[0].y) & 0xFFFF)));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000021A30FC4890(4,15-23): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..47059fa
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_private.wgsl.expected.glsl
@@ -0,0 +1,25 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec2 inner_0;
+  f16vec2 inner_1;
+} u;
+
+f16mat2 p = f16mat2(0.0hf, 0.0hf, 0.0hf, 0.0hf);
+f16mat2 load_u_inner() {
+  return f16mat2(u.inner_0, u.inner_1);
+}
+
+void f() {
+  p = load_u_inner();
+  p[1] = u.inner_0;
+  p[1] = u.inner_0.yx;
+  p[0][1] = u.inner_1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..4d82450
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_private.wgsl.expected.msl
@@ -0,0 +1,12 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f(const constant half2x2* tint_symbol_1 [[buffer(0)]]) {
+  thread half2x2 tint_symbol = half2x2(0.0h);
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[0];
+  tint_symbol[1] = half2((*(tint_symbol_1))[0]).yx;
+  tint_symbol[0][1] = (*(tint_symbol_1))[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_private.wgsl.expected.spvasm
new file mode 100644
index 0000000..6dc9b47
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_private.wgsl.expected.spvasm
@@ -0,0 +1,77 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 47
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpName %u "u"
+               OpName %p "p"
+               OpName %load_u_inner "load_u_inner"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 4
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+%u_block_std140 = OpTypeStruct %v2half %v2half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat2v2half = OpTypeMatrix %v2half 2
+%_ptr_Private_mat2v2half = OpTypePointer Private %mat2v2half
+          %9 = OpConstantNull %mat2v2half
+          %p = OpVariable %_ptr_Private_mat2v2half Private %9
+         %10 = OpTypeFunction %mat2v2half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+     %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %25 = OpTypeFunction %void
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Private_v2half = OpTypePointer Private %v2half
+         %40 = OpConstantNull %int
+%_ptr_Private_half = OpTypePointer Private %half
+         %43 = OpConstantNull %uint
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+%load_u_inner = OpFunction %mat2v2half None %10
+         %12 = OpLabel
+         %18 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0
+         %19 = OpLoad %v2half %18
+         %22 = OpAccessChain %_ptr_Uniform_v2half %u %uint_1
+         %23 = OpLoad %v2half %22
+         %24 = OpCompositeConstruct %mat2v2half %19 %23
+               OpReturnValue %24
+               OpFunctionEnd
+          %f = OpFunction %void None %25
+         %28 = OpLabel
+         %29 = OpFunctionCall %mat2v2half %load_u_inner
+               OpStore %p %29
+         %33 = OpAccessChain %_ptr_Private_v2half %p %int_1
+         %34 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0
+         %35 = OpLoad %v2half %34
+               OpStore %33 %35
+         %36 = OpAccessChain %_ptr_Private_v2half %p %int_1
+         %37 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0
+         %38 = OpLoad %v2half %37
+         %39 = OpVectorShuffle %v2half %38 %38 1 0
+               OpStore %36 %39
+         %42 = OpAccessChain %_ptr_Private_half %p %40 %int_1
+         %45 = OpAccessChain %_ptr_Uniform_half %u %uint_1 %43
+         %46 = OpLoad %half %45
+               OpStore %42 %46
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..b8bd5b6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_private.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat2x2<f16>;
+
+var<private> p : mat2x2<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[0];
+  p[1] = u[0].yx;
+  p[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_storage.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_storage.wgsl
new file mode 100644
index 0000000..a35fbc0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_storage.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat2x2<f16>;
+@group(0) @binding(1) var<storage, read_write> s : mat2x2<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[0];
+    s[1] = u[0].yx;
+    s[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_storage.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..365c3b2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_storage.wgsl.expected.dxc.hlsl
@@ -0,0 +1,28 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 2, 2> value) {
+  buffer.Store<vector<float16_t, 2> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 4u), value[1u]);
+}
+
+matrix<float16_t, 2, 2> tint_symbol_2(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  return matrix<float16_t, 2, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_2(u, 0u));
+  uint ubo_load_2 = u[0].x;
+  s.Store<vector<float16_t, 2> >(4u, vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))));
+  uint ubo_load_3 = u[0].x;
+  s.Store<vector<float16_t, 2> >(4u, vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))).yx);
+  s.Store<float16_t>(2u, float16_t(f16tof32(((u[0].y) & 0xFFFF))));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_storage.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..1883b2f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_storage.wgsl.expected.fxc.hlsl
@@ -0,0 +1,34 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 2, 2> value) {
+  buffer.Store<vector<float16_t, 2> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 4u), value[1u]);
+}
+
+matrix<float16_t, 2, 2> tint_symbol_2(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  return matrix<float16_t, 2, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_2(u, 0u));
+  uint ubo_load_2 = u[0].x;
+  s.Store<vector<float16_t, 2> >(4u, vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))));
+  uint ubo_load_3 = u[0].x;
+  s.Store<vector<float16_t, 2> >(4u, vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))).yx);
+  s.Store<float16_t>(2u, float16_t(f16tof32(((u[0].y) & 0xFFFF))));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001FAF34C3EE0(6,66-74): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001FAF34C3EE0(7,3-14): error X3018: invalid subscript 'Store'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..78515dd
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_storage.wgsl.expected.glsl
@@ -0,0 +1,28 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec2 inner_0;
+  f16vec2 inner_1;
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  f16mat2 inner;
+} s;
+
+f16mat2 load_u_inner() {
+  return f16mat2(u.inner_0, u.inner_1);
+}
+
+void f() {
+  s.inner = load_u_inner();
+  s.inner[1] = u.inner_0;
+  s.inner[1] = u.inner_0.yx;
+  s.inner[0][1] = u.inner_1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..52b1327
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_storage.wgsl.expected.msl
@@ -0,0 +1,11 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f(device half2x2* tint_symbol [[buffer(1)]], const constant half2x2* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[0];
+  (*(tint_symbol))[1] = half2((*(tint_symbol_1))[0]).yx;
+  (*(tint_symbol))[0][1] = (*(tint_symbol_1))[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_storage.wgsl.expected.spvasm
new file mode 100644
index 0000000..7bf94ab
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_storage.wgsl.expected.spvasm
@@ -0,0 +1,87 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 49
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpName %u "u"
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %s "s"
+               OpName %load_u_inner "load_u_inner"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 4
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 4
+               OpDecorate %s DescriptorSet 0
+               OpDecorate %s Binding 1
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+%u_block_std140 = OpTypeStruct %v2half %v2half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat2v2half = OpTypeMatrix %v2half 2
+    %u_block = OpTypeStruct %mat2v2half
+%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
+          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+         %10 = OpTypeFunction %mat2v2half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+     %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %25 = OpTypeFunction %void
+%_ptr_StorageBuffer_mat2v2half = OpTypePointer StorageBuffer %mat2v2half
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_v2half = OpTypePointer StorageBuffer %v2half
+         %42 = OpConstantNull %int
+%_ptr_StorageBuffer_half = OpTypePointer StorageBuffer %half
+         %45 = OpConstantNull %uint
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+%load_u_inner = OpFunction %mat2v2half None %10
+         %12 = OpLabel
+         %18 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0
+         %19 = OpLoad %v2half %18
+         %22 = OpAccessChain %_ptr_Uniform_v2half %u %uint_1
+         %23 = OpLoad %v2half %22
+         %24 = OpCompositeConstruct %mat2v2half %19 %23
+               OpReturnValue %24
+               OpFunctionEnd
+          %f = OpFunction %void None %25
+         %28 = OpLabel
+         %30 = OpAccessChain %_ptr_StorageBuffer_mat2v2half %s %uint_0
+         %31 = OpFunctionCall %mat2v2half %load_u_inner
+               OpStore %30 %31
+         %35 = OpAccessChain %_ptr_StorageBuffer_v2half %s %uint_0 %int_1
+         %36 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0
+         %37 = OpLoad %v2half %36
+               OpStore %35 %37
+         %38 = OpAccessChain %_ptr_StorageBuffer_v2half %s %uint_0 %int_1
+         %39 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0
+         %40 = OpLoad %v2half %39
+         %41 = OpVectorShuffle %v2half %40 %40 1 0
+               OpStore %38 %41
+         %44 = OpAccessChain %_ptr_StorageBuffer_half %s %uint_0 %42 %int_1
+         %47 = OpAccessChain %_ptr_Uniform_half %u %uint_1 %45
+         %48 = OpLoad %half %47
+               OpStore %44 %48
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..eb79e59
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat2x2<f16>;
+
+@group(0) @binding(1) var<storage, read_write> s : mat2x2<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[0];
+  s[1] = u[0].yx;
+  s[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_workgroup.wgsl
new file mode 100644
index 0000000..8702c67
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_workgroup.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat2x2<f16>;
+var<workgroup> w : mat2x2<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[0];
+    w[1] = u[0].yx;
+    w[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_workgroup.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..3bf9f07
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_workgroup.wgsl.expected.dxc.hlsl
@@ -0,0 +1,35 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+groupshared matrix<float16_t, 2, 2> w;
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 2, 2> tint_symbol_2(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  return matrix<float16_t, 2, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))));
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    w = matrix<float16_t, 2, 2>((float16_t(0.0h)).xx, (float16_t(0.0h)).xx);
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  uint ubo_load_2 = u[0].x;
+  w[1] = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16)));
+  uint ubo_load_3 = u[0].x;
+  w[1] = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))).yx;
+  w[0][1] = float16_t(f16tof32(((u[0].y) & 0xFFFF)));
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_workgroup.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..90c5813
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_workgroup.wgsl.expected.fxc.hlsl
@@ -0,0 +1,40 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+groupshared matrix<float16_t, 2, 2> w;
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 2, 2> tint_symbol_2(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  return matrix<float16_t, 2, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))));
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    w = matrix<float16_t, 2, 2>((float16_t(0.0h)).xx, (float16_t(0.0h)).xx);
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  uint ubo_load_2 = u[0].x;
+  w[1] = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16)));
+  uint ubo_load_3 = u[0].x;
+  w[1] = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))).yx;
+  w[0][1] = float16_t(f16tof32(((u[0].y) & 0xFFFF)));
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000022F004DAD50(4,20-28): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..5f2c7dd
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,29 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec2 inner_0;
+  f16vec2 inner_1;
+} u;
+
+shared f16mat2 w;
+f16mat2 load_u_inner() {
+  return f16mat2(u.inner_0, u.inner_1);
+}
+
+void f(uint local_invocation_index) {
+  {
+    w = f16mat2(f16vec2(0.0hf), f16vec2(0.0hf));
+  }
+  barrier();
+  w = load_u_inner();
+  w[1] = u.inner_0;
+  w[1] = u.inner_0.yx;
+  w[0][1] = u.inner_1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..270a66d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,24 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct tint_symbol_5 {
+  half2x2 w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup half2x2* const tint_symbol, const constant half2x2* const tint_symbol_1) {
+  {
+    *(tint_symbol) = half2x2(half2(0.0h), half2(0.0h));
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[0];
+  (*(tint_symbol))[1] = half2((*(tint_symbol_1))[0]).yx;
+  (*(tint_symbol))[0][1] = (*(tint_symbol_1))[1][0];
+}
+
+kernel void f(const constant half2x2* tint_symbol_4 [[buffer(0)]], threadgroup tint_symbol_5* tint_symbol_3 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup half2x2* const tint_symbol_2 = &((*(tint_symbol_3)).w);
+  f_inner(local_invocation_index, tint_symbol_2, tint_symbol_4);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_workgroup.wgsl.expected.spvasm
new file mode 100644
index 0000000..b174799
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_workgroup.wgsl.expected.spvasm
@@ -0,0 +1,95 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 58
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %local_invocation_index_1 "local_invocation_index_1"
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpName %u "u"
+               OpName %w "w"
+               OpName %load_u_inner "load_u_inner"
+               OpName %f_inner "f_inner"
+               OpName %local_invocation_index "local_invocation_index"
+               OpName %f "f"
+               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 4
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+%u_block_std140 = OpTypeStruct %v2half %v2half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat2v2half = OpTypeMatrix %v2half 2
+%_ptr_Workgroup_mat2v2half = OpTypePointer Workgroup %mat2v2half
+          %w = OpVariable %_ptr_Workgroup_mat2v2half Workgroup
+         %12 = OpTypeFunction %mat2v2half
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+     %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %26 = OpTypeFunction %void %uint
+         %31 = OpConstantNull %mat2v2half
+     %uint_2 = OpConstant %uint 2
+   %uint_264 = OpConstant %uint 264
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Workgroup_v2half = OpTypePointer Workgroup %v2half
+         %46 = OpConstantNull %int
+%_ptr_Workgroup_half = OpTypePointer Workgroup %half
+         %49 = OpConstantNull %uint
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+         %53 = OpTypeFunction %void
+%load_u_inner = OpFunction %mat2v2half None %12
+         %14 = OpLabel
+         %19 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0
+         %20 = OpLoad %v2half %19
+         %23 = OpAccessChain %_ptr_Uniform_v2half %u %uint_1
+         %24 = OpLoad %v2half %23
+         %25 = OpCompositeConstruct %mat2v2half %20 %24
+               OpReturnValue %25
+               OpFunctionEnd
+    %f_inner = OpFunction %void None %26
+%local_invocation_index = OpFunctionParameter %uint
+         %30 = OpLabel
+               OpStore %w %31
+               OpControlBarrier %uint_2 %uint_2 %uint_264
+         %35 = OpFunctionCall %mat2v2half %load_u_inner
+               OpStore %w %35
+         %39 = OpAccessChain %_ptr_Workgroup_v2half %w %int_1
+         %40 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0
+         %41 = OpLoad %v2half %40
+               OpStore %39 %41
+         %42 = OpAccessChain %_ptr_Workgroup_v2half %w %int_1
+         %43 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0
+         %44 = OpLoad %v2half %43
+         %45 = OpVectorShuffle %v2half %44 %44 1 0
+               OpStore %42 %45
+         %48 = OpAccessChain %_ptr_Workgroup_half %w %46 %int_1
+         %51 = OpAccessChain %_ptr_Uniform_half %u %uint_1 %49
+         %52 = OpLoad %half %51
+               OpStore %48 %52
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %53
+         %55 = OpLabel
+         %57 = OpLoad %uint %local_invocation_index_1
+         %56 = OpFunctionCall %void %f_inner %57
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..a343bf1
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x2_f16/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat2x2<f16>;
+
+var<workgroup> w : mat2x2<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[0];
+  w[1] = u[0].yx;
+  w[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/dynamic_index_via_ptr.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/dynamic_index_via_ptr.wgsl
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/dynamic_index_via_ptr.wgsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/dynamic_index_via_ptr.wgsl.expected.glsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/dynamic_index_via_ptr.wgsl.expected.glsl
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/dynamic_index_via_ptr.wgsl.expected.glsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/dynamic_index_via_ptr.wgsl.expected.msl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/dynamic_index_via_ptr.wgsl.expected.msl
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/dynamic_index_via_ptr.wgsl.expected.msl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/dynamic_index_via_ptr.wgsl.expected.spvasm
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/dynamic_index_via_ptr.wgsl.expected.wgsl
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/static_index_via_ptr.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/static_index_via_ptr.wgsl
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/static_index_via_ptr.wgsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/static_index_via_ptr.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/static_index_via_ptr.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/static_index_via_ptr.wgsl.expected.glsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/static_index_via_ptr.wgsl.expected.glsl
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/static_index_via_ptr.wgsl.expected.glsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/static_index_via_ptr.wgsl.expected.msl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/static_index_via_ptr.wgsl.expected.msl
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/static_index_via_ptr.wgsl.expected.msl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/static_index_via_ptr.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/static_index_via_ptr.wgsl.expected.spvasm
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/static_index_via_ptr.wgsl.expected.spvasm
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/static_index_via_ptr.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/static_index_via_ptr.wgsl.expected.wgsl
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/static_index_via_ptr.wgsl.expected.wgsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/to_builtin.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_builtin.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/to_builtin.wgsl
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_builtin.wgsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_builtin.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/to_builtin.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_builtin.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_builtin.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/to_builtin.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_builtin.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_builtin.wgsl.expected.glsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/to_builtin.wgsl.expected.glsl
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_builtin.wgsl.expected.glsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_builtin.wgsl.expected.msl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/to_builtin.wgsl.expected.msl
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_builtin.wgsl.expected.msl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_builtin.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/to_builtin.wgsl.expected.spvasm
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_builtin.wgsl.expected.spvasm
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_builtin.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/to_builtin.wgsl.expected.wgsl
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_builtin.wgsl.expected.wgsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/to_fn.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_fn.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/to_fn.wgsl
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_fn.wgsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_fn.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/to_fn.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_fn.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_fn.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/to_fn.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_fn.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_fn.wgsl.expected.glsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/to_fn.wgsl.expected.glsl
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_fn.wgsl.expected.glsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_fn.wgsl.expected.msl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/to_fn.wgsl.expected.msl
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_fn.wgsl.expected.msl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_fn.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/to_fn.wgsl.expected.spvasm
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_fn.wgsl.expected.spvasm
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_fn.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/to_fn.wgsl.expected.wgsl
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_fn.wgsl.expected.wgsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/to_private.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_private.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/to_private.wgsl
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_private.wgsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_private.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/to_private.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_private.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_private.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/to_private.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_private.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_private.wgsl.expected.glsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/to_private.wgsl.expected.glsl
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_private.wgsl.expected.glsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_private.wgsl.expected.msl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/to_private.wgsl.expected.msl
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_private.wgsl.expected.msl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_private.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/to_private.wgsl.expected.spvasm
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_private.wgsl.expected.spvasm
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_private.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/to_private.wgsl.expected.wgsl
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_private.wgsl.expected.wgsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/to_storage.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_storage.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/to_storage.wgsl
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_storage.wgsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_storage.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/to_storage.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_storage.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_storage.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/to_storage.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_storage.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_storage.wgsl.expected.glsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/to_storage.wgsl.expected.glsl
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_storage.wgsl.expected.glsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_storage.wgsl.expected.msl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/to_storage.wgsl.expected.msl
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_storage.wgsl.expected.msl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_storage.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/to_storage.wgsl.expected.spvasm
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_storage.wgsl.expected.spvasm
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_storage.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/to_storage.wgsl.expected.wgsl
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_storage.wgsl.expected.wgsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_workgroup.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/to_workgroup.wgsl
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_workgroup.wgsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_workgroup.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/to_workgroup.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_workgroup.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_workgroup.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/to_workgroup.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_workgroup.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_workgroup.wgsl.expected.glsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/to_workgroup.wgsl.expected.glsl
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_workgroup.wgsl.expected.glsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_workgroup.wgsl.expected.msl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/to_workgroup.wgsl.expected.msl
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_workgroup.wgsl.expected.msl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_workgroup.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/to_workgroup.wgsl.expected.spvasm
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_workgroup.wgsl.expected.spvasm
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x2/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_workgroup.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat2x2/to_workgroup.wgsl.expected.wgsl
rename to test/tint/buffer/uniform/std140/unnested/mat2x2_f32/to_workgroup.wgsl.expected.wgsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/dynamic_index_via_ptr.wgsl
new file mode 100644
index 0000000..0042446
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/dynamic_index_via_ptr.wgsl
@@ -0,0 +1,15 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> m : mat2x3<f16>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m   = &m;
+  let p_m_i = &((*p_m)[i()]);
+
+  let l_m   : mat2x3<f16> = *p_m;
+  let l_m_i : vec3<f16>   = *p_m_i;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..c493360
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,36 @@
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[1];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 2, 3> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_m_i_save = i();
+  const matrix<float16_t, 2, 3> l_m = tint_symbol(m, 0u);
+  const uint scalar_offset_2 = ((8u * uint(p_m_i_save))) / 4;
+  uint4 ubo_load_5 = m[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const vector<float16_t, 3> l_m_i = vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..a0e5889
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,41 @@
+SKIP: FAILED
+
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[1];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 2, 3> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_m_i_save = i();
+  const matrix<float16_t, 2, 3> l_m = tint_symbol(m, 0u);
+  const uint scalar_offset_2 = ((8u * uint(p_m_i_save))) / 4;
+  uint4 ubo_load_5 = m[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const vector<float16_t, 3> l_m_i = vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000002573701B0D0(11,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..b5758b5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,48 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform m_block_std140_ubo {
+  f16vec3 inner_0;
+  f16vec3 inner_1;
+} m;
+
+int counter = 0;
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+f16mat2x3 load_m_inner() {
+  return f16mat2x3(m.inner_0, m.inner_1);
+}
+
+f16vec3 load_m_inner_p0(uint p0) {
+  switch(p0) {
+    case 0u: {
+      return m.inner_0;
+      break;
+    }
+    case 1u: {
+      return m.inner_1;
+      break;
+    }
+    default: {
+      return f16vec3(0.0hf);
+      break;
+    }
+  }
+}
+
+void f() {
+  f16mat2x3 p_m = load_m_inner();
+  int tint_symbol = i();
+  f16vec3 p_m_i = load_m_inner_p0(uint(tint_symbol));
+  f16mat2x3 l_m = load_m_inner();
+  f16vec3 l_m_i = load_m_inner_p0(uint(tint_symbol));
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..f4a04e8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,17 @@
+#include <metal_stdlib>
+
+using namespace metal;
+int i() {
+  thread int tint_symbol_1 = 0;
+  tint_symbol_1 = as_type<int>((as_type<uint>(tint_symbol_1) + as_type<uint>(1)));
+  return tint_symbol_1;
+}
+
+kernel void f(const constant half2x3* tint_symbol_2 [[buffer(0)]]) {
+  int const tint_symbol = i();
+  int const p_m_i_save = tint_symbol;
+  half2x3 const l_m = *(tint_symbol_2);
+  half3 const l_m_i = (*(tint_symbol_2))[p_m_i_save];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..6e27b10
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,93 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 54
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %m_block_std140 "m_block_std140"
+               OpMemberName %m_block_std140 0 "inner_0"
+               OpMemberName %m_block_std140 1 "inner_1"
+               OpName %m "m"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %load_m_inner "load_m_inner"
+               OpName %load_m_inner_p0 "load_m_inner_p0"
+               OpName %p0 "p0"
+               OpName %f "f"
+               OpDecorate %m_block_std140 Block
+               OpMemberDecorate %m_block_std140 0 Offset 0
+               OpMemberDecorate %m_block_std140 1 Offset 8
+               OpDecorate %m NonWritable
+               OpDecorate %m DescriptorSet 0
+               OpDecorate %m Binding 0
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+%m_block_std140 = OpTypeStruct %v3half %v3half
+%_ptr_Uniform_m_block_std140 = OpTypePointer Uniform %m_block_std140
+          %m = OpVariable %_ptr_Uniform_m_block_std140 Uniform
+        %int = OpTypeInt 32 1
+          %7 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %7
+         %10 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+ %mat2v3half = OpTypeMatrix %v3half 2
+         %17 = OpTypeFunction %mat2v3half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+     %uint_1 = OpConstant %uint 1
+         %33 = OpTypeFunction %v3half %uint
+         %45 = OpConstantNull %v3half
+       %void = OpTypeVoid
+         %46 = OpTypeFunction %void
+          %i = OpFunction %int None %10
+         %12 = OpLabel
+         %13 = OpLoad %int %counter
+         %15 = OpIAdd %int %13 %int_1
+               OpStore %counter %15
+         %16 = OpLoad %int %counter
+               OpReturnValue %16
+               OpFunctionEnd
+%load_m_inner = OpFunction %mat2v3half None %17
+         %20 = OpLabel
+         %26 = OpAccessChain %_ptr_Uniform_v3half %m %uint_0
+         %27 = OpLoad %v3half %26
+         %30 = OpAccessChain %_ptr_Uniform_v3half %m %uint_1
+         %31 = OpLoad %v3half %30
+         %32 = OpCompositeConstruct %mat2v3half %27 %31
+               OpReturnValue %32
+               OpFunctionEnd
+%load_m_inner_p0 = OpFunction %v3half None %33
+         %p0 = OpFunctionParameter %uint
+         %36 = OpLabel
+               OpSelectionMerge %37 None
+               OpSwitch %p0 %38 0 %39 1 %40
+         %39 = OpLabel
+         %41 = OpAccessChain %_ptr_Uniform_v3half %m %uint_0
+         %42 = OpLoad %v3half %41
+               OpReturnValue %42
+         %40 = OpLabel
+         %43 = OpAccessChain %_ptr_Uniform_v3half %m %uint_1
+         %44 = OpLoad %v3half %43
+               OpReturnValue %44
+         %38 = OpLabel
+               OpReturnValue %45
+         %37 = OpLabel
+               OpReturnValue %45
+               OpFunctionEnd
+          %f = OpFunction %void None %46
+         %49 = OpLabel
+         %50 = OpFunctionCall %int %i
+         %51 = OpFunctionCall %mat2v3half %load_m_inner
+         %53 = OpBitcast %uint %50
+         %52 = OpFunctionCall %v3half %load_m_inner_p0 %53
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..ba171d7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> m : mat2x3<f16>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m = &(m);
+  let p_m_i = &((*(p_m))[i()]);
+  let l_m : mat2x3<f16> = *(p_m);
+  let l_m_i : vec3<f16> = *(p_m_i);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/static_index_via_ptr.wgsl
new file mode 100644
index 0000000..69415d8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/static_index_via_ptr.wgsl
@@ -0,0 +1,15 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> m : mat2x3<f16>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m   = &m;
+  let p_m_1 = &((*p_m)[1]);
+
+  let l_m   : mat2x3<f16> = *p_m;
+  let l_m_1 : vec3<f16>   = *p_m_1;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..994033f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,33 @@
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[1];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 2, 3> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 2, 3> l_m = tint_symbol(m, 0u);
+  uint2 ubo_load_4 = m[0].zw;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const vector<float16_t, 3> l_m_1 = vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..74aeaa6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,38 @@
+SKIP: FAILED
+
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[1];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 2, 3> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 2, 3> l_m = tint_symbol(m, 0u);
+  uint2 ubo_load_4 = m[0].zw;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const vector<float16_t, 3> l_m_1 = vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001F0B4D13EF0(11,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/static_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..15bc655
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/static_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,24 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform m_block_std140_ubo {
+  f16vec3 inner_0;
+  f16vec3 inner_1;
+} m;
+
+f16mat2x3 load_m_inner() {
+  return f16mat2x3(m.inner_0, m.inner_1);
+}
+
+void f() {
+  f16mat2x3 p_m = load_m_inner();
+  f16vec3 p_m_1 = m.inner_1;
+  f16mat2x3 l_m = load_m_inner();
+  f16vec3 l_m_1 = m.inner_1;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/static_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..036bb82
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/static_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,15 @@
+#include <metal_stdlib>
+
+using namespace metal;
+int i() {
+  thread int tint_symbol = 0;
+  tint_symbol = as_type<int>((as_type<uint>(tint_symbol) + as_type<uint>(1)));
+  return tint_symbol;
+}
+
+kernel void f(const constant half2x3* tint_symbol_1 [[buffer(0)]]) {
+  half2x3 const l_m = *(tint_symbol_1);
+  half3 const l_m_1 = (*(tint_symbol_1))[1];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/static_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..84284de
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/static_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,70 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 40
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %m_block_std140 "m_block_std140"
+               OpMemberName %m_block_std140 0 "inner_0"
+               OpMemberName %m_block_std140 1 "inner_1"
+               OpName %m "m"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %load_m_inner "load_m_inner"
+               OpName %f "f"
+               OpDecorate %m_block_std140 Block
+               OpMemberDecorate %m_block_std140 0 Offset 0
+               OpMemberDecorate %m_block_std140 1 Offset 8
+               OpDecorate %m NonWritable
+               OpDecorate %m DescriptorSet 0
+               OpDecorate %m Binding 0
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+%m_block_std140 = OpTypeStruct %v3half %v3half
+%_ptr_Uniform_m_block_std140 = OpTypePointer Uniform %m_block_std140
+          %m = OpVariable %_ptr_Uniform_m_block_std140 Uniform
+        %int = OpTypeInt 32 1
+          %7 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %7
+         %10 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+ %mat2v3half = OpTypeMatrix %v3half 2
+         %17 = OpTypeFunction %mat2v3half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+     %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %33 = OpTypeFunction %void
+          %i = OpFunction %int None %10
+         %12 = OpLabel
+         %13 = OpLoad %int %counter
+         %15 = OpIAdd %int %13 %int_1
+               OpStore %counter %15
+         %16 = OpLoad %int %counter
+               OpReturnValue %16
+               OpFunctionEnd
+%load_m_inner = OpFunction %mat2v3half None %17
+         %20 = OpLabel
+         %26 = OpAccessChain %_ptr_Uniform_v3half %m %uint_0
+         %27 = OpLoad %v3half %26
+         %30 = OpAccessChain %_ptr_Uniform_v3half %m %uint_1
+         %31 = OpLoad %v3half %30
+         %32 = OpCompositeConstruct %mat2v3half %27 %31
+               OpReturnValue %32
+               OpFunctionEnd
+          %f = OpFunction %void None %33
+         %36 = OpLabel
+         %37 = OpFunctionCall %mat2v3half %load_m_inner
+         %38 = OpAccessChain %_ptr_Uniform_v3half %m %uint_1
+         %39 = OpLoad %v3half %38
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/static_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..450a760
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/static_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> m : mat2x3<f16>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m = &(m);
+  let p_m_1 = &((*(p_m))[1]);
+  let l_m : mat2x3<f16> = *(p_m);
+  let l_m_1 : vec3<f16> = *(p_m_1);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_builtin.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_builtin.wgsl
new file mode 100644
index 0000000..02280d5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_builtin.wgsl
@@ -0,0 +1,10 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat2x3<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+    let t = transpose(u);
+    let l = length(u[1]);
+    let a = abs(u[0].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_builtin.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..c3d1652
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_builtin.wgsl.expected.dxc.hlsl
@@ -0,0 +1,31 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+matrix<float16_t, 2, 3> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 3, 2> t = transpose(tint_symbol(u, 0u));
+  uint2 ubo_load_4 = u[0].zw;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const float16_t l = length(vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]));
+  uint2 ubo_load_5 = u[0].xy;
+  vector<float16_t, 2> ubo_load_5_xz = vector<float16_t, 2>(f16tof32(ubo_load_5 & 0xFFFF));
+  float16_t ubo_load_5_y = f16tof32(ubo_load_5[0] >> 16);
+  const float16_t a = abs(vector<float16_t, 3>(ubo_load_5_xz[0], ubo_load_5_y, ubo_load_5_xz[1]).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_builtin.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..8774da1
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_builtin.wgsl.expected.fxc.hlsl
@@ -0,0 +1,36 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+matrix<float16_t, 2, 3> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 3, 2> t = transpose(tint_symbol(u, 0u));
+  uint2 ubo_load_4 = u[0].zw;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const float16_t l = length(vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]));
+  uint2 ubo_load_5 = u[0].xy;
+  vector<float16_t, 2> ubo_load_5_xz = vector<float16_t, 2>(f16tof32(ubo_load_5 & 0xFFFF));
+  float16_t ubo_load_5_y = f16tof32(ubo_load_5[0] >> 16);
+  const float16_t a = abs(vector<float16_t, 3>(ubo_load_5_xz[0], ubo_load_5_y, ubo_load_5_xz[1]).zxy.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000024F9111AD30(5,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_builtin.wgsl.expected.glsl
new file mode 100644
index 0000000..33cf0d2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_builtin.wgsl.expected.glsl
@@ -0,0 +1,23 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec3 inner_0;
+  f16vec3 inner_1;
+} u;
+
+f16mat2x3 load_u_inner() {
+  return f16mat2x3(u.inner_0, u.inner_1);
+}
+
+void f() {
+  f16mat3x2 t = transpose(load_u_inner());
+  float16_t l = length(u.inner_1);
+  float16_t a = abs(u.inner_0.zxy[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_builtin.wgsl.expected.msl
new file mode 100644
index 0000000..c81aee4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_builtin.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f(const constant half2x3* tint_symbol [[buffer(0)]]) {
+  half3x2 const t = transpose(*(tint_symbol));
+  half const l = length((*(tint_symbol))[1]);
+  half const a = fabs(half3((*(tint_symbol))[0]).zxy[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_builtin.wgsl.expected.spvasm
new file mode 100644
index 0000000..07fdde3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_builtin.wgsl.expected.spvasm
@@ -0,0 +1,65 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 40
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+         %31 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpName %u "u"
+               OpName %load_u_inner "load_u_inner"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 8
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+%u_block_std140 = OpTypeStruct %v3half %v3half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat2v3half = OpTypeMatrix %v3half 2
+          %6 = OpTypeFunction %mat2v3half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+     %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %22 = OpTypeFunction %void
+     %v2half = OpTypeVector %half 2
+ %mat3v2half = OpTypeMatrix %v2half 3
+         %38 = OpConstantNull %uint
+%load_u_inner = OpFunction %mat2v3half None %6
+          %9 = OpLabel
+         %15 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0
+         %16 = OpLoad %v3half %15
+         %19 = OpAccessChain %_ptr_Uniform_v3half %u %uint_1
+         %20 = OpLoad %v3half %19
+         %21 = OpCompositeConstruct %mat2v3half %16 %20
+               OpReturnValue %21
+               OpFunctionEnd
+          %f = OpFunction %void None %22
+         %25 = OpLabel
+         %29 = OpFunctionCall %mat2v3half %load_u_inner
+         %26 = OpTranspose %mat3v2half %29
+         %32 = OpAccessChain %_ptr_Uniform_v3half %u %uint_1
+         %33 = OpLoad %v3half %32
+         %30 = OpExtInst %half %31 Length %33
+         %35 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0
+         %36 = OpLoad %v3half %35
+         %37 = OpVectorShuffle %v3half %36 %36 2 0 1
+         %39 = OpCompositeExtract %half %37 0
+         %34 = OpExtInst %half %31 FAbs %39
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_builtin.wgsl.expected.wgsl
new file mode 100644
index 0000000..84e0049
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_builtin.wgsl.expected.wgsl
@@ -0,0 +1,10 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat2x3<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let t = transpose(u);
+  let l = length(u[1]);
+  let a = abs(u[0].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_fn.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_fn.wgsl
new file mode 100644
index 0000000..3d67c49
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_fn.wgsl
@@ -0,0 +1,16 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat2x3<f16>;
+
+fn a(m : mat2x3<f16>) {}
+fn b(v : vec3<f16>) {}
+fn c(f : f16) {}
+
+@compute @workgroup_size(1)
+fn f() {
+    a(u);
+    b(u[1]);
+    b(u[1].zxy);
+    c(u[1].x);
+    c(u[1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_fn.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..4003a4e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_fn.wgsl.expected.dxc.hlsl
@@ -0,0 +1,45 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+void a(matrix<float16_t, 2, 3> m) {
+}
+
+void b(vector<float16_t, 3> v) {
+}
+
+void c(float16_t f_1) {
+}
+
+matrix<float16_t, 2, 3> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  uint2 ubo_load_4 = u[0].zw;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  b(vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]));
+  uint2 ubo_load_5 = u[0].zw;
+  vector<float16_t, 2> ubo_load_5_xz = vector<float16_t, 2>(f16tof32(ubo_load_5 & 0xFFFF));
+  float16_t ubo_load_5_y = f16tof32(ubo_load_5[0] >> 16);
+  b(vector<float16_t, 3>(ubo_load_5_xz[0], ubo_load_5_y, ubo_load_5_xz[1]).zxy);
+  c(float16_t(f16tof32(((u[0].z) & 0xFFFF))));
+  uint2 ubo_load_6 = u[0].zw;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  c(vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_fn.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..5aa92fe
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_fn.wgsl.expected.fxc.hlsl
@@ -0,0 +1,52 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+void a(matrix<float16_t, 2, 3> m) {
+}
+
+void b(vector<float16_t, 3> v) {
+}
+
+void c(float16_t f_1) {
+}
+
+matrix<float16_t, 2, 3> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  uint2 ubo_load_4 = u[0].zw;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  b(vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]));
+  uint2 ubo_load_5 = u[0].zw;
+  vector<float16_t, 2> ubo_load_5_xz = vector<float16_t, 2>(f16tof32(ubo_load_5 & 0xFFFF));
+  float16_t ubo_load_5_y = f16tof32(ubo_load_5[0] >> 16);
+  b(vector<float16_t, 3>(ubo_load_5_xz[0], ubo_load_5_y, ubo_load_5_xz[1]).zxy);
+  c(float16_t(f16tof32(((u[0].z) & 0xFFFF))));
+  uint2 ubo_load_6 = u[0].zw;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  c(vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]).zxy.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x00000239ABA8AAE0(5,15-23): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x00000239ABA8AAE0(8,15-23): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x00000239ABA8AAE0(11,8-16): error X3000: unrecognized identifier 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_fn.wgsl.expected.glsl
new file mode 100644
index 0000000..3938a63
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_fn.wgsl.expected.glsl
@@ -0,0 +1,34 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec3 inner_0;
+  f16vec3 inner_1;
+} u;
+
+void a(f16mat2x3 m) {
+}
+
+void b(f16vec3 v) {
+}
+
+void c(float16_t f_1) {
+}
+
+f16mat2x3 load_u_inner() {
+  return f16mat2x3(u.inner_0, u.inner_1);
+}
+
+void f() {
+  a(load_u_inner());
+  b(u.inner_1);
+  b(u.inner_1.zxy);
+  c(u.inner_1[0u]);
+  c(u.inner_1.zxy[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_fn.wgsl.expected.msl
new file mode 100644
index 0000000..339491e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_fn.wgsl.expected.msl
@@ -0,0 +1,21 @@
+#include <metal_stdlib>
+
+using namespace metal;
+void a(half2x3 m) {
+}
+
+void b(half3 v) {
+}
+
+void c(half f_1) {
+}
+
+kernel void f(const constant half2x3* tint_symbol [[buffer(0)]]) {
+  a(*(tint_symbol));
+  b((*(tint_symbol))[1]);
+  b(half3((*(tint_symbol))[1]).zxy);
+  c((*(tint_symbol))[1][0]);
+  c(half3((*(tint_symbol))[1]).zxy[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_fn.wgsl.expected.spvasm
new file mode 100644
index 0000000..c2eb2c2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_fn.wgsl.expected.spvasm
@@ -0,0 +1,94 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 57
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpName %u "u"
+               OpName %a "a"
+               OpName %m "m"
+               OpName %b "b"
+               OpName %v "v"
+               OpName %c "c"
+               OpName %f_1 "f_1"
+               OpName %load_u_inner "load_u_inner"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 8
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+%u_block_std140 = OpTypeStruct %v3half %v3half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+       %void = OpTypeVoid
+ %mat2v3half = OpTypeMatrix %v3half 2
+          %6 = OpTypeFunction %void %mat2v3half
+         %12 = OpTypeFunction %void %v3half
+         %16 = OpTypeFunction %void %half
+         %20 = OpTypeFunction %mat2v3half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+     %uint_1 = OpConstant %uint 1
+         %35 = OpTypeFunction %void
+         %48 = OpConstantNull %uint
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+          %a = OpFunction %void None %6
+          %m = OpFunctionParameter %mat2v3half
+         %11 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %b = OpFunction %void None %12
+          %v = OpFunctionParameter %v3half
+         %15 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %c = OpFunction %void None %16
+        %f_1 = OpFunctionParameter %half
+         %19 = OpLabel
+               OpReturn
+               OpFunctionEnd
+%load_u_inner = OpFunction %mat2v3half None %20
+         %22 = OpLabel
+         %28 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0
+         %29 = OpLoad %v3half %28
+         %32 = OpAccessChain %_ptr_Uniform_v3half %u %uint_1
+         %33 = OpLoad %v3half %32
+         %34 = OpCompositeConstruct %mat2v3half %29 %33
+               OpReturnValue %34
+               OpFunctionEnd
+          %f = OpFunction %void None %35
+         %37 = OpLabel
+         %39 = OpFunctionCall %mat2v3half %load_u_inner
+         %38 = OpFunctionCall %void %a %39
+         %41 = OpAccessChain %_ptr_Uniform_v3half %u %uint_1
+         %42 = OpLoad %v3half %41
+         %40 = OpFunctionCall %void %b %42
+         %44 = OpAccessChain %_ptr_Uniform_v3half %u %uint_1
+         %45 = OpLoad %v3half %44
+         %46 = OpVectorShuffle %v3half %45 %45 2 0 1
+         %43 = OpFunctionCall %void %b %46
+         %50 = OpAccessChain %_ptr_Uniform_half %u %uint_1 %48
+         %51 = OpLoad %half %50
+         %47 = OpFunctionCall %void %c %51
+         %53 = OpAccessChain %_ptr_Uniform_v3half %u %uint_1
+         %54 = OpLoad %v3half %53
+         %55 = OpVectorShuffle %v3half %54 %54 2 0 1
+         %56 = OpCompositeExtract %half %55 0
+         %52 = OpFunctionCall %void %c %56
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_fn.wgsl.expected.wgsl
new file mode 100644
index 0000000..ff22761
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_fn.wgsl.expected.wgsl
@@ -0,0 +1,21 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat2x3<f16>;
+
+fn a(m : mat2x3<f16>) {
+}
+
+fn b(v : vec3<f16>) {
+}
+
+fn c(f : f16) {
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  a(u);
+  b(u[1]);
+  b(u[1].zxy);
+  c(u[1].x);
+  c(u[1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_private.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_private.wgsl
new file mode 100644
index 0000000..4fa4b5a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_private.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat2x3<f16>;
+var<private> p : mat2x3<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[0];
+    p[1] = u[0].zxy;
+    p[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_private.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..5cec9ae
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_private.wgsl.expected.dxc.hlsl
@@ -0,0 +1,33 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+static matrix<float16_t, 2, 3> p = matrix<float16_t, 2, 3>(float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h));
+
+matrix<float16_t, 2, 3> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  uint2 ubo_load_4 = u[0].xy;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  p[1] = vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]);
+  uint2 ubo_load_5 = u[0].xy;
+  vector<float16_t, 2> ubo_load_5_xz = vector<float16_t, 2>(f16tof32(ubo_load_5 & 0xFFFF));
+  float16_t ubo_load_5_y = f16tof32(ubo_load_5[0] >> 16);
+  p[1] = vector<float16_t, 3>(ubo_load_5_xz[0], ubo_load_5_y, ubo_load_5_xz[1]).zxy;
+  p[0][1] = float16_t(f16tof32(((u[0].z) & 0xFFFF)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_private.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..9ceeb9d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_private.wgsl.expected.fxc.hlsl
@@ -0,0 +1,38 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+static matrix<float16_t, 2, 3> p = matrix<float16_t, 2, 3>(float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h));
+
+matrix<float16_t, 2, 3> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  uint2 ubo_load_4 = u[0].xy;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  p[1] = vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]);
+  uint2 ubo_load_5 = u[0].xy;
+  vector<float16_t, 2> ubo_load_5_xz = vector<float16_t, 2>(f16tof32(ubo_load_5 & 0xFFFF));
+  float16_t ubo_load_5_y = f16tof32(ubo_load_5[0] >> 16);
+  p[1] = vector<float16_t, 3>(ubo_load_5_xz[0], ubo_load_5_y, ubo_load_5_xz[1]).zxy;
+  p[0][1] = float16_t(f16tof32(((u[0].z) & 0xFFFF)));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000017EBF6D45E0(4,15-23): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..ea309f4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_private.wgsl.expected.glsl
@@ -0,0 +1,25 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec3 inner_0;
+  f16vec3 inner_1;
+} u;
+
+f16mat2x3 p = f16mat2x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf);
+f16mat2x3 load_u_inner() {
+  return f16mat2x3(u.inner_0, u.inner_1);
+}
+
+void f() {
+  p = load_u_inner();
+  p[1] = u.inner_0;
+  p[1] = u.inner_0.zxy;
+  p[0][1] = u.inner_1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..a233531
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_private.wgsl.expected.msl
@@ -0,0 +1,12 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f(const constant half2x3* tint_symbol_1 [[buffer(0)]]) {
+  thread half2x3 tint_symbol = half2x3(0.0h);
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[0];
+  tint_symbol[1] = half3((*(tint_symbol_1))[0]).zxy;
+  tint_symbol[0][1] = (*(tint_symbol_1))[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_private.wgsl.expected.spvasm
new file mode 100644
index 0000000..651b673
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_private.wgsl.expected.spvasm
@@ -0,0 +1,77 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 47
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpName %u "u"
+               OpName %p "p"
+               OpName %load_u_inner "load_u_inner"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 8
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+%u_block_std140 = OpTypeStruct %v3half %v3half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat2v3half = OpTypeMatrix %v3half 2
+%_ptr_Private_mat2v3half = OpTypePointer Private %mat2v3half
+          %9 = OpConstantNull %mat2v3half
+          %p = OpVariable %_ptr_Private_mat2v3half Private %9
+         %10 = OpTypeFunction %mat2v3half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+     %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %25 = OpTypeFunction %void
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Private_v3half = OpTypePointer Private %v3half
+         %40 = OpConstantNull %int
+%_ptr_Private_half = OpTypePointer Private %half
+         %43 = OpConstantNull %uint
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+%load_u_inner = OpFunction %mat2v3half None %10
+         %12 = OpLabel
+         %18 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0
+         %19 = OpLoad %v3half %18
+         %22 = OpAccessChain %_ptr_Uniform_v3half %u %uint_1
+         %23 = OpLoad %v3half %22
+         %24 = OpCompositeConstruct %mat2v3half %19 %23
+               OpReturnValue %24
+               OpFunctionEnd
+          %f = OpFunction %void None %25
+         %28 = OpLabel
+         %29 = OpFunctionCall %mat2v3half %load_u_inner
+               OpStore %p %29
+         %33 = OpAccessChain %_ptr_Private_v3half %p %int_1
+         %34 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0
+         %35 = OpLoad %v3half %34
+               OpStore %33 %35
+         %36 = OpAccessChain %_ptr_Private_v3half %p %int_1
+         %37 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0
+         %38 = OpLoad %v3half %37
+         %39 = OpVectorShuffle %v3half %38 %38 2 0 1
+               OpStore %36 %39
+         %42 = OpAccessChain %_ptr_Private_half %p %40 %int_1
+         %45 = OpAccessChain %_ptr_Uniform_half %u %uint_1 %43
+         %46 = OpLoad %half %45
+               OpStore %42 %46
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..0a0d370
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_private.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat2x3<f16>;
+
+var<private> p : mat2x3<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[0];
+  p[1] = u[0].zxy;
+  p[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_storage.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_storage.wgsl
new file mode 100644
index 0000000..e14acf2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_storage.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat2x3<f16>;
+@group(0) @binding(1) var<storage, read_write> s : mat2x3<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[0];
+    s[1] = u[0].zxy;
+    s[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_storage.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..4655996
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_storage.wgsl.expected.dxc.hlsl
@@ -0,0 +1,38 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 2, 3> value) {
+  buffer.Store<vector<float16_t, 3> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 8u), value[1u]);
+}
+
+matrix<float16_t, 2, 3> tint_symbol_2(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_2(u, 0u));
+  uint2 ubo_load_4 = u[0].xy;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  s.Store<vector<float16_t, 3> >(8u, vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]));
+  uint2 ubo_load_5 = u[0].xy;
+  vector<float16_t, 2> ubo_load_5_xz = vector<float16_t, 2>(f16tof32(ubo_load_5 & 0xFFFF));
+  float16_t ubo_load_5_y = f16tof32(ubo_load_5[0] >> 16);
+  s.Store<vector<float16_t, 3> >(8u, vector<float16_t, 3>(ubo_load_5_xz[0], ubo_load_5_y, ubo_load_5_xz[1]).zxy);
+  s.Store<float16_t>(2u, float16_t(f16tof32(((u[0].z) & 0xFFFF))));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_storage.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..ddbe694
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_storage.wgsl.expected.fxc.hlsl
@@ -0,0 +1,44 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 2, 3> value) {
+  buffer.Store<vector<float16_t, 3> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 8u), value[1u]);
+}
+
+matrix<float16_t, 2, 3> tint_symbol_2(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_2(u, 0u));
+  uint2 ubo_load_4 = u[0].xy;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  s.Store<vector<float16_t, 3> >(8u, vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]));
+  uint2 ubo_load_5 = u[0].xy;
+  vector<float16_t, 2> ubo_load_5_xz = vector<float16_t, 2>(f16tof32(ubo_load_5 & 0xFFFF));
+  float16_t ubo_load_5_y = f16tof32(ubo_load_5[0] >> 16);
+  s.Store<vector<float16_t, 3> >(8u, vector<float16_t, 3>(ubo_load_5_xz[0], ubo_load_5_y, ubo_load_5_xz[1]).zxy);
+  s.Store<float16_t>(2u, float16_t(f16tof32(((u[0].z) & 0xFFFF))));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000015012B07F20(6,66-74): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000015012B07F20(7,3-14): error X3018: invalid subscript 'Store'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..ba0c55a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_storage.wgsl.expected.glsl
@@ -0,0 +1,28 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec3 inner_0;
+  f16vec3 inner_1;
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  f16mat2x3 inner;
+} s;
+
+f16mat2x3 load_u_inner() {
+  return f16mat2x3(u.inner_0, u.inner_1);
+}
+
+void f() {
+  s.inner = load_u_inner();
+  s.inner[1] = u.inner_0;
+  s.inner[1] = u.inner_0.zxy;
+  s.inner[0][1] = u.inner_1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..495bebf
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_storage.wgsl.expected.msl
@@ -0,0 +1,11 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f(device half2x3* tint_symbol [[buffer(1)]], const constant half2x3* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[0];
+  (*(tint_symbol))[1] = half3((*(tint_symbol_1))[0]).zxy;
+  (*(tint_symbol))[0][1] = (*(tint_symbol_1))[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_storage.wgsl.expected.spvasm
new file mode 100644
index 0000000..67096f3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_storage.wgsl.expected.spvasm
@@ -0,0 +1,87 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 49
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpName %u "u"
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %s "s"
+               OpName %load_u_inner "load_u_inner"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 8
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 8
+               OpDecorate %s DescriptorSet 0
+               OpDecorate %s Binding 1
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+%u_block_std140 = OpTypeStruct %v3half %v3half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat2v3half = OpTypeMatrix %v3half 2
+    %u_block = OpTypeStruct %mat2v3half
+%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
+          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+         %10 = OpTypeFunction %mat2v3half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+     %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %25 = OpTypeFunction %void
+%_ptr_StorageBuffer_mat2v3half = OpTypePointer StorageBuffer %mat2v3half
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_v3half = OpTypePointer StorageBuffer %v3half
+         %42 = OpConstantNull %int
+%_ptr_StorageBuffer_half = OpTypePointer StorageBuffer %half
+         %45 = OpConstantNull %uint
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+%load_u_inner = OpFunction %mat2v3half None %10
+         %12 = OpLabel
+         %18 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0
+         %19 = OpLoad %v3half %18
+         %22 = OpAccessChain %_ptr_Uniform_v3half %u %uint_1
+         %23 = OpLoad %v3half %22
+         %24 = OpCompositeConstruct %mat2v3half %19 %23
+               OpReturnValue %24
+               OpFunctionEnd
+          %f = OpFunction %void None %25
+         %28 = OpLabel
+         %30 = OpAccessChain %_ptr_StorageBuffer_mat2v3half %s %uint_0
+         %31 = OpFunctionCall %mat2v3half %load_u_inner
+               OpStore %30 %31
+         %35 = OpAccessChain %_ptr_StorageBuffer_v3half %s %uint_0 %int_1
+         %36 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0
+         %37 = OpLoad %v3half %36
+               OpStore %35 %37
+         %38 = OpAccessChain %_ptr_StorageBuffer_v3half %s %uint_0 %int_1
+         %39 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0
+         %40 = OpLoad %v3half %39
+         %41 = OpVectorShuffle %v3half %40 %40 2 0 1
+               OpStore %38 %41
+         %44 = OpAccessChain %_ptr_StorageBuffer_half %s %uint_0 %42 %int_1
+         %47 = OpAccessChain %_ptr_Uniform_half %u %uint_1 %45
+         %48 = OpLoad %half %47
+               OpStore %44 %48
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..3e7f84b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat2x3<f16>;
+
+@group(0) @binding(1) var<storage, read_write> s : mat2x3<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[0];
+  s[1] = u[0].zxy;
+  s[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_workgroup.wgsl
new file mode 100644
index 0000000..0fec122
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_workgroup.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat2x3<f16>;
+var<workgroup> w : mat2x3<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[0];
+    w[1] = u[0].zxy;
+    w[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_workgroup.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..5826664
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_workgroup.wgsl.expected.dxc.hlsl
@@ -0,0 +1,45 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+groupshared matrix<float16_t, 2, 3> w;
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 2, 3> tint_symbol_2(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    w = matrix<float16_t, 2, 3>((float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx);
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  uint2 ubo_load_4 = u[0].xy;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  w[1] = vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]);
+  uint2 ubo_load_5 = u[0].xy;
+  vector<float16_t, 2> ubo_load_5_xz = vector<float16_t, 2>(f16tof32(ubo_load_5 & 0xFFFF));
+  float16_t ubo_load_5_y = f16tof32(ubo_load_5[0] >> 16);
+  w[1] = vector<float16_t, 3>(ubo_load_5_xz[0], ubo_load_5_y, ubo_load_5_xz[1]).zxy;
+  w[0][1] = float16_t(f16tof32(((u[0].z) & 0xFFFF)));
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_workgroup.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..2285b54
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_workgroup.wgsl.expected.fxc.hlsl
@@ -0,0 +1,50 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+groupshared matrix<float16_t, 2, 3> w;
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 2, 3> tint_symbol_2(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    w = matrix<float16_t, 2, 3>((float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx);
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  uint2 ubo_load_4 = u[0].xy;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  w[1] = vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]);
+  uint2 ubo_load_5 = u[0].xy;
+  vector<float16_t, 2> ubo_load_5_xz = vector<float16_t, 2>(f16tof32(ubo_load_5 & 0xFFFF));
+  float16_t ubo_load_5_y = f16tof32(ubo_load_5[0] >> 16);
+  w[1] = vector<float16_t, 3>(ubo_load_5_xz[0], ubo_load_5_y, ubo_load_5_xz[1]).zxy;
+  w[0][1] = float16_t(f16tof32(((u[0].z) & 0xFFFF)));
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x00000293678839C0(4,20-28): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..c99e017
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,29 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec3 inner_0;
+  f16vec3 inner_1;
+} u;
+
+shared f16mat2x3 w;
+f16mat2x3 load_u_inner() {
+  return f16mat2x3(u.inner_0, u.inner_1);
+}
+
+void f(uint local_invocation_index) {
+  {
+    w = f16mat2x3(f16vec3(0.0hf), f16vec3(0.0hf));
+  }
+  barrier();
+  w = load_u_inner();
+  w[1] = u.inner_0;
+  w[1] = u.inner_0.zxy;
+  w[0][1] = u.inner_1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..4ccd046
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,24 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct tint_symbol_5 {
+  half2x3 w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup half2x3* const tint_symbol, const constant half2x3* const tint_symbol_1) {
+  {
+    *(tint_symbol) = half2x3(half3(0.0h), half3(0.0h));
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[0];
+  (*(tint_symbol))[1] = half3((*(tint_symbol_1))[0]).zxy;
+  (*(tint_symbol))[0][1] = (*(tint_symbol_1))[1][0];
+}
+
+kernel void f(const constant half2x3* tint_symbol_4 [[buffer(0)]], threadgroup tint_symbol_5* tint_symbol_3 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup half2x3* const tint_symbol_2 = &((*(tint_symbol_3)).w);
+  f_inner(local_invocation_index, tint_symbol_2, tint_symbol_4);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_workgroup.wgsl.expected.spvasm
new file mode 100644
index 0000000..167a8c9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_workgroup.wgsl.expected.spvasm
@@ -0,0 +1,95 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 58
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %local_invocation_index_1 "local_invocation_index_1"
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpName %u "u"
+               OpName %w "w"
+               OpName %load_u_inner "load_u_inner"
+               OpName %f_inner "f_inner"
+               OpName %local_invocation_index "local_invocation_index"
+               OpName %f "f"
+               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 8
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+%u_block_std140 = OpTypeStruct %v3half %v3half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat2v3half = OpTypeMatrix %v3half 2
+%_ptr_Workgroup_mat2v3half = OpTypePointer Workgroup %mat2v3half
+          %w = OpVariable %_ptr_Workgroup_mat2v3half Workgroup
+         %12 = OpTypeFunction %mat2v3half
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+     %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %26 = OpTypeFunction %void %uint
+         %31 = OpConstantNull %mat2v3half
+     %uint_2 = OpConstant %uint 2
+   %uint_264 = OpConstant %uint 264
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Workgroup_v3half = OpTypePointer Workgroup %v3half
+         %46 = OpConstantNull %int
+%_ptr_Workgroup_half = OpTypePointer Workgroup %half
+         %49 = OpConstantNull %uint
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+         %53 = OpTypeFunction %void
+%load_u_inner = OpFunction %mat2v3half None %12
+         %14 = OpLabel
+         %19 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0
+         %20 = OpLoad %v3half %19
+         %23 = OpAccessChain %_ptr_Uniform_v3half %u %uint_1
+         %24 = OpLoad %v3half %23
+         %25 = OpCompositeConstruct %mat2v3half %20 %24
+               OpReturnValue %25
+               OpFunctionEnd
+    %f_inner = OpFunction %void None %26
+%local_invocation_index = OpFunctionParameter %uint
+         %30 = OpLabel
+               OpStore %w %31
+               OpControlBarrier %uint_2 %uint_2 %uint_264
+         %35 = OpFunctionCall %mat2v3half %load_u_inner
+               OpStore %w %35
+         %39 = OpAccessChain %_ptr_Workgroup_v3half %w %int_1
+         %40 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0
+         %41 = OpLoad %v3half %40
+               OpStore %39 %41
+         %42 = OpAccessChain %_ptr_Workgroup_v3half %w %int_1
+         %43 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0
+         %44 = OpLoad %v3half %43
+         %45 = OpVectorShuffle %v3half %44 %44 2 0 1
+               OpStore %42 %45
+         %48 = OpAccessChain %_ptr_Workgroup_half %w %46 %int_1
+         %51 = OpAccessChain %_ptr_Uniform_half %u %uint_1 %49
+         %52 = OpLoad %half %51
+               OpStore %48 %52
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %53
+         %55 = OpLabel
+         %57 = OpLoad %uint %local_invocation_index_1
+         %56 = OpFunctionCall %void %f_inner %57
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..81f551f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f16/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat2x3<f16>;
+
+var<workgroup> w : mat2x3<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[0];
+  w[1] = u[0].zxy;
+  w[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/dynamic_index_via_ptr.wgsl
new file mode 100644
index 0000000..13510bd
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/dynamic_index_via_ptr.wgsl
@@ -0,0 +1,13 @@
+@group(0) @binding(0) var<uniform> m : mat2x3<f32>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m   = &m;
+  let p_m_i = &((*p_m)[i()]);
+
+  let l_m   : mat2x3<f32> = *p_m;
+  let l_m_i : vec3<f32>   = *p_m_i;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..0cf7edc
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,24 @@
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[2];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float2x3 tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_m_i_save = i();
+  const float2x3 l_m = tint_symbol(m, 0u);
+  const uint scalar_offset_2 = ((16u * uint(p_m_i_save))) / 4;
+  const float3 l_m_i = asfloat(m[scalar_offset_2 / 4].xyz);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..0cf7edc
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,24 @@
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[2];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float2x3 tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_m_i_save = i();
+  const float2x3 l_m = tint_symbol(m, 0u);
+  const uint scalar_offset_2 = ((16u * uint(p_m_i_save))) / 4;
+  const float3 l_m_i = asfloat(m[scalar_offset_2 / 4].xyz);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..8fefc25
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,24 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform m_block_ubo {
+  mat2x3 inner;
+} m;
+
+int counter = 0;
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+void f() {
+  int tint_symbol = i();
+  int p_m_i_save = tint_symbol;
+  mat2x3 l_m = m.inner;
+  vec3 l_m_i = m.inner[p_m_i_save];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..cecbfbb
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,17 @@
+#include <metal_stdlib>
+
+using namespace metal;
+int i() {
+  thread int tint_symbol_1 = 0;
+  tint_symbol_1 = as_type<int>((as_type<uint>(tint_symbol_1) + as_type<uint>(1)));
+  return tint_symbol_1;
+}
+
+kernel void f(const constant float2x3* tint_symbol_2 [[buffer(0)]]) {
+  int const tint_symbol = i();
+  int const p_m_i_save = tint_symbol;
+  float2x3 const l_m = *(tint_symbol_2);
+  float3 const l_m_i = (*(tint_symbol_2))[p_m_i_save];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..8530a81
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,57 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 31
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %m_block "m_block"
+               OpMemberName %m_block 0 "inner"
+               OpName %m "m"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %f "f"
+               OpDecorate %m_block Block
+               OpMemberDecorate %m_block 0 Offset 0
+               OpMemberDecorate %m_block 0 ColMajor
+               OpMemberDecorate %m_block 0 MatrixStride 16
+               OpDecorate %m NonWritable
+               OpDecorate %m DescriptorSet 0
+               OpDecorate %m Binding 0
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat2v3float = OpTypeMatrix %v3float 2
+    %m_block = OpTypeStruct %mat2v3float
+%_ptr_Uniform_m_block = OpTypePointer Uniform %m_block
+          %m = OpVariable %_ptr_Uniform_m_block Uniform
+        %int = OpTypeInt 32 1
+          %8 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %8
+         %11 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+       %void = OpTypeVoid
+         %18 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_mat2v3float = OpTypePointer Uniform %mat2v3float
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+          %i = OpFunction %int None %11
+         %13 = OpLabel
+         %14 = OpLoad %int %counter
+         %16 = OpIAdd %int %14 %int_1
+               OpStore %counter %16
+         %17 = OpLoad %int %counter
+               OpReturnValue %17
+               OpFunctionEnd
+          %f = OpFunction %void None %18
+         %21 = OpLabel
+         %22 = OpFunctionCall %int %i
+         %26 = OpAccessChain %_ptr_Uniform_mat2v3float %m %uint_0
+         %27 = OpLoad %mat2v3float %26
+         %29 = OpAccessChain %_ptr_Uniform_v3float %m %uint_0 %22
+         %30 = OpLoad %v3float %29
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..54241eb
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,16 @@
+@group(0) @binding(0) var<uniform> m : mat2x3<f32>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m = &(m);
+  let p_m_i = &((*(p_m))[i()]);
+  let l_m : mat2x3<f32> = *(p_m);
+  let l_m_i : vec3<f32> = *(p_m_i);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/static_index_via_ptr.wgsl
new file mode 100644
index 0000000..3444b96
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/static_index_via_ptr.wgsl
@@ -0,0 +1,13 @@
+@group(0) @binding(0) var<uniform> m : mat2x3<f32>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m   = &m;
+  let p_m_1 = &((*p_m)[1]);
+
+  let l_m   : mat2x3<f32> = *p_m;
+  let l_m_1 : vec3<f32>   = *p_m_1;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..e43ed37
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,22 @@
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[2];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float2x3 tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float2x3 l_m = tint_symbol(m, 0u);
+  const float3 l_m_1 = asfloat(m[1].xyz);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..e43ed37
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,22 @@
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[2];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float2x3 tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float2x3 l_m = tint_symbol(m, 0u);
+  const float3 l_m_1 = asfloat(m[1].xyz);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/static_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..804b6a8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/static_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,16 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform m_block_ubo {
+  mat2x3 inner;
+} m;
+
+void f() {
+  mat2x3 l_m = m.inner;
+  vec3 l_m_1 = m.inner[1];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/static_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..68130f7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/static_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,15 @@
+#include <metal_stdlib>
+
+using namespace metal;
+int i() {
+  thread int tint_symbol = 0;
+  tint_symbol = as_type<int>((as_type<uint>(tint_symbol) + as_type<uint>(1)));
+  return tint_symbol;
+}
+
+kernel void f(const constant float2x3* tint_symbol_1 [[buffer(0)]]) {
+  float2x3 const l_m = *(tint_symbol_1);
+  float3 const l_m_1 = (*(tint_symbol_1))[1];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/static_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..d325f64
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/static_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,56 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 30
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %m_block "m_block"
+               OpMemberName %m_block 0 "inner"
+               OpName %m "m"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %f "f"
+               OpDecorate %m_block Block
+               OpMemberDecorate %m_block 0 Offset 0
+               OpMemberDecorate %m_block 0 ColMajor
+               OpMemberDecorate %m_block 0 MatrixStride 16
+               OpDecorate %m NonWritable
+               OpDecorate %m DescriptorSet 0
+               OpDecorate %m Binding 0
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat2v3float = OpTypeMatrix %v3float 2
+    %m_block = OpTypeStruct %mat2v3float
+%_ptr_Uniform_m_block = OpTypePointer Uniform %m_block
+          %m = OpVariable %_ptr_Uniform_m_block Uniform
+        %int = OpTypeInt 32 1
+          %8 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %8
+         %11 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+       %void = OpTypeVoid
+         %18 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_mat2v3float = OpTypePointer Uniform %mat2v3float
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+          %i = OpFunction %int None %11
+         %13 = OpLabel
+         %14 = OpLoad %int %counter
+         %16 = OpIAdd %int %14 %int_1
+               OpStore %counter %16
+         %17 = OpLoad %int %counter
+               OpReturnValue %17
+               OpFunctionEnd
+          %f = OpFunction %void None %18
+         %21 = OpLabel
+         %25 = OpAccessChain %_ptr_Uniform_mat2v3float %m %uint_0
+         %26 = OpLoad %mat2v3float %25
+         %28 = OpAccessChain %_ptr_Uniform_v3float %m %uint_0 %int_1
+         %29 = OpLoad %v3float %28
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/static_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..cb741be
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/static_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,16 @@
+@group(0) @binding(0) var<uniform> m : mat2x3<f32>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m = &(m);
+  let p_m_1 = &((*(p_m))[1]);
+  let l_m : mat2x3<f32> = *(p_m);
+  let l_m_1 : vec3<f32> = *(p_m_1);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_builtin.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_builtin.wgsl
new file mode 100644
index 0000000..358bb94
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_builtin.wgsl
@@ -0,0 +1,8 @@
+@group(0) @binding(0) var<uniform> u : mat2x3<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+    let t = transpose(u);
+    let l = length(u[1]);
+    let a = abs(u[0].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_builtin.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..8f85f93
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_builtin.wgsl.expected.dxc.hlsl
@@ -0,0 +1,17 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+
+float2x3 tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float3x2 t = transpose(tint_symbol(u, 0u));
+  const float l = length(asfloat(u[1].xyz));
+  const float a = abs(asfloat(u[0].xyz).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_builtin.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..8f85f93
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_builtin.wgsl.expected.fxc.hlsl
@@ -0,0 +1,17 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+
+float2x3 tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float3x2 t = transpose(tint_symbol(u, 0u));
+  const float l = length(asfloat(u[1].xyz));
+  const float a = abs(asfloat(u[0].xyz).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_builtin.wgsl.expected.glsl
new file mode 100644
index 0000000..462a2df
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_builtin.wgsl.expected.glsl
@@ -0,0 +1,17 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat2x3 inner;
+} u;
+
+void f() {
+  mat3x2 t = transpose(u.inner);
+  float l = length(u.inner[1]);
+  float a = abs(u.inner[0].zxy.x);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_builtin.wgsl.expected.msl
new file mode 100644
index 0000000..96989c8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_builtin.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f(const constant float2x3* tint_symbol [[buffer(0)]]) {
+  float3x2 const t = transpose(*(tint_symbol));
+  float const l = length((*(tint_symbol))[1]);
+  float const a = fabs(float3((*(tint_symbol))[0]).zxy[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_builtin.wgsl.expected.spvasm
new file mode 100644
index 0000000..138d236
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_builtin.wgsl.expected.spvasm
@@ -0,0 +1,53 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 32
+; Schema: 0
+               OpCapability Shader
+         %20 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat2v3float = OpTypeMatrix %v3float 2
+    %u_block = OpTypeStruct %mat2v3float
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+          %7 = OpTypeFunction %void
+    %v2float = OpTypeVector %float 2
+%mat3v2float = OpTypeMatrix %v2float 3
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_mat2v3float = OpTypePointer Uniform %mat2v3float
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+         %27 = OpConstantNull %int
+          %f = OpFunction %void None %7
+         %10 = OpLabel
+         %17 = OpAccessChain %_ptr_Uniform_mat2v3float %u %uint_0
+         %18 = OpLoad %mat2v3float %17
+         %11 = OpTranspose %mat3v2float %18
+         %24 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %int_1
+         %25 = OpLoad %v3float %24
+         %19 = OpExtInst %float %20 Length %25
+         %28 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %27
+         %29 = OpLoad %v3float %28
+         %30 = OpVectorShuffle %v3float %29 %29 2 0 1
+         %31 = OpCompositeExtract %float %30 0
+         %26 = OpExtInst %float %20 FAbs %31
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_builtin.wgsl.expected.wgsl
new file mode 100644
index 0000000..af3e193
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_builtin.wgsl.expected.wgsl
@@ -0,0 +1,8 @@
+@group(0) @binding(0) var<uniform> u : mat2x3<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let t = transpose(u);
+  let l = length(u[1]);
+  let a = abs(u[0].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_fn.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_fn.wgsl
new file mode 100644
index 0000000..3099888
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_fn.wgsl
@@ -0,0 +1,14 @@
+@group(0) @binding(0) var<uniform> u : mat2x3<f32>;
+
+fn a(m : mat2x3<f32>) {}
+fn b(v : vec3<f32>) {}
+fn c(f : f32) {}
+
+@compute @workgroup_size(1)
+fn f() {
+    a(u);
+    b(u[1]);
+    b(u[1].zxy);
+    c(u[1].x);
+    c(u[1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_fn.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..1fc478d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_fn.wgsl.expected.dxc.hlsl
@@ -0,0 +1,28 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+
+void a(float2x3 m) {
+}
+
+void b(float3 v) {
+}
+
+void c(float f_1) {
+}
+
+float2x3 tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(asfloat(u[1].xyz));
+  b(asfloat(u[1].xyz).zxy);
+  c(asfloat(u[1].x));
+  c(asfloat(u[1].xyz).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_fn.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..1fc478d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_fn.wgsl.expected.fxc.hlsl
@@ -0,0 +1,28 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+
+void a(float2x3 m) {
+}
+
+void b(float3 v) {
+}
+
+void c(float f_1) {
+}
+
+float2x3 tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(asfloat(u[1].xyz));
+  b(asfloat(u[1].xyz).zxy);
+  c(asfloat(u[1].x));
+  c(asfloat(u[1].xyz).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_fn.wgsl.expected.glsl
new file mode 100644
index 0000000..b4d5c5e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_fn.wgsl.expected.glsl
@@ -0,0 +1,28 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat2x3 inner;
+} u;
+
+void a(mat2x3 m) {
+}
+
+void b(vec3 v) {
+}
+
+void c(float f_1) {
+}
+
+void f() {
+  a(u.inner);
+  b(u.inner[1]);
+  b(u.inner[1].zxy);
+  c(u.inner[1].x);
+  c(u.inner[1].zxy.x);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_fn.wgsl.expected.msl
new file mode 100644
index 0000000..9d84e31
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_fn.wgsl.expected.msl
@@ -0,0 +1,21 @@
+#include <metal_stdlib>
+
+using namespace metal;
+void a(float2x3 m) {
+}
+
+void b(float3 v) {
+}
+
+void c(float f_1) {
+}
+
+kernel void f(const constant float2x3* tint_symbol [[buffer(0)]]) {
+  a(*(tint_symbol));
+  b((*(tint_symbol))[1]);
+  b(float3((*(tint_symbol))[1]).zxy);
+  c((*(tint_symbol))[1][0]);
+  c(float3((*(tint_symbol))[1]).zxy[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_fn.wgsl.expected.spvasm
new file mode 100644
index 0000000..aae65de
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_fn.wgsl.expected.spvasm
@@ -0,0 +1,81 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 48
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %a "a"
+               OpName %m "m"
+               OpName %b "b"
+               OpName %v "v"
+               OpName %c "c"
+               OpName %f_1 "f_1"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat2v3float = OpTypeMatrix %v3float 2
+    %u_block = OpTypeStruct %mat2v3float
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+          %7 = OpTypeFunction %void %mat2v3float
+         %12 = OpTypeFunction %void %v3float
+         %16 = OpTypeFunction %void %float
+         %20 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_mat2v3float = OpTypePointer Uniform %mat2v3float
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+          %a = OpFunction %void None %7
+          %m = OpFunctionParameter %mat2v3float
+         %11 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %b = OpFunction %void None %12
+          %v = OpFunctionParameter %v3float
+         %15 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %c = OpFunction %void None %16
+        %f_1 = OpFunctionParameter %float
+         %19 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %20
+         %22 = OpLabel
+         %27 = OpAccessChain %_ptr_Uniform_mat2v3float %u %uint_0
+         %28 = OpLoad %mat2v3float %27
+         %23 = OpFunctionCall %void %a %28
+         %33 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %int_1
+         %34 = OpLoad %v3float %33
+         %29 = OpFunctionCall %void %b %34
+         %36 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %int_1
+         %37 = OpLoad %v3float %36
+         %38 = OpVectorShuffle %v3float %37 %37 2 0 1
+         %35 = OpFunctionCall %void %b %38
+         %41 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %int_1 %uint_0
+         %42 = OpLoad %float %41
+         %39 = OpFunctionCall %void %c %42
+         %44 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %int_1
+         %45 = OpLoad %v3float %44
+         %46 = OpVectorShuffle %v3float %45 %45 2 0 1
+         %47 = OpCompositeExtract %float %46 0
+         %43 = OpFunctionCall %void %c %47
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_fn.wgsl.expected.wgsl
new file mode 100644
index 0000000..549cefc
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_fn.wgsl.expected.wgsl
@@ -0,0 +1,19 @@
+@group(0) @binding(0) var<uniform> u : mat2x3<f32>;
+
+fn a(m : mat2x3<f32>) {
+}
+
+fn b(v : vec3<f32>) {
+}
+
+fn c(f : f32) {
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  a(u);
+  b(u[1]);
+  b(u[1].zxy);
+  c(u[1].x);
+  c(u[1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_private.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_private.wgsl
new file mode 100644
index 0000000..3b29757
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_private.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0) var<uniform> u : mat2x3<f32>;
+var<private> p : mat2x3<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[0];
+    p[1] = u[0].zxy;
+    p[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_private.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..568d66f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_private.wgsl.expected.dxc.hlsl
@@ -0,0 +1,19 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+static float2x3 p = float2x3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
+
+float2x3 tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = asfloat(u[0].xyz);
+  p[1] = asfloat(u[0].xyz).zxy;
+  p[0][1] = asfloat(u[1].x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_private.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..568d66f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_private.wgsl.expected.fxc.hlsl
@@ -0,0 +1,19 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+static float2x3 p = float2x3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
+
+float2x3 tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = asfloat(u[0].xyz);
+  p[1] = asfloat(u[0].xyz).zxy;
+  p[0][1] = asfloat(u[1].x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..ba27583
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_private.wgsl.expected.glsl
@@ -0,0 +1,19 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat2x3 inner;
+} u;
+
+mat2x3 p = mat2x3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
+void f() {
+  p = u.inner;
+  p[1] = u.inner[0];
+  p[1] = u.inner[0].zxy;
+  p[0][1] = u.inner[1][0];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..d2181af
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_private.wgsl.expected.msl
@@ -0,0 +1,12 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f(const constant float2x3* tint_symbol_1 [[buffer(0)]]) {
+  thread float2x3 tint_symbol = float2x3(0.0f);
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[0];
+  tint_symbol[1] = float3((*(tint_symbol_1))[0]).zxy;
+  tint_symbol[0][1] = (*(tint_symbol_1))[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_private.wgsl.expected.spvasm
new file mode 100644
index 0000000..ac9477e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_private.wgsl.expected.spvasm
@@ -0,0 +1,62 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 36
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %p "p"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat2v3float = OpTypeMatrix %v3float 2
+    %u_block = OpTypeStruct %mat2v3float
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_Private_mat2v3float = OpTypePointer Private %mat2v3float
+          %9 = OpConstantNull %mat2v3float
+          %p = OpVariable %_ptr_Private_mat2v3float Private %9
+       %void = OpTypeVoid
+         %10 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_mat2v3float = OpTypePointer Uniform %mat2v3float
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Private_v3float = OpTypePointer Private %v3float
+         %23 = OpConstantNull %int
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+%_ptr_Private_float = OpTypePointer Private %float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+          %f = OpFunction %void None %10
+         %13 = OpLabel
+         %17 = OpAccessChain %_ptr_Uniform_mat2v3float %u %uint_0
+         %18 = OpLoad %mat2v3float %17
+               OpStore %p %18
+         %22 = OpAccessChain %_ptr_Private_v3float %p %int_1
+         %25 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %23
+         %26 = OpLoad %v3float %25
+               OpStore %22 %26
+         %27 = OpAccessChain %_ptr_Private_v3float %p %int_1
+         %28 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %23
+         %29 = OpLoad %v3float %28
+         %30 = OpVectorShuffle %v3float %29 %29 2 0 1
+               OpStore %27 %30
+         %32 = OpAccessChain %_ptr_Private_float %p %23 %int_1
+         %34 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %int_1 %23
+         %35 = OpLoad %float %34
+               OpStore %32 %35
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..46b652d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_private.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> u : mat2x3<f32>;
+
+var<private> p : mat2x3<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[0];
+  p[1] = u[0].zxy;
+  p[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_storage.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_storage.wgsl
new file mode 100644
index 0000000..9db0775
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_storage.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0) var<uniform> u : mat2x3<f32>;
+@group(0) @binding(1) var<storage, read_write> s : mat2x3<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[0];
+    s[1] = u[0].zxy;
+    s[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_storage.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..c3906dd
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_storage.wgsl.expected.dxc.hlsl
@@ -0,0 +1,24 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, float2x3 value) {
+  buffer.Store3((offset + 0u), asuint(value[0u]));
+  buffer.Store3((offset + 16u), asuint(value[1u]));
+}
+
+float2x3 tint_symbol_2(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_2(u, 0u));
+  s.Store3(16u, asuint(asfloat(u[0].xyz)));
+  s.Store3(16u, asuint(asfloat(u[0].xyz).zxy));
+  s.Store(4u, asuint(asfloat(u[1].x)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_storage.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..c3906dd
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_storage.wgsl.expected.fxc.hlsl
@@ -0,0 +1,24 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, float2x3 value) {
+  buffer.Store3((offset + 0u), asuint(value[0u]));
+  buffer.Store3((offset + 16u), asuint(value[1u]));
+}
+
+float2x3 tint_symbol_2(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_2(u, 0u));
+  s.Store3(16u, asuint(asfloat(u[0].xyz)));
+  s.Store3(16u, asuint(asfloat(u[0].xyz).zxy));
+  s.Store(4u, asuint(asfloat(u[1].x)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..bd4b73c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_storage.wgsl.expected.glsl
@@ -0,0 +1,22 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat2x3 inner;
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  mat2x3 inner;
+} s;
+
+void f() {
+  s.inner = u.inner;
+  s.inner[1] = u.inner[0];
+  s.inner[1] = u.inner[0].zxy;
+  s.inner[0][1] = u.inner[1][0];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..59569b4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_storage.wgsl.expected.msl
@@ -0,0 +1,11 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f(device float2x3* tint_symbol [[buffer(1)]], const constant float2x3* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[0];
+  (*(tint_symbol))[1] = float3((*(tint_symbol_1))[0]).zxy;
+  (*(tint_symbol))[0][1] = (*(tint_symbol_1))[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_storage.wgsl.expected.spvasm
new file mode 100644
index 0000000..faf129f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_storage.wgsl.expected.spvasm
@@ -0,0 +1,65 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 37
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %s "s"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %s DescriptorSet 0
+               OpDecorate %s Binding 1
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat2v3float = OpTypeMatrix %v3float 2
+    %u_block = OpTypeStruct %mat2v3float
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
+          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+       %void = OpTypeVoid
+          %9 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_mat2v3float = OpTypePointer StorageBuffer %mat2v3float
+%_ptr_Uniform_mat2v3float = OpTypePointer Uniform %mat2v3float
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_v3float = OpTypePointer StorageBuffer %v3float
+         %24 = OpConstantNull %int
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+          %f = OpFunction %void None %9
+         %12 = OpLabel
+         %16 = OpAccessChain %_ptr_StorageBuffer_mat2v3float %s %uint_0
+         %18 = OpAccessChain %_ptr_Uniform_mat2v3float %u %uint_0
+         %19 = OpLoad %mat2v3float %18
+               OpStore %16 %19
+         %23 = OpAccessChain %_ptr_StorageBuffer_v3float %s %uint_0 %int_1
+         %26 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %24
+         %27 = OpLoad %v3float %26
+               OpStore %23 %27
+         %28 = OpAccessChain %_ptr_StorageBuffer_v3float %s %uint_0 %int_1
+         %29 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %24
+         %30 = OpLoad %v3float %29
+         %31 = OpVectorShuffle %v3float %30 %30 2 0 1
+               OpStore %28 %31
+         %33 = OpAccessChain %_ptr_StorageBuffer_float %s %uint_0 %24 %int_1
+         %35 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %int_1 %24
+         %36 = OpLoad %float %35
+               OpStore %33 %36
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..198bf58
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> u : mat2x3<f32>;
+
+@group(0) @binding(1) var<storage, read_write> s : mat2x3<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[0];
+  s[1] = u[0].zxy;
+  s[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_workgroup.wgsl
new file mode 100644
index 0000000..b35fd21
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_workgroup.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0) var<uniform> u : mat2x3<f32>;
+var<workgroup> w : mat2x3<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[0];
+    w[1] = u[0].zxy;
+    w[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_workgroup.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..bdc3667
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_workgroup.wgsl.expected.dxc.hlsl
@@ -0,0 +1,31 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+groupshared float2x3 w;
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+float2x3 tint_symbol_2(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    w = float2x3((0.0f).xxx, (0.0f).xxx);
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = asfloat(u[0].xyz);
+  w[1] = asfloat(u[0].xyz).zxy;
+  w[0][1] = asfloat(u[1].x);
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_workgroup.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..bdc3667
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_workgroup.wgsl.expected.fxc.hlsl
@@ -0,0 +1,31 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+groupshared float2x3 w;
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+float2x3 tint_symbol_2(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz));
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    w = float2x3((0.0f).xxx, (0.0f).xxx);
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = asfloat(u[0].xyz);
+  w[1] = asfloat(u[0].xyz).zxy;
+  w[0][1] = asfloat(u[1].x);
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..22145fa
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,23 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat2x3 inner;
+} u;
+
+shared mat2x3 w;
+void f(uint local_invocation_index) {
+  {
+    w = mat2x3(vec3(0.0f), vec3(0.0f));
+  }
+  barrier();
+  w = u.inner;
+  w[1] = u.inner[0];
+  w[1] = u.inner[0].zxy;
+  w[0][1] = u.inner[1][0];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..9bf471f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,24 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct tint_symbol_5 {
+  float2x3 w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup float2x3* const tint_symbol, const constant float2x3* const tint_symbol_1) {
+  {
+    *(tint_symbol) = float2x3(float3(0.0f), float3(0.0f));
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[0];
+  (*(tint_symbol))[1] = float3((*(tint_symbol_1))[0]).zxy;
+  (*(tint_symbol))[0][1] = (*(tint_symbol_1))[1][0];
+}
+
+kernel void f(const constant float2x3* tint_symbol_4 [[buffer(0)]], threadgroup tint_symbol_5* tint_symbol_3 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup float2x3* const tint_symbol_2 = &((*(tint_symbol_3)).w);
+  f_inner(local_invocation_index, tint_symbol_2, tint_symbol_4);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_workgroup.wgsl.expected.spvasm
new file mode 100644
index 0000000..5f4d380
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_workgroup.wgsl.expected.spvasm
@@ -0,0 +1,80 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 47
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %local_invocation_index_1 "local_invocation_index_1"
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %w "w"
+               OpName %f_inner "f_inner"
+               OpName %local_invocation_index "local_invocation_index"
+               OpName %f "f"
+               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat2v3float = OpTypeMatrix %v3float 2
+    %u_block = OpTypeStruct %mat2v3float
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_Workgroup_mat2v3float = OpTypePointer Workgroup %mat2v3float
+          %w = OpVariable %_ptr_Workgroup_mat2v3float Workgroup
+       %void = OpTypeVoid
+         %12 = OpTypeFunction %void %uint
+         %17 = OpConstantNull %mat2v3float
+     %uint_2 = OpConstant %uint 2
+   %uint_264 = OpConstant %uint 264
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_mat2v3float = OpTypePointer Uniform %mat2v3float
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Workgroup_v3float = OpTypePointer Workgroup %v3float
+         %29 = OpConstantNull %int
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+%_ptr_Workgroup_float = OpTypePointer Workgroup %float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+         %42 = OpTypeFunction %void
+    %f_inner = OpFunction %void None %12
+%local_invocation_index = OpFunctionParameter %uint
+         %16 = OpLabel
+               OpStore %w %17
+               OpControlBarrier %uint_2 %uint_2 %uint_264
+         %23 = OpAccessChain %_ptr_Uniform_mat2v3float %u %uint_0
+         %24 = OpLoad %mat2v3float %23
+               OpStore %w %24
+         %28 = OpAccessChain %_ptr_Workgroup_v3float %w %int_1
+         %31 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %29
+         %32 = OpLoad %v3float %31
+               OpStore %28 %32
+         %33 = OpAccessChain %_ptr_Workgroup_v3float %w %int_1
+         %34 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %29
+         %35 = OpLoad %v3float %34
+         %36 = OpVectorShuffle %v3float %35 %35 2 0 1
+               OpStore %33 %36
+         %38 = OpAccessChain %_ptr_Workgroup_float %w %29 %int_1
+         %40 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %int_1 %29
+         %41 = OpLoad %float %40
+               OpStore %38 %41
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %42
+         %44 = OpLabel
+         %46 = OpLoad %uint %local_invocation_index_1
+         %45 = OpFunctionCall %void %f_inner %46
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..5d72743
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x3_f32/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> u : mat2x3<f32>;
+
+var<workgroup> w : mat2x3<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[0];
+  w[1] = u[0].zxy;
+  w[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/dynamic_index_via_ptr.wgsl
new file mode 100644
index 0000000..d266aa9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/dynamic_index_via_ptr.wgsl
@@ -0,0 +1,15 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> m : mat2x4<f16>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m   = &m;
+  let p_m_i = &((*p_m)[i()]);
+
+  let l_m   : mat2x4<f16> = *p_m;
+  let l_m_i : vec4<f16>   = *p_m_i;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..aafb4cc
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,36 @@
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[1];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 2, 4> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_m_i_save = i();
+  const matrix<float16_t, 2, 4> l_m = tint_symbol(m, 0u);
+  const uint scalar_offset_2 = ((8u * uint(p_m_i_save))) / 4;
+  uint4 ubo_load_5 = m[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const vector<float16_t, 4> l_m_i = vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..10e8ba9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,41 @@
+SKIP: FAILED
+
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[1];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 2, 4> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_m_i_save = i();
+  const matrix<float16_t, 2, 4> l_m = tint_symbol(m, 0u);
+  const uint scalar_offset_2 = ((8u * uint(p_m_i_save))) / 4;
+  uint4 ubo_load_5 = m[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const vector<float16_t, 4> l_m_i = vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001F513868710(11,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..90a745a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,48 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform m_block_std140_ubo {
+  f16vec4 inner_0;
+  f16vec4 inner_1;
+} m;
+
+int counter = 0;
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+f16mat2x4 load_m_inner() {
+  return f16mat2x4(m.inner_0, m.inner_1);
+}
+
+f16vec4 load_m_inner_p0(uint p0) {
+  switch(p0) {
+    case 0u: {
+      return m.inner_0;
+      break;
+    }
+    case 1u: {
+      return m.inner_1;
+      break;
+    }
+    default: {
+      return f16vec4(0.0hf);
+      break;
+    }
+  }
+}
+
+void f() {
+  f16mat2x4 p_m = load_m_inner();
+  int tint_symbol = i();
+  f16vec4 p_m_i = load_m_inner_p0(uint(tint_symbol));
+  f16mat2x4 l_m = load_m_inner();
+  f16vec4 l_m_i = load_m_inner_p0(uint(tint_symbol));
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..7ecbd42
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,17 @@
+#include <metal_stdlib>
+
+using namespace metal;
+int i() {
+  thread int tint_symbol_1 = 0;
+  tint_symbol_1 = as_type<int>((as_type<uint>(tint_symbol_1) + as_type<uint>(1)));
+  return tint_symbol_1;
+}
+
+kernel void f(const constant half2x4* tint_symbol_2 [[buffer(0)]]) {
+  int const tint_symbol = i();
+  int const p_m_i_save = tint_symbol;
+  half2x4 const l_m = *(tint_symbol_2);
+  half4 const l_m_i = (*(tint_symbol_2))[p_m_i_save];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..837fa42
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,93 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 54
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %m_block_std140 "m_block_std140"
+               OpMemberName %m_block_std140 0 "inner_0"
+               OpMemberName %m_block_std140 1 "inner_1"
+               OpName %m "m"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %load_m_inner "load_m_inner"
+               OpName %load_m_inner_p0 "load_m_inner_p0"
+               OpName %p0 "p0"
+               OpName %f "f"
+               OpDecorate %m_block_std140 Block
+               OpMemberDecorate %m_block_std140 0 Offset 0
+               OpMemberDecorate %m_block_std140 1 Offset 8
+               OpDecorate %m NonWritable
+               OpDecorate %m DescriptorSet 0
+               OpDecorate %m Binding 0
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+%m_block_std140 = OpTypeStruct %v4half %v4half
+%_ptr_Uniform_m_block_std140 = OpTypePointer Uniform %m_block_std140
+          %m = OpVariable %_ptr_Uniform_m_block_std140 Uniform
+        %int = OpTypeInt 32 1
+          %7 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %7
+         %10 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+ %mat2v4half = OpTypeMatrix %v4half 2
+         %17 = OpTypeFunction %mat2v4half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+     %uint_1 = OpConstant %uint 1
+         %33 = OpTypeFunction %v4half %uint
+         %45 = OpConstantNull %v4half
+       %void = OpTypeVoid
+         %46 = OpTypeFunction %void
+          %i = OpFunction %int None %10
+         %12 = OpLabel
+         %13 = OpLoad %int %counter
+         %15 = OpIAdd %int %13 %int_1
+               OpStore %counter %15
+         %16 = OpLoad %int %counter
+               OpReturnValue %16
+               OpFunctionEnd
+%load_m_inner = OpFunction %mat2v4half None %17
+         %20 = OpLabel
+         %26 = OpAccessChain %_ptr_Uniform_v4half %m %uint_0
+         %27 = OpLoad %v4half %26
+         %30 = OpAccessChain %_ptr_Uniform_v4half %m %uint_1
+         %31 = OpLoad %v4half %30
+         %32 = OpCompositeConstruct %mat2v4half %27 %31
+               OpReturnValue %32
+               OpFunctionEnd
+%load_m_inner_p0 = OpFunction %v4half None %33
+         %p0 = OpFunctionParameter %uint
+         %36 = OpLabel
+               OpSelectionMerge %37 None
+               OpSwitch %p0 %38 0 %39 1 %40
+         %39 = OpLabel
+         %41 = OpAccessChain %_ptr_Uniform_v4half %m %uint_0
+         %42 = OpLoad %v4half %41
+               OpReturnValue %42
+         %40 = OpLabel
+         %43 = OpAccessChain %_ptr_Uniform_v4half %m %uint_1
+         %44 = OpLoad %v4half %43
+               OpReturnValue %44
+         %38 = OpLabel
+               OpReturnValue %45
+         %37 = OpLabel
+               OpReturnValue %45
+               OpFunctionEnd
+          %f = OpFunction %void None %46
+         %49 = OpLabel
+         %50 = OpFunctionCall %int %i
+         %51 = OpFunctionCall %mat2v4half %load_m_inner
+         %53 = OpBitcast %uint %50
+         %52 = OpFunctionCall %v4half %load_m_inner_p0 %53
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..d23fb14
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> m : mat2x4<f16>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m = &(m);
+  let p_m_i = &((*(p_m))[i()]);
+  let l_m : mat2x4<f16> = *(p_m);
+  let l_m_i : vec4<f16> = *(p_m_i);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/static_index_via_ptr.wgsl
new file mode 100644
index 0000000..964fb95
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/static_index_via_ptr.wgsl
@@ -0,0 +1,15 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> m : mat2x4<f16>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m   = &m;
+  let p_m_1 = &((*p_m)[1]);
+
+  let l_m   : mat2x4<f16> = *p_m;
+  let l_m_1 : vec4<f16>   = *p_m_1;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..26c4533
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,33 @@
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[1];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 2, 4> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 2, 4> l_m = tint_symbol(m, 0u);
+  uint2 ubo_load_4 = m[0].zw;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const vector<float16_t, 4> l_m_1 = vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..fe05023
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,38 @@
+SKIP: FAILED
+
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[1];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 2, 4> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 2, 4> l_m = tint_symbol(m, 0u);
+  uint2 ubo_load_4 = m[0].zw;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const vector<float16_t, 4> l_m_1 = vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000002523DBC4780(11,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/static_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..2583326
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/static_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,24 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform m_block_std140_ubo {
+  f16vec4 inner_0;
+  f16vec4 inner_1;
+} m;
+
+f16mat2x4 load_m_inner() {
+  return f16mat2x4(m.inner_0, m.inner_1);
+}
+
+void f() {
+  f16mat2x4 p_m = load_m_inner();
+  f16vec4 p_m_1 = m.inner_1;
+  f16mat2x4 l_m = load_m_inner();
+  f16vec4 l_m_1 = m.inner_1;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/static_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..760d2d2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/static_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,15 @@
+#include <metal_stdlib>
+
+using namespace metal;
+int i() {
+  thread int tint_symbol = 0;
+  tint_symbol = as_type<int>((as_type<uint>(tint_symbol) + as_type<uint>(1)));
+  return tint_symbol;
+}
+
+kernel void f(const constant half2x4* tint_symbol_1 [[buffer(0)]]) {
+  half2x4 const l_m = *(tint_symbol_1);
+  half4 const l_m_1 = (*(tint_symbol_1))[1];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/static_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..435bc26
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/static_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,70 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 40
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %m_block_std140 "m_block_std140"
+               OpMemberName %m_block_std140 0 "inner_0"
+               OpMemberName %m_block_std140 1 "inner_1"
+               OpName %m "m"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %load_m_inner "load_m_inner"
+               OpName %f "f"
+               OpDecorate %m_block_std140 Block
+               OpMemberDecorate %m_block_std140 0 Offset 0
+               OpMemberDecorate %m_block_std140 1 Offset 8
+               OpDecorate %m NonWritable
+               OpDecorate %m DescriptorSet 0
+               OpDecorate %m Binding 0
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+%m_block_std140 = OpTypeStruct %v4half %v4half
+%_ptr_Uniform_m_block_std140 = OpTypePointer Uniform %m_block_std140
+          %m = OpVariable %_ptr_Uniform_m_block_std140 Uniform
+        %int = OpTypeInt 32 1
+          %7 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %7
+         %10 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+ %mat2v4half = OpTypeMatrix %v4half 2
+         %17 = OpTypeFunction %mat2v4half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+     %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %33 = OpTypeFunction %void
+          %i = OpFunction %int None %10
+         %12 = OpLabel
+         %13 = OpLoad %int %counter
+         %15 = OpIAdd %int %13 %int_1
+               OpStore %counter %15
+         %16 = OpLoad %int %counter
+               OpReturnValue %16
+               OpFunctionEnd
+%load_m_inner = OpFunction %mat2v4half None %17
+         %20 = OpLabel
+         %26 = OpAccessChain %_ptr_Uniform_v4half %m %uint_0
+         %27 = OpLoad %v4half %26
+         %30 = OpAccessChain %_ptr_Uniform_v4half %m %uint_1
+         %31 = OpLoad %v4half %30
+         %32 = OpCompositeConstruct %mat2v4half %27 %31
+               OpReturnValue %32
+               OpFunctionEnd
+          %f = OpFunction %void None %33
+         %36 = OpLabel
+         %37 = OpFunctionCall %mat2v4half %load_m_inner
+         %38 = OpAccessChain %_ptr_Uniform_v4half %m %uint_1
+         %39 = OpLoad %v4half %38
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/static_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..9bbe2cf
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/static_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> m : mat2x4<f16>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m = &(m);
+  let p_m_1 = &((*(p_m))[1]);
+  let l_m : mat2x4<f16> = *(p_m);
+  let l_m_1 : vec4<f16> = *(p_m_1);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_builtin.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_builtin.wgsl
new file mode 100644
index 0000000..2897573
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_builtin.wgsl
@@ -0,0 +1,10 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat2x4<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+    let t = transpose(u);
+    let l = length(u[1]);
+    let a = abs(u[0].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_builtin.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..8fc92b1
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_builtin.wgsl.expected.dxc.hlsl
@@ -0,0 +1,31 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+matrix<float16_t, 2, 4> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 4, 2> t = transpose(tint_symbol(u, 0u));
+  uint2 ubo_load_4 = u[0].zw;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const float16_t l = length(vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]));
+  uint2 ubo_load_5 = u[0].xy;
+  vector<float16_t, 2> ubo_load_5_xz = vector<float16_t, 2>(f16tof32(ubo_load_5 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_5_yw = vector<float16_t, 2>(f16tof32(ubo_load_5 >> 16));
+  const float16_t a = abs(vector<float16_t, 4>(ubo_load_5_xz[0], ubo_load_5_yw[0], ubo_load_5_xz[1], ubo_load_5_yw[1]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_builtin.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..db1a663
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_builtin.wgsl.expected.fxc.hlsl
@@ -0,0 +1,36 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+matrix<float16_t, 2, 4> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 4, 2> t = transpose(tint_symbol(u, 0u));
+  uint2 ubo_load_4 = u[0].zw;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const float16_t l = length(vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]));
+  uint2 ubo_load_5 = u[0].xy;
+  vector<float16_t, 2> ubo_load_5_xz = vector<float16_t, 2>(f16tof32(ubo_load_5 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_5_yw = vector<float16_t, 2>(f16tof32(ubo_load_5 >> 16));
+  const float16_t a = abs(vector<float16_t, 4>(ubo_load_5_xz[0], ubo_load_5_yw[0], ubo_load_5_xz[1], ubo_load_5_yw[1]).ywxz.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000020C30943680(5,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_builtin.wgsl.expected.glsl
new file mode 100644
index 0000000..d7f7cc7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_builtin.wgsl.expected.glsl
@@ -0,0 +1,23 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec4 inner_0;
+  f16vec4 inner_1;
+} u;
+
+f16mat2x4 load_u_inner() {
+  return f16mat2x4(u.inner_0, u.inner_1);
+}
+
+void f() {
+  f16mat4x2 t = transpose(load_u_inner());
+  float16_t l = length(u.inner_1);
+  float16_t a = abs(u.inner_0.ywxz[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_builtin.wgsl.expected.msl
new file mode 100644
index 0000000..ab20cc5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_builtin.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f(const constant half2x4* tint_symbol [[buffer(0)]]) {
+  half4x2 const t = transpose(*(tint_symbol));
+  half const l = length((*(tint_symbol))[1]);
+  half const a = fabs(half4((*(tint_symbol))[0]).ywxz[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_builtin.wgsl.expected.spvasm
new file mode 100644
index 0000000..3947aef
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_builtin.wgsl.expected.spvasm
@@ -0,0 +1,65 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 40
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+         %31 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpName %u "u"
+               OpName %load_u_inner "load_u_inner"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 8
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+%u_block_std140 = OpTypeStruct %v4half %v4half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat2v4half = OpTypeMatrix %v4half 2
+          %6 = OpTypeFunction %mat2v4half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+     %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %22 = OpTypeFunction %void
+     %v2half = OpTypeVector %half 2
+ %mat4v2half = OpTypeMatrix %v2half 4
+         %38 = OpConstantNull %uint
+%load_u_inner = OpFunction %mat2v4half None %6
+          %9 = OpLabel
+         %15 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0
+         %16 = OpLoad %v4half %15
+         %19 = OpAccessChain %_ptr_Uniform_v4half %u %uint_1
+         %20 = OpLoad %v4half %19
+         %21 = OpCompositeConstruct %mat2v4half %16 %20
+               OpReturnValue %21
+               OpFunctionEnd
+          %f = OpFunction %void None %22
+         %25 = OpLabel
+         %29 = OpFunctionCall %mat2v4half %load_u_inner
+         %26 = OpTranspose %mat4v2half %29
+         %32 = OpAccessChain %_ptr_Uniform_v4half %u %uint_1
+         %33 = OpLoad %v4half %32
+         %30 = OpExtInst %half %31 Length %33
+         %35 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0
+         %36 = OpLoad %v4half %35
+         %37 = OpVectorShuffle %v4half %36 %36 1 3 0 2
+         %39 = OpCompositeExtract %half %37 0
+         %34 = OpExtInst %half %31 FAbs %39
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_builtin.wgsl.expected.wgsl
new file mode 100644
index 0000000..04c4e6d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_builtin.wgsl.expected.wgsl
@@ -0,0 +1,10 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat2x4<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let t = transpose(u);
+  let l = length(u[1]);
+  let a = abs(u[0].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_fn.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_fn.wgsl
new file mode 100644
index 0000000..159b73a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_fn.wgsl
@@ -0,0 +1,16 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat2x4<f16>;
+
+fn a(m : mat2x4<f16>) {}
+fn b(v : vec4<f16>) {}
+fn c(f : f16) {}
+
+@compute @workgroup_size(1)
+fn f() {
+    a(u);
+    b(u[1]);
+    b(u[1].ywxz);
+    c(u[1].x);
+    c(u[1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_fn.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..82bbdcc
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_fn.wgsl.expected.dxc.hlsl
@@ -0,0 +1,45 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+void a(matrix<float16_t, 2, 4> m) {
+}
+
+void b(vector<float16_t, 4> v) {
+}
+
+void c(float16_t f_1) {
+}
+
+matrix<float16_t, 2, 4> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  uint2 ubo_load_4 = u[0].zw;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  b(vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]));
+  uint2 ubo_load_5 = u[0].zw;
+  vector<float16_t, 2> ubo_load_5_xz = vector<float16_t, 2>(f16tof32(ubo_load_5 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_5_yw = vector<float16_t, 2>(f16tof32(ubo_load_5 >> 16));
+  b(vector<float16_t, 4>(ubo_load_5_xz[0], ubo_load_5_yw[0], ubo_load_5_xz[1], ubo_load_5_yw[1]).ywxz);
+  c(float16_t(f16tof32(((u[0].z) & 0xFFFF))));
+  uint2 ubo_load_6 = u[0].zw;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  c(vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_fn.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..7305b4e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_fn.wgsl.expected.fxc.hlsl
@@ -0,0 +1,52 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+void a(matrix<float16_t, 2, 4> m) {
+}
+
+void b(vector<float16_t, 4> v) {
+}
+
+void c(float16_t f_1) {
+}
+
+matrix<float16_t, 2, 4> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  uint2 ubo_load_4 = u[0].zw;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  b(vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]));
+  uint2 ubo_load_5 = u[0].zw;
+  vector<float16_t, 2> ubo_load_5_xz = vector<float16_t, 2>(f16tof32(ubo_load_5 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_5_yw = vector<float16_t, 2>(f16tof32(ubo_load_5 >> 16));
+  b(vector<float16_t, 4>(ubo_load_5_xz[0], ubo_load_5_yw[0], ubo_load_5_xz[1], ubo_load_5_yw[1]).ywxz);
+  c(float16_t(f16tof32(((u[0].z) & 0xFFFF))));
+  uint2 ubo_load_6 = u[0].zw;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  c(vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]).ywxz.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x00000273F7AEC5E0(5,15-23): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x00000273F7AEC5E0(8,15-23): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x00000273F7AEC5E0(11,8-16): error X3000: unrecognized identifier 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_fn.wgsl.expected.glsl
new file mode 100644
index 0000000..89087d3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_fn.wgsl.expected.glsl
@@ -0,0 +1,34 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec4 inner_0;
+  f16vec4 inner_1;
+} u;
+
+void a(f16mat2x4 m) {
+}
+
+void b(f16vec4 v) {
+}
+
+void c(float16_t f_1) {
+}
+
+f16mat2x4 load_u_inner() {
+  return f16mat2x4(u.inner_0, u.inner_1);
+}
+
+void f() {
+  a(load_u_inner());
+  b(u.inner_1);
+  b(u.inner_1.ywxz);
+  c(u.inner_1[0u]);
+  c(u.inner_1.ywxz[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_fn.wgsl.expected.msl
new file mode 100644
index 0000000..e58cdf3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_fn.wgsl.expected.msl
@@ -0,0 +1,21 @@
+#include <metal_stdlib>
+
+using namespace metal;
+void a(half2x4 m) {
+}
+
+void b(half4 v) {
+}
+
+void c(half f_1) {
+}
+
+kernel void f(const constant half2x4* tint_symbol [[buffer(0)]]) {
+  a(*(tint_symbol));
+  b((*(tint_symbol))[1]);
+  b(half4((*(tint_symbol))[1]).ywxz);
+  c((*(tint_symbol))[1][0]);
+  c(half4((*(tint_symbol))[1]).ywxz[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_fn.wgsl.expected.spvasm
new file mode 100644
index 0000000..d125966
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_fn.wgsl.expected.spvasm
@@ -0,0 +1,94 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 57
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpName %u "u"
+               OpName %a "a"
+               OpName %m "m"
+               OpName %b "b"
+               OpName %v "v"
+               OpName %c "c"
+               OpName %f_1 "f_1"
+               OpName %load_u_inner "load_u_inner"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 8
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+%u_block_std140 = OpTypeStruct %v4half %v4half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+       %void = OpTypeVoid
+ %mat2v4half = OpTypeMatrix %v4half 2
+          %6 = OpTypeFunction %void %mat2v4half
+         %12 = OpTypeFunction %void %v4half
+         %16 = OpTypeFunction %void %half
+         %20 = OpTypeFunction %mat2v4half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+     %uint_1 = OpConstant %uint 1
+         %35 = OpTypeFunction %void
+         %48 = OpConstantNull %uint
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+          %a = OpFunction %void None %6
+          %m = OpFunctionParameter %mat2v4half
+         %11 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %b = OpFunction %void None %12
+          %v = OpFunctionParameter %v4half
+         %15 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %c = OpFunction %void None %16
+        %f_1 = OpFunctionParameter %half
+         %19 = OpLabel
+               OpReturn
+               OpFunctionEnd
+%load_u_inner = OpFunction %mat2v4half None %20
+         %22 = OpLabel
+         %28 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0
+         %29 = OpLoad %v4half %28
+         %32 = OpAccessChain %_ptr_Uniform_v4half %u %uint_1
+         %33 = OpLoad %v4half %32
+         %34 = OpCompositeConstruct %mat2v4half %29 %33
+               OpReturnValue %34
+               OpFunctionEnd
+          %f = OpFunction %void None %35
+         %37 = OpLabel
+         %39 = OpFunctionCall %mat2v4half %load_u_inner
+         %38 = OpFunctionCall %void %a %39
+         %41 = OpAccessChain %_ptr_Uniform_v4half %u %uint_1
+         %42 = OpLoad %v4half %41
+         %40 = OpFunctionCall %void %b %42
+         %44 = OpAccessChain %_ptr_Uniform_v4half %u %uint_1
+         %45 = OpLoad %v4half %44
+         %46 = OpVectorShuffle %v4half %45 %45 1 3 0 2
+         %43 = OpFunctionCall %void %b %46
+         %50 = OpAccessChain %_ptr_Uniform_half %u %uint_1 %48
+         %51 = OpLoad %half %50
+         %47 = OpFunctionCall %void %c %51
+         %53 = OpAccessChain %_ptr_Uniform_v4half %u %uint_1
+         %54 = OpLoad %v4half %53
+         %55 = OpVectorShuffle %v4half %54 %54 1 3 0 2
+         %56 = OpCompositeExtract %half %55 0
+         %52 = OpFunctionCall %void %c %56
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_fn.wgsl.expected.wgsl
new file mode 100644
index 0000000..a57941a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_fn.wgsl.expected.wgsl
@@ -0,0 +1,21 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat2x4<f16>;
+
+fn a(m : mat2x4<f16>) {
+}
+
+fn b(v : vec4<f16>) {
+}
+
+fn c(f : f16) {
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  a(u);
+  b(u[1]);
+  b(u[1].ywxz);
+  c(u[1].x);
+  c(u[1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_private.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_private.wgsl
new file mode 100644
index 0000000..ebc8498
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_private.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat2x4<f16>;
+var<private> p : mat2x4<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[0];
+    p[1] = u[0].ywxz;
+    p[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_private.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..9781a40
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_private.wgsl.expected.dxc.hlsl
@@ -0,0 +1,33 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+static matrix<float16_t, 2, 4> p = matrix<float16_t, 2, 4>(float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h));
+
+matrix<float16_t, 2, 4> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  uint2 ubo_load_4 = u[0].xy;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  p[1] = vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]);
+  uint2 ubo_load_5 = u[0].xy;
+  vector<float16_t, 2> ubo_load_5_xz = vector<float16_t, 2>(f16tof32(ubo_load_5 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_5_yw = vector<float16_t, 2>(f16tof32(ubo_load_5 >> 16));
+  p[1] = vector<float16_t, 4>(ubo_load_5_xz[0], ubo_load_5_yw[0], ubo_load_5_xz[1], ubo_load_5_yw[1]).ywxz;
+  p[0][1] = float16_t(f16tof32(((u[0].z) & 0xFFFF)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_private.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..94095cb
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_private.wgsl.expected.fxc.hlsl
@@ -0,0 +1,38 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+static matrix<float16_t, 2, 4> p = matrix<float16_t, 2, 4>(float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h));
+
+matrix<float16_t, 2, 4> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  uint2 ubo_load_4 = u[0].xy;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  p[1] = vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]);
+  uint2 ubo_load_5 = u[0].xy;
+  vector<float16_t, 2> ubo_load_5_xz = vector<float16_t, 2>(f16tof32(ubo_load_5 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_5_yw = vector<float16_t, 2>(f16tof32(ubo_load_5 >> 16));
+  p[1] = vector<float16_t, 4>(ubo_load_5_xz[0], ubo_load_5_yw[0], ubo_load_5_xz[1], ubo_load_5_yw[1]).ywxz;
+  p[0][1] = float16_t(f16tof32(((u[0].z) & 0xFFFF)));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000014E53D58AD0(4,15-23): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..19af901
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_private.wgsl.expected.glsl
@@ -0,0 +1,25 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec4 inner_0;
+  f16vec4 inner_1;
+} u;
+
+f16mat2x4 p = f16mat2x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf);
+f16mat2x4 load_u_inner() {
+  return f16mat2x4(u.inner_0, u.inner_1);
+}
+
+void f() {
+  p = load_u_inner();
+  p[1] = u.inner_0;
+  p[1] = u.inner_0.ywxz;
+  p[0][1] = u.inner_1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..5042d02
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_private.wgsl.expected.msl
@@ -0,0 +1,12 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f(const constant half2x4* tint_symbol_1 [[buffer(0)]]) {
+  thread half2x4 tint_symbol = half2x4(0.0h);
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[0];
+  tint_symbol[1] = half4((*(tint_symbol_1))[0]).ywxz;
+  tint_symbol[0][1] = (*(tint_symbol_1))[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_private.wgsl.expected.spvasm
new file mode 100644
index 0000000..910985b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_private.wgsl.expected.spvasm
@@ -0,0 +1,77 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 47
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpName %u "u"
+               OpName %p "p"
+               OpName %load_u_inner "load_u_inner"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 8
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+%u_block_std140 = OpTypeStruct %v4half %v4half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat2v4half = OpTypeMatrix %v4half 2
+%_ptr_Private_mat2v4half = OpTypePointer Private %mat2v4half
+          %9 = OpConstantNull %mat2v4half
+          %p = OpVariable %_ptr_Private_mat2v4half Private %9
+         %10 = OpTypeFunction %mat2v4half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+     %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %25 = OpTypeFunction %void
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Private_v4half = OpTypePointer Private %v4half
+         %40 = OpConstantNull %int
+%_ptr_Private_half = OpTypePointer Private %half
+         %43 = OpConstantNull %uint
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+%load_u_inner = OpFunction %mat2v4half None %10
+         %12 = OpLabel
+         %18 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0
+         %19 = OpLoad %v4half %18
+         %22 = OpAccessChain %_ptr_Uniform_v4half %u %uint_1
+         %23 = OpLoad %v4half %22
+         %24 = OpCompositeConstruct %mat2v4half %19 %23
+               OpReturnValue %24
+               OpFunctionEnd
+          %f = OpFunction %void None %25
+         %28 = OpLabel
+         %29 = OpFunctionCall %mat2v4half %load_u_inner
+               OpStore %p %29
+         %33 = OpAccessChain %_ptr_Private_v4half %p %int_1
+         %34 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0
+         %35 = OpLoad %v4half %34
+               OpStore %33 %35
+         %36 = OpAccessChain %_ptr_Private_v4half %p %int_1
+         %37 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0
+         %38 = OpLoad %v4half %37
+         %39 = OpVectorShuffle %v4half %38 %38 1 3 0 2
+               OpStore %36 %39
+         %42 = OpAccessChain %_ptr_Private_half %p %40 %int_1
+         %45 = OpAccessChain %_ptr_Uniform_half %u %uint_1 %43
+         %46 = OpLoad %half %45
+               OpStore %42 %46
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..105af55
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_private.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat2x4<f16>;
+
+var<private> p : mat2x4<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[0];
+  p[1] = u[0].ywxz;
+  p[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_storage.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_storage.wgsl
new file mode 100644
index 0000000..0a74180
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_storage.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat2x4<f16>;
+@group(0) @binding(1) var<storage, read_write> s : mat2x4<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[0];
+    s[1] = u[0].ywxz;
+    s[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_storage.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..bd96423
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_storage.wgsl.expected.dxc.hlsl
@@ -0,0 +1,38 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 2, 4> value) {
+  buffer.Store<vector<float16_t, 4> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 8u), value[1u]);
+}
+
+matrix<float16_t, 2, 4> tint_symbol_2(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_2(u, 0u));
+  uint2 ubo_load_4 = u[0].xy;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  s.Store<vector<float16_t, 4> >(8u, vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]));
+  uint2 ubo_load_5 = u[0].xy;
+  vector<float16_t, 2> ubo_load_5_xz = vector<float16_t, 2>(f16tof32(ubo_load_5 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_5_yw = vector<float16_t, 2>(f16tof32(ubo_load_5 >> 16));
+  s.Store<vector<float16_t, 4> >(8u, vector<float16_t, 4>(ubo_load_5_xz[0], ubo_load_5_yw[0], ubo_load_5_xz[1], ubo_load_5_yw[1]).ywxz);
+  s.Store<float16_t>(2u, float16_t(f16tof32(((u[0].z) & 0xFFFF))));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_storage.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..8723863
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_storage.wgsl.expected.fxc.hlsl
@@ -0,0 +1,44 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 2, 4> value) {
+  buffer.Store<vector<float16_t, 4> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 8u), value[1u]);
+}
+
+matrix<float16_t, 2, 4> tint_symbol_2(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_2(u, 0u));
+  uint2 ubo_load_4 = u[0].xy;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  s.Store<vector<float16_t, 4> >(8u, vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]));
+  uint2 ubo_load_5 = u[0].xy;
+  vector<float16_t, 2> ubo_load_5_xz = vector<float16_t, 2>(f16tof32(ubo_load_5 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_5_yw = vector<float16_t, 2>(f16tof32(ubo_load_5 >> 16));
+  s.Store<vector<float16_t, 4> >(8u, vector<float16_t, 4>(ubo_load_5_xz[0], ubo_load_5_yw[0], ubo_load_5_xz[1], ubo_load_5_yw[1]).ywxz);
+  s.Store<float16_t>(2u, float16_t(f16tof32(((u[0].z) & 0xFFFF))));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000015E10277FD0(6,66-74): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000015E10277FD0(7,3-14): error X3018: invalid subscript 'Store'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..00bc62e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_storage.wgsl.expected.glsl
@@ -0,0 +1,28 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec4 inner_0;
+  f16vec4 inner_1;
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  f16mat2x4 inner;
+} s;
+
+f16mat2x4 load_u_inner() {
+  return f16mat2x4(u.inner_0, u.inner_1);
+}
+
+void f() {
+  s.inner = load_u_inner();
+  s.inner[1] = u.inner_0;
+  s.inner[1] = u.inner_0.ywxz;
+  s.inner[0][1] = u.inner_1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..44e2bbb
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_storage.wgsl.expected.msl
@@ -0,0 +1,11 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f(device half2x4* tint_symbol [[buffer(1)]], const constant half2x4* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[0];
+  (*(tint_symbol))[1] = half4((*(tint_symbol_1))[0]).ywxz;
+  (*(tint_symbol))[0][1] = (*(tint_symbol_1))[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_storage.wgsl.expected.spvasm
new file mode 100644
index 0000000..0350c58
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_storage.wgsl.expected.spvasm
@@ -0,0 +1,87 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 49
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpName %u "u"
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %s "s"
+               OpName %load_u_inner "load_u_inner"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 8
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 8
+               OpDecorate %s DescriptorSet 0
+               OpDecorate %s Binding 1
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+%u_block_std140 = OpTypeStruct %v4half %v4half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat2v4half = OpTypeMatrix %v4half 2
+    %u_block = OpTypeStruct %mat2v4half
+%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
+          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+         %10 = OpTypeFunction %mat2v4half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+     %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %25 = OpTypeFunction %void
+%_ptr_StorageBuffer_mat2v4half = OpTypePointer StorageBuffer %mat2v4half
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_v4half = OpTypePointer StorageBuffer %v4half
+         %42 = OpConstantNull %int
+%_ptr_StorageBuffer_half = OpTypePointer StorageBuffer %half
+         %45 = OpConstantNull %uint
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+%load_u_inner = OpFunction %mat2v4half None %10
+         %12 = OpLabel
+         %18 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0
+         %19 = OpLoad %v4half %18
+         %22 = OpAccessChain %_ptr_Uniform_v4half %u %uint_1
+         %23 = OpLoad %v4half %22
+         %24 = OpCompositeConstruct %mat2v4half %19 %23
+               OpReturnValue %24
+               OpFunctionEnd
+          %f = OpFunction %void None %25
+         %28 = OpLabel
+         %30 = OpAccessChain %_ptr_StorageBuffer_mat2v4half %s %uint_0
+         %31 = OpFunctionCall %mat2v4half %load_u_inner
+               OpStore %30 %31
+         %35 = OpAccessChain %_ptr_StorageBuffer_v4half %s %uint_0 %int_1
+         %36 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0
+         %37 = OpLoad %v4half %36
+               OpStore %35 %37
+         %38 = OpAccessChain %_ptr_StorageBuffer_v4half %s %uint_0 %int_1
+         %39 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0
+         %40 = OpLoad %v4half %39
+         %41 = OpVectorShuffle %v4half %40 %40 1 3 0 2
+               OpStore %38 %41
+         %44 = OpAccessChain %_ptr_StorageBuffer_half %s %uint_0 %42 %int_1
+         %47 = OpAccessChain %_ptr_Uniform_half %u %uint_1 %45
+         %48 = OpLoad %half %47
+               OpStore %44 %48
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..261f1c3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat2x4<f16>;
+
+@group(0) @binding(1) var<storage, read_write> s : mat2x4<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[0];
+  s[1] = u[0].ywxz;
+  s[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_workgroup.wgsl
new file mode 100644
index 0000000..b74dcd9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_workgroup.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat2x4<f16>;
+var<workgroup> w : mat2x4<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[0];
+    w[1] = u[0].ywxz;
+    w[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_workgroup.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..dc8da4d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_workgroup.wgsl.expected.dxc.hlsl
@@ -0,0 +1,45 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+groupshared matrix<float16_t, 2, 4> w;
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 2, 4> tint_symbol_2(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    w = matrix<float16_t, 2, 4>((float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx);
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  uint2 ubo_load_4 = u[0].xy;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  w[1] = vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]);
+  uint2 ubo_load_5 = u[0].xy;
+  vector<float16_t, 2> ubo_load_5_xz = vector<float16_t, 2>(f16tof32(ubo_load_5 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_5_yw = vector<float16_t, 2>(f16tof32(ubo_load_5 >> 16));
+  w[1] = vector<float16_t, 4>(ubo_load_5_xz[0], ubo_load_5_yw[0], ubo_load_5_xz[1], ubo_load_5_yw[1]).ywxz;
+  w[0][1] = float16_t(f16tof32(((u[0].z) & 0xFFFF)));
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_workgroup.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..b2c263b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_workgroup.wgsl.expected.fxc.hlsl
@@ -0,0 +1,50 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+groupshared matrix<float16_t, 2, 4> w;
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 2, 4> tint_symbol_2(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    w = matrix<float16_t, 2, 4>((float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx);
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  uint2 ubo_load_4 = u[0].xy;
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  w[1] = vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]);
+  uint2 ubo_load_5 = u[0].xy;
+  vector<float16_t, 2> ubo_load_5_xz = vector<float16_t, 2>(f16tof32(ubo_load_5 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_5_yw = vector<float16_t, 2>(f16tof32(ubo_load_5 >> 16));
+  w[1] = vector<float16_t, 4>(ubo_load_5_xz[0], ubo_load_5_yw[0], ubo_load_5_xz[1], ubo_load_5_yw[1]).ywxz;
+  w[0][1] = float16_t(f16tof32(((u[0].z) & 0xFFFF)));
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000018E62EDA940(4,20-28): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..03193cd
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,29 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec4 inner_0;
+  f16vec4 inner_1;
+} u;
+
+shared f16mat2x4 w;
+f16mat2x4 load_u_inner() {
+  return f16mat2x4(u.inner_0, u.inner_1);
+}
+
+void f(uint local_invocation_index) {
+  {
+    w = f16mat2x4(f16vec4(0.0hf), f16vec4(0.0hf));
+  }
+  barrier();
+  w = load_u_inner();
+  w[1] = u.inner_0;
+  w[1] = u.inner_0.ywxz;
+  w[0][1] = u.inner_1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..879dc14
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,24 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct tint_symbol_5 {
+  half2x4 w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup half2x4* const tint_symbol, const constant half2x4* const tint_symbol_1) {
+  {
+    *(tint_symbol) = half2x4(half4(0.0h), half4(0.0h));
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[0];
+  (*(tint_symbol))[1] = half4((*(tint_symbol_1))[0]).ywxz;
+  (*(tint_symbol))[0][1] = (*(tint_symbol_1))[1][0];
+}
+
+kernel void f(const constant half2x4* tint_symbol_4 [[buffer(0)]], threadgroup tint_symbol_5* tint_symbol_3 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup half2x4* const tint_symbol_2 = &((*(tint_symbol_3)).w);
+  f_inner(local_invocation_index, tint_symbol_2, tint_symbol_4);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_workgroup.wgsl.expected.spvasm
new file mode 100644
index 0000000..007777b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_workgroup.wgsl.expected.spvasm
@@ -0,0 +1,95 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 58
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %local_invocation_index_1 "local_invocation_index_1"
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpName %u "u"
+               OpName %w "w"
+               OpName %load_u_inner "load_u_inner"
+               OpName %f_inner "f_inner"
+               OpName %local_invocation_index "local_invocation_index"
+               OpName %f "f"
+               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 8
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+%u_block_std140 = OpTypeStruct %v4half %v4half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat2v4half = OpTypeMatrix %v4half 2
+%_ptr_Workgroup_mat2v4half = OpTypePointer Workgroup %mat2v4half
+          %w = OpVariable %_ptr_Workgroup_mat2v4half Workgroup
+         %12 = OpTypeFunction %mat2v4half
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+     %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %26 = OpTypeFunction %void %uint
+         %31 = OpConstantNull %mat2v4half
+     %uint_2 = OpConstant %uint 2
+   %uint_264 = OpConstant %uint 264
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Workgroup_v4half = OpTypePointer Workgroup %v4half
+         %46 = OpConstantNull %int
+%_ptr_Workgroup_half = OpTypePointer Workgroup %half
+         %49 = OpConstantNull %uint
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+         %53 = OpTypeFunction %void
+%load_u_inner = OpFunction %mat2v4half None %12
+         %14 = OpLabel
+         %19 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0
+         %20 = OpLoad %v4half %19
+         %23 = OpAccessChain %_ptr_Uniform_v4half %u %uint_1
+         %24 = OpLoad %v4half %23
+         %25 = OpCompositeConstruct %mat2v4half %20 %24
+               OpReturnValue %25
+               OpFunctionEnd
+    %f_inner = OpFunction %void None %26
+%local_invocation_index = OpFunctionParameter %uint
+         %30 = OpLabel
+               OpStore %w %31
+               OpControlBarrier %uint_2 %uint_2 %uint_264
+         %35 = OpFunctionCall %mat2v4half %load_u_inner
+               OpStore %w %35
+         %39 = OpAccessChain %_ptr_Workgroup_v4half %w %int_1
+         %40 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0
+         %41 = OpLoad %v4half %40
+               OpStore %39 %41
+         %42 = OpAccessChain %_ptr_Workgroup_v4half %w %int_1
+         %43 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0
+         %44 = OpLoad %v4half %43
+         %45 = OpVectorShuffle %v4half %44 %44 1 3 0 2
+               OpStore %42 %45
+         %48 = OpAccessChain %_ptr_Workgroup_half %w %46 %int_1
+         %51 = OpAccessChain %_ptr_Uniform_half %u %uint_1 %49
+         %52 = OpLoad %half %51
+               OpStore %48 %52
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %53
+         %55 = OpLabel
+         %57 = OpLoad %uint %local_invocation_index_1
+         %56 = OpFunctionCall %void %f_inner %57
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..1ba1243
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f16/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat2x4<f16>;
+
+var<workgroup> w : mat2x4<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[0];
+  w[1] = u[0].ywxz;
+  w[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/dynamic_index_via_ptr.wgsl
new file mode 100644
index 0000000..cae6dfd
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/dynamic_index_via_ptr.wgsl
@@ -0,0 +1,13 @@
+@group(0) @binding(0) var<uniform> m : mat2x4<f32>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m   = &m;
+  let p_m_i = &((*p_m)[i()]);
+
+  let l_m   : mat2x4<f32> = *p_m;
+  let l_m_i : vec4<f32>   = *p_m_i;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..c31f9b9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,24 @@
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[2];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float2x4 tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_m_i_save = i();
+  const float2x4 l_m = tint_symbol(m, 0u);
+  const uint scalar_offset_2 = ((16u * uint(p_m_i_save))) / 4;
+  const float4 l_m_i = asfloat(m[scalar_offset_2 / 4]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..c31f9b9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,24 @@
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[2];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float2x4 tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_m_i_save = i();
+  const float2x4 l_m = tint_symbol(m, 0u);
+  const uint scalar_offset_2 = ((16u * uint(p_m_i_save))) / 4;
+  const float4 l_m_i = asfloat(m[scalar_offset_2 / 4]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..f993ff6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,24 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform m_block_ubo {
+  mat2x4 inner;
+} m;
+
+int counter = 0;
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+void f() {
+  int tint_symbol = i();
+  int p_m_i_save = tint_symbol;
+  mat2x4 l_m = m.inner;
+  vec4 l_m_i = m.inner[p_m_i_save];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..5c7026b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,17 @@
+#include <metal_stdlib>
+
+using namespace metal;
+int i() {
+  thread int tint_symbol_1 = 0;
+  tint_symbol_1 = as_type<int>((as_type<uint>(tint_symbol_1) + as_type<uint>(1)));
+  return tint_symbol_1;
+}
+
+kernel void f(const constant float2x4* tint_symbol_2 [[buffer(0)]]) {
+  int const tint_symbol = i();
+  int const p_m_i_save = tint_symbol;
+  float2x4 const l_m = *(tint_symbol_2);
+  float4 const l_m_i = (*(tint_symbol_2))[p_m_i_save];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..bce9daa
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,57 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 31
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %m_block "m_block"
+               OpMemberName %m_block 0 "inner"
+               OpName %m "m"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %f "f"
+               OpDecorate %m_block Block
+               OpMemberDecorate %m_block 0 Offset 0
+               OpMemberDecorate %m_block 0 ColMajor
+               OpMemberDecorate %m_block 0 MatrixStride 16
+               OpDecorate %m NonWritable
+               OpDecorate %m DescriptorSet 0
+               OpDecorate %m Binding 0
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat2v4float = OpTypeMatrix %v4float 2
+    %m_block = OpTypeStruct %mat2v4float
+%_ptr_Uniform_m_block = OpTypePointer Uniform %m_block
+          %m = OpVariable %_ptr_Uniform_m_block Uniform
+        %int = OpTypeInt 32 1
+          %8 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %8
+         %11 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+       %void = OpTypeVoid
+         %18 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_mat2v4float = OpTypePointer Uniform %mat2v4float
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+          %i = OpFunction %int None %11
+         %13 = OpLabel
+         %14 = OpLoad %int %counter
+         %16 = OpIAdd %int %14 %int_1
+               OpStore %counter %16
+         %17 = OpLoad %int %counter
+               OpReturnValue %17
+               OpFunctionEnd
+          %f = OpFunction %void None %18
+         %21 = OpLabel
+         %22 = OpFunctionCall %int %i
+         %26 = OpAccessChain %_ptr_Uniform_mat2v4float %m %uint_0
+         %27 = OpLoad %mat2v4float %26
+         %29 = OpAccessChain %_ptr_Uniform_v4float %m %uint_0 %22
+         %30 = OpLoad %v4float %29
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..fa24961
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,16 @@
+@group(0) @binding(0) var<uniform> m : mat2x4<f32>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m = &(m);
+  let p_m_i = &((*(p_m))[i()]);
+  let l_m : mat2x4<f32> = *(p_m);
+  let l_m_i : vec4<f32> = *(p_m_i);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/static_index_via_ptr.wgsl
new file mode 100644
index 0000000..8f94035
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/static_index_via_ptr.wgsl
@@ -0,0 +1,13 @@
+@group(0) @binding(0) var<uniform> m : mat2x4<f32>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m   = &m;
+  let p_m_1 = &((*p_m)[1]);
+
+  let l_m   : mat2x4<f32> = *p_m;
+  let l_m_1 : vec4<f32>   = *p_m_1;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..5f5a358
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,22 @@
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[2];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float2x4 tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float2x4 l_m = tint_symbol(m, 0u);
+  const float4 l_m_1 = asfloat(m[1]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..5f5a358
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,22 @@
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[2];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float2x4 tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float2x4 l_m = tint_symbol(m, 0u);
+  const float4 l_m_1 = asfloat(m[1]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/static_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..3c1a06f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/static_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,16 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform m_block_ubo {
+  mat2x4 inner;
+} m;
+
+void f() {
+  mat2x4 l_m = m.inner;
+  vec4 l_m_1 = m.inner[1];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/static_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..51566cb
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/static_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,15 @@
+#include <metal_stdlib>
+
+using namespace metal;
+int i() {
+  thread int tint_symbol = 0;
+  tint_symbol = as_type<int>((as_type<uint>(tint_symbol) + as_type<uint>(1)));
+  return tint_symbol;
+}
+
+kernel void f(const constant float2x4* tint_symbol_1 [[buffer(0)]]) {
+  float2x4 const l_m = *(tint_symbol_1);
+  float4 const l_m_1 = (*(tint_symbol_1))[1];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/static_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..5405654
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/static_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,56 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 30
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %m_block "m_block"
+               OpMemberName %m_block 0 "inner"
+               OpName %m "m"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %f "f"
+               OpDecorate %m_block Block
+               OpMemberDecorate %m_block 0 Offset 0
+               OpMemberDecorate %m_block 0 ColMajor
+               OpMemberDecorate %m_block 0 MatrixStride 16
+               OpDecorate %m NonWritable
+               OpDecorate %m DescriptorSet 0
+               OpDecorate %m Binding 0
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat2v4float = OpTypeMatrix %v4float 2
+    %m_block = OpTypeStruct %mat2v4float
+%_ptr_Uniform_m_block = OpTypePointer Uniform %m_block
+          %m = OpVariable %_ptr_Uniform_m_block Uniform
+        %int = OpTypeInt 32 1
+          %8 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %8
+         %11 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+       %void = OpTypeVoid
+         %18 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_mat2v4float = OpTypePointer Uniform %mat2v4float
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+          %i = OpFunction %int None %11
+         %13 = OpLabel
+         %14 = OpLoad %int %counter
+         %16 = OpIAdd %int %14 %int_1
+               OpStore %counter %16
+         %17 = OpLoad %int %counter
+               OpReturnValue %17
+               OpFunctionEnd
+          %f = OpFunction %void None %18
+         %21 = OpLabel
+         %25 = OpAccessChain %_ptr_Uniform_mat2v4float %m %uint_0
+         %26 = OpLoad %mat2v4float %25
+         %28 = OpAccessChain %_ptr_Uniform_v4float %m %uint_0 %int_1
+         %29 = OpLoad %v4float %28
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/static_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..5129b61
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/static_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,16 @@
+@group(0) @binding(0) var<uniform> m : mat2x4<f32>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m = &(m);
+  let p_m_1 = &((*(p_m))[1]);
+  let l_m : mat2x4<f32> = *(p_m);
+  let l_m_1 : vec4<f32> = *(p_m_1);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_builtin.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_builtin.wgsl
new file mode 100644
index 0000000..81d1c25
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_builtin.wgsl
@@ -0,0 +1,8 @@
+@group(0) @binding(0) var<uniform> u : mat2x4<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+    let t = transpose(u);
+    let l = length(u[1]);
+    let a = abs(u[0].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_builtin.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..77df7cf
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_builtin.wgsl.expected.dxc.hlsl
@@ -0,0 +1,17 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+
+float2x4 tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float4x2 t = transpose(tint_symbol(u, 0u));
+  const float l = length(asfloat(u[1]));
+  const float a = abs(asfloat(u[0]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_builtin.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..77df7cf
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_builtin.wgsl.expected.fxc.hlsl
@@ -0,0 +1,17 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+
+float2x4 tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float4x2 t = transpose(tint_symbol(u, 0u));
+  const float l = length(asfloat(u[1]));
+  const float a = abs(asfloat(u[0]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_builtin.wgsl.expected.glsl
new file mode 100644
index 0000000..6d9a4df
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_builtin.wgsl.expected.glsl
@@ -0,0 +1,17 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat2x4 inner;
+} u;
+
+void f() {
+  mat4x2 t = transpose(u.inner);
+  float l = length(u.inner[1]);
+  float a = abs(u.inner[0].ywxz.x);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_builtin.wgsl.expected.msl
new file mode 100644
index 0000000..e4ca0da
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_builtin.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f(const constant float2x4* tint_symbol [[buffer(0)]]) {
+  float4x2 const t = transpose(*(tint_symbol));
+  float const l = length((*(tint_symbol))[1]);
+  float const a = fabs(float4((*(tint_symbol))[0]).ywxz[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_builtin.wgsl.expected.spvasm
new file mode 100644
index 0000000..f1231b5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_builtin.wgsl.expected.spvasm
@@ -0,0 +1,53 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 32
+; Schema: 0
+               OpCapability Shader
+         %20 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat2v4float = OpTypeMatrix %v4float 2
+    %u_block = OpTypeStruct %mat2v4float
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+          %7 = OpTypeFunction %void
+    %v2float = OpTypeVector %float 2
+%mat4v2float = OpTypeMatrix %v2float 4
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_mat2v4float = OpTypePointer Uniform %mat2v4float
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+         %27 = OpConstantNull %int
+          %f = OpFunction %void None %7
+         %10 = OpLabel
+         %17 = OpAccessChain %_ptr_Uniform_mat2v4float %u %uint_0
+         %18 = OpLoad %mat2v4float %17
+         %11 = OpTranspose %mat4v2float %18
+         %24 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %int_1
+         %25 = OpLoad %v4float %24
+         %19 = OpExtInst %float %20 Length %25
+         %28 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %27
+         %29 = OpLoad %v4float %28
+         %30 = OpVectorShuffle %v4float %29 %29 1 3 0 2
+         %31 = OpCompositeExtract %float %30 0
+         %26 = OpExtInst %float %20 FAbs %31
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_builtin.wgsl.expected.wgsl
new file mode 100644
index 0000000..58e7bdd
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_builtin.wgsl.expected.wgsl
@@ -0,0 +1,8 @@
+@group(0) @binding(0) var<uniform> u : mat2x4<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let t = transpose(u);
+  let l = length(u[1]);
+  let a = abs(u[0].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_fn.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_fn.wgsl
new file mode 100644
index 0000000..227b46c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_fn.wgsl
@@ -0,0 +1,14 @@
+@group(0) @binding(0) var<uniform> u : mat2x4<f32>;
+
+fn a(m : mat2x4<f32>) {}
+fn b(v : vec4<f32>) {}
+fn c(f : f32) {}
+
+@compute @workgroup_size(1)
+fn f() {
+    a(u);
+    b(u[1]);
+    b(u[1].ywxz);
+    c(u[1].x);
+    c(u[1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_fn.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..5f64389
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_fn.wgsl.expected.dxc.hlsl
@@ -0,0 +1,28 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+
+void a(float2x4 m) {
+}
+
+void b(float4 v) {
+}
+
+void c(float f_1) {
+}
+
+float2x4 tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(asfloat(u[1]));
+  b(asfloat(u[1]).ywxz);
+  c(asfloat(u[1].x));
+  c(asfloat(u[1]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_fn.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..5f64389
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_fn.wgsl.expected.fxc.hlsl
@@ -0,0 +1,28 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+
+void a(float2x4 m) {
+}
+
+void b(float4 v) {
+}
+
+void c(float f_1) {
+}
+
+float2x4 tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(asfloat(u[1]));
+  b(asfloat(u[1]).ywxz);
+  c(asfloat(u[1].x));
+  c(asfloat(u[1]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_fn.wgsl.expected.glsl
new file mode 100644
index 0000000..0abb3cd
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_fn.wgsl.expected.glsl
@@ -0,0 +1,28 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat2x4 inner;
+} u;
+
+void a(mat2x4 m) {
+}
+
+void b(vec4 v) {
+}
+
+void c(float f_1) {
+}
+
+void f() {
+  a(u.inner);
+  b(u.inner[1]);
+  b(u.inner[1].ywxz);
+  c(u.inner[1].x);
+  c(u.inner[1].ywxz.x);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_fn.wgsl.expected.msl
new file mode 100644
index 0000000..c0abb91
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_fn.wgsl.expected.msl
@@ -0,0 +1,21 @@
+#include <metal_stdlib>
+
+using namespace metal;
+void a(float2x4 m) {
+}
+
+void b(float4 v) {
+}
+
+void c(float f_1) {
+}
+
+kernel void f(const constant float2x4* tint_symbol [[buffer(0)]]) {
+  a(*(tint_symbol));
+  b((*(tint_symbol))[1]);
+  b(float4((*(tint_symbol))[1]).ywxz);
+  c((*(tint_symbol))[1][0]);
+  c(float4((*(tint_symbol))[1]).ywxz[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_fn.wgsl.expected.spvasm
new file mode 100644
index 0000000..12cb8ec
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_fn.wgsl.expected.spvasm
@@ -0,0 +1,81 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 48
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %a "a"
+               OpName %m "m"
+               OpName %b "b"
+               OpName %v "v"
+               OpName %c "c"
+               OpName %f_1 "f_1"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat2v4float = OpTypeMatrix %v4float 2
+    %u_block = OpTypeStruct %mat2v4float
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+          %7 = OpTypeFunction %void %mat2v4float
+         %12 = OpTypeFunction %void %v4float
+         %16 = OpTypeFunction %void %float
+         %20 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_mat2v4float = OpTypePointer Uniform %mat2v4float
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+          %a = OpFunction %void None %7
+          %m = OpFunctionParameter %mat2v4float
+         %11 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %b = OpFunction %void None %12
+          %v = OpFunctionParameter %v4float
+         %15 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %c = OpFunction %void None %16
+        %f_1 = OpFunctionParameter %float
+         %19 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %20
+         %22 = OpLabel
+         %27 = OpAccessChain %_ptr_Uniform_mat2v4float %u %uint_0
+         %28 = OpLoad %mat2v4float %27
+         %23 = OpFunctionCall %void %a %28
+         %33 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %int_1
+         %34 = OpLoad %v4float %33
+         %29 = OpFunctionCall %void %b %34
+         %36 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %int_1
+         %37 = OpLoad %v4float %36
+         %38 = OpVectorShuffle %v4float %37 %37 1 3 0 2
+         %35 = OpFunctionCall %void %b %38
+         %41 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %int_1 %uint_0
+         %42 = OpLoad %float %41
+         %39 = OpFunctionCall %void %c %42
+         %44 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %int_1
+         %45 = OpLoad %v4float %44
+         %46 = OpVectorShuffle %v4float %45 %45 1 3 0 2
+         %47 = OpCompositeExtract %float %46 0
+         %43 = OpFunctionCall %void %c %47
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_fn.wgsl.expected.wgsl
new file mode 100644
index 0000000..4983317
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_fn.wgsl.expected.wgsl
@@ -0,0 +1,19 @@
+@group(0) @binding(0) var<uniform> u : mat2x4<f32>;
+
+fn a(m : mat2x4<f32>) {
+}
+
+fn b(v : vec4<f32>) {
+}
+
+fn c(f : f32) {
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  a(u);
+  b(u[1]);
+  b(u[1].ywxz);
+  c(u[1].x);
+  c(u[1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_private.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_private.wgsl
new file mode 100644
index 0000000..0f35977
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_private.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0) var<uniform> u : mat2x4<f32>;
+var<private> p : mat2x4<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[0];
+    p[1] = u[0].ywxz;
+    p[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_private.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..c81f694
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_private.wgsl.expected.dxc.hlsl
@@ -0,0 +1,19 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+static float2x4 p = float2x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
+
+float2x4 tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = asfloat(u[0]);
+  p[1] = asfloat(u[0]).ywxz;
+  p[0][1] = asfloat(u[1].x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_private.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..c81f694
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_private.wgsl.expected.fxc.hlsl
@@ -0,0 +1,19 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+static float2x4 p = float2x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
+
+float2x4 tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = asfloat(u[0]);
+  p[1] = asfloat(u[0]).ywxz;
+  p[0][1] = asfloat(u[1].x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..d3e2387
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_private.wgsl.expected.glsl
@@ -0,0 +1,19 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat2x4 inner;
+} u;
+
+mat2x4 p = mat2x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
+void f() {
+  p = u.inner;
+  p[1] = u.inner[0];
+  p[1] = u.inner[0].ywxz;
+  p[0][1] = u.inner[1][0];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..8405e42
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_private.wgsl.expected.msl
@@ -0,0 +1,12 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f(const constant float2x4* tint_symbol_1 [[buffer(0)]]) {
+  thread float2x4 tint_symbol = float2x4(0.0f);
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[0];
+  tint_symbol[1] = float4((*(tint_symbol_1))[0]).ywxz;
+  tint_symbol[0][1] = (*(tint_symbol_1))[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_private.wgsl.expected.spvasm
new file mode 100644
index 0000000..733c620
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_private.wgsl.expected.spvasm
@@ -0,0 +1,62 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 36
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %p "p"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat2v4float = OpTypeMatrix %v4float 2
+    %u_block = OpTypeStruct %mat2v4float
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_Private_mat2v4float = OpTypePointer Private %mat2v4float
+          %9 = OpConstantNull %mat2v4float
+          %p = OpVariable %_ptr_Private_mat2v4float Private %9
+       %void = OpTypeVoid
+         %10 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_mat2v4float = OpTypePointer Uniform %mat2v4float
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Private_v4float = OpTypePointer Private %v4float
+         %23 = OpConstantNull %int
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+%_ptr_Private_float = OpTypePointer Private %float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+          %f = OpFunction %void None %10
+         %13 = OpLabel
+         %17 = OpAccessChain %_ptr_Uniform_mat2v4float %u %uint_0
+         %18 = OpLoad %mat2v4float %17
+               OpStore %p %18
+         %22 = OpAccessChain %_ptr_Private_v4float %p %int_1
+         %25 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %23
+         %26 = OpLoad %v4float %25
+               OpStore %22 %26
+         %27 = OpAccessChain %_ptr_Private_v4float %p %int_1
+         %28 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %23
+         %29 = OpLoad %v4float %28
+         %30 = OpVectorShuffle %v4float %29 %29 1 3 0 2
+               OpStore %27 %30
+         %32 = OpAccessChain %_ptr_Private_float %p %23 %int_1
+         %34 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %int_1 %23
+         %35 = OpLoad %float %34
+               OpStore %32 %35
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..76ce420
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_private.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> u : mat2x4<f32>;
+
+var<private> p : mat2x4<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[0];
+  p[1] = u[0].ywxz;
+  p[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_storage.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_storage.wgsl
new file mode 100644
index 0000000..abb20b6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_storage.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0) var<uniform> u : mat2x4<f32>;
+@group(0) @binding(1) var<storage, read_write> s : mat2x4<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[0];
+    s[1] = u[0].ywxz;
+    s[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_storage.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..8bc830a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_storage.wgsl.expected.dxc.hlsl
@@ -0,0 +1,24 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, float2x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+}
+
+float2x4 tint_symbol_2(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_2(u, 0u));
+  s.Store4(16u, asuint(asfloat(u[0])));
+  s.Store4(16u, asuint(asfloat(u[0]).ywxz));
+  s.Store(4u, asuint(asfloat(u[1].x)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_storage.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..8bc830a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_storage.wgsl.expected.fxc.hlsl
@@ -0,0 +1,24 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, float2x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+}
+
+float2x4 tint_symbol_2(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_2(u, 0u));
+  s.Store4(16u, asuint(asfloat(u[0])));
+  s.Store4(16u, asuint(asfloat(u[0]).ywxz));
+  s.Store(4u, asuint(asfloat(u[1].x)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..01c2122
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_storage.wgsl.expected.glsl
@@ -0,0 +1,22 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat2x4 inner;
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  mat2x4 inner;
+} s;
+
+void f() {
+  s.inner = u.inner;
+  s.inner[1] = u.inner[0];
+  s.inner[1] = u.inner[0].ywxz;
+  s.inner[0][1] = u.inner[1][0];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..a99b798
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_storage.wgsl.expected.msl
@@ -0,0 +1,11 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f(device float2x4* tint_symbol [[buffer(1)]], const constant float2x4* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[0];
+  (*(tint_symbol))[1] = float4((*(tint_symbol_1))[0]).ywxz;
+  (*(tint_symbol))[0][1] = (*(tint_symbol_1))[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_storage.wgsl.expected.spvasm
new file mode 100644
index 0000000..59d48a0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_storage.wgsl.expected.spvasm
@@ -0,0 +1,65 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 37
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %s "s"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %s DescriptorSet 0
+               OpDecorate %s Binding 1
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat2v4float = OpTypeMatrix %v4float 2
+    %u_block = OpTypeStruct %mat2v4float
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
+          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+       %void = OpTypeVoid
+          %9 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_mat2v4float = OpTypePointer StorageBuffer %mat2v4float
+%_ptr_Uniform_mat2v4float = OpTypePointer Uniform %mat2v4float
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_v4float = OpTypePointer StorageBuffer %v4float
+         %24 = OpConstantNull %int
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+          %f = OpFunction %void None %9
+         %12 = OpLabel
+         %16 = OpAccessChain %_ptr_StorageBuffer_mat2v4float %s %uint_0
+         %18 = OpAccessChain %_ptr_Uniform_mat2v4float %u %uint_0
+         %19 = OpLoad %mat2v4float %18
+               OpStore %16 %19
+         %23 = OpAccessChain %_ptr_StorageBuffer_v4float %s %uint_0 %int_1
+         %26 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %24
+         %27 = OpLoad %v4float %26
+               OpStore %23 %27
+         %28 = OpAccessChain %_ptr_StorageBuffer_v4float %s %uint_0 %int_1
+         %29 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %24
+         %30 = OpLoad %v4float %29
+         %31 = OpVectorShuffle %v4float %30 %30 1 3 0 2
+               OpStore %28 %31
+         %33 = OpAccessChain %_ptr_StorageBuffer_float %s %uint_0 %24 %int_1
+         %35 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %int_1 %24
+         %36 = OpLoad %float %35
+               OpStore %33 %36
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..79cb0f5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> u : mat2x4<f32>;
+
+@group(0) @binding(1) var<storage, read_write> s : mat2x4<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[0];
+  s[1] = u[0].ywxz;
+  s[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_workgroup.wgsl
new file mode 100644
index 0000000..6d92e5a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_workgroup.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0) var<uniform> u : mat2x4<f32>;
+var<workgroup> w : mat2x4<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[0];
+    w[1] = u[0].ywxz;
+    w[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_workgroup.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..23c91dd
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_workgroup.wgsl.expected.dxc.hlsl
@@ -0,0 +1,31 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+groupshared float2x4 w;
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+float2x4 tint_symbol_2(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    w = float2x4((0.0f).xxxx, (0.0f).xxxx);
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = asfloat(u[0]);
+  w[1] = asfloat(u[0]).ywxz;
+  w[0][1] = asfloat(u[1].x);
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_workgroup.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..23c91dd
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_workgroup.wgsl.expected.fxc.hlsl
@@ -0,0 +1,31 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+groupshared float2x4 w;
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+float2x4 tint_symbol_2(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    w = float2x4((0.0f).xxxx, (0.0f).xxxx);
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = asfloat(u[0]);
+  w[1] = asfloat(u[0]).ywxz;
+  w[0][1] = asfloat(u[1].x);
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..b021a5c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,23 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat2x4 inner;
+} u;
+
+shared mat2x4 w;
+void f(uint local_invocation_index) {
+  {
+    w = mat2x4(vec4(0.0f), vec4(0.0f));
+  }
+  barrier();
+  w = u.inner;
+  w[1] = u.inner[0];
+  w[1] = u.inner[0].ywxz;
+  w[0][1] = u.inner[1][0];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..35d7ce5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,24 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct tint_symbol_5 {
+  float2x4 w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup float2x4* const tint_symbol, const constant float2x4* const tint_symbol_1) {
+  {
+    *(tint_symbol) = float2x4(float4(0.0f), float4(0.0f));
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[0];
+  (*(tint_symbol))[1] = float4((*(tint_symbol_1))[0]).ywxz;
+  (*(tint_symbol))[0][1] = (*(tint_symbol_1))[1][0];
+}
+
+kernel void f(const constant float2x4* tint_symbol_4 [[buffer(0)]], threadgroup tint_symbol_5* tint_symbol_3 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup float2x4* const tint_symbol_2 = &((*(tint_symbol_3)).w);
+  f_inner(local_invocation_index, tint_symbol_2, tint_symbol_4);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_workgroup.wgsl.expected.spvasm
new file mode 100644
index 0000000..e1add4d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_workgroup.wgsl.expected.spvasm
@@ -0,0 +1,80 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 47
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %local_invocation_index_1 "local_invocation_index_1"
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %w "w"
+               OpName %f_inner "f_inner"
+               OpName %local_invocation_index "local_invocation_index"
+               OpName %f "f"
+               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat2v4float = OpTypeMatrix %v4float 2
+    %u_block = OpTypeStruct %mat2v4float
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_Workgroup_mat2v4float = OpTypePointer Workgroup %mat2v4float
+          %w = OpVariable %_ptr_Workgroup_mat2v4float Workgroup
+       %void = OpTypeVoid
+         %12 = OpTypeFunction %void %uint
+         %17 = OpConstantNull %mat2v4float
+     %uint_2 = OpConstant %uint 2
+   %uint_264 = OpConstant %uint 264
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_mat2v4float = OpTypePointer Uniform %mat2v4float
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Workgroup_v4float = OpTypePointer Workgroup %v4float
+         %29 = OpConstantNull %int
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+%_ptr_Workgroup_float = OpTypePointer Workgroup %float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+         %42 = OpTypeFunction %void
+    %f_inner = OpFunction %void None %12
+%local_invocation_index = OpFunctionParameter %uint
+         %16 = OpLabel
+               OpStore %w %17
+               OpControlBarrier %uint_2 %uint_2 %uint_264
+         %23 = OpAccessChain %_ptr_Uniform_mat2v4float %u %uint_0
+         %24 = OpLoad %mat2v4float %23
+               OpStore %w %24
+         %28 = OpAccessChain %_ptr_Workgroup_v4float %w %int_1
+         %31 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %29
+         %32 = OpLoad %v4float %31
+               OpStore %28 %32
+         %33 = OpAccessChain %_ptr_Workgroup_v4float %w %int_1
+         %34 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %29
+         %35 = OpLoad %v4float %34
+         %36 = OpVectorShuffle %v4float %35 %35 1 3 0 2
+               OpStore %33 %36
+         %38 = OpAccessChain %_ptr_Workgroup_float %w %29 %int_1
+         %40 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %int_1 %29
+         %41 = OpLoad %float %40
+               OpStore %38 %41
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %42
+         %44 = OpLabel
+         %46 = OpLoad %uint %local_invocation_index_1
+         %45 = OpFunctionCall %void %f_inner %46
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..974dc1f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat2x4_f32/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> u : mat2x4<f32>;
+
+var<workgroup> w : mat2x4<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[0];
+  w[1] = u[0].ywxz;
+  w[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/dynamic_index_via_ptr.wgsl
new file mode 100644
index 0000000..ae5cc00
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/dynamic_index_via_ptr.wgsl
@@ -0,0 +1,15 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> m : mat3x2<f16>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m   = &m;
+  let p_m_i = &((*p_m)[i()]);
+
+  let l_m   : mat3x2<f16> = *p_m;
+  let l_m_i : vec2<f16>   = *p_m_i;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..710277f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,29 @@
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[1];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 3, 2> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  return matrix<float16_t, 3, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_m_i_save = i();
+  const matrix<float16_t, 3, 2> l_m = tint_symbol(m, 0u);
+  const uint scalar_offset_3 = ((4u * uint(p_m_i_save))) / 4;
+  uint ubo_load_3 = m[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  const vector<float16_t, 2> l_m_i = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..aa9b9a5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,34 @@
+SKIP: FAILED
+
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[1];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 3, 2> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  return matrix<float16_t, 3, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_m_i_save = i();
+  const matrix<float16_t, 3, 2> l_m = tint_symbol(m, 0u);
+  const uint scalar_offset_3 = ((4u * uint(p_m_i_save))) / 4;
+  uint ubo_load_3 = m[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  const vector<float16_t, 2> l_m_i = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16)));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000022586D0B760(11,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/dynamic_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..6b87658
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,53 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform m_block_std140_ubo {
+  f16vec2 inner_0;
+  f16vec2 inner_1;
+  f16vec2 inner_2;
+} m;
+
+int counter = 0;
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+f16mat3x2 load_m_inner() {
+  return f16mat3x2(m.inner_0, m.inner_1, m.inner_2);
+}
+
+f16vec2 load_m_inner_p0(uint p0) {
+  switch(p0) {
+    case 0u: {
+      return m.inner_0;
+      break;
+    }
+    case 1u: {
+      return m.inner_1;
+      break;
+    }
+    case 2u: {
+      return m.inner_2;
+      break;
+    }
+    default: {
+      return f16vec2(0.0hf);
+      break;
+    }
+  }
+}
+
+void f() {
+  f16mat3x2 p_m = load_m_inner();
+  int tint_symbol = i();
+  f16vec2 p_m_i = load_m_inner_p0(uint(tint_symbol));
+  f16mat3x2 l_m = load_m_inner();
+  f16vec2 l_m_i = load_m_inner_p0(uint(tint_symbol));
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/dynamic_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..fec7c16
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/dynamic_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,17 @@
+#include <metal_stdlib>
+
+using namespace metal;
+int i() {
+  thread int tint_symbol_1 = 0;
+  tint_symbol_1 = as_type<int>((as_type<uint>(tint_symbol_1) + as_type<uint>(1)));
+  return tint_symbol_1;
+}
+
+kernel void f(const constant half3x2* tint_symbol_2 [[buffer(0)]]) {
+  int const tint_symbol = i();
+  int const p_m_i_save = tint_symbol;
+  half3x2 const l_m = *(tint_symbol_2);
+  half2 const l_m_i = (*(tint_symbol_2))[p_m_i_save];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..e9d22a9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,102 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 61
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %m_block_std140 "m_block_std140"
+               OpMemberName %m_block_std140 0 "inner_0"
+               OpMemberName %m_block_std140 1 "inner_1"
+               OpMemberName %m_block_std140 2 "inner_2"
+               OpName %m "m"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %load_m_inner "load_m_inner"
+               OpName %load_m_inner_p0 "load_m_inner_p0"
+               OpName %p0 "p0"
+               OpName %f "f"
+               OpDecorate %m_block_std140 Block
+               OpMemberDecorate %m_block_std140 0 Offset 0
+               OpMemberDecorate %m_block_std140 1 Offset 4
+               OpMemberDecorate %m_block_std140 2 Offset 8
+               OpDecorate %m NonWritable
+               OpDecorate %m DescriptorSet 0
+               OpDecorate %m Binding 0
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+%m_block_std140 = OpTypeStruct %v2half %v2half %v2half
+%_ptr_Uniform_m_block_std140 = OpTypePointer Uniform %m_block_std140
+          %m = OpVariable %_ptr_Uniform_m_block_std140 Uniform
+        %int = OpTypeInt 32 1
+          %7 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %7
+         %10 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+ %mat3v2half = OpTypeMatrix %v2half 3
+         %17 = OpTypeFunction %mat3v2half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+         %37 = OpTypeFunction %v2half %uint
+         %52 = OpConstantNull %v2half
+       %void = OpTypeVoid
+         %53 = OpTypeFunction %void
+          %i = OpFunction %int None %10
+         %12 = OpLabel
+         %13 = OpLoad %int %counter
+         %15 = OpIAdd %int %13 %int_1
+               OpStore %counter %15
+         %16 = OpLoad %int %counter
+               OpReturnValue %16
+               OpFunctionEnd
+%load_m_inner = OpFunction %mat3v2half None %17
+         %20 = OpLabel
+         %26 = OpAccessChain %_ptr_Uniform_v2half %m %uint_0
+         %27 = OpLoad %v2half %26
+         %30 = OpAccessChain %_ptr_Uniform_v2half %m %uint_1
+         %31 = OpLoad %v2half %30
+         %34 = OpAccessChain %_ptr_Uniform_v2half %m %uint_2
+         %35 = OpLoad %v2half %34
+         %36 = OpCompositeConstruct %mat3v2half %27 %31 %35
+               OpReturnValue %36
+               OpFunctionEnd
+%load_m_inner_p0 = OpFunction %v2half None %37
+         %p0 = OpFunctionParameter %uint
+         %40 = OpLabel
+               OpSelectionMerge %41 None
+               OpSwitch %p0 %42 0 %43 1 %44 2 %45
+         %43 = OpLabel
+         %46 = OpAccessChain %_ptr_Uniform_v2half %m %uint_0
+         %47 = OpLoad %v2half %46
+               OpReturnValue %47
+         %44 = OpLabel
+         %48 = OpAccessChain %_ptr_Uniform_v2half %m %uint_1
+         %49 = OpLoad %v2half %48
+               OpReturnValue %49
+         %45 = OpLabel
+         %50 = OpAccessChain %_ptr_Uniform_v2half %m %uint_2
+         %51 = OpLoad %v2half %50
+               OpReturnValue %51
+         %42 = OpLabel
+               OpReturnValue %52
+         %41 = OpLabel
+               OpReturnValue %52
+               OpFunctionEnd
+          %f = OpFunction %void None %53
+         %56 = OpLabel
+         %57 = OpFunctionCall %int %i
+         %58 = OpFunctionCall %mat3v2half %load_m_inner
+         %60 = OpBitcast %uint %57
+         %59 = OpFunctionCall %v2half %load_m_inner_p0 %60
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..e4bb940
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> m : mat3x2<f16>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m = &(m);
+  let p_m_i = &((*(p_m))[i()]);
+  let l_m : mat3x2<f16> = *(p_m);
+  let l_m_i : vec2<f16> = *(p_m_i);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/static_index_via_ptr.wgsl
new file mode 100644
index 0000000..2d2c4a2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/static_index_via_ptr.wgsl
@@ -0,0 +1,15 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> m : mat3x2<f16>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m   = &m;
+  let p_m_1 = &((*p_m)[1]);
+
+  let l_m   : mat3x2<f16> = *p_m;
+  let l_m_1 : vec2<f16>   = *p_m_1;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..c5bbdca
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,27 @@
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[1];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 3, 2> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  return matrix<float16_t, 3, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 3, 2> l_m = tint_symbol(m, 0u);
+  uint ubo_load_3 = m[0].y;
+  const vector<float16_t, 2> l_m_1 = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..09304d6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,32 @@
+SKIP: FAILED
+
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[1];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 3, 2> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  return matrix<float16_t, 3, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 3, 2> l_m = tint_symbol(m, 0u);
+  uint ubo_load_3 = m[0].y;
+  const vector<float16_t, 2> l_m_1 = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16)));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x00000213B52029A0(11,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/static_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..2ed83ea
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/static_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,25 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform m_block_std140_ubo {
+  f16vec2 inner_0;
+  f16vec2 inner_1;
+  f16vec2 inner_2;
+} m;
+
+f16mat3x2 load_m_inner() {
+  return f16mat3x2(m.inner_0, m.inner_1, m.inner_2);
+}
+
+void f() {
+  f16mat3x2 p_m = load_m_inner();
+  f16vec2 p_m_1 = m.inner_1;
+  f16mat3x2 l_m = load_m_inner();
+  f16vec2 l_m_1 = m.inner_1;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/static_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..20f3c6a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/static_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,15 @@
+#include <metal_stdlib>
+
+using namespace metal;
+int i() {
+  thread int tint_symbol = 0;
+  tint_symbol = as_type<int>((as_type<uint>(tint_symbol) + as_type<uint>(1)));
+  return tint_symbol;
+}
+
+kernel void f(const constant half3x2* tint_symbol_1 [[buffer(0)]]) {
+  half3x2 const l_m = *(tint_symbol_1);
+  half2 const l_m_1 = (*(tint_symbol_1))[1];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/static_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..1741d5b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/static_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,75 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 44
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %m_block_std140 "m_block_std140"
+               OpMemberName %m_block_std140 0 "inner_0"
+               OpMemberName %m_block_std140 1 "inner_1"
+               OpMemberName %m_block_std140 2 "inner_2"
+               OpName %m "m"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %load_m_inner "load_m_inner"
+               OpName %f "f"
+               OpDecorate %m_block_std140 Block
+               OpMemberDecorate %m_block_std140 0 Offset 0
+               OpMemberDecorate %m_block_std140 1 Offset 4
+               OpMemberDecorate %m_block_std140 2 Offset 8
+               OpDecorate %m NonWritable
+               OpDecorate %m DescriptorSet 0
+               OpDecorate %m Binding 0
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+%m_block_std140 = OpTypeStruct %v2half %v2half %v2half
+%_ptr_Uniform_m_block_std140 = OpTypePointer Uniform %m_block_std140
+          %m = OpVariable %_ptr_Uniform_m_block_std140 Uniform
+        %int = OpTypeInt 32 1
+          %7 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %7
+         %10 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+ %mat3v2half = OpTypeMatrix %v2half 3
+         %17 = OpTypeFunction %mat3v2half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+       %void = OpTypeVoid
+         %37 = OpTypeFunction %void
+          %i = OpFunction %int None %10
+         %12 = OpLabel
+         %13 = OpLoad %int %counter
+         %15 = OpIAdd %int %13 %int_1
+               OpStore %counter %15
+         %16 = OpLoad %int %counter
+               OpReturnValue %16
+               OpFunctionEnd
+%load_m_inner = OpFunction %mat3v2half None %17
+         %20 = OpLabel
+         %26 = OpAccessChain %_ptr_Uniform_v2half %m %uint_0
+         %27 = OpLoad %v2half %26
+         %30 = OpAccessChain %_ptr_Uniform_v2half %m %uint_1
+         %31 = OpLoad %v2half %30
+         %34 = OpAccessChain %_ptr_Uniform_v2half %m %uint_2
+         %35 = OpLoad %v2half %34
+         %36 = OpCompositeConstruct %mat3v2half %27 %31 %35
+               OpReturnValue %36
+               OpFunctionEnd
+          %f = OpFunction %void None %37
+         %40 = OpLabel
+         %41 = OpFunctionCall %mat3v2half %load_m_inner
+         %42 = OpAccessChain %_ptr_Uniform_v2half %m %uint_1
+         %43 = OpLoad %v2half %42
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/static_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..5717427
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/static_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> m : mat3x2<f16>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m = &(m);
+  let p_m_1 = &((*(p_m))[1]);
+  let l_m : mat3x2<f16> = *(p_m);
+  let l_m_1 : vec2<f16> = *(p_m_1);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_builtin.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_builtin.wgsl
new file mode 100644
index 0000000..8f9ab07
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_builtin.wgsl
@@ -0,0 +1,10 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat3x2<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+    let t = transpose(u);
+    let l = length(u[1]);
+    let a = abs(u[0].yx.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_builtin.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..c099203
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_builtin.wgsl.expected.dxc.hlsl
@@ -0,0 +1,23 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+matrix<float16_t, 3, 2> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  return matrix<float16_t, 3, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 2, 3> t = transpose(tint_symbol(u, 0u));
+  uint ubo_load_3 = u[0].y;
+  const float16_t l = length(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+  uint ubo_load_4 = u[0].x;
+  const float16_t a = abs(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16))).yx.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_builtin.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..6906207
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_builtin.wgsl.expected.fxc.hlsl
@@ -0,0 +1,28 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+matrix<float16_t, 3, 2> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  return matrix<float16_t, 3, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 2, 3> t = transpose(tint_symbol(u, 0u));
+  uint ubo_load_3 = u[0].y;
+  const float16_t l = length(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+  uint ubo_load_4 = u[0].x;
+  const float16_t a = abs(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16))).yx.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000002BC2002A7B0(5,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_builtin.wgsl.expected.glsl
new file mode 100644
index 0000000..44171a8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_builtin.wgsl.expected.glsl
@@ -0,0 +1,24 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec2 inner_0;
+  f16vec2 inner_1;
+  f16vec2 inner_2;
+} u;
+
+f16mat3x2 load_u_inner() {
+  return f16mat3x2(u.inner_0, u.inner_1, u.inner_2);
+}
+
+void f() {
+  f16mat2x3 t = transpose(load_u_inner());
+  float16_t l = length(u.inner_1);
+  float16_t a = abs(u.inner_0.yx[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_builtin.wgsl.expected.msl
new file mode 100644
index 0000000..5a86f0d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_builtin.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f(const constant half3x2* tint_symbol [[buffer(0)]]) {
+  half2x3 const t = transpose(*(tint_symbol));
+  half const l = length((*(tint_symbol))[1]);
+  half const a = fabs(half2((*(tint_symbol))[0]).yx[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_builtin.wgsl.expected.spvasm
new file mode 100644
index 0000000..7eec8a6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_builtin.wgsl.expected.spvasm
@@ -0,0 +1,70 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 44
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+         %35 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpMemberName %u_block_std140 2 "inner_2"
+               OpName %u "u"
+               OpName %load_u_inner "load_u_inner"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 4
+               OpMemberDecorate %u_block_std140 2 Offset 8
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+%u_block_std140 = OpTypeStruct %v2half %v2half %v2half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat3v2half = OpTypeMatrix %v2half 3
+          %6 = OpTypeFunction %mat3v2half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+       %void = OpTypeVoid
+         %26 = OpTypeFunction %void
+     %v3half = OpTypeVector %half 3
+ %mat2v3half = OpTypeMatrix %v3half 2
+         %42 = OpConstantNull %uint
+%load_u_inner = OpFunction %mat3v2half None %6
+          %9 = OpLabel
+         %15 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0
+         %16 = OpLoad %v2half %15
+         %19 = OpAccessChain %_ptr_Uniform_v2half %u %uint_1
+         %20 = OpLoad %v2half %19
+         %23 = OpAccessChain %_ptr_Uniform_v2half %u %uint_2
+         %24 = OpLoad %v2half %23
+         %25 = OpCompositeConstruct %mat3v2half %16 %20 %24
+               OpReturnValue %25
+               OpFunctionEnd
+          %f = OpFunction %void None %26
+         %29 = OpLabel
+         %33 = OpFunctionCall %mat3v2half %load_u_inner
+         %30 = OpTranspose %mat2v3half %33
+         %36 = OpAccessChain %_ptr_Uniform_v2half %u %uint_1
+         %37 = OpLoad %v2half %36
+         %34 = OpExtInst %half %35 Length %37
+         %39 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0
+         %40 = OpLoad %v2half %39
+         %41 = OpVectorShuffle %v2half %40 %40 1 0
+         %43 = OpCompositeExtract %half %41 0
+         %38 = OpExtInst %half %35 FAbs %43
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_builtin.wgsl.expected.wgsl
new file mode 100644
index 0000000..1746747
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_builtin.wgsl.expected.wgsl
@@ -0,0 +1,10 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat3x2<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let t = transpose(u);
+  let l = length(u[1]);
+  let a = abs(u[0].yx.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_fn.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_fn.wgsl
new file mode 100644
index 0000000..7fc7da5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_fn.wgsl
@@ -0,0 +1,16 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat3x2<f16>;
+
+fn a(m : mat3x2<f16>) {}
+fn b(v : vec2<f16>) {}
+fn c(f : f16) {}
+
+@compute @workgroup_size(1)
+fn f() {
+    a(u);
+    b(u[1]);
+    b(u[1].yx);
+    c(u[1].x);
+    c(u[1].yx.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_fn.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..0de6e6d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_fn.wgsl.expected.dxc.hlsl
@@ -0,0 +1,35 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+void a(matrix<float16_t, 3, 2> m) {
+}
+
+void b(vector<float16_t, 2> v) {
+}
+
+void c(float16_t f_1) {
+}
+
+matrix<float16_t, 3, 2> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  return matrix<float16_t, 3, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  uint ubo_load_3 = u[0].y;
+  b(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+  uint ubo_load_4 = u[0].y;
+  b(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16))).yx);
+  c(float16_t(f16tof32(((u[0].y) & 0xFFFF))));
+  uint ubo_load_5 = u[0].y;
+  c(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_5 & 0xFFFF)), float16_t(f16tof32(ubo_load_5 >> 16))).yx.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_fn.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..2f2e1d5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_fn.wgsl.expected.fxc.hlsl
@@ -0,0 +1,42 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+void a(matrix<float16_t, 3, 2> m) {
+}
+
+void b(vector<float16_t, 2> v) {
+}
+
+void c(float16_t f_1) {
+}
+
+matrix<float16_t, 3, 2> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  return matrix<float16_t, 3, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  uint ubo_load_3 = u[0].y;
+  b(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+  uint ubo_load_4 = u[0].y;
+  b(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16))).yx);
+  c(float16_t(f16tof32(((u[0].y) & 0xFFFF))));
+  uint ubo_load_5 = u[0].y;
+  c(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_5 & 0xFFFF)), float16_t(f16tof32(ubo_load_5 >> 16))).yx.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000014896F24370(5,15-23): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000014896F24370(8,15-23): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000014896F24370(11,8-16): error X3000: unrecognized identifier 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_fn.wgsl.expected.glsl
new file mode 100644
index 0000000..2775f5e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_fn.wgsl.expected.glsl
@@ -0,0 +1,35 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec2 inner_0;
+  f16vec2 inner_1;
+  f16vec2 inner_2;
+} u;
+
+void a(f16mat3x2 m) {
+}
+
+void b(f16vec2 v) {
+}
+
+void c(float16_t f_1) {
+}
+
+f16mat3x2 load_u_inner() {
+  return f16mat3x2(u.inner_0, u.inner_1, u.inner_2);
+}
+
+void f() {
+  a(load_u_inner());
+  b(u.inner_1);
+  b(u.inner_1.yx);
+  c(u.inner_1[0u]);
+  c(u.inner_1.yx[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_fn.wgsl.expected.msl
new file mode 100644
index 0000000..04006cd
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_fn.wgsl.expected.msl
@@ -0,0 +1,21 @@
+#include <metal_stdlib>
+
+using namespace metal;
+void a(half3x2 m) {
+}
+
+void b(half2 v) {
+}
+
+void c(half f_1) {
+}
+
+kernel void f(const constant half3x2* tint_symbol [[buffer(0)]]) {
+  a(*(tint_symbol));
+  b((*(tint_symbol))[1]);
+  b(half2((*(tint_symbol))[1]).yx);
+  c((*(tint_symbol))[1][0]);
+  c(half2((*(tint_symbol))[1]).yx[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_fn.wgsl.expected.spvasm
new file mode 100644
index 0000000..96d6933
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_fn.wgsl.expected.spvasm
@@ -0,0 +1,99 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 61
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpMemberName %u_block_std140 2 "inner_2"
+               OpName %u "u"
+               OpName %a "a"
+               OpName %m "m"
+               OpName %b "b"
+               OpName %v "v"
+               OpName %c "c"
+               OpName %f_1 "f_1"
+               OpName %load_u_inner "load_u_inner"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 4
+               OpMemberDecorate %u_block_std140 2 Offset 8
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+%u_block_std140 = OpTypeStruct %v2half %v2half %v2half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+       %void = OpTypeVoid
+ %mat3v2half = OpTypeMatrix %v2half 3
+          %6 = OpTypeFunction %void %mat3v2half
+         %12 = OpTypeFunction %void %v2half
+         %16 = OpTypeFunction %void %half
+         %20 = OpTypeFunction %mat3v2half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+         %39 = OpTypeFunction %void
+         %52 = OpConstantNull %uint
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+          %a = OpFunction %void None %6
+          %m = OpFunctionParameter %mat3v2half
+         %11 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %b = OpFunction %void None %12
+          %v = OpFunctionParameter %v2half
+         %15 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %c = OpFunction %void None %16
+        %f_1 = OpFunctionParameter %half
+         %19 = OpLabel
+               OpReturn
+               OpFunctionEnd
+%load_u_inner = OpFunction %mat3v2half None %20
+         %22 = OpLabel
+         %28 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0
+         %29 = OpLoad %v2half %28
+         %32 = OpAccessChain %_ptr_Uniform_v2half %u %uint_1
+         %33 = OpLoad %v2half %32
+         %36 = OpAccessChain %_ptr_Uniform_v2half %u %uint_2
+         %37 = OpLoad %v2half %36
+         %38 = OpCompositeConstruct %mat3v2half %29 %33 %37
+               OpReturnValue %38
+               OpFunctionEnd
+          %f = OpFunction %void None %39
+         %41 = OpLabel
+         %43 = OpFunctionCall %mat3v2half %load_u_inner
+         %42 = OpFunctionCall %void %a %43
+         %45 = OpAccessChain %_ptr_Uniform_v2half %u %uint_1
+         %46 = OpLoad %v2half %45
+         %44 = OpFunctionCall %void %b %46
+         %48 = OpAccessChain %_ptr_Uniform_v2half %u %uint_1
+         %49 = OpLoad %v2half %48
+         %50 = OpVectorShuffle %v2half %49 %49 1 0
+         %47 = OpFunctionCall %void %b %50
+         %54 = OpAccessChain %_ptr_Uniform_half %u %uint_1 %52
+         %55 = OpLoad %half %54
+         %51 = OpFunctionCall %void %c %55
+         %57 = OpAccessChain %_ptr_Uniform_v2half %u %uint_1
+         %58 = OpLoad %v2half %57
+         %59 = OpVectorShuffle %v2half %58 %58 1 0
+         %60 = OpCompositeExtract %half %59 0
+         %56 = OpFunctionCall %void %c %60
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_fn.wgsl.expected.wgsl
new file mode 100644
index 0000000..ef40b52
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_fn.wgsl.expected.wgsl
@@ -0,0 +1,21 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat3x2<f16>;
+
+fn a(m : mat3x2<f16>) {
+}
+
+fn b(v : vec2<f16>) {
+}
+
+fn c(f : f16) {
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  a(u);
+  b(u[1]);
+  b(u[1].yx);
+  c(u[1].x);
+  c(u[1].yx.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_private.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_private.wgsl
new file mode 100644
index 0000000..d1ad4f5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_private.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat3x2<f16>;
+var<private> p : mat3x2<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[0];
+    p[1] = u[0].yx;
+    p[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_private.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..ae2fee4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_private.wgsl.expected.dxc.hlsl
@@ -0,0 +1,25 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+static matrix<float16_t, 3, 2> p = matrix<float16_t, 3, 2>(float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h));
+
+matrix<float16_t, 3, 2> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  return matrix<float16_t, 3, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  uint ubo_load_3 = u[0].x;
+  p[1] = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16)));
+  uint ubo_load_4 = u[0].x;
+  p[1] = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16))).yx;
+  p[0][1] = float16_t(f16tof32(((u[0].y) & 0xFFFF)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_private.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..d8d5d22
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_private.wgsl.expected.fxc.hlsl
@@ -0,0 +1,30 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+static matrix<float16_t, 3, 2> p = matrix<float16_t, 3, 2>(float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h));
+
+matrix<float16_t, 3, 2> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  return matrix<float16_t, 3, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  uint ubo_load_3 = u[0].x;
+  p[1] = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16)));
+  uint ubo_load_4 = u[0].x;
+  p[1] = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16))).yx;
+  p[0][1] = float16_t(f16tof32(((u[0].y) & 0xFFFF)));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001D559EA82A0(4,15-23): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..deb133c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_private.wgsl.expected.glsl
@@ -0,0 +1,26 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec2 inner_0;
+  f16vec2 inner_1;
+  f16vec2 inner_2;
+} u;
+
+f16mat3x2 p = f16mat3x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf);
+f16mat3x2 load_u_inner() {
+  return f16mat3x2(u.inner_0, u.inner_1, u.inner_2);
+}
+
+void f() {
+  p = load_u_inner();
+  p[1] = u.inner_0;
+  p[1] = u.inner_0.yx;
+  p[0][1] = u.inner_1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..85a9952
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_private.wgsl.expected.msl
@@ -0,0 +1,12 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f(const constant half3x2* tint_symbol_1 [[buffer(0)]]) {
+  thread half3x2 tint_symbol = half3x2(0.0h);
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[0];
+  tint_symbol[1] = half2((*(tint_symbol_1))[0]).yx;
+  tint_symbol[0][1] = (*(tint_symbol_1))[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_private.wgsl.expected.spvasm
new file mode 100644
index 0000000..0f299f0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_private.wgsl.expected.spvasm
@@ -0,0 +1,82 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 51
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpMemberName %u_block_std140 2 "inner_2"
+               OpName %u "u"
+               OpName %p "p"
+               OpName %load_u_inner "load_u_inner"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 4
+               OpMemberDecorate %u_block_std140 2 Offset 8
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+%u_block_std140 = OpTypeStruct %v2half %v2half %v2half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat3v2half = OpTypeMatrix %v2half 3
+%_ptr_Private_mat3v2half = OpTypePointer Private %mat3v2half
+          %9 = OpConstantNull %mat3v2half
+          %p = OpVariable %_ptr_Private_mat3v2half Private %9
+         %10 = OpTypeFunction %mat3v2half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+       %void = OpTypeVoid
+         %29 = OpTypeFunction %void
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Private_v2half = OpTypePointer Private %v2half
+         %44 = OpConstantNull %int
+%_ptr_Private_half = OpTypePointer Private %half
+         %47 = OpConstantNull %uint
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+%load_u_inner = OpFunction %mat3v2half None %10
+         %12 = OpLabel
+         %18 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0
+         %19 = OpLoad %v2half %18
+         %22 = OpAccessChain %_ptr_Uniform_v2half %u %uint_1
+         %23 = OpLoad %v2half %22
+         %26 = OpAccessChain %_ptr_Uniform_v2half %u %uint_2
+         %27 = OpLoad %v2half %26
+         %28 = OpCompositeConstruct %mat3v2half %19 %23 %27
+               OpReturnValue %28
+               OpFunctionEnd
+          %f = OpFunction %void None %29
+         %32 = OpLabel
+         %33 = OpFunctionCall %mat3v2half %load_u_inner
+               OpStore %p %33
+         %37 = OpAccessChain %_ptr_Private_v2half %p %int_1
+         %38 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0
+         %39 = OpLoad %v2half %38
+               OpStore %37 %39
+         %40 = OpAccessChain %_ptr_Private_v2half %p %int_1
+         %41 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0
+         %42 = OpLoad %v2half %41
+         %43 = OpVectorShuffle %v2half %42 %42 1 0
+               OpStore %40 %43
+         %46 = OpAccessChain %_ptr_Private_half %p %44 %int_1
+         %49 = OpAccessChain %_ptr_Uniform_half %u %uint_1 %47
+         %50 = OpLoad %half %49
+               OpStore %46 %50
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..2966c25
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_private.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat3x2<f16>;
+
+var<private> p : mat3x2<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[0];
+  p[1] = u[0].yx;
+  p[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_storage.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_storage.wgsl
new file mode 100644
index 0000000..73f77ef
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_storage.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat3x2<f16>;
+@group(0) @binding(1) var<storage, read_write> s : mat3x2<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[0];
+    s[1] = u[0].yx;
+    s[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_storage.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..ad86e04
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_storage.wgsl.expected.dxc.hlsl
@@ -0,0 +1,31 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 3, 2> value) {
+  buffer.Store<vector<float16_t, 2> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 4u), value[1u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 8u), value[2u]);
+}
+
+matrix<float16_t, 3, 2> tint_symbol_2(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  return matrix<float16_t, 3, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_2(u, 0u));
+  uint ubo_load_3 = u[0].x;
+  s.Store<vector<float16_t, 2> >(4u, vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+  uint ubo_load_4 = u[0].x;
+  s.Store<vector<float16_t, 2> >(4u, vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16))).yx);
+  s.Store<float16_t>(2u, float16_t(f16tof32(((u[0].y) & 0xFFFF))));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_storage.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..3e6bbdf
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_storage.wgsl.expected.fxc.hlsl
@@ -0,0 +1,37 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 3, 2> value) {
+  buffer.Store<vector<float16_t, 2> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 4u), value[1u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 8u), value[2u]);
+}
+
+matrix<float16_t, 3, 2> tint_symbol_2(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  return matrix<float16_t, 3, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_2(u, 0u));
+  uint ubo_load_3 = u[0].x;
+  s.Store<vector<float16_t, 2> >(4u, vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+  uint ubo_load_4 = u[0].x;
+  s.Store<vector<float16_t, 2> >(4u, vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16))).yx);
+  s.Store<float16_t>(2u, float16_t(f16tof32(((u[0].y) & 0xFFFF))));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000027290DF7F00(6,66-74): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000027290DF7F00(7,3-14): error X3018: invalid subscript 'Store'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..3e01638
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_storage.wgsl.expected.glsl
@@ -0,0 +1,29 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec2 inner_0;
+  f16vec2 inner_1;
+  f16vec2 inner_2;
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  f16mat3x2 inner;
+} s;
+
+f16mat3x2 load_u_inner() {
+  return f16mat3x2(u.inner_0, u.inner_1, u.inner_2);
+}
+
+void f() {
+  s.inner = load_u_inner();
+  s.inner[1] = u.inner_0;
+  s.inner[1] = u.inner_0.yx;
+  s.inner[0][1] = u.inner_1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..2109a16
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_storage.wgsl.expected.msl
@@ -0,0 +1,11 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f(device half3x2* tint_symbol [[buffer(1)]], const constant half3x2* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[0];
+  (*(tint_symbol))[1] = half2((*(tint_symbol_1))[0]).yx;
+  (*(tint_symbol))[0][1] = (*(tint_symbol_1))[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_storage.wgsl.expected.spvasm
new file mode 100644
index 0000000..efdff11
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_storage.wgsl.expected.spvasm
@@ -0,0 +1,92 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 53
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpMemberName %u_block_std140 2 "inner_2"
+               OpName %u "u"
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %s "s"
+               OpName %load_u_inner "load_u_inner"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 4
+               OpMemberDecorate %u_block_std140 2 Offset 8
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 4
+               OpDecorate %s DescriptorSet 0
+               OpDecorate %s Binding 1
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+%u_block_std140 = OpTypeStruct %v2half %v2half %v2half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat3v2half = OpTypeMatrix %v2half 3
+    %u_block = OpTypeStruct %mat3v2half
+%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
+          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+         %10 = OpTypeFunction %mat3v2half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+       %void = OpTypeVoid
+         %29 = OpTypeFunction %void
+%_ptr_StorageBuffer_mat3v2half = OpTypePointer StorageBuffer %mat3v2half
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_v2half = OpTypePointer StorageBuffer %v2half
+         %46 = OpConstantNull %int
+%_ptr_StorageBuffer_half = OpTypePointer StorageBuffer %half
+         %49 = OpConstantNull %uint
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+%load_u_inner = OpFunction %mat3v2half None %10
+         %12 = OpLabel
+         %18 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0
+         %19 = OpLoad %v2half %18
+         %22 = OpAccessChain %_ptr_Uniform_v2half %u %uint_1
+         %23 = OpLoad %v2half %22
+         %26 = OpAccessChain %_ptr_Uniform_v2half %u %uint_2
+         %27 = OpLoad %v2half %26
+         %28 = OpCompositeConstruct %mat3v2half %19 %23 %27
+               OpReturnValue %28
+               OpFunctionEnd
+          %f = OpFunction %void None %29
+         %32 = OpLabel
+         %34 = OpAccessChain %_ptr_StorageBuffer_mat3v2half %s %uint_0
+         %35 = OpFunctionCall %mat3v2half %load_u_inner
+               OpStore %34 %35
+         %39 = OpAccessChain %_ptr_StorageBuffer_v2half %s %uint_0 %int_1
+         %40 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0
+         %41 = OpLoad %v2half %40
+               OpStore %39 %41
+         %42 = OpAccessChain %_ptr_StorageBuffer_v2half %s %uint_0 %int_1
+         %43 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0
+         %44 = OpLoad %v2half %43
+         %45 = OpVectorShuffle %v2half %44 %44 1 0
+               OpStore %42 %45
+         %48 = OpAccessChain %_ptr_StorageBuffer_half %s %uint_0 %46 %int_1
+         %51 = OpAccessChain %_ptr_Uniform_half %u %uint_1 %49
+         %52 = OpLoad %half %51
+               OpStore %48 %52
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..74831c6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat3x2<f16>;
+
+@group(0) @binding(1) var<storage, read_write> s : mat3x2<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[0];
+  s[1] = u[0].yx;
+  s[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_workgroup.wgsl
new file mode 100644
index 0000000..6128796
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_workgroup.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat3x2<f16>;
+var<workgroup> w : mat3x2<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[0];
+    w[1] = u[0].yx;
+    w[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_workgroup.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..2b66c9a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_workgroup.wgsl.expected.dxc.hlsl
@@ -0,0 +1,37 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+groupshared matrix<float16_t, 3, 2> w;
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 3, 2> tint_symbol_2(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  return matrix<float16_t, 3, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))));
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    w = matrix<float16_t, 3, 2>((float16_t(0.0h)).xx, (float16_t(0.0h)).xx, (float16_t(0.0h)).xx);
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  uint ubo_load_3 = u[0].x;
+  w[1] = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16)));
+  uint ubo_load_4 = u[0].x;
+  w[1] = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16))).yx;
+  w[0][1] = float16_t(f16tof32(((u[0].y) & 0xFFFF)));
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_workgroup.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..ed15e19
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_workgroup.wgsl.expected.fxc.hlsl
@@ -0,0 +1,42 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+groupshared matrix<float16_t, 3, 2> w;
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 3, 2> tint_symbol_2(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  return matrix<float16_t, 3, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))));
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    w = matrix<float16_t, 3, 2>((float16_t(0.0h)).xx, (float16_t(0.0h)).xx, (float16_t(0.0h)).xx);
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  uint ubo_load_3 = u[0].x;
+  w[1] = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16)));
+  uint ubo_load_4 = u[0].x;
+  w[1] = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16))).yx;
+  w[0][1] = float16_t(f16tof32(((u[0].y) & 0xFFFF)));
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000020735C921C0(4,20-28): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..aafa15e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,30 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec2 inner_0;
+  f16vec2 inner_1;
+  f16vec2 inner_2;
+} u;
+
+shared f16mat3x2 w;
+f16mat3x2 load_u_inner() {
+  return f16mat3x2(u.inner_0, u.inner_1, u.inner_2);
+}
+
+void f(uint local_invocation_index) {
+  {
+    w = f16mat3x2(f16vec2(0.0hf), f16vec2(0.0hf), f16vec2(0.0hf));
+  }
+  barrier();
+  w = load_u_inner();
+  w[1] = u.inner_0;
+  w[1] = u.inner_0.yx;
+  w[0][1] = u.inner_1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..bfd1bb3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,24 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct tint_symbol_5 {
+  half3x2 w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup half3x2* const tint_symbol, const constant half3x2* const tint_symbol_1) {
+  {
+    *(tint_symbol) = half3x2(half2(0.0h), half2(0.0h), half2(0.0h));
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[0];
+  (*(tint_symbol))[1] = half2((*(tint_symbol_1))[0]).yx;
+  (*(tint_symbol))[0][1] = (*(tint_symbol_1))[1][0];
+}
+
+kernel void f(const constant half3x2* tint_symbol_4 [[buffer(0)]], threadgroup tint_symbol_5* tint_symbol_3 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup half3x2* const tint_symbol_2 = &((*(tint_symbol_3)).w);
+  f_inner(local_invocation_index, tint_symbol_2, tint_symbol_4);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_workgroup.wgsl.expected.spvasm
new file mode 100644
index 0000000..036e270
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_workgroup.wgsl.expected.spvasm
@@ -0,0 +1,99 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 61
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %local_invocation_index_1 "local_invocation_index_1"
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpMemberName %u_block_std140 2 "inner_2"
+               OpName %u "u"
+               OpName %w "w"
+               OpName %load_u_inner "load_u_inner"
+               OpName %f_inner "f_inner"
+               OpName %local_invocation_index "local_invocation_index"
+               OpName %f "f"
+               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 4
+               OpMemberDecorate %u_block_std140 2 Offset 8
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+%u_block_std140 = OpTypeStruct %v2half %v2half %v2half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat3v2half = OpTypeMatrix %v2half 3
+%_ptr_Workgroup_mat3v2half = OpTypePointer Workgroup %mat3v2half
+          %w = OpVariable %_ptr_Workgroup_mat3v2half Workgroup
+         %12 = OpTypeFunction %mat3v2half
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+       %void = OpTypeVoid
+         %30 = OpTypeFunction %void %uint
+         %35 = OpConstantNull %mat3v2half
+   %uint_264 = OpConstant %uint 264
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Workgroup_v2half = OpTypePointer Workgroup %v2half
+         %49 = OpConstantNull %int
+%_ptr_Workgroup_half = OpTypePointer Workgroup %half
+         %52 = OpConstantNull %uint
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+         %56 = OpTypeFunction %void
+%load_u_inner = OpFunction %mat3v2half None %12
+         %14 = OpLabel
+         %19 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0
+         %20 = OpLoad %v2half %19
+         %23 = OpAccessChain %_ptr_Uniform_v2half %u %uint_1
+         %24 = OpLoad %v2half %23
+         %27 = OpAccessChain %_ptr_Uniform_v2half %u %uint_2
+         %28 = OpLoad %v2half %27
+         %29 = OpCompositeConstruct %mat3v2half %20 %24 %28
+               OpReturnValue %29
+               OpFunctionEnd
+    %f_inner = OpFunction %void None %30
+%local_invocation_index = OpFunctionParameter %uint
+         %34 = OpLabel
+               OpStore %w %35
+               OpControlBarrier %uint_2 %uint_2 %uint_264
+         %38 = OpFunctionCall %mat3v2half %load_u_inner
+               OpStore %w %38
+         %42 = OpAccessChain %_ptr_Workgroup_v2half %w %int_1
+         %43 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0
+         %44 = OpLoad %v2half %43
+               OpStore %42 %44
+         %45 = OpAccessChain %_ptr_Workgroup_v2half %w %int_1
+         %46 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0
+         %47 = OpLoad %v2half %46
+         %48 = OpVectorShuffle %v2half %47 %47 1 0
+               OpStore %45 %48
+         %51 = OpAccessChain %_ptr_Workgroup_half %w %49 %int_1
+         %54 = OpAccessChain %_ptr_Uniform_half %u %uint_1 %52
+         %55 = OpLoad %half %54
+               OpStore %51 %55
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %56
+         %58 = OpLabel
+         %60 = OpLoad %uint %local_invocation_index_1
+         %59 = OpFunctionCall %void %f_inner %60
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..b7f4955
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x2_f16/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat3x2<f16>;
+
+var<workgroup> w : mat3x2<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[0];
+  w[1] = u[0].yx;
+  w[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/dynamic_index_via_ptr.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/dynamic_index_via_ptr.wgsl
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/dynamic_index_via_ptr.wgsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/dynamic_index_via_ptr.wgsl.expected.glsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/dynamic_index_via_ptr.wgsl.expected.glsl
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/dynamic_index_via_ptr.wgsl.expected.glsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/dynamic_index_via_ptr.wgsl.expected.msl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/dynamic_index_via_ptr.wgsl.expected.msl
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/dynamic_index_via_ptr.wgsl.expected.msl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/dynamic_index_via_ptr.wgsl.expected.spvasm
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/dynamic_index_via_ptr.wgsl.expected.wgsl
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/static_index_via_ptr.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/static_index_via_ptr.wgsl
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/static_index_via_ptr.wgsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/static_index_via_ptr.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/static_index_via_ptr.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/static_index_via_ptr.wgsl.expected.glsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/static_index_via_ptr.wgsl.expected.glsl
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/static_index_via_ptr.wgsl.expected.glsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/static_index_via_ptr.wgsl.expected.msl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/static_index_via_ptr.wgsl.expected.msl
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/static_index_via_ptr.wgsl.expected.msl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/static_index_via_ptr.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/static_index_via_ptr.wgsl.expected.spvasm
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/static_index_via_ptr.wgsl.expected.spvasm
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/static_index_via_ptr.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/static_index_via_ptr.wgsl.expected.wgsl
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/static_index_via_ptr.wgsl.expected.wgsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/to_builtin.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_builtin.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/to_builtin.wgsl
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_builtin.wgsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_builtin.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/to_builtin.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_builtin.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_builtin.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/to_builtin.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_builtin.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_builtin.wgsl.expected.glsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/to_builtin.wgsl.expected.glsl
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_builtin.wgsl.expected.glsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_builtin.wgsl.expected.msl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/to_builtin.wgsl.expected.msl
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_builtin.wgsl.expected.msl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_builtin.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/to_builtin.wgsl.expected.spvasm
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_builtin.wgsl.expected.spvasm
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_builtin.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/to_builtin.wgsl.expected.wgsl
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_builtin.wgsl.expected.wgsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/to_fn.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_fn.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/to_fn.wgsl
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_fn.wgsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_fn.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/to_fn.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_fn.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_fn.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/to_fn.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_fn.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_fn.wgsl.expected.glsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/to_fn.wgsl.expected.glsl
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_fn.wgsl.expected.glsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_fn.wgsl.expected.msl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/to_fn.wgsl.expected.msl
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_fn.wgsl.expected.msl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_fn.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/to_fn.wgsl.expected.spvasm
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_fn.wgsl.expected.spvasm
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_fn.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/to_fn.wgsl.expected.wgsl
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_fn.wgsl.expected.wgsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/to_private.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_private.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/to_private.wgsl
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_private.wgsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_private.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/to_private.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_private.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_private.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/to_private.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_private.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_private.wgsl.expected.glsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/to_private.wgsl.expected.glsl
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_private.wgsl.expected.glsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_private.wgsl.expected.msl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/to_private.wgsl.expected.msl
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_private.wgsl.expected.msl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_private.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/to_private.wgsl.expected.spvasm
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_private.wgsl.expected.spvasm
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_private.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/to_private.wgsl.expected.wgsl
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_private.wgsl.expected.wgsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/to_storage.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_storage.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/to_storage.wgsl
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_storage.wgsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_storage.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/to_storage.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_storage.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_storage.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/to_storage.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_storage.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_storage.wgsl.expected.glsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/to_storage.wgsl.expected.glsl
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_storage.wgsl.expected.glsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_storage.wgsl.expected.msl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/to_storage.wgsl.expected.msl
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_storage.wgsl.expected.msl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_storage.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/to_storage.wgsl.expected.spvasm
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_storage.wgsl.expected.spvasm
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_storage.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/to_storage.wgsl.expected.wgsl
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_storage.wgsl.expected.wgsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_workgroup.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/to_workgroup.wgsl
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_workgroup.wgsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_workgroup.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/to_workgroup.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_workgroup.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_workgroup.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/to_workgroup.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_workgroup.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_workgroup.wgsl.expected.glsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/to_workgroup.wgsl.expected.glsl
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_workgroup.wgsl.expected.glsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_workgroup.wgsl.expected.msl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/to_workgroup.wgsl.expected.msl
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_workgroup.wgsl.expected.msl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_workgroup.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/to_workgroup.wgsl.expected.spvasm
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_workgroup.wgsl.expected.spvasm
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x2/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_workgroup.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat3x2/to_workgroup.wgsl.expected.wgsl
rename to test/tint/buffer/uniform/std140/unnested/mat3x2_f32/to_workgroup.wgsl.expected.wgsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/dynamic_index_via_ptr.wgsl
new file mode 100644
index 0000000..470248a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/dynamic_index_via_ptr.wgsl
@@ -0,0 +1,15 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> m : mat3x3<f16>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m   = &m;
+  let p_m_i = &((*p_m)[i()]);
+
+  let l_m   : mat3x3<f16> = *p_m;
+  let l_m_i : vec3<f16>   = *p_m_i;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..9e97415
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,41 @@
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[2];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 3, 3> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  return matrix<float16_t, 3, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_m_i_save = i();
+  const matrix<float16_t, 3, 3> l_m = tint_symbol(m, 0u);
+  const uint scalar_offset_3 = ((8u * uint(p_m_i_save))) / 4;
+  uint4 ubo_load_7 = m[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  const vector<float16_t, 3> l_m_i = vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..dd2a0ab
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,46 @@
+SKIP: FAILED
+
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[2];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 3, 3> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  return matrix<float16_t, 3, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_m_i_save = i();
+  const matrix<float16_t, 3, 3> l_m = tint_symbol(m, 0u);
+  const uint scalar_offset_3 = ((8u * uint(p_m_i_save))) / 4;
+  uint4 ubo_load_7 = m[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  const vector<float16_t, 3> l_m_i = vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001F17CCCC790(11,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/dynamic_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..eecfed8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,53 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform m_block_std140_ubo {
+  f16vec3 inner_0;
+  f16vec3 inner_1;
+  f16vec3 inner_2;
+} m;
+
+int counter = 0;
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+f16mat3 load_m_inner() {
+  return f16mat3(m.inner_0, m.inner_1, m.inner_2);
+}
+
+f16vec3 load_m_inner_p0(uint p0) {
+  switch(p0) {
+    case 0u: {
+      return m.inner_0;
+      break;
+    }
+    case 1u: {
+      return m.inner_1;
+      break;
+    }
+    case 2u: {
+      return m.inner_2;
+      break;
+    }
+    default: {
+      return f16vec3(0.0hf);
+      break;
+    }
+  }
+}
+
+void f() {
+  f16mat3 p_m = load_m_inner();
+  int tint_symbol = i();
+  f16vec3 p_m_i = load_m_inner_p0(uint(tint_symbol));
+  f16mat3 l_m = load_m_inner();
+  f16vec3 l_m_i = load_m_inner_p0(uint(tint_symbol));
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/dynamic_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..7d5c27c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/dynamic_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,17 @@
+#include <metal_stdlib>
+
+using namespace metal;
+int i() {
+  thread int tint_symbol_1 = 0;
+  tint_symbol_1 = as_type<int>((as_type<uint>(tint_symbol_1) + as_type<uint>(1)));
+  return tint_symbol_1;
+}
+
+kernel void f(const constant half3x3* tint_symbol_2 [[buffer(0)]]) {
+  int const tint_symbol = i();
+  int const p_m_i_save = tint_symbol;
+  half3x3 const l_m = *(tint_symbol_2);
+  half3 const l_m_i = (*(tint_symbol_2))[p_m_i_save];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..e158133
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,102 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 61
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %m_block_std140 "m_block_std140"
+               OpMemberName %m_block_std140 0 "inner_0"
+               OpMemberName %m_block_std140 1 "inner_1"
+               OpMemberName %m_block_std140 2 "inner_2"
+               OpName %m "m"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %load_m_inner "load_m_inner"
+               OpName %load_m_inner_p0 "load_m_inner_p0"
+               OpName %p0 "p0"
+               OpName %f "f"
+               OpDecorate %m_block_std140 Block
+               OpMemberDecorate %m_block_std140 0 Offset 0
+               OpMemberDecorate %m_block_std140 1 Offset 8
+               OpMemberDecorate %m_block_std140 2 Offset 16
+               OpDecorate %m NonWritable
+               OpDecorate %m DescriptorSet 0
+               OpDecorate %m Binding 0
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+%m_block_std140 = OpTypeStruct %v3half %v3half %v3half
+%_ptr_Uniform_m_block_std140 = OpTypePointer Uniform %m_block_std140
+          %m = OpVariable %_ptr_Uniform_m_block_std140 Uniform
+        %int = OpTypeInt 32 1
+          %7 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %7
+         %10 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+ %mat3v3half = OpTypeMatrix %v3half 3
+         %17 = OpTypeFunction %mat3v3half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+         %37 = OpTypeFunction %v3half %uint
+         %52 = OpConstantNull %v3half
+       %void = OpTypeVoid
+         %53 = OpTypeFunction %void
+          %i = OpFunction %int None %10
+         %12 = OpLabel
+         %13 = OpLoad %int %counter
+         %15 = OpIAdd %int %13 %int_1
+               OpStore %counter %15
+         %16 = OpLoad %int %counter
+               OpReturnValue %16
+               OpFunctionEnd
+%load_m_inner = OpFunction %mat3v3half None %17
+         %20 = OpLabel
+         %26 = OpAccessChain %_ptr_Uniform_v3half %m %uint_0
+         %27 = OpLoad %v3half %26
+         %30 = OpAccessChain %_ptr_Uniform_v3half %m %uint_1
+         %31 = OpLoad %v3half %30
+         %34 = OpAccessChain %_ptr_Uniform_v3half %m %uint_2
+         %35 = OpLoad %v3half %34
+         %36 = OpCompositeConstruct %mat3v3half %27 %31 %35
+               OpReturnValue %36
+               OpFunctionEnd
+%load_m_inner_p0 = OpFunction %v3half None %37
+         %p0 = OpFunctionParameter %uint
+         %40 = OpLabel
+               OpSelectionMerge %41 None
+               OpSwitch %p0 %42 0 %43 1 %44 2 %45
+         %43 = OpLabel
+         %46 = OpAccessChain %_ptr_Uniform_v3half %m %uint_0
+         %47 = OpLoad %v3half %46
+               OpReturnValue %47
+         %44 = OpLabel
+         %48 = OpAccessChain %_ptr_Uniform_v3half %m %uint_1
+         %49 = OpLoad %v3half %48
+               OpReturnValue %49
+         %45 = OpLabel
+         %50 = OpAccessChain %_ptr_Uniform_v3half %m %uint_2
+         %51 = OpLoad %v3half %50
+               OpReturnValue %51
+         %42 = OpLabel
+               OpReturnValue %52
+         %41 = OpLabel
+               OpReturnValue %52
+               OpFunctionEnd
+          %f = OpFunction %void None %53
+         %56 = OpLabel
+         %57 = OpFunctionCall %int %i
+         %58 = OpFunctionCall %mat3v3half %load_m_inner
+         %60 = OpBitcast %uint %57
+         %59 = OpFunctionCall %v3half %load_m_inner_p0 %60
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..df87b72
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> m : mat3x3<f16>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m = &(m);
+  let p_m_i = &((*(p_m))[i()]);
+  let l_m : mat3x3<f16> = *(p_m);
+  let l_m_i : vec3<f16> = *(p_m_i);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/static_index_via_ptr.wgsl
new file mode 100644
index 0000000..81de27a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/static_index_via_ptr.wgsl
@@ -0,0 +1,15 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> m : mat3x3<f16>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m   = &m;
+  let p_m_1 = &((*p_m)[1]);
+
+  let l_m   : mat3x3<f16> = *p_m;
+  let l_m_1 : vec3<f16>   = *p_m_1;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..f1b227c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,38 @@
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[2];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 3, 3> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  return matrix<float16_t, 3, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 3, 3> l_m = tint_symbol(m, 0u);
+  uint2 ubo_load_6 = m[0].zw;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  const vector<float16_t, 3> l_m_1 = vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..fa7dc22
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,43 @@
+SKIP: FAILED
+
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[2];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 3, 3> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  return matrix<float16_t, 3, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 3, 3> l_m = tint_symbol(m, 0u);
+  uint2 ubo_load_6 = m[0].zw;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  const vector<float16_t, 3> l_m_1 = vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001DA8C8147C0(11,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/static_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..2104f3b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/static_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,25 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform m_block_std140_ubo {
+  f16vec3 inner_0;
+  f16vec3 inner_1;
+  f16vec3 inner_2;
+} m;
+
+f16mat3 load_m_inner() {
+  return f16mat3(m.inner_0, m.inner_1, m.inner_2);
+}
+
+void f() {
+  f16mat3 p_m = load_m_inner();
+  f16vec3 p_m_1 = m.inner_1;
+  f16mat3 l_m = load_m_inner();
+  f16vec3 l_m_1 = m.inner_1;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/static_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..8950017
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/static_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,15 @@
+#include <metal_stdlib>
+
+using namespace metal;
+int i() {
+  thread int tint_symbol = 0;
+  tint_symbol = as_type<int>((as_type<uint>(tint_symbol) + as_type<uint>(1)));
+  return tint_symbol;
+}
+
+kernel void f(const constant half3x3* tint_symbol_1 [[buffer(0)]]) {
+  half3x3 const l_m = *(tint_symbol_1);
+  half3 const l_m_1 = (*(tint_symbol_1))[1];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/static_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..2a58a57
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/static_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,75 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 44
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %m_block_std140 "m_block_std140"
+               OpMemberName %m_block_std140 0 "inner_0"
+               OpMemberName %m_block_std140 1 "inner_1"
+               OpMemberName %m_block_std140 2 "inner_2"
+               OpName %m "m"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %load_m_inner "load_m_inner"
+               OpName %f "f"
+               OpDecorate %m_block_std140 Block
+               OpMemberDecorate %m_block_std140 0 Offset 0
+               OpMemberDecorate %m_block_std140 1 Offset 8
+               OpMemberDecorate %m_block_std140 2 Offset 16
+               OpDecorate %m NonWritable
+               OpDecorate %m DescriptorSet 0
+               OpDecorate %m Binding 0
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+%m_block_std140 = OpTypeStruct %v3half %v3half %v3half
+%_ptr_Uniform_m_block_std140 = OpTypePointer Uniform %m_block_std140
+          %m = OpVariable %_ptr_Uniform_m_block_std140 Uniform
+        %int = OpTypeInt 32 1
+          %7 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %7
+         %10 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+ %mat3v3half = OpTypeMatrix %v3half 3
+         %17 = OpTypeFunction %mat3v3half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+       %void = OpTypeVoid
+         %37 = OpTypeFunction %void
+          %i = OpFunction %int None %10
+         %12 = OpLabel
+         %13 = OpLoad %int %counter
+         %15 = OpIAdd %int %13 %int_1
+               OpStore %counter %15
+         %16 = OpLoad %int %counter
+               OpReturnValue %16
+               OpFunctionEnd
+%load_m_inner = OpFunction %mat3v3half None %17
+         %20 = OpLabel
+         %26 = OpAccessChain %_ptr_Uniform_v3half %m %uint_0
+         %27 = OpLoad %v3half %26
+         %30 = OpAccessChain %_ptr_Uniform_v3half %m %uint_1
+         %31 = OpLoad %v3half %30
+         %34 = OpAccessChain %_ptr_Uniform_v3half %m %uint_2
+         %35 = OpLoad %v3half %34
+         %36 = OpCompositeConstruct %mat3v3half %27 %31 %35
+               OpReturnValue %36
+               OpFunctionEnd
+          %f = OpFunction %void None %37
+         %40 = OpLabel
+         %41 = OpFunctionCall %mat3v3half %load_m_inner
+         %42 = OpAccessChain %_ptr_Uniform_v3half %m %uint_1
+         %43 = OpLoad %v3half %42
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/static_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..25749f7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/static_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> m : mat3x3<f16>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m = &(m);
+  let p_m_1 = &((*(p_m))[1]);
+  let l_m : mat3x3<f16> = *(p_m);
+  let l_m_1 : vec3<f16> = *(p_m_1);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_builtin.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_builtin.wgsl
new file mode 100644
index 0000000..9650ea6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_builtin.wgsl
@@ -0,0 +1,10 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat3x3<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+    let t = transpose(u);
+    let l = length(u[1]);
+    let a = abs(u[0].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_builtin.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..437c9aa
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_builtin.wgsl.expected.dxc.hlsl
@@ -0,0 +1,36 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+
+matrix<float16_t, 3, 3> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  return matrix<float16_t, 3, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 3, 3> t = transpose(tint_symbol(u, 0u));
+  uint2 ubo_load_6 = u[0].zw;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  const float16_t l = length(vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+  uint2 ubo_load_7 = u[0].xy;
+  vector<float16_t, 2> ubo_load_7_xz = vector<float16_t, 2>(f16tof32(ubo_load_7 & 0xFFFF));
+  float16_t ubo_load_7_y = f16tof32(ubo_load_7[0] >> 16);
+  const float16_t a = abs(vector<float16_t, 3>(ubo_load_7_xz[0], ubo_load_7_y, ubo_load_7_xz[1]).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_builtin.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..b0bfbfc
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_builtin.wgsl.expected.fxc.hlsl
@@ -0,0 +1,41 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+
+matrix<float16_t, 3, 3> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  return matrix<float16_t, 3, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 3, 3> t = transpose(tint_symbol(u, 0u));
+  uint2 ubo_load_6 = u[0].zw;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  const float16_t l = length(vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+  uint2 ubo_load_7 = u[0].xy;
+  vector<float16_t, 2> ubo_load_7_xz = vector<float16_t, 2>(f16tof32(ubo_load_7 & 0xFFFF));
+  float16_t ubo_load_7_y = f16tof32(ubo_load_7[0] >> 16);
+  const float16_t a = abs(vector<float16_t, 3>(ubo_load_7_xz[0], ubo_load_7_y, ubo_load_7_xz[1]).zxy.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x00000233E8349550(5,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_builtin.wgsl.expected.glsl
new file mode 100644
index 0000000..fddaa3c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_builtin.wgsl.expected.glsl
@@ -0,0 +1,24 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec3 inner_0;
+  f16vec3 inner_1;
+  f16vec3 inner_2;
+} u;
+
+f16mat3 load_u_inner() {
+  return f16mat3(u.inner_0, u.inner_1, u.inner_2);
+}
+
+void f() {
+  f16mat3 t = transpose(load_u_inner());
+  float16_t l = length(u.inner_1);
+  float16_t a = abs(u.inner_0.zxy[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_builtin.wgsl.expected.msl
new file mode 100644
index 0000000..3b7e954
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_builtin.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f(const constant half3x3* tint_symbol [[buffer(0)]]) {
+  half3x3 const t = transpose(*(tint_symbol));
+  half const l = length((*(tint_symbol))[1]);
+  half const a = fabs(half3((*(tint_symbol))[0]).zxy[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_builtin.wgsl.expected.spvasm
new file mode 100644
index 0000000..663829b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_builtin.wgsl.expected.spvasm
@@ -0,0 +1,68 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 42
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+         %33 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpMemberName %u_block_std140 2 "inner_2"
+               OpName %u "u"
+               OpName %load_u_inner "load_u_inner"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 8
+               OpMemberDecorate %u_block_std140 2 Offset 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+%u_block_std140 = OpTypeStruct %v3half %v3half %v3half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat3v3half = OpTypeMatrix %v3half 3
+          %6 = OpTypeFunction %mat3v3half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+       %void = OpTypeVoid
+         %26 = OpTypeFunction %void
+         %40 = OpConstantNull %uint
+%load_u_inner = OpFunction %mat3v3half None %6
+          %9 = OpLabel
+         %15 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0
+         %16 = OpLoad %v3half %15
+         %19 = OpAccessChain %_ptr_Uniform_v3half %u %uint_1
+         %20 = OpLoad %v3half %19
+         %23 = OpAccessChain %_ptr_Uniform_v3half %u %uint_2
+         %24 = OpLoad %v3half %23
+         %25 = OpCompositeConstruct %mat3v3half %16 %20 %24
+               OpReturnValue %25
+               OpFunctionEnd
+          %f = OpFunction %void None %26
+         %29 = OpLabel
+         %31 = OpFunctionCall %mat3v3half %load_u_inner
+         %30 = OpTranspose %mat3v3half %31
+         %34 = OpAccessChain %_ptr_Uniform_v3half %u %uint_1
+         %35 = OpLoad %v3half %34
+         %32 = OpExtInst %half %33 Length %35
+         %37 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0
+         %38 = OpLoad %v3half %37
+         %39 = OpVectorShuffle %v3half %38 %38 2 0 1
+         %41 = OpCompositeExtract %half %39 0
+         %36 = OpExtInst %half %33 FAbs %41
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_builtin.wgsl.expected.wgsl
new file mode 100644
index 0000000..e0a64f6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_builtin.wgsl.expected.wgsl
@@ -0,0 +1,10 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat3x3<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let t = transpose(u);
+  let l = length(u[1]);
+  let a = abs(u[0].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_fn.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_fn.wgsl
new file mode 100644
index 0000000..37f0a59
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_fn.wgsl
@@ -0,0 +1,16 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat3x3<f16>;
+
+fn a(m : mat3x3<f16>) {}
+fn b(v : vec3<f16>) {}
+fn c(f : f16) {}
+
+@compute @workgroup_size(1)
+fn f() {
+    a(u);
+    b(u[1]);
+    b(u[1].zxy);
+    c(u[1].x);
+    c(u[1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_fn.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..a6528bd
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_fn.wgsl.expected.dxc.hlsl
@@ -0,0 +1,50 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+
+void a(matrix<float16_t, 3, 3> m) {
+}
+
+void b(vector<float16_t, 3> v) {
+}
+
+void c(float16_t f_1) {
+}
+
+matrix<float16_t, 3, 3> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  return matrix<float16_t, 3, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  uint2 ubo_load_6 = u[0].zw;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  b(vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+  uint2 ubo_load_7 = u[0].zw;
+  vector<float16_t, 2> ubo_load_7_xz = vector<float16_t, 2>(f16tof32(ubo_load_7 & 0xFFFF));
+  float16_t ubo_load_7_y = f16tof32(ubo_load_7[0] >> 16);
+  b(vector<float16_t, 3>(ubo_load_7_xz[0], ubo_load_7_y, ubo_load_7_xz[1]).zxy);
+  c(float16_t(f16tof32(((u[0].z) & 0xFFFF))));
+  uint2 ubo_load_8 = u[0].zw;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  float16_t ubo_load_8_y = f16tof32(ubo_load_8[0] >> 16);
+  c(vector<float16_t, 3>(ubo_load_8_xz[0], ubo_load_8_y, ubo_load_8_xz[1]).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_fn.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..88bb888
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_fn.wgsl.expected.fxc.hlsl
@@ -0,0 +1,57 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+
+void a(matrix<float16_t, 3, 3> m) {
+}
+
+void b(vector<float16_t, 3> v) {
+}
+
+void c(float16_t f_1) {
+}
+
+matrix<float16_t, 3, 3> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  return matrix<float16_t, 3, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  uint2 ubo_load_6 = u[0].zw;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  b(vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+  uint2 ubo_load_7 = u[0].zw;
+  vector<float16_t, 2> ubo_load_7_xz = vector<float16_t, 2>(f16tof32(ubo_load_7 & 0xFFFF));
+  float16_t ubo_load_7_y = f16tof32(ubo_load_7[0] >> 16);
+  b(vector<float16_t, 3>(ubo_load_7_xz[0], ubo_load_7_y, ubo_load_7_xz[1]).zxy);
+  c(float16_t(f16tof32(((u[0].z) & 0xFFFF))));
+  uint2 ubo_load_8 = u[0].zw;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  float16_t ubo_load_8_y = f16tof32(ubo_load_8[0] >> 16);
+  c(vector<float16_t, 3>(ubo_load_8_xz[0], ubo_load_8_y, ubo_load_8_xz[1]).zxy.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000024400654510(5,15-23): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000024400654510(8,15-23): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000024400654510(11,8-16): error X3000: unrecognized identifier 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_fn.wgsl.expected.glsl
new file mode 100644
index 0000000..5bf5833
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_fn.wgsl.expected.glsl
@@ -0,0 +1,35 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec3 inner_0;
+  f16vec3 inner_1;
+  f16vec3 inner_2;
+} u;
+
+void a(f16mat3 m) {
+}
+
+void b(f16vec3 v) {
+}
+
+void c(float16_t f_1) {
+}
+
+f16mat3 load_u_inner() {
+  return f16mat3(u.inner_0, u.inner_1, u.inner_2);
+}
+
+void f() {
+  a(load_u_inner());
+  b(u.inner_1);
+  b(u.inner_1.zxy);
+  c(u.inner_1[0u]);
+  c(u.inner_1.zxy[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_fn.wgsl.expected.msl
new file mode 100644
index 0000000..3ae8932
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_fn.wgsl.expected.msl
@@ -0,0 +1,21 @@
+#include <metal_stdlib>
+
+using namespace metal;
+void a(half3x3 m) {
+}
+
+void b(half3 v) {
+}
+
+void c(half f_1) {
+}
+
+kernel void f(const constant half3x3* tint_symbol [[buffer(0)]]) {
+  a(*(tint_symbol));
+  b((*(tint_symbol))[1]);
+  b(half3((*(tint_symbol))[1]).zxy);
+  c((*(tint_symbol))[1][0]);
+  c(half3((*(tint_symbol))[1]).zxy[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_fn.wgsl.expected.spvasm
new file mode 100644
index 0000000..e2590e2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_fn.wgsl.expected.spvasm
@@ -0,0 +1,99 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 61
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpMemberName %u_block_std140 2 "inner_2"
+               OpName %u "u"
+               OpName %a "a"
+               OpName %m "m"
+               OpName %b "b"
+               OpName %v "v"
+               OpName %c "c"
+               OpName %f_1 "f_1"
+               OpName %load_u_inner "load_u_inner"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 8
+               OpMemberDecorate %u_block_std140 2 Offset 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+%u_block_std140 = OpTypeStruct %v3half %v3half %v3half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+       %void = OpTypeVoid
+ %mat3v3half = OpTypeMatrix %v3half 3
+          %6 = OpTypeFunction %void %mat3v3half
+         %12 = OpTypeFunction %void %v3half
+         %16 = OpTypeFunction %void %half
+         %20 = OpTypeFunction %mat3v3half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+         %39 = OpTypeFunction %void
+         %52 = OpConstantNull %uint
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+          %a = OpFunction %void None %6
+          %m = OpFunctionParameter %mat3v3half
+         %11 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %b = OpFunction %void None %12
+          %v = OpFunctionParameter %v3half
+         %15 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %c = OpFunction %void None %16
+        %f_1 = OpFunctionParameter %half
+         %19 = OpLabel
+               OpReturn
+               OpFunctionEnd
+%load_u_inner = OpFunction %mat3v3half None %20
+         %22 = OpLabel
+         %28 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0
+         %29 = OpLoad %v3half %28
+         %32 = OpAccessChain %_ptr_Uniform_v3half %u %uint_1
+         %33 = OpLoad %v3half %32
+         %36 = OpAccessChain %_ptr_Uniform_v3half %u %uint_2
+         %37 = OpLoad %v3half %36
+         %38 = OpCompositeConstruct %mat3v3half %29 %33 %37
+               OpReturnValue %38
+               OpFunctionEnd
+          %f = OpFunction %void None %39
+         %41 = OpLabel
+         %43 = OpFunctionCall %mat3v3half %load_u_inner
+         %42 = OpFunctionCall %void %a %43
+         %45 = OpAccessChain %_ptr_Uniform_v3half %u %uint_1
+         %46 = OpLoad %v3half %45
+         %44 = OpFunctionCall %void %b %46
+         %48 = OpAccessChain %_ptr_Uniform_v3half %u %uint_1
+         %49 = OpLoad %v3half %48
+         %50 = OpVectorShuffle %v3half %49 %49 2 0 1
+         %47 = OpFunctionCall %void %b %50
+         %54 = OpAccessChain %_ptr_Uniform_half %u %uint_1 %52
+         %55 = OpLoad %half %54
+         %51 = OpFunctionCall %void %c %55
+         %57 = OpAccessChain %_ptr_Uniform_v3half %u %uint_1
+         %58 = OpLoad %v3half %57
+         %59 = OpVectorShuffle %v3half %58 %58 2 0 1
+         %60 = OpCompositeExtract %half %59 0
+         %56 = OpFunctionCall %void %c %60
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_fn.wgsl.expected.wgsl
new file mode 100644
index 0000000..191c69a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_fn.wgsl.expected.wgsl
@@ -0,0 +1,21 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat3x3<f16>;
+
+fn a(m : mat3x3<f16>) {
+}
+
+fn b(v : vec3<f16>) {
+}
+
+fn c(f : f16) {
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  a(u);
+  b(u[1]);
+  b(u[1].zxy);
+  c(u[1].x);
+  c(u[1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_private.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_private.wgsl
new file mode 100644
index 0000000..6c80a59
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_private.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat3x3<f16>;
+var<private> p : mat3x3<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[0];
+    p[1] = u[0].zxy;
+    p[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_private.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..fe3d739
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_private.wgsl.expected.dxc.hlsl
@@ -0,0 +1,38 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+static matrix<float16_t, 3, 3> p = matrix<float16_t, 3, 3>(float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h));
+
+matrix<float16_t, 3, 3> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  return matrix<float16_t, 3, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  uint2 ubo_load_6 = u[0].xy;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  p[1] = vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]);
+  uint2 ubo_load_7 = u[0].xy;
+  vector<float16_t, 2> ubo_load_7_xz = vector<float16_t, 2>(f16tof32(ubo_load_7 & 0xFFFF));
+  float16_t ubo_load_7_y = f16tof32(ubo_load_7[0] >> 16);
+  p[1] = vector<float16_t, 3>(ubo_load_7_xz[0], ubo_load_7_y, ubo_load_7_xz[1]).zxy;
+  p[0][1] = float16_t(f16tof32(((u[0].z) & 0xFFFF)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_private.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..51b24ed
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_private.wgsl.expected.fxc.hlsl
@@ -0,0 +1,43 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+static matrix<float16_t, 3, 3> p = matrix<float16_t, 3, 3>(float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h));
+
+matrix<float16_t, 3, 3> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  return matrix<float16_t, 3, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  uint2 ubo_load_6 = u[0].xy;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  p[1] = vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]);
+  uint2 ubo_load_7 = u[0].xy;
+  vector<float16_t, 2> ubo_load_7_xz = vector<float16_t, 2>(f16tof32(ubo_load_7 & 0xFFFF));
+  float16_t ubo_load_7_y = f16tof32(ubo_load_7[0] >> 16);
+  p[1] = vector<float16_t, 3>(ubo_load_7_xz[0], ubo_load_7_y, ubo_load_7_xz[1]).zxy;
+  p[0][1] = float16_t(f16tof32(((u[0].z) & 0xFFFF)));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000024859339490(4,15-23): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..6d7d10a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_private.wgsl.expected.glsl
@@ -0,0 +1,26 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec3 inner_0;
+  f16vec3 inner_1;
+  f16vec3 inner_2;
+} u;
+
+f16mat3 p = f16mat3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf);
+f16mat3 load_u_inner() {
+  return f16mat3(u.inner_0, u.inner_1, u.inner_2);
+}
+
+void f() {
+  p = load_u_inner();
+  p[1] = u.inner_0;
+  p[1] = u.inner_0.zxy;
+  p[0][1] = u.inner_1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..7e3877d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_private.wgsl.expected.msl
@@ -0,0 +1,12 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f(const constant half3x3* tint_symbol_1 [[buffer(0)]]) {
+  thread half3x3 tint_symbol = half3x3(0.0h);
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[0];
+  tint_symbol[1] = half3((*(tint_symbol_1))[0]).zxy;
+  tint_symbol[0][1] = (*(tint_symbol_1))[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_private.wgsl.expected.spvasm
new file mode 100644
index 0000000..2e8ef86
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_private.wgsl.expected.spvasm
@@ -0,0 +1,82 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 51
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpMemberName %u_block_std140 2 "inner_2"
+               OpName %u "u"
+               OpName %p "p"
+               OpName %load_u_inner "load_u_inner"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 8
+               OpMemberDecorate %u_block_std140 2 Offset 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+%u_block_std140 = OpTypeStruct %v3half %v3half %v3half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat3v3half = OpTypeMatrix %v3half 3
+%_ptr_Private_mat3v3half = OpTypePointer Private %mat3v3half
+          %9 = OpConstantNull %mat3v3half
+          %p = OpVariable %_ptr_Private_mat3v3half Private %9
+         %10 = OpTypeFunction %mat3v3half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+       %void = OpTypeVoid
+         %29 = OpTypeFunction %void
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Private_v3half = OpTypePointer Private %v3half
+         %44 = OpConstantNull %int
+%_ptr_Private_half = OpTypePointer Private %half
+         %47 = OpConstantNull %uint
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+%load_u_inner = OpFunction %mat3v3half None %10
+         %12 = OpLabel
+         %18 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0
+         %19 = OpLoad %v3half %18
+         %22 = OpAccessChain %_ptr_Uniform_v3half %u %uint_1
+         %23 = OpLoad %v3half %22
+         %26 = OpAccessChain %_ptr_Uniform_v3half %u %uint_2
+         %27 = OpLoad %v3half %26
+         %28 = OpCompositeConstruct %mat3v3half %19 %23 %27
+               OpReturnValue %28
+               OpFunctionEnd
+          %f = OpFunction %void None %29
+         %32 = OpLabel
+         %33 = OpFunctionCall %mat3v3half %load_u_inner
+               OpStore %p %33
+         %37 = OpAccessChain %_ptr_Private_v3half %p %int_1
+         %38 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0
+         %39 = OpLoad %v3half %38
+               OpStore %37 %39
+         %40 = OpAccessChain %_ptr_Private_v3half %p %int_1
+         %41 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0
+         %42 = OpLoad %v3half %41
+         %43 = OpVectorShuffle %v3half %42 %42 2 0 1
+               OpStore %40 %43
+         %46 = OpAccessChain %_ptr_Private_half %p %44 %int_1
+         %49 = OpAccessChain %_ptr_Uniform_half %u %uint_1 %47
+         %50 = OpLoad %half %49
+               OpStore %46 %50
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..50d1f96
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_private.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat3x3<f16>;
+
+var<private> p : mat3x3<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[0];
+  p[1] = u[0].zxy;
+  p[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_storage.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_storage.wgsl
new file mode 100644
index 0000000..b3e56a4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_storage.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat3x3<f16>;
+@group(0) @binding(1) var<storage, read_write> s : mat3x3<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[0];
+    s[1] = u[0].zxy;
+    s[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_storage.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..2a2db34
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_storage.wgsl.expected.dxc.hlsl
@@ -0,0 +1,44 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 3, 3> value) {
+  buffer.Store<vector<float16_t, 3> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 8u), value[1u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 16u), value[2u]);
+}
+
+matrix<float16_t, 3, 3> tint_symbol_2(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  return matrix<float16_t, 3, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_2(u, 0u));
+  uint2 ubo_load_6 = u[0].xy;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  s.Store<vector<float16_t, 3> >(8u, vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+  uint2 ubo_load_7 = u[0].xy;
+  vector<float16_t, 2> ubo_load_7_xz = vector<float16_t, 2>(f16tof32(ubo_load_7 & 0xFFFF));
+  float16_t ubo_load_7_y = f16tof32(ubo_load_7[0] >> 16);
+  s.Store<vector<float16_t, 3> >(8u, vector<float16_t, 3>(ubo_load_7_xz[0], ubo_load_7_y, ubo_load_7_xz[1]).zxy);
+  s.Store<float16_t>(2u, float16_t(f16tof32(((u[0].z) & 0xFFFF))));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_storage.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..b7409a7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_storage.wgsl.expected.fxc.hlsl
@@ -0,0 +1,50 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 3, 3> value) {
+  buffer.Store<vector<float16_t, 3> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 8u), value[1u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 16u), value[2u]);
+}
+
+matrix<float16_t, 3, 3> tint_symbol_2(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  return matrix<float16_t, 3, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_2(u, 0u));
+  uint2 ubo_load_6 = u[0].xy;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  s.Store<vector<float16_t, 3> >(8u, vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+  uint2 ubo_load_7 = u[0].xy;
+  vector<float16_t, 2> ubo_load_7_xz = vector<float16_t, 2>(f16tof32(ubo_load_7 & 0xFFFF));
+  float16_t ubo_load_7_y = f16tof32(ubo_load_7[0] >> 16);
+  s.Store<vector<float16_t, 3> >(8u, vector<float16_t, 3>(ubo_load_7_xz[0], ubo_load_7_y, ubo_load_7_xz[1]).zxy);
+  s.Store<float16_t>(2u, float16_t(f16tof32(((u[0].z) & 0xFFFF))));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000002A95A169E30(6,66-74): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000002A95A169E30(7,3-14): error X3018: invalid subscript 'Store'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..740aecc
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_storage.wgsl.expected.glsl
@@ -0,0 +1,29 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec3 inner_0;
+  f16vec3 inner_1;
+  f16vec3 inner_2;
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  f16mat3 inner;
+} s;
+
+f16mat3 load_u_inner() {
+  return f16mat3(u.inner_0, u.inner_1, u.inner_2);
+}
+
+void f() {
+  s.inner = load_u_inner();
+  s.inner[1] = u.inner_0;
+  s.inner[1] = u.inner_0.zxy;
+  s.inner[0][1] = u.inner_1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..88e665b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_storage.wgsl.expected.msl
@@ -0,0 +1,11 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f(device half3x3* tint_symbol [[buffer(1)]], const constant half3x3* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[0];
+  (*(tint_symbol))[1] = half3((*(tint_symbol_1))[0]).zxy;
+  (*(tint_symbol))[0][1] = (*(tint_symbol_1))[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_storage.wgsl.expected.spvasm
new file mode 100644
index 0000000..405f643
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_storage.wgsl.expected.spvasm
@@ -0,0 +1,92 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 53
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpMemberName %u_block_std140 2 "inner_2"
+               OpName %u "u"
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %s "s"
+               OpName %load_u_inner "load_u_inner"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 8
+               OpMemberDecorate %u_block_std140 2 Offset 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 8
+               OpDecorate %s DescriptorSet 0
+               OpDecorate %s Binding 1
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+%u_block_std140 = OpTypeStruct %v3half %v3half %v3half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat3v3half = OpTypeMatrix %v3half 3
+    %u_block = OpTypeStruct %mat3v3half
+%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
+          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+         %10 = OpTypeFunction %mat3v3half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+       %void = OpTypeVoid
+         %29 = OpTypeFunction %void
+%_ptr_StorageBuffer_mat3v3half = OpTypePointer StorageBuffer %mat3v3half
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_v3half = OpTypePointer StorageBuffer %v3half
+         %46 = OpConstantNull %int
+%_ptr_StorageBuffer_half = OpTypePointer StorageBuffer %half
+         %49 = OpConstantNull %uint
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+%load_u_inner = OpFunction %mat3v3half None %10
+         %12 = OpLabel
+         %18 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0
+         %19 = OpLoad %v3half %18
+         %22 = OpAccessChain %_ptr_Uniform_v3half %u %uint_1
+         %23 = OpLoad %v3half %22
+         %26 = OpAccessChain %_ptr_Uniform_v3half %u %uint_2
+         %27 = OpLoad %v3half %26
+         %28 = OpCompositeConstruct %mat3v3half %19 %23 %27
+               OpReturnValue %28
+               OpFunctionEnd
+          %f = OpFunction %void None %29
+         %32 = OpLabel
+         %34 = OpAccessChain %_ptr_StorageBuffer_mat3v3half %s %uint_0
+         %35 = OpFunctionCall %mat3v3half %load_u_inner
+               OpStore %34 %35
+         %39 = OpAccessChain %_ptr_StorageBuffer_v3half %s %uint_0 %int_1
+         %40 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0
+         %41 = OpLoad %v3half %40
+               OpStore %39 %41
+         %42 = OpAccessChain %_ptr_StorageBuffer_v3half %s %uint_0 %int_1
+         %43 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0
+         %44 = OpLoad %v3half %43
+         %45 = OpVectorShuffle %v3half %44 %44 2 0 1
+               OpStore %42 %45
+         %48 = OpAccessChain %_ptr_StorageBuffer_half %s %uint_0 %46 %int_1
+         %51 = OpAccessChain %_ptr_Uniform_half %u %uint_1 %49
+         %52 = OpLoad %half %51
+               OpStore %48 %52
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..8bf2700
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat3x3<f16>;
+
+@group(0) @binding(1) var<storage, read_write> s : mat3x3<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[0];
+  s[1] = u[0].zxy;
+  s[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_workgroup.wgsl
new file mode 100644
index 0000000..8dbebb4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_workgroup.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat3x3<f16>;
+var<workgroup> w : mat3x3<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[0];
+    w[1] = u[0].zxy;
+    w[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_workgroup.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..b6830ac
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_workgroup.wgsl.expected.dxc.hlsl
@@ -0,0 +1,50 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+groupshared matrix<float16_t, 3, 3> w;
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 3, 3> tint_symbol_2(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  return matrix<float16_t, 3, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]));
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    w = matrix<float16_t, 3, 3>((float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx);
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  uint2 ubo_load_6 = u[0].xy;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  w[1] = vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]);
+  uint2 ubo_load_7 = u[0].xy;
+  vector<float16_t, 2> ubo_load_7_xz = vector<float16_t, 2>(f16tof32(ubo_load_7 & 0xFFFF));
+  float16_t ubo_load_7_y = f16tof32(ubo_load_7[0] >> 16);
+  w[1] = vector<float16_t, 3>(ubo_load_7_xz[0], ubo_load_7_y, ubo_load_7_xz[1]).zxy;
+  w[0][1] = float16_t(f16tof32(((u[0].z) & 0xFFFF)));
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_workgroup.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..960e913
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_workgroup.wgsl.expected.fxc.hlsl
@@ -0,0 +1,55 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+groupshared matrix<float16_t, 3, 3> w;
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 3, 3> tint_symbol_2(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  return matrix<float16_t, 3, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]));
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    w = matrix<float16_t, 3, 3>((float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx);
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  uint2 ubo_load_6 = u[0].xy;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  w[1] = vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]);
+  uint2 ubo_load_7 = u[0].xy;
+  vector<float16_t, 2> ubo_load_7_xz = vector<float16_t, 2>(f16tof32(ubo_load_7 & 0xFFFF));
+  float16_t ubo_load_7_y = f16tof32(ubo_load_7[0] >> 16);
+  w[1] = vector<float16_t, 3>(ubo_load_7_xz[0], ubo_load_7_y, ubo_load_7_xz[1]).zxy;
+  w[0][1] = float16_t(f16tof32(((u[0].z) & 0xFFFF)));
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000027B0D02C6A0(4,20-28): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..e3c304b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,30 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec3 inner_0;
+  f16vec3 inner_1;
+  f16vec3 inner_2;
+} u;
+
+shared f16mat3 w;
+f16mat3 load_u_inner() {
+  return f16mat3(u.inner_0, u.inner_1, u.inner_2);
+}
+
+void f(uint local_invocation_index) {
+  {
+    w = f16mat3(f16vec3(0.0hf), f16vec3(0.0hf), f16vec3(0.0hf));
+  }
+  barrier();
+  w = load_u_inner();
+  w[1] = u.inner_0;
+  w[1] = u.inner_0.zxy;
+  w[0][1] = u.inner_1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..849494f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,24 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct tint_symbol_5 {
+  half3x3 w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup half3x3* const tint_symbol, const constant half3x3* const tint_symbol_1) {
+  {
+    *(tint_symbol) = half3x3(half3(0.0h), half3(0.0h), half3(0.0h));
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[0];
+  (*(tint_symbol))[1] = half3((*(tint_symbol_1))[0]).zxy;
+  (*(tint_symbol))[0][1] = (*(tint_symbol_1))[1][0];
+}
+
+kernel void f(const constant half3x3* tint_symbol_4 [[buffer(0)]], threadgroup tint_symbol_5* tint_symbol_3 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup half3x3* const tint_symbol_2 = &((*(tint_symbol_3)).w);
+  f_inner(local_invocation_index, tint_symbol_2, tint_symbol_4);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_workgroup.wgsl.expected.spvasm
new file mode 100644
index 0000000..3482df8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_workgroup.wgsl.expected.spvasm
@@ -0,0 +1,99 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 61
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %local_invocation_index_1 "local_invocation_index_1"
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpMemberName %u_block_std140 2 "inner_2"
+               OpName %u "u"
+               OpName %w "w"
+               OpName %load_u_inner "load_u_inner"
+               OpName %f_inner "f_inner"
+               OpName %local_invocation_index "local_invocation_index"
+               OpName %f "f"
+               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 8
+               OpMemberDecorate %u_block_std140 2 Offset 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+%u_block_std140 = OpTypeStruct %v3half %v3half %v3half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat3v3half = OpTypeMatrix %v3half 3
+%_ptr_Workgroup_mat3v3half = OpTypePointer Workgroup %mat3v3half
+          %w = OpVariable %_ptr_Workgroup_mat3v3half Workgroup
+         %12 = OpTypeFunction %mat3v3half
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+       %void = OpTypeVoid
+         %30 = OpTypeFunction %void %uint
+         %35 = OpConstantNull %mat3v3half
+   %uint_264 = OpConstant %uint 264
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Workgroup_v3half = OpTypePointer Workgroup %v3half
+         %49 = OpConstantNull %int
+%_ptr_Workgroup_half = OpTypePointer Workgroup %half
+         %52 = OpConstantNull %uint
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+         %56 = OpTypeFunction %void
+%load_u_inner = OpFunction %mat3v3half None %12
+         %14 = OpLabel
+         %19 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0
+         %20 = OpLoad %v3half %19
+         %23 = OpAccessChain %_ptr_Uniform_v3half %u %uint_1
+         %24 = OpLoad %v3half %23
+         %27 = OpAccessChain %_ptr_Uniform_v3half %u %uint_2
+         %28 = OpLoad %v3half %27
+         %29 = OpCompositeConstruct %mat3v3half %20 %24 %28
+               OpReturnValue %29
+               OpFunctionEnd
+    %f_inner = OpFunction %void None %30
+%local_invocation_index = OpFunctionParameter %uint
+         %34 = OpLabel
+               OpStore %w %35
+               OpControlBarrier %uint_2 %uint_2 %uint_264
+         %38 = OpFunctionCall %mat3v3half %load_u_inner
+               OpStore %w %38
+         %42 = OpAccessChain %_ptr_Workgroup_v3half %w %int_1
+         %43 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0
+         %44 = OpLoad %v3half %43
+               OpStore %42 %44
+         %45 = OpAccessChain %_ptr_Workgroup_v3half %w %int_1
+         %46 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0
+         %47 = OpLoad %v3half %46
+         %48 = OpVectorShuffle %v3half %47 %47 2 0 1
+               OpStore %45 %48
+         %51 = OpAccessChain %_ptr_Workgroup_half %w %49 %int_1
+         %54 = OpAccessChain %_ptr_Uniform_half %u %uint_1 %52
+         %55 = OpLoad %half %54
+               OpStore %51 %55
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %56
+         %58 = OpLabel
+         %60 = OpLoad %uint %local_invocation_index_1
+         %59 = OpFunctionCall %void %f_inner %60
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..8770580
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f16/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat3x3<f16>;
+
+var<workgroup> w : mat3x3<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[0];
+  w[1] = u[0].zxy;
+  w[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/dynamic_index_via_ptr.wgsl
new file mode 100644
index 0000000..a927b2d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/dynamic_index_via_ptr.wgsl
@@ -0,0 +1,13 @@
+@group(0) @binding(0) var<uniform> m : mat3x3<f32>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m   = &m;
+  let p_m_i = &((*p_m)[i()]);
+
+  let l_m   : mat3x3<f32> = *p_m;
+  let l_m_i : vec3<f32>   = *p_m_i;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..ee3d2c3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,25 @@
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[3];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float3x3 tint_symbol(uint4 buffer[3], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_m_i_save = i();
+  const float3x3 l_m = tint_symbol(m, 0u);
+  const uint scalar_offset_3 = ((16u * uint(p_m_i_save))) / 4;
+  const float3 l_m_i = asfloat(m[scalar_offset_3 / 4].xyz);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..ee3d2c3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,25 @@
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[3];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float3x3 tint_symbol(uint4 buffer[3], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_m_i_save = i();
+  const float3x3 l_m = tint_symbol(m, 0u);
+  const uint scalar_offset_3 = ((16u * uint(p_m_i_save))) / 4;
+  const float3 l_m_i = asfloat(m[scalar_offset_3 / 4].xyz);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..b92e950
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,24 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform m_block_ubo {
+  mat3 inner;
+} m;
+
+int counter = 0;
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+void f() {
+  int tint_symbol = i();
+  int p_m_i_save = tint_symbol;
+  mat3 l_m = m.inner;
+  vec3 l_m_i = m.inner[p_m_i_save];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..f7cf012
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,17 @@
+#include <metal_stdlib>
+
+using namespace metal;
+int i() {
+  thread int tint_symbol_1 = 0;
+  tint_symbol_1 = as_type<int>((as_type<uint>(tint_symbol_1) + as_type<uint>(1)));
+  return tint_symbol_1;
+}
+
+kernel void f(const constant float3x3* tint_symbol_2 [[buffer(0)]]) {
+  int const tint_symbol = i();
+  int const p_m_i_save = tint_symbol;
+  float3x3 const l_m = *(tint_symbol_2);
+  float3 const l_m_i = (*(tint_symbol_2))[p_m_i_save];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..c24fe7536
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,57 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 31
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %m_block "m_block"
+               OpMemberName %m_block 0 "inner"
+               OpName %m "m"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %f "f"
+               OpDecorate %m_block Block
+               OpMemberDecorate %m_block 0 Offset 0
+               OpMemberDecorate %m_block 0 ColMajor
+               OpMemberDecorate %m_block 0 MatrixStride 16
+               OpDecorate %m NonWritable
+               OpDecorate %m DescriptorSet 0
+               OpDecorate %m Binding 0
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+    %m_block = OpTypeStruct %mat3v3float
+%_ptr_Uniform_m_block = OpTypePointer Uniform %m_block
+          %m = OpVariable %_ptr_Uniform_m_block Uniform
+        %int = OpTypeInt 32 1
+          %8 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %8
+         %11 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+       %void = OpTypeVoid
+         %18 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_mat3v3float = OpTypePointer Uniform %mat3v3float
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+          %i = OpFunction %int None %11
+         %13 = OpLabel
+         %14 = OpLoad %int %counter
+         %16 = OpIAdd %int %14 %int_1
+               OpStore %counter %16
+         %17 = OpLoad %int %counter
+               OpReturnValue %17
+               OpFunctionEnd
+          %f = OpFunction %void None %18
+         %21 = OpLabel
+         %22 = OpFunctionCall %int %i
+         %26 = OpAccessChain %_ptr_Uniform_mat3v3float %m %uint_0
+         %27 = OpLoad %mat3v3float %26
+         %29 = OpAccessChain %_ptr_Uniform_v3float %m %uint_0 %22
+         %30 = OpLoad %v3float %29
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..b38a53e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,16 @@
+@group(0) @binding(0) var<uniform> m : mat3x3<f32>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m = &(m);
+  let p_m_i = &((*(p_m))[i()]);
+  let l_m : mat3x3<f32> = *(p_m);
+  let l_m_i : vec3<f32> = *(p_m_i);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/static_index_via_ptr.wgsl
new file mode 100644
index 0000000..73cc3d4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/static_index_via_ptr.wgsl
@@ -0,0 +1,13 @@
+@group(0) @binding(0) var<uniform> m : mat3x3<f32>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m   = &m;
+  let p_m_1 = &((*p_m)[1]);
+
+  let l_m   : mat3x3<f32> = *p_m;
+  let l_m_1 : vec3<f32>   = *p_m_1;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..bc49773
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,23 @@
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[3];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float3x3 tint_symbol(uint4 buffer[3], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float3x3 l_m = tint_symbol(m, 0u);
+  const float3 l_m_1 = asfloat(m[1].xyz);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..bc49773
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,23 @@
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[3];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float3x3 tint_symbol(uint4 buffer[3], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float3x3 l_m = tint_symbol(m, 0u);
+  const float3 l_m_1 = asfloat(m[1].xyz);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/static_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..825d355
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/static_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,16 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform m_block_ubo {
+  mat3 inner;
+} m;
+
+void f() {
+  mat3 l_m = m.inner;
+  vec3 l_m_1 = m.inner[1];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/static_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..8d47ca6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/static_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,15 @@
+#include <metal_stdlib>
+
+using namespace metal;
+int i() {
+  thread int tint_symbol = 0;
+  tint_symbol = as_type<int>((as_type<uint>(tint_symbol) + as_type<uint>(1)));
+  return tint_symbol;
+}
+
+kernel void f(const constant float3x3* tint_symbol_1 [[buffer(0)]]) {
+  float3x3 const l_m = *(tint_symbol_1);
+  float3 const l_m_1 = (*(tint_symbol_1))[1];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/static_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..3e3f49f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/static_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,56 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 30
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %m_block "m_block"
+               OpMemberName %m_block 0 "inner"
+               OpName %m "m"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %f "f"
+               OpDecorate %m_block Block
+               OpMemberDecorate %m_block 0 Offset 0
+               OpMemberDecorate %m_block 0 ColMajor
+               OpMemberDecorate %m_block 0 MatrixStride 16
+               OpDecorate %m NonWritable
+               OpDecorate %m DescriptorSet 0
+               OpDecorate %m Binding 0
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+    %m_block = OpTypeStruct %mat3v3float
+%_ptr_Uniform_m_block = OpTypePointer Uniform %m_block
+          %m = OpVariable %_ptr_Uniform_m_block Uniform
+        %int = OpTypeInt 32 1
+          %8 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %8
+         %11 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+       %void = OpTypeVoid
+         %18 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_mat3v3float = OpTypePointer Uniform %mat3v3float
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+          %i = OpFunction %int None %11
+         %13 = OpLabel
+         %14 = OpLoad %int %counter
+         %16 = OpIAdd %int %14 %int_1
+               OpStore %counter %16
+         %17 = OpLoad %int %counter
+               OpReturnValue %17
+               OpFunctionEnd
+          %f = OpFunction %void None %18
+         %21 = OpLabel
+         %25 = OpAccessChain %_ptr_Uniform_mat3v3float %m %uint_0
+         %26 = OpLoad %mat3v3float %25
+         %28 = OpAccessChain %_ptr_Uniform_v3float %m %uint_0 %int_1
+         %29 = OpLoad %v3float %28
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/static_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..a518e93
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/static_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,16 @@
+@group(0) @binding(0) var<uniform> m : mat3x3<f32>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m = &(m);
+  let p_m_1 = &((*(p_m))[1]);
+  let l_m : mat3x3<f32> = *(p_m);
+  let l_m_1 : vec3<f32> = *(p_m_1);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_builtin.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_builtin.wgsl
new file mode 100644
index 0000000..8d72d67
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_builtin.wgsl
@@ -0,0 +1,8 @@
+@group(0) @binding(0) var<uniform> u : mat3x3<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+    let t = transpose(u);
+    let l = length(u[1]);
+    let a = abs(u[0].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_builtin.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..47e86de
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_builtin.wgsl.expected.dxc.hlsl
@@ -0,0 +1,18 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[3];
+};
+
+float3x3 tint_symbol(uint4 buffer[3], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float3x3 t = transpose(tint_symbol(u, 0u));
+  const float l = length(asfloat(u[1].xyz));
+  const float a = abs(asfloat(u[0].xyz).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_builtin.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..47e86de
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_builtin.wgsl.expected.fxc.hlsl
@@ -0,0 +1,18 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[3];
+};
+
+float3x3 tint_symbol(uint4 buffer[3], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float3x3 t = transpose(tint_symbol(u, 0u));
+  const float l = length(asfloat(u[1].xyz));
+  const float a = abs(asfloat(u[0].xyz).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_builtin.wgsl.expected.glsl
new file mode 100644
index 0000000..a0cddf0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_builtin.wgsl.expected.glsl
@@ -0,0 +1,17 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat3 inner;
+} u;
+
+void f() {
+  mat3 t = transpose(u.inner);
+  float l = length(u.inner[1]);
+  float a = abs(u.inner[0].zxy.x);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_builtin.wgsl.expected.msl
new file mode 100644
index 0000000..448c8e0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_builtin.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f(const constant float3x3* tint_symbol [[buffer(0)]]) {
+  float3x3 const t = transpose(*(tint_symbol));
+  float const l = length((*(tint_symbol))[1]);
+  float const a = fabs(float3((*(tint_symbol))[0]).zxy[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_builtin.wgsl.expected.spvasm
new file mode 100644
index 0000000..0c566a8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_builtin.wgsl.expected.spvasm
@@ -0,0 +1,51 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 30
+; Schema: 0
+               OpCapability Shader
+         %18 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+    %u_block = OpTypeStruct %mat3v3float
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+          %7 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_mat3v3float = OpTypePointer Uniform %mat3v3float
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+         %25 = OpConstantNull %int
+          %f = OpFunction %void None %7
+         %10 = OpLabel
+         %15 = OpAccessChain %_ptr_Uniform_mat3v3float %u %uint_0
+         %16 = OpLoad %mat3v3float %15
+         %11 = OpTranspose %mat3v3float %16
+         %22 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %int_1
+         %23 = OpLoad %v3float %22
+         %17 = OpExtInst %float %18 Length %23
+         %26 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %25
+         %27 = OpLoad %v3float %26
+         %28 = OpVectorShuffle %v3float %27 %27 2 0 1
+         %29 = OpCompositeExtract %float %28 0
+         %24 = OpExtInst %float %18 FAbs %29
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_builtin.wgsl.expected.wgsl
new file mode 100644
index 0000000..5903946
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_builtin.wgsl.expected.wgsl
@@ -0,0 +1,8 @@
+@group(0) @binding(0) var<uniform> u : mat3x3<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let t = transpose(u);
+  let l = length(u[1]);
+  let a = abs(u[0].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_fn.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_fn.wgsl
new file mode 100644
index 0000000..528d3e3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_fn.wgsl
@@ -0,0 +1,14 @@
+@group(0) @binding(0) var<uniform> u : mat3x3<f32>;
+
+fn a(m : mat3x3<f32>) {}
+fn b(v : vec3<f32>) {}
+fn c(f : f32) {}
+
+@compute @workgroup_size(1)
+fn f() {
+    a(u);
+    b(u[1]);
+    b(u[1].zxy);
+    c(u[1].x);
+    c(u[1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_fn.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..e871bd0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_fn.wgsl.expected.dxc.hlsl
@@ -0,0 +1,29 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[3];
+};
+
+void a(float3x3 m) {
+}
+
+void b(float3 v) {
+}
+
+void c(float f_1) {
+}
+
+float3x3 tint_symbol(uint4 buffer[3], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(asfloat(u[1].xyz));
+  b(asfloat(u[1].xyz).zxy);
+  c(asfloat(u[1].x));
+  c(asfloat(u[1].xyz).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_fn.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..e871bd0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_fn.wgsl.expected.fxc.hlsl
@@ -0,0 +1,29 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[3];
+};
+
+void a(float3x3 m) {
+}
+
+void b(float3 v) {
+}
+
+void c(float f_1) {
+}
+
+float3x3 tint_symbol(uint4 buffer[3], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(asfloat(u[1].xyz));
+  b(asfloat(u[1].xyz).zxy);
+  c(asfloat(u[1].x));
+  c(asfloat(u[1].xyz).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_fn.wgsl.expected.glsl
new file mode 100644
index 0000000..e16f33a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_fn.wgsl.expected.glsl
@@ -0,0 +1,28 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat3 inner;
+} u;
+
+void a(mat3 m) {
+}
+
+void b(vec3 v) {
+}
+
+void c(float f_1) {
+}
+
+void f() {
+  a(u.inner);
+  b(u.inner[1]);
+  b(u.inner[1].zxy);
+  c(u.inner[1].x);
+  c(u.inner[1].zxy.x);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_fn.wgsl.expected.msl
new file mode 100644
index 0000000..e0131fb
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_fn.wgsl.expected.msl
@@ -0,0 +1,21 @@
+#include <metal_stdlib>
+
+using namespace metal;
+void a(float3x3 m) {
+}
+
+void b(float3 v) {
+}
+
+void c(float f_1) {
+}
+
+kernel void f(const constant float3x3* tint_symbol [[buffer(0)]]) {
+  a(*(tint_symbol));
+  b((*(tint_symbol))[1]);
+  b(float3((*(tint_symbol))[1]).zxy);
+  c((*(tint_symbol))[1][0]);
+  c(float3((*(tint_symbol))[1]).zxy[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_fn.wgsl.expected.spvasm
new file mode 100644
index 0000000..368867a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_fn.wgsl.expected.spvasm
@@ -0,0 +1,81 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 48
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %a "a"
+               OpName %m "m"
+               OpName %b "b"
+               OpName %v "v"
+               OpName %c "c"
+               OpName %f_1 "f_1"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+    %u_block = OpTypeStruct %mat3v3float
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+          %7 = OpTypeFunction %void %mat3v3float
+         %12 = OpTypeFunction %void %v3float
+         %16 = OpTypeFunction %void %float
+         %20 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_mat3v3float = OpTypePointer Uniform %mat3v3float
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+          %a = OpFunction %void None %7
+          %m = OpFunctionParameter %mat3v3float
+         %11 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %b = OpFunction %void None %12
+          %v = OpFunctionParameter %v3float
+         %15 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %c = OpFunction %void None %16
+        %f_1 = OpFunctionParameter %float
+         %19 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %20
+         %22 = OpLabel
+         %27 = OpAccessChain %_ptr_Uniform_mat3v3float %u %uint_0
+         %28 = OpLoad %mat3v3float %27
+         %23 = OpFunctionCall %void %a %28
+         %33 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %int_1
+         %34 = OpLoad %v3float %33
+         %29 = OpFunctionCall %void %b %34
+         %36 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %int_1
+         %37 = OpLoad %v3float %36
+         %38 = OpVectorShuffle %v3float %37 %37 2 0 1
+         %35 = OpFunctionCall %void %b %38
+         %41 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %int_1 %uint_0
+         %42 = OpLoad %float %41
+         %39 = OpFunctionCall %void %c %42
+         %44 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %int_1
+         %45 = OpLoad %v3float %44
+         %46 = OpVectorShuffle %v3float %45 %45 2 0 1
+         %47 = OpCompositeExtract %float %46 0
+         %43 = OpFunctionCall %void %c %47
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_fn.wgsl.expected.wgsl
new file mode 100644
index 0000000..f4f9ace
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_fn.wgsl.expected.wgsl
@@ -0,0 +1,19 @@
+@group(0) @binding(0) var<uniform> u : mat3x3<f32>;
+
+fn a(m : mat3x3<f32>) {
+}
+
+fn b(v : vec3<f32>) {
+}
+
+fn c(f : f32) {
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  a(u);
+  b(u[1]);
+  b(u[1].zxy);
+  c(u[1].x);
+  c(u[1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_private.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_private.wgsl
new file mode 100644
index 0000000..06230bf
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_private.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0) var<uniform> u : mat3x3<f32>;
+var<private> p : mat3x3<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[0];
+    p[1] = u[0].zxy;
+    p[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_private.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..0d4ad6d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_private.wgsl.expected.dxc.hlsl
@@ -0,0 +1,20 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[3];
+};
+static float3x3 p = float3x3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
+
+float3x3 tint_symbol(uint4 buffer[3], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = asfloat(u[0].xyz);
+  p[1] = asfloat(u[0].xyz).zxy;
+  p[0][1] = asfloat(u[1].x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_private.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..0d4ad6d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_private.wgsl.expected.fxc.hlsl
@@ -0,0 +1,20 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[3];
+};
+static float3x3 p = float3x3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
+
+float3x3 tint_symbol(uint4 buffer[3], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = asfloat(u[0].xyz);
+  p[1] = asfloat(u[0].xyz).zxy;
+  p[0][1] = asfloat(u[1].x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..13d4c1f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_private.wgsl.expected.glsl
@@ -0,0 +1,19 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat3 inner;
+} u;
+
+mat3 p = mat3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
+void f() {
+  p = u.inner;
+  p[1] = u.inner[0];
+  p[1] = u.inner[0].zxy;
+  p[0][1] = u.inner[1][0];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..4471b02
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_private.wgsl.expected.msl
@@ -0,0 +1,12 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f(const constant float3x3* tint_symbol_1 [[buffer(0)]]) {
+  thread float3x3 tint_symbol = float3x3(0.0f);
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[0];
+  tint_symbol[1] = float3((*(tint_symbol_1))[0]).zxy;
+  tint_symbol[0][1] = (*(tint_symbol_1))[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_private.wgsl.expected.spvasm
new file mode 100644
index 0000000..e71a764
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_private.wgsl.expected.spvasm
@@ -0,0 +1,62 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 36
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %p "p"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+    %u_block = OpTypeStruct %mat3v3float
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_Private_mat3v3float = OpTypePointer Private %mat3v3float
+          %9 = OpConstantNull %mat3v3float
+          %p = OpVariable %_ptr_Private_mat3v3float Private %9
+       %void = OpTypeVoid
+         %10 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_mat3v3float = OpTypePointer Uniform %mat3v3float
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Private_v3float = OpTypePointer Private %v3float
+         %23 = OpConstantNull %int
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+%_ptr_Private_float = OpTypePointer Private %float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+          %f = OpFunction %void None %10
+         %13 = OpLabel
+         %17 = OpAccessChain %_ptr_Uniform_mat3v3float %u %uint_0
+         %18 = OpLoad %mat3v3float %17
+               OpStore %p %18
+         %22 = OpAccessChain %_ptr_Private_v3float %p %int_1
+         %25 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %23
+         %26 = OpLoad %v3float %25
+               OpStore %22 %26
+         %27 = OpAccessChain %_ptr_Private_v3float %p %int_1
+         %28 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %23
+         %29 = OpLoad %v3float %28
+         %30 = OpVectorShuffle %v3float %29 %29 2 0 1
+               OpStore %27 %30
+         %32 = OpAccessChain %_ptr_Private_float %p %23 %int_1
+         %34 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %int_1 %23
+         %35 = OpLoad %float %34
+               OpStore %32 %35
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..a9b219a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_private.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> u : mat3x3<f32>;
+
+var<private> p : mat3x3<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[0];
+  p[1] = u[0].zxy;
+  p[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_storage.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_storage.wgsl
new file mode 100644
index 0000000..21b61b2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_storage.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0) var<uniform> u : mat3x3<f32>;
+@group(0) @binding(1) var<storage, read_write> s : mat3x3<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[0];
+    s[1] = u[0].zxy;
+    s[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_storage.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..6b28dd2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_storage.wgsl.expected.dxc.hlsl
@@ -0,0 +1,26 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[3];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, float3x3 value) {
+  buffer.Store3((offset + 0u), asuint(value[0u]));
+  buffer.Store3((offset + 16u), asuint(value[1u]));
+  buffer.Store3((offset + 32u), asuint(value[2u]));
+}
+
+float3x3 tint_symbol_2(uint4 buffer[3], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_2(u, 0u));
+  s.Store3(16u, asuint(asfloat(u[0].xyz)));
+  s.Store3(16u, asuint(asfloat(u[0].xyz).zxy));
+  s.Store(4u, asuint(asfloat(u[1].x)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_storage.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..6b28dd2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_storage.wgsl.expected.fxc.hlsl
@@ -0,0 +1,26 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[3];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, float3x3 value) {
+  buffer.Store3((offset + 0u), asuint(value[0u]));
+  buffer.Store3((offset + 16u), asuint(value[1u]));
+  buffer.Store3((offset + 32u), asuint(value[2u]));
+}
+
+float3x3 tint_symbol_2(uint4 buffer[3], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_2(u, 0u));
+  s.Store3(16u, asuint(asfloat(u[0].xyz)));
+  s.Store3(16u, asuint(asfloat(u[0].xyz).zxy));
+  s.Store(4u, asuint(asfloat(u[1].x)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..2e910e8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_storage.wgsl.expected.glsl
@@ -0,0 +1,22 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat3 inner;
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  mat3 inner;
+} s;
+
+void f() {
+  s.inner = u.inner;
+  s.inner[1] = u.inner[0];
+  s.inner[1] = u.inner[0].zxy;
+  s.inner[0][1] = u.inner[1][0];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..207c6b0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_storage.wgsl.expected.msl
@@ -0,0 +1,11 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f(device float3x3* tint_symbol [[buffer(1)]], const constant float3x3* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[0];
+  (*(tint_symbol))[1] = float3((*(tint_symbol_1))[0]).zxy;
+  (*(tint_symbol))[0][1] = (*(tint_symbol_1))[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_storage.wgsl.expected.spvasm
new file mode 100644
index 0000000..fd0a6f8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_storage.wgsl.expected.spvasm
@@ -0,0 +1,65 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 37
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %s "s"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %s DescriptorSet 0
+               OpDecorate %s Binding 1
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+    %u_block = OpTypeStruct %mat3v3float
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
+          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+       %void = OpTypeVoid
+          %9 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_mat3v3float = OpTypePointer StorageBuffer %mat3v3float
+%_ptr_Uniform_mat3v3float = OpTypePointer Uniform %mat3v3float
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_v3float = OpTypePointer StorageBuffer %v3float
+         %24 = OpConstantNull %int
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+          %f = OpFunction %void None %9
+         %12 = OpLabel
+         %16 = OpAccessChain %_ptr_StorageBuffer_mat3v3float %s %uint_0
+         %18 = OpAccessChain %_ptr_Uniform_mat3v3float %u %uint_0
+         %19 = OpLoad %mat3v3float %18
+               OpStore %16 %19
+         %23 = OpAccessChain %_ptr_StorageBuffer_v3float %s %uint_0 %int_1
+         %26 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %24
+         %27 = OpLoad %v3float %26
+               OpStore %23 %27
+         %28 = OpAccessChain %_ptr_StorageBuffer_v3float %s %uint_0 %int_1
+         %29 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %24
+         %30 = OpLoad %v3float %29
+         %31 = OpVectorShuffle %v3float %30 %30 2 0 1
+               OpStore %28 %31
+         %33 = OpAccessChain %_ptr_StorageBuffer_float %s %uint_0 %24 %int_1
+         %35 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %int_1 %24
+         %36 = OpLoad %float %35
+               OpStore %33 %36
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..a32a4b9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> u : mat3x3<f32>;
+
+@group(0) @binding(1) var<storage, read_write> s : mat3x3<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[0];
+  s[1] = u[0].zxy;
+  s[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_workgroup.wgsl
new file mode 100644
index 0000000..db3ec99
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_workgroup.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0) var<uniform> u : mat3x3<f32>;
+var<workgroup> w : mat3x3<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[0];
+    w[1] = u[0].zxy;
+    w[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_workgroup.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..b51cc7d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_workgroup.wgsl.expected.dxc.hlsl
@@ -0,0 +1,32 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[3];
+};
+groupshared float3x3 w;
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+float3x3 tint_symbol_2(uint4 buffer[3], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    w = float3x3((0.0f).xxx, (0.0f).xxx, (0.0f).xxx);
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = asfloat(u[0].xyz);
+  w[1] = asfloat(u[0].xyz).zxy;
+  w[0][1] = asfloat(u[1].x);
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_workgroup.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..b51cc7d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_workgroup.wgsl.expected.fxc.hlsl
@@ -0,0 +1,32 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[3];
+};
+groupshared float3x3 w;
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+float3x3 tint_symbol_2(uint4 buffer[3], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    w = float3x3((0.0f).xxx, (0.0f).xxx, (0.0f).xxx);
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = asfloat(u[0].xyz);
+  w[1] = asfloat(u[0].xyz).zxy;
+  w[0][1] = asfloat(u[1].x);
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..4356fb5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,23 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat3 inner;
+} u;
+
+shared mat3 w;
+void f(uint local_invocation_index) {
+  {
+    w = mat3(vec3(0.0f), vec3(0.0f), vec3(0.0f));
+  }
+  barrier();
+  w = u.inner;
+  w[1] = u.inner[0];
+  w[1] = u.inner[0].zxy;
+  w[0][1] = u.inner[1][0];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..9c73286
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,24 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct tint_symbol_5 {
+  float3x3 w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup float3x3* const tint_symbol, const constant float3x3* const tint_symbol_1) {
+  {
+    *(tint_symbol) = float3x3(float3(0.0f), float3(0.0f), float3(0.0f));
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[0];
+  (*(tint_symbol))[1] = float3((*(tint_symbol_1))[0]).zxy;
+  (*(tint_symbol))[0][1] = (*(tint_symbol_1))[1][0];
+}
+
+kernel void f(const constant float3x3* tint_symbol_4 [[buffer(0)]], threadgroup tint_symbol_5* tint_symbol_3 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup float3x3* const tint_symbol_2 = &((*(tint_symbol_3)).w);
+  f_inner(local_invocation_index, tint_symbol_2, tint_symbol_4);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_workgroup.wgsl.expected.spvasm
new file mode 100644
index 0000000..f737673
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_workgroup.wgsl.expected.spvasm
@@ -0,0 +1,80 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 47
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %local_invocation_index_1 "local_invocation_index_1"
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %w "w"
+               OpName %f_inner "f_inner"
+               OpName %local_invocation_index "local_invocation_index"
+               OpName %f "f"
+               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+    %u_block = OpTypeStruct %mat3v3float
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_Workgroup_mat3v3float = OpTypePointer Workgroup %mat3v3float
+          %w = OpVariable %_ptr_Workgroup_mat3v3float Workgroup
+       %void = OpTypeVoid
+         %12 = OpTypeFunction %void %uint
+         %17 = OpConstantNull %mat3v3float
+     %uint_2 = OpConstant %uint 2
+   %uint_264 = OpConstant %uint 264
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_mat3v3float = OpTypePointer Uniform %mat3v3float
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Workgroup_v3float = OpTypePointer Workgroup %v3float
+         %29 = OpConstantNull %int
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+%_ptr_Workgroup_float = OpTypePointer Workgroup %float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+         %42 = OpTypeFunction %void
+    %f_inner = OpFunction %void None %12
+%local_invocation_index = OpFunctionParameter %uint
+         %16 = OpLabel
+               OpStore %w %17
+               OpControlBarrier %uint_2 %uint_2 %uint_264
+         %23 = OpAccessChain %_ptr_Uniform_mat3v3float %u %uint_0
+         %24 = OpLoad %mat3v3float %23
+               OpStore %w %24
+         %28 = OpAccessChain %_ptr_Workgroup_v3float %w %int_1
+         %31 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %29
+         %32 = OpLoad %v3float %31
+               OpStore %28 %32
+         %33 = OpAccessChain %_ptr_Workgroup_v3float %w %int_1
+         %34 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %29
+         %35 = OpLoad %v3float %34
+         %36 = OpVectorShuffle %v3float %35 %35 2 0 1
+               OpStore %33 %36
+         %38 = OpAccessChain %_ptr_Workgroup_float %w %29 %int_1
+         %40 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %int_1 %29
+         %41 = OpLoad %float %40
+               OpStore %38 %41
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %42
+         %44 = OpLabel
+         %46 = OpLoad %uint %local_invocation_index_1
+         %45 = OpFunctionCall %void %f_inner %46
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..165ffb8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x3_f32/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> u : mat3x3<f32>;
+
+var<workgroup> w : mat3x3<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[0];
+  w[1] = u[0].zxy;
+  w[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/dynamic_index_via_ptr.wgsl
new file mode 100644
index 0000000..9fbc14f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/dynamic_index_via_ptr.wgsl
@@ -0,0 +1,15 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> m : mat3x4<f16>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m   = &m;
+  let p_m_i = &((*p_m)[i()]);
+
+  let l_m   : mat3x4<f16> = *p_m;
+  let l_m_i : vec4<f16>   = *p_m_i;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..6373d70
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,41 @@
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[2];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 3, 4> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  return matrix<float16_t, 3, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_m_i_save = i();
+  const matrix<float16_t, 3, 4> l_m = tint_symbol(m, 0u);
+  const uint scalar_offset_3 = ((8u * uint(p_m_i_save))) / 4;
+  uint4 ubo_load_7 = m[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  const vector<float16_t, 4> l_m_i = vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..2f16db2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,46 @@
+SKIP: FAILED
+
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[2];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 3, 4> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  return matrix<float16_t, 3, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_m_i_save = i();
+  const matrix<float16_t, 3, 4> l_m = tint_symbol(m, 0u);
+  const uint scalar_offset_3 = ((8u * uint(p_m_i_save))) / 4;
+  uint4 ubo_load_7 = m[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  const vector<float16_t, 4> l_m_i = vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001FCC8F3EC10(11,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/dynamic_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..3199f82
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,53 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform m_block_std140_ubo {
+  f16vec4 inner_0;
+  f16vec4 inner_1;
+  f16vec4 inner_2;
+} m;
+
+int counter = 0;
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+f16mat3x4 load_m_inner() {
+  return f16mat3x4(m.inner_0, m.inner_1, m.inner_2);
+}
+
+f16vec4 load_m_inner_p0(uint p0) {
+  switch(p0) {
+    case 0u: {
+      return m.inner_0;
+      break;
+    }
+    case 1u: {
+      return m.inner_1;
+      break;
+    }
+    case 2u: {
+      return m.inner_2;
+      break;
+    }
+    default: {
+      return f16vec4(0.0hf);
+      break;
+    }
+  }
+}
+
+void f() {
+  f16mat3x4 p_m = load_m_inner();
+  int tint_symbol = i();
+  f16vec4 p_m_i = load_m_inner_p0(uint(tint_symbol));
+  f16mat3x4 l_m = load_m_inner();
+  f16vec4 l_m_i = load_m_inner_p0(uint(tint_symbol));
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/dynamic_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..70345b3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/dynamic_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,17 @@
+#include <metal_stdlib>
+
+using namespace metal;
+int i() {
+  thread int tint_symbol_1 = 0;
+  tint_symbol_1 = as_type<int>((as_type<uint>(tint_symbol_1) + as_type<uint>(1)));
+  return tint_symbol_1;
+}
+
+kernel void f(const constant half3x4* tint_symbol_2 [[buffer(0)]]) {
+  int const tint_symbol = i();
+  int const p_m_i_save = tint_symbol;
+  half3x4 const l_m = *(tint_symbol_2);
+  half4 const l_m_i = (*(tint_symbol_2))[p_m_i_save];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..caeaa70
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,102 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 61
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %m_block_std140 "m_block_std140"
+               OpMemberName %m_block_std140 0 "inner_0"
+               OpMemberName %m_block_std140 1 "inner_1"
+               OpMemberName %m_block_std140 2 "inner_2"
+               OpName %m "m"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %load_m_inner "load_m_inner"
+               OpName %load_m_inner_p0 "load_m_inner_p0"
+               OpName %p0 "p0"
+               OpName %f "f"
+               OpDecorate %m_block_std140 Block
+               OpMemberDecorate %m_block_std140 0 Offset 0
+               OpMemberDecorate %m_block_std140 1 Offset 8
+               OpMemberDecorate %m_block_std140 2 Offset 16
+               OpDecorate %m NonWritable
+               OpDecorate %m DescriptorSet 0
+               OpDecorate %m Binding 0
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+%m_block_std140 = OpTypeStruct %v4half %v4half %v4half
+%_ptr_Uniform_m_block_std140 = OpTypePointer Uniform %m_block_std140
+          %m = OpVariable %_ptr_Uniform_m_block_std140 Uniform
+        %int = OpTypeInt 32 1
+          %7 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %7
+         %10 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+ %mat3v4half = OpTypeMatrix %v4half 3
+         %17 = OpTypeFunction %mat3v4half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+         %37 = OpTypeFunction %v4half %uint
+         %52 = OpConstantNull %v4half
+       %void = OpTypeVoid
+         %53 = OpTypeFunction %void
+          %i = OpFunction %int None %10
+         %12 = OpLabel
+         %13 = OpLoad %int %counter
+         %15 = OpIAdd %int %13 %int_1
+               OpStore %counter %15
+         %16 = OpLoad %int %counter
+               OpReturnValue %16
+               OpFunctionEnd
+%load_m_inner = OpFunction %mat3v4half None %17
+         %20 = OpLabel
+         %26 = OpAccessChain %_ptr_Uniform_v4half %m %uint_0
+         %27 = OpLoad %v4half %26
+         %30 = OpAccessChain %_ptr_Uniform_v4half %m %uint_1
+         %31 = OpLoad %v4half %30
+         %34 = OpAccessChain %_ptr_Uniform_v4half %m %uint_2
+         %35 = OpLoad %v4half %34
+         %36 = OpCompositeConstruct %mat3v4half %27 %31 %35
+               OpReturnValue %36
+               OpFunctionEnd
+%load_m_inner_p0 = OpFunction %v4half None %37
+         %p0 = OpFunctionParameter %uint
+         %40 = OpLabel
+               OpSelectionMerge %41 None
+               OpSwitch %p0 %42 0 %43 1 %44 2 %45
+         %43 = OpLabel
+         %46 = OpAccessChain %_ptr_Uniform_v4half %m %uint_0
+         %47 = OpLoad %v4half %46
+               OpReturnValue %47
+         %44 = OpLabel
+         %48 = OpAccessChain %_ptr_Uniform_v4half %m %uint_1
+         %49 = OpLoad %v4half %48
+               OpReturnValue %49
+         %45 = OpLabel
+         %50 = OpAccessChain %_ptr_Uniform_v4half %m %uint_2
+         %51 = OpLoad %v4half %50
+               OpReturnValue %51
+         %42 = OpLabel
+               OpReturnValue %52
+         %41 = OpLabel
+               OpReturnValue %52
+               OpFunctionEnd
+          %f = OpFunction %void None %53
+         %56 = OpLabel
+         %57 = OpFunctionCall %int %i
+         %58 = OpFunctionCall %mat3v4half %load_m_inner
+         %60 = OpBitcast %uint %57
+         %59 = OpFunctionCall %v4half %load_m_inner_p0 %60
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..29d87ff
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> m : mat3x4<f16>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m = &(m);
+  let p_m_i = &((*(p_m))[i()]);
+  let l_m : mat3x4<f16> = *(p_m);
+  let l_m_i : vec4<f16> = *(p_m_i);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/static_index_via_ptr.wgsl
new file mode 100644
index 0000000..dc27594
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/static_index_via_ptr.wgsl
@@ -0,0 +1,15 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> m : mat3x4<f16>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m   = &m;
+  let p_m_1 = &((*p_m)[1]);
+
+  let l_m   : mat3x4<f16> = *p_m;
+  let l_m_1 : vec4<f16>   = *p_m_1;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..cfc99ea
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,38 @@
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[2];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 3, 4> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  return matrix<float16_t, 3, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 3, 4> l_m = tint_symbol(m, 0u);
+  uint2 ubo_load_6 = m[0].zw;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  const vector<float16_t, 4> l_m_1 = vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..be7103a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,43 @@
+SKIP: FAILED
+
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[2];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 3, 4> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  return matrix<float16_t, 3, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 3, 4> l_m = tint_symbol(m, 0u);
+  uint2 ubo_load_6 = m[0].zw;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  const vector<float16_t, 4> l_m_1 = vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000017BEAA5D290(11,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/static_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..b40e9bb
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/static_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,25 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform m_block_std140_ubo {
+  f16vec4 inner_0;
+  f16vec4 inner_1;
+  f16vec4 inner_2;
+} m;
+
+f16mat3x4 load_m_inner() {
+  return f16mat3x4(m.inner_0, m.inner_1, m.inner_2);
+}
+
+void f() {
+  f16mat3x4 p_m = load_m_inner();
+  f16vec4 p_m_1 = m.inner_1;
+  f16mat3x4 l_m = load_m_inner();
+  f16vec4 l_m_1 = m.inner_1;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/static_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..82f5ec8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/static_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,15 @@
+#include <metal_stdlib>
+
+using namespace metal;
+int i() {
+  thread int tint_symbol = 0;
+  tint_symbol = as_type<int>((as_type<uint>(tint_symbol) + as_type<uint>(1)));
+  return tint_symbol;
+}
+
+kernel void f(const constant half3x4* tint_symbol_1 [[buffer(0)]]) {
+  half3x4 const l_m = *(tint_symbol_1);
+  half4 const l_m_1 = (*(tint_symbol_1))[1];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/static_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..546939d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/static_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,75 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 44
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %m_block_std140 "m_block_std140"
+               OpMemberName %m_block_std140 0 "inner_0"
+               OpMemberName %m_block_std140 1 "inner_1"
+               OpMemberName %m_block_std140 2 "inner_2"
+               OpName %m "m"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %load_m_inner "load_m_inner"
+               OpName %f "f"
+               OpDecorate %m_block_std140 Block
+               OpMemberDecorate %m_block_std140 0 Offset 0
+               OpMemberDecorate %m_block_std140 1 Offset 8
+               OpMemberDecorate %m_block_std140 2 Offset 16
+               OpDecorate %m NonWritable
+               OpDecorate %m DescriptorSet 0
+               OpDecorate %m Binding 0
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+%m_block_std140 = OpTypeStruct %v4half %v4half %v4half
+%_ptr_Uniform_m_block_std140 = OpTypePointer Uniform %m_block_std140
+          %m = OpVariable %_ptr_Uniform_m_block_std140 Uniform
+        %int = OpTypeInt 32 1
+          %7 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %7
+         %10 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+ %mat3v4half = OpTypeMatrix %v4half 3
+         %17 = OpTypeFunction %mat3v4half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+       %void = OpTypeVoid
+         %37 = OpTypeFunction %void
+          %i = OpFunction %int None %10
+         %12 = OpLabel
+         %13 = OpLoad %int %counter
+         %15 = OpIAdd %int %13 %int_1
+               OpStore %counter %15
+         %16 = OpLoad %int %counter
+               OpReturnValue %16
+               OpFunctionEnd
+%load_m_inner = OpFunction %mat3v4half None %17
+         %20 = OpLabel
+         %26 = OpAccessChain %_ptr_Uniform_v4half %m %uint_0
+         %27 = OpLoad %v4half %26
+         %30 = OpAccessChain %_ptr_Uniform_v4half %m %uint_1
+         %31 = OpLoad %v4half %30
+         %34 = OpAccessChain %_ptr_Uniform_v4half %m %uint_2
+         %35 = OpLoad %v4half %34
+         %36 = OpCompositeConstruct %mat3v4half %27 %31 %35
+               OpReturnValue %36
+               OpFunctionEnd
+          %f = OpFunction %void None %37
+         %40 = OpLabel
+         %41 = OpFunctionCall %mat3v4half %load_m_inner
+         %42 = OpAccessChain %_ptr_Uniform_v4half %m %uint_1
+         %43 = OpLoad %v4half %42
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/static_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..a814872
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/static_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> m : mat3x4<f16>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m = &(m);
+  let p_m_1 = &((*(p_m))[1]);
+  let l_m : mat3x4<f16> = *(p_m);
+  let l_m_1 : vec4<f16> = *(p_m_1);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_builtin.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_builtin.wgsl
new file mode 100644
index 0000000..289193b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_builtin.wgsl
@@ -0,0 +1,10 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat3x4<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+    let t = transpose(u);
+    let l = length(u[1]);
+    let a = abs(u[0].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_builtin.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..80a685f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_builtin.wgsl.expected.dxc.hlsl
@@ -0,0 +1,36 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+
+matrix<float16_t, 3, 4> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  return matrix<float16_t, 3, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 4, 3> t = transpose(tint_symbol(u, 0u));
+  uint2 ubo_load_6 = u[0].zw;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  const float16_t l = length(vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+  uint2 ubo_load_7 = u[0].xy;
+  vector<float16_t, 2> ubo_load_7_xz = vector<float16_t, 2>(f16tof32(ubo_load_7 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_7_yw = vector<float16_t, 2>(f16tof32(ubo_load_7 >> 16));
+  const float16_t a = abs(vector<float16_t, 4>(ubo_load_7_xz[0], ubo_load_7_yw[0], ubo_load_7_xz[1], ubo_load_7_yw[1]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_builtin.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..c2fde4f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_builtin.wgsl.expected.fxc.hlsl
@@ -0,0 +1,41 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+
+matrix<float16_t, 3, 4> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  return matrix<float16_t, 3, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 4, 3> t = transpose(tint_symbol(u, 0u));
+  uint2 ubo_load_6 = u[0].zw;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  const float16_t l = length(vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+  uint2 ubo_load_7 = u[0].xy;
+  vector<float16_t, 2> ubo_load_7_xz = vector<float16_t, 2>(f16tof32(ubo_load_7 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_7_yw = vector<float16_t, 2>(f16tof32(ubo_load_7 >> 16));
+  const float16_t a = abs(vector<float16_t, 4>(ubo_load_7_xz[0], ubo_load_7_yw[0], ubo_load_7_xz[1], ubo_load_7_yw[1]).ywxz.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001DE25EAC9C0(5,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_builtin.wgsl.expected.glsl
new file mode 100644
index 0000000..ea7d264
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_builtin.wgsl.expected.glsl
@@ -0,0 +1,24 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec4 inner_0;
+  f16vec4 inner_1;
+  f16vec4 inner_2;
+} u;
+
+f16mat3x4 load_u_inner() {
+  return f16mat3x4(u.inner_0, u.inner_1, u.inner_2);
+}
+
+void f() {
+  f16mat4x3 t = transpose(load_u_inner());
+  float16_t l = length(u.inner_1);
+  float16_t a = abs(u.inner_0.ywxz[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_builtin.wgsl.expected.msl
new file mode 100644
index 0000000..45f91fd
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_builtin.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f(const constant half3x4* tint_symbol [[buffer(0)]]) {
+  half4x3 const t = transpose(*(tint_symbol));
+  half const l = length((*(tint_symbol))[1]);
+  half const a = fabs(half4((*(tint_symbol))[0]).ywxz[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_builtin.wgsl.expected.spvasm
new file mode 100644
index 0000000..da62171
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_builtin.wgsl.expected.spvasm
@@ -0,0 +1,70 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 44
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+         %35 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpMemberName %u_block_std140 2 "inner_2"
+               OpName %u "u"
+               OpName %load_u_inner "load_u_inner"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 8
+               OpMemberDecorate %u_block_std140 2 Offset 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+%u_block_std140 = OpTypeStruct %v4half %v4half %v4half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat3v4half = OpTypeMatrix %v4half 3
+          %6 = OpTypeFunction %mat3v4half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+       %void = OpTypeVoid
+         %26 = OpTypeFunction %void
+     %v3half = OpTypeVector %half 3
+ %mat4v3half = OpTypeMatrix %v3half 4
+         %42 = OpConstantNull %uint
+%load_u_inner = OpFunction %mat3v4half None %6
+          %9 = OpLabel
+         %15 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0
+         %16 = OpLoad %v4half %15
+         %19 = OpAccessChain %_ptr_Uniform_v4half %u %uint_1
+         %20 = OpLoad %v4half %19
+         %23 = OpAccessChain %_ptr_Uniform_v4half %u %uint_2
+         %24 = OpLoad %v4half %23
+         %25 = OpCompositeConstruct %mat3v4half %16 %20 %24
+               OpReturnValue %25
+               OpFunctionEnd
+          %f = OpFunction %void None %26
+         %29 = OpLabel
+         %33 = OpFunctionCall %mat3v4half %load_u_inner
+         %30 = OpTranspose %mat4v3half %33
+         %36 = OpAccessChain %_ptr_Uniform_v4half %u %uint_1
+         %37 = OpLoad %v4half %36
+         %34 = OpExtInst %half %35 Length %37
+         %39 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0
+         %40 = OpLoad %v4half %39
+         %41 = OpVectorShuffle %v4half %40 %40 1 3 0 2
+         %43 = OpCompositeExtract %half %41 0
+         %38 = OpExtInst %half %35 FAbs %43
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_builtin.wgsl.expected.wgsl
new file mode 100644
index 0000000..2dd842a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_builtin.wgsl.expected.wgsl
@@ -0,0 +1,10 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat3x4<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let t = transpose(u);
+  let l = length(u[1]);
+  let a = abs(u[0].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_fn.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_fn.wgsl
new file mode 100644
index 0000000..842e96b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_fn.wgsl
@@ -0,0 +1,16 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat3x4<f16>;
+
+fn a(m : mat3x4<f16>) {}
+fn b(v : vec4<f16>) {}
+fn c(f : f16) {}
+
+@compute @workgroup_size(1)
+fn f() {
+    a(u);
+    b(u[1]);
+    b(u[1].ywxz);
+    c(u[1].x);
+    c(u[1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_fn.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..e92c783
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_fn.wgsl.expected.dxc.hlsl
@@ -0,0 +1,50 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+
+void a(matrix<float16_t, 3, 4> m) {
+}
+
+void b(vector<float16_t, 4> v) {
+}
+
+void c(float16_t f_1) {
+}
+
+matrix<float16_t, 3, 4> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  return matrix<float16_t, 3, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  uint2 ubo_load_6 = u[0].zw;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  b(vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+  uint2 ubo_load_7 = u[0].zw;
+  vector<float16_t, 2> ubo_load_7_xz = vector<float16_t, 2>(f16tof32(ubo_load_7 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_7_yw = vector<float16_t, 2>(f16tof32(ubo_load_7 >> 16));
+  b(vector<float16_t, 4>(ubo_load_7_xz[0], ubo_load_7_yw[0], ubo_load_7_xz[1], ubo_load_7_yw[1]).ywxz);
+  c(float16_t(f16tof32(((u[0].z) & 0xFFFF))));
+  uint2 ubo_load_8 = u[0].zw;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_8_yw = vector<float16_t, 2>(f16tof32(ubo_load_8 >> 16));
+  c(vector<float16_t, 4>(ubo_load_8_xz[0], ubo_load_8_yw[0], ubo_load_8_xz[1], ubo_load_8_yw[1]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_fn.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..be27f56
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_fn.wgsl.expected.fxc.hlsl
@@ -0,0 +1,57 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+
+void a(matrix<float16_t, 3, 4> m) {
+}
+
+void b(vector<float16_t, 4> v) {
+}
+
+void c(float16_t f_1) {
+}
+
+matrix<float16_t, 3, 4> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  return matrix<float16_t, 3, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  uint2 ubo_load_6 = u[0].zw;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  b(vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+  uint2 ubo_load_7 = u[0].zw;
+  vector<float16_t, 2> ubo_load_7_xz = vector<float16_t, 2>(f16tof32(ubo_load_7 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_7_yw = vector<float16_t, 2>(f16tof32(ubo_load_7 >> 16));
+  b(vector<float16_t, 4>(ubo_load_7_xz[0], ubo_load_7_yw[0], ubo_load_7_xz[1], ubo_load_7_yw[1]).ywxz);
+  c(float16_t(f16tof32(((u[0].z) & 0xFFFF))));
+  uint2 ubo_load_8 = u[0].zw;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_8_yw = vector<float16_t, 2>(f16tof32(ubo_load_8 >> 16));
+  c(vector<float16_t, 4>(ubo_load_8_xz[0], ubo_load_8_yw[0], ubo_load_8_xz[1], ubo_load_8_yw[1]).ywxz.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000002E63B0EDB50(5,15-23): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000002E63B0EDB50(8,15-23): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000002E63B0EDB50(11,8-16): error X3000: unrecognized identifier 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_fn.wgsl.expected.glsl
new file mode 100644
index 0000000..94fbbaa
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_fn.wgsl.expected.glsl
@@ -0,0 +1,35 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec4 inner_0;
+  f16vec4 inner_1;
+  f16vec4 inner_2;
+} u;
+
+void a(f16mat3x4 m) {
+}
+
+void b(f16vec4 v) {
+}
+
+void c(float16_t f_1) {
+}
+
+f16mat3x4 load_u_inner() {
+  return f16mat3x4(u.inner_0, u.inner_1, u.inner_2);
+}
+
+void f() {
+  a(load_u_inner());
+  b(u.inner_1);
+  b(u.inner_1.ywxz);
+  c(u.inner_1[0u]);
+  c(u.inner_1.ywxz[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_fn.wgsl.expected.msl
new file mode 100644
index 0000000..8f44101
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_fn.wgsl.expected.msl
@@ -0,0 +1,21 @@
+#include <metal_stdlib>
+
+using namespace metal;
+void a(half3x4 m) {
+}
+
+void b(half4 v) {
+}
+
+void c(half f_1) {
+}
+
+kernel void f(const constant half3x4* tint_symbol [[buffer(0)]]) {
+  a(*(tint_symbol));
+  b((*(tint_symbol))[1]);
+  b(half4((*(tint_symbol))[1]).ywxz);
+  c((*(tint_symbol))[1][0]);
+  c(half4((*(tint_symbol))[1]).ywxz[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_fn.wgsl.expected.spvasm
new file mode 100644
index 0000000..13f9566
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_fn.wgsl.expected.spvasm
@@ -0,0 +1,99 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 61
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpMemberName %u_block_std140 2 "inner_2"
+               OpName %u "u"
+               OpName %a "a"
+               OpName %m "m"
+               OpName %b "b"
+               OpName %v "v"
+               OpName %c "c"
+               OpName %f_1 "f_1"
+               OpName %load_u_inner "load_u_inner"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 8
+               OpMemberDecorate %u_block_std140 2 Offset 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+%u_block_std140 = OpTypeStruct %v4half %v4half %v4half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+       %void = OpTypeVoid
+ %mat3v4half = OpTypeMatrix %v4half 3
+          %6 = OpTypeFunction %void %mat3v4half
+         %12 = OpTypeFunction %void %v4half
+         %16 = OpTypeFunction %void %half
+         %20 = OpTypeFunction %mat3v4half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+         %39 = OpTypeFunction %void
+         %52 = OpConstantNull %uint
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+          %a = OpFunction %void None %6
+          %m = OpFunctionParameter %mat3v4half
+         %11 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %b = OpFunction %void None %12
+          %v = OpFunctionParameter %v4half
+         %15 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %c = OpFunction %void None %16
+        %f_1 = OpFunctionParameter %half
+         %19 = OpLabel
+               OpReturn
+               OpFunctionEnd
+%load_u_inner = OpFunction %mat3v4half None %20
+         %22 = OpLabel
+         %28 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0
+         %29 = OpLoad %v4half %28
+         %32 = OpAccessChain %_ptr_Uniform_v4half %u %uint_1
+         %33 = OpLoad %v4half %32
+         %36 = OpAccessChain %_ptr_Uniform_v4half %u %uint_2
+         %37 = OpLoad %v4half %36
+         %38 = OpCompositeConstruct %mat3v4half %29 %33 %37
+               OpReturnValue %38
+               OpFunctionEnd
+          %f = OpFunction %void None %39
+         %41 = OpLabel
+         %43 = OpFunctionCall %mat3v4half %load_u_inner
+         %42 = OpFunctionCall %void %a %43
+         %45 = OpAccessChain %_ptr_Uniform_v4half %u %uint_1
+         %46 = OpLoad %v4half %45
+         %44 = OpFunctionCall %void %b %46
+         %48 = OpAccessChain %_ptr_Uniform_v4half %u %uint_1
+         %49 = OpLoad %v4half %48
+         %50 = OpVectorShuffle %v4half %49 %49 1 3 0 2
+         %47 = OpFunctionCall %void %b %50
+         %54 = OpAccessChain %_ptr_Uniform_half %u %uint_1 %52
+         %55 = OpLoad %half %54
+         %51 = OpFunctionCall %void %c %55
+         %57 = OpAccessChain %_ptr_Uniform_v4half %u %uint_1
+         %58 = OpLoad %v4half %57
+         %59 = OpVectorShuffle %v4half %58 %58 1 3 0 2
+         %60 = OpCompositeExtract %half %59 0
+         %56 = OpFunctionCall %void %c %60
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_fn.wgsl.expected.wgsl
new file mode 100644
index 0000000..87d6244
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_fn.wgsl.expected.wgsl
@@ -0,0 +1,21 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat3x4<f16>;
+
+fn a(m : mat3x4<f16>) {
+}
+
+fn b(v : vec4<f16>) {
+}
+
+fn c(f : f16) {
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  a(u);
+  b(u[1]);
+  b(u[1].ywxz);
+  c(u[1].x);
+  c(u[1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_private.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_private.wgsl
new file mode 100644
index 0000000..cd35569
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_private.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat3x4<f16>;
+var<private> p : mat3x4<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[0];
+    p[1] = u[0].ywxz;
+    p[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_private.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..1d40f2b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_private.wgsl.expected.dxc.hlsl
@@ -0,0 +1,38 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+static matrix<float16_t, 3, 4> p = matrix<float16_t, 3, 4>(float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h));
+
+matrix<float16_t, 3, 4> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  return matrix<float16_t, 3, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  uint2 ubo_load_6 = u[0].xy;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  p[1] = vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]);
+  uint2 ubo_load_7 = u[0].xy;
+  vector<float16_t, 2> ubo_load_7_xz = vector<float16_t, 2>(f16tof32(ubo_load_7 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_7_yw = vector<float16_t, 2>(f16tof32(ubo_load_7 >> 16));
+  p[1] = vector<float16_t, 4>(ubo_load_7_xz[0], ubo_load_7_yw[0], ubo_load_7_xz[1], ubo_load_7_yw[1]).ywxz;
+  p[0][1] = float16_t(f16tof32(((u[0].z) & 0xFFFF)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_private.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..6db6a05
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_private.wgsl.expected.fxc.hlsl
@@ -0,0 +1,43 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+static matrix<float16_t, 3, 4> p = matrix<float16_t, 3, 4>(float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h));
+
+matrix<float16_t, 3, 4> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  return matrix<float16_t, 3, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  uint2 ubo_load_6 = u[0].xy;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  p[1] = vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]);
+  uint2 ubo_load_7 = u[0].xy;
+  vector<float16_t, 2> ubo_load_7_xz = vector<float16_t, 2>(f16tof32(ubo_load_7 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_7_yw = vector<float16_t, 2>(f16tof32(ubo_load_7 >> 16));
+  p[1] = vector<float16_t, 4>(ubo_load_7_xz[0], ubo_load_7_yw[0], ubo_load_7_xz[1], ubo_load_7_yw[1]).ywxz;
+  p[0][1] = float16_t(f16tof32(((u[0].z) & 0xFFFF)));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000002EEEBC7D430(4,15-23): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..3adf16e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_private.wgsl.expected.glsl
@@ -0,0 +1,26 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec4 inner_0;
+  f16vec4 inner_1;
+  f16vec4 inner_2;
+} u;
+
+f16mat3x4 p = f16mat3x4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf);
+f16mat3x4 load_u_inner() {
+  return f16mat3x4(u.inner_0, u.inner_1, u.inner_2);
+}
+
+void f() {
+  p = load_u_inner();
+  p[1] = u.inner_0;
+  p[1] = u.inner_0.ywxz;
+  p[0][1] = u.inner_1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..2293b30
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_private.wgsl.expected.msl
@@ -0,0 +1,12 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f(const constant half3x4* tint_symbol_1 [[buffer(0)]]) {
+  thread half3x4 tint_symbol = half3x4(0.0h);
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[0];
+  tint_symbol[1] = half4((*(tint_symbol_1))[0]).ywxz;
+  tint_symbol[0][1] = (*(tint_symbol_1))[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_private.wgsl.expected.spvasm
new file mode 100644
index 0000000..03f3553
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_private.wgsl.expected.spvasm
@@ -0,0 +1,82 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 51
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpMemberName %u_block_std140 2 "inner_2"
+               OpName %u "u"
+               OpName %p "p"
+               OpName %load_u_inner "load_u_inner"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 8
+               OpMemberDecorate %u_block_std140 2 Offset 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+%u_block_std140 = OpTypeStruct %v4half %v4half %v4half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat3v4half = OpTypeMatrix %v4half 3
+%_ptr_Private_mat3v4half = OpTypePointer Private %mat3v4half
+          %9 = OpConstantNull %mat3v4half
+          %p = OpVariable %_ptr_Private_mat3v4half Private %9
+         %10 = OpTypeFunction %mat3v4half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+       %void = OpTypeVoid
+         %29 = OpTypeFunction %void
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Private_v4half = OpTypePointer Private %v4half
+         %44 = OpConstantNull %int
+%_ptr_Private_half = OpTypePointer Private %half
+         %47 = OpConstantNull %uint
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+%load_u_inner = OpFunction %mat3v4half None %10
+         %12 = OpLabel
+         %18 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0
+         %19 = OpLoad %v4half %18
+         %22 = OpAccessChain %_ptr_Uniform_v4half %u %uint_1
+         %23 = OpLoad %v4half %22
+         %26 = OpAccessChain %_ptr_Uniform_v4half %u %uint_2
+         %27 = OpLoad %v4half %26
+         %28 = OpCompositeConstruct %mat3v4half %19 %23 %27
+               OpReturnValue %28
+               OpFunctionEnd
+          %f = OpFunction %void None %29
+         %32 = OpLabel
+         %33 = OpFunctionCall %mat3v4half %load_u_inner
+               OpStore %p %33
+         %37 = OpAccessChain %_ptr_Private_v4half %p %int_1
+         %38 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0
+         %39 = OpLoad %v4half %38
+               OpStore %37 %39
+         %40 = OpAccessChain %_ptr_Private_v4half %p %int_1
+         %41 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0
+         %42 = OpLoad %v4half %41
+         %43 = OpVectorShuffle %v4half %42 %42 1 3 0 2
+               OpStore %40 %43
+         %46 = OpAccessChain %_ptr_Private_half %p %44 %int_1
+         %49 = OpAccessChain %_ptr_Uniform_half %u %uint_1 %47
+         %50 = OpLoad %half %49
+               OpStore %46 %50
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..d80add7d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_private.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat3x4<f16>;
+
+var<private> p : mat3x4<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[0];
+  p[1] = u[0].ywxz;
+  p[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_storage.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_storage.wgsl
new file mode 100644
index 0000000..a57d0c6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_storage.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat3x4<f16>;
+@group(0) @binding(1) var<storage, read_write> s : mat3x4<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[0];
+    s[1] = u[0].ywxz;
+    s[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_storage.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..a4c97e9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_storage.wgsl.expected.dxc.hlsl
@@ -0,0 +1,44 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 3, 4> value) {
+  buffer.Store<vector<float16_t, 4> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 8u), value[1u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 16u), value[2u]);
+}
+
+matrix<float16_t, 3, 4> tint_symbol_2(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  return matrix<float16_t, 3, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_2(u, 0u));
+  uint2 ubo_load_6 = u[0].xy;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  s.Store<vector<float16_t, 4> >(8u, vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+  uint2 ubo_load_7 = u[0].xy;
+  vector<float16_t, 2> ubo_load_7_xz = vector<float16_t, 2>(f16tof32(ubo_load_7 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_7_yw = vector<float16_t, 2>(f16tof32(ubo_load_7 >> 16));
+  s.Store<vector<float16_t, 4> >(8u, vector<float16_t, 4>(ubo_load_7_xz[0], ubo_load_7_yw[0], ubo_load_7_xz[1], ubo_load_7_yw[1]).ywxz);
+  s.Store<float16_t>(2u, float16_t(f16tof32(((u[0].z) & 0xFFFF))));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_storage.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..627d5f9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_storage.wgsl.expected.fxc.hlsl
@@ -0,0 +1,50 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 3, 4> value) {
+  buffer.Store<vector<float16_t, 4> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 8u), value[1u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 16u), value[2u]);
+}
+
+matrix<float16_t, 3, 4> tint_symbol_2(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  return matrix<float16_t, 3, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_2(u, 0u));
+  uint2 ubo_load_6 = u[0].xy;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  s.Store<vector<float16_t, 4> >(8u, vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+  uint2 ubo_load_7 = u[0].xy;
+  vector<float16_t, 2> ubo_load_7_xz = vector<float16_t, 2>(f16tof32(ubo_load_7 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_7_yw = vector<float16_t, 2>(f16tof32(ubo_load_7 >> 16));
+  s.Store<vector<float16_t, 4> >(8u, vector<float16_t, 4>(ubo_load_7_xz[0], ubo_load_7_yw[0], ubo_load_7_xz[1], ubo_load_7_yw[1]).ywxz);
+  s.Store<float16_t>(2u, float16_t(f16tof32(((u[0].z) & 0xFFFF))));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000002438C2DBBB0(6,66-74): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000002438C2DBBB0(7,3-14): error X3018: invalid subscript 'Store'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..ac8aaf9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_storage.wgsl.expected.glsl
@@ -0,0 +1,29 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec4 inner_0;
+  f16vec4 inner_1;
+  f16vec4 inner_2;
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  f16mat3x4 inner;
+} s;
+
+f16mat3x4 load_u_inner() {
+  return f16mat3x4(u.inner_0, u.inner_1, u.inner_2);
+}
+
+void f() {
+  s.inner = load_u_inner();
+  s.inner[1] = u.inner_0;
+  s.inner[1] = u.inner_0.ywxz;
+  s.inner[0][1] = u.inner_1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..7684631
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_storage.wgsl.expected.msl
@@ -0,0 +1,11 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f(device half3x4* tint_symbol [[buffer(1)]], const constant half3x4* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[0];
+  (*(tint_symbol))[1] = half4((*(tint_symbol_1))[0]).ywxz;
+  (*(tint_symbol))[0][1] = (*(tint_symbol_1))[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_storage.wgsl.expected.spvasm
new file mode 100644
index 0000000..6f45e68
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_storage.wgsl.expected.spvasm
@@ -0,0 +1,92 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 53
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpMemberName %u_block_std140 2 "inner_2"
+               OpName %u "u"
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %s "s"
+               OpName %load_u_inner "load_u_inner"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 8
+               OpMemberDecorate %u_block_std140 2 Offset 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 8
+               OpDecorate %s DescriptorSet 0
+               OpDecorate %s Binding 1
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+%u_block_std140 = OpTypeStruct %v4half %v4half %v4half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat3v4half = OpTypeMatrix %v4half 3
+    %u_block = OpTypeStruct %mat3v4half
+%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
+          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+         %10 = OpTypeFunction %mat3v4half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+       %void = OpTypeVoid
+         %29 = OpTypeFunction %void
+%_ptr_StorageBuffer_mat3v4half = OpTypePointer StorageBuffer %mat3v4half
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_v4half = OpTypePointer StorageBuffer %v4half
+         %46 = OpConstantNull %int
+%_ptr_StorageBuffer_half = OpTypePointer StorageBuffer %half
+         %49 = OpConstantNull %uint
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+%load_u_inner = OpFunction %mat3v4half None %10
+         %12 = OpLabel
+         %18 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0
+         %19 = OpLoad %v4half %18
+         %22 = OpAccessChain %_ptr_Uniform_v4half %u %uint_1
+         %23 = OpLoad %v4half %22
+         %26 = OpAccessChain %_ptr_Uniform_v4half %u %uint_2
+         %27 = OpLoad %v4half %26
+         %28 = OpCompositeConstruct %mat3v4half %19 %23 %27
+               OpReturnValue %28
+               OpFunctionEnd
+          %f = OpFunction %void None %29
+         %32 = OpLabel
+         %34 = OpAccessChain %_ptr_StorageBuffer_mat3v4half %s %uint_0
+         %35 = OpFunctionCall %mat3v4half %load_u_inner
+               OpStore %34 %35
+         %39 = OpAccessChain %_ptr_StorageBuffer_v4half %s %uint_0 %int_1
+         %40 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0
+         %41 = OpLoad %v4half %40
+               OpStore %39 %41
+         %42 = OpAccessChain %_ptr_StorageBuffer_v4half %s %uint_0 %int_1
+         %43 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0
+         %44 = OpLoad %v4half %43
+         %45 = OpVectorShuffle %v4half %44 %44 1 3 0 2
+               OpStore %42 %45
+         %48 = OpAccessChain %_ptr_StorageBuffer_half %s %uint_0 %46 %int_1
+         %51 = OpAccessChain %_ptr_Uniform_half %u %uint_1 %49
+         %52 = OpLoad %half %51
+               OpStore %48 %52
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..9a28896
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat3x4<f16>;
+
+@group(0) @binding(1) var<storage, read_write> s : mat3x4<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[0];
+  s[1] = u[0].ywxz;
+  s[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_workgroup.wgsl
new file mode 100644
index 0000000..6c66c2f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_workgroup.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat3x4<f16>;
+var<workgroup> w : mat3x4<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[0];
+    w[1] = u[0].ywxz;
+    w[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_workgroup.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..5dd6888
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_workgroup.wgsl.expected.dxc.hlsl
@@ -0,0 +1,50 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+groupshared matrix<float16_t, 3, 4> w;
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 3, 4> tint_symbol_2(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  return matrix<float16_t, 3, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]));
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    w = matrix<float16_t, 3, 4>((float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx);
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  uint2 ubo_load_6 = u[0].xy;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  w[1] = vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]);
+  uint2 ubo_load_7 = u[0].xy;
+  vector<float16_t, 2> ubo_load_7_xz = vector<float16_t, 2>(f16tof32(ubo_load_7 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_7_yw = vector<float16_t, 2>(f16tof32(ubo_load_7 >> 16));
+  w[1] = vector<float16_t, 4>(ubo_load_7_xz[0], ubo_load_7_yw[0], ubo_load_7_xz[1], ubo_load_7_yw[1]).ywxz;
+  w[0][1] = float16_t(f16tof32(((u[0].z) & 0xFFFF)));
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_workgroup.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..9774f46
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_workgroup.wgsl.expected.fxc.hlsl
@@ -0,0 +1,55 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+groupshared matrix<float16_t, 3, 4> w;
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 3, 4> tint_symbol_2(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  return matrix<float16_t, 3, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]));
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    w = matrix<float16_t, 3, 4>((float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx);
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  uint2 ubo_load_6 = u[0].xy;
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  w[1] = vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]);
+  uint2 ubo_load_7 = u[0].xy;
+  vector<float16_t, 2> ubo_load_7_xz = vector<float16_t, 2>(f16tof32(ubo_load_7 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_7_yw = vector<float16_t, 2>(f16tof32(ubo_load_7 >> 16));
+  w[1] = vector<float16_t, 4>(ubo_load_7_xz[0], ubo_load_7_yw[0], ubo_load_7_xz[1], ubo_load_7_yw[1]).ywxz;
+  w[0][1] = float16_t(f16tof32(((u[0].z) & 0xFFFF)));
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000002AEEC70C750(4,20-28): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..d937cd8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,30 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec4 inner_0;
+  f16vec4 inner_1;
+  f16vec4 inner_2;
+} u;
+
+shared f16mat3x4 w;
+f16mat3x4 load_u_inner() {
+  return f16mat3x4(u.inner_0, u.inner_1, u.inner_2);
+}
+
+void f(uint local_invocation_index) {
+  {
+    w = f16mat3x4(f16vec4(0.0hf), f16vec4(0.0hf), f16vec4(0.0hf));
+  }
+  barrier();
+  w = load_u_inner();
+  w[1] = u.inner_0;
+  w[1] = u.inner_0.ywxz;
+  w[0][1] = u.inner_1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..8291498
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,24 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct tint_symbol_5 {
+  half3x4 w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup half3x4* const tint_symbol, const constant half3x4* const tint_symbol_1) {
+  {
+    *(tint_symbol) = half3x4(half4(0.0h), half4(0.0h), half4(0.0h));
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[0];
+  (*(tint_symbol))[1] = half4((*(tint_symbol_1))[0]).ywxz;
+  (*(tint_symbol))[0][1] = (*(tint_symbol_1))[1][0];
+}
+
+kernel void f(const constant half3x4* tint_symbol_4 [[buffer(0)]], threadgroup tint_symbol_5* tint_symbol_3 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup half3x4* const tint_symbol_2 = &((*(tint_symbol_3)).w);
+  f_inner(local_invocation_index, tint_symbol_2, tint_symbol_4);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_workgroup.wgsl.expected.spvasm
new file mode 100644
index 0000000..962956a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_workgroup.wgsl.expected.spvasm
@@ -0,0 +1,99 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 61
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %local_invocation_index_1 "local_invocation_index_1"
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpMemberName %u_block_std140 2 "inner_2"
+               OpName %u "u"
+               OpName %w "w"
+               OpName %load_u_inner "load_u_inner"
+               OpName %f_inner "f_inner"
+               OpName %local_invocation_index "local_invocation_index"
+               OpName %f "f"
+               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 8
+               OpMemberDecorate %u_block_std140 2 Offset 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+%u_block_std140 = OpTypeStruct %v4half %v4half %v4half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat3v4half = OpTypeMatrix %v4half 3
+%_ptr_Workgroup_mat3v4half = OpTypePointer Workgroup %mat3v4half
+          %w = OpVariable %_ptr_Workgroup_mat3v4half Workgroup
+         %12 = OpTypeFunction %mat3v4half
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+       %void = OpTypeVoid
+         %30 = OpTypeFunction %void %uint
+         %35 = OpConstantNull %mat3v4half
+   %uint_264 = OpConstant %uint 264
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Workgroup_v4half = OpTypePointer Workgroup %v4half
+         %49 = OpConstantNull %int
+%_ptr_Workgroup_half = OpTypePointer Workgroup %half
+         %52 = OpConstantNull %uint
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+         %56 = OpTypeFunction %void
+%load_u_inner = OpFunction %mat3v4half None %12
+         %14 = OpLabel
+         %19 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0
+         %20 = OpLoad %v4half %19
+         %23 = OpAccessChain %_ptr_Uniform_v4half %u %uint_1
+         %24 = OpLoad %v4half %23
+         %27 = OpAccessChain %_ptr_Uniform_v4half %u %uint_2
+         %28 = OpLoad %v4half %27
+         %29 = OpCompositeConstruct %mat3v4half %20 %24 %28
+               OpReturnValue %29
+               OpFunctionEnd
+    %f_inner = OpFunction %void None %30
+%local_invocation_index = OpFunctionParameter %uint
+         %34 = OpLabel
+               OpStore %w %35
+               OpControlBarrier %uint_2 %uint_2 %uint_264
+         %38 = OpFunctionCall %mat3v4half %load_u_inner
+               OpStore %w %38
+         %42 = OpAccessChain %_ptr_Workgroup_v4half %w %int_1
+         %43 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0
+         %44 = OpLoad %v4half %43
+               OpStore %42 %44
+         %45 = OpAccessChain %_ptr_Workgroup_v4half %w %int_1
+         %46 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0
+         %47 = OpLoad %v4half %46
+         %48 = OpVectorShuffle %v4half %47 %47 1 3 0 2
+               OpStore %45 %48
+         %51 = OpAccessChain %_ptr_Workgroup_half %w %49 %int_1
+         %54 = OpAccessChain %_ptr_Uniform_half %u %uint_1 %52
+         %55 = OpLoad %half %54
+               OpStore %51 %55
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %56
+         %58 = OpLabel
+         %60 = OpLoad %uint %local_invocation_index_1
+         %59 = OpFunctionCall %void %f_inner %60
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..911c3d7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f16/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat3x4<f16>;
+
+var<workgroup> w : mat3x4<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[0];
+  w[1] = u[0].ywxz;
+  w[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/dynamic_index_via_ptr.wgsl
new file mode 100644
index 0000000..a737e2d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/dynamic_index_via_ptr.wgsl
@@ -0,0 +1,13 @@
+@group(0) @binding(0) var<uniform> m : mat3x4<f32>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m   = &m;
+  let p_m_i = &((*p_m)[i()]);
+
+  let l_m   : mat3x4<f32> = *p_m;
+  let l_m_i : vec4<f32>   = *p_m_i;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..4fad9a2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,25 @@
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[3];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float3x4 tint_symbol(uint4 buffer[3], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_m_i_save = i();
+  const float3x4 l_m = tint_symbol(m, 0u);
+  const uint scalar_offset_3 = ((16u * uint(p_m_i_save))) / 4;
+  const float4 l_m_i = asfloat(m[scalar_offset_3 / 4]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..4fad9a2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,25 @@
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[3];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float3x4 tint_symbol(uint4 buffer[3], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_m_i_save = i();
+  const float3x4 l_m = tint_symbol(m, 0u);
+  const uint scalar_offset_3 = ((16u * uint(p_m_i_save))) / 4;
+  const float4 l_m_i = asfloat(m[scalar_offset_3 / 4]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..405239b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,24 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform m_block_ubo {
+  mat3x4 inner;
+} m;
+
+int counter = 0;
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+void f() {
+  int tint_symbol = i();
+  int p_m_i_save = tint_symbol;
+  mat3x4 l_m = m.inner;
+  vec4 l_m_i = m.inner[p_m_i_save];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..8774e83
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,17 @@
+#include <metal_stdlib>
+
+using namespace metal;
+int i() {
+  thread int tint_symbol_1 = 0;
+  tint_symbol_1 = as_type<int>((as_type<uint>(tint_symbol_1) + as_type<uint>(1)));
+  return tint_symbol_1;
+}
+
+kernel void f(const constant float3x4* tint_symbol_2 [[buffer(0)]]) {
+  int const tint_symbol = i();
+  int const p_m_i_save = tint_symbol;
+  float3x4 const l_m = *(tint_symbol_2);
+  float4 const l_m_i = (*(tint_symbol_2))[p_m_i_save];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..65b4895
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,57 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 31
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %m_block "m_block"
+               OpMemberName %m_block 0 "inner"
+               OpName %m "m"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %f "f"
+               OpDecorate %m_block Block
+               OpMemberDecorate %m_block 0 Offset 0
+               OpMemberDecorate %m_block 0 ColMajor
+               OpMemberDecorate %m_block 0 MatrixStride 16
+               OpDecorate %m NonWritable
+               OpDecorate %m DescriptorSet 0
+               OpDecorate %m Binding 0
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat3v4float = OpTypeMatrix %v4float 3
+    %m_block = OpTypeStruct %mat3v4float
+%_ptr_Uniform_m_block = OpTypePointer Uniform %m_block
+          %m = OpVariable %_ptr_Uniform_m_block Uniform
+        %int = OpTypeInt 32 1
+          %8 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %8
+         %11 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+       %void = OpTypeVoid
+         %18 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_mat3v4float = OpTypePointer Uniform %mat3v4float
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+          %i = OpFunction %int None %11
+         %13 = OpLabel
+         %14 = OpLoad %int %counter
+         %16 = OpIAdd %int %14 %int_1
+               OpStore %counter %16
+         %17 = OpLoad %int %counter
+               OpReturnValue %17
+               OpFunctionEnd
+          %f = OpFunction %void None %18
+         %21 = OpLabel
+         %22 = OpFunctionCall %int %i
+         %26 = OpAccessChain %_ptr_Uniform_mat3v4float %m %uint_0
+         %27 = OpLoad %mat3v4float %26
+         %29 = OpAccessChain %_ptr_Uniform_v4float %m %uint_0 %22
+         %30 = OpLoad %v4float %29
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..625ea9a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,16 @@
+@group(0) @binding(0) var<uniform> m : mat3x4<f32>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m = &(m);
+  let p_m_i = &((*(p_m))[i()]);
+  let l_m : mat3x4<f32> = *(p_m);
+  let l_m_i : vec4<f32> = *(p_m_i);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/static_index_via_ptr.wgsl
new file mode 100644
index 0000000..62f9041
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/static_index_via_ptr.wgsl
@@ -0,0 +1,13 @@
+@group(0) @binding(0) var<uniform> m : mat3x4<f32>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m   = &m;
+  let p_m_1 = &((*p_m)[1]);
+
+  let l_m   : mat3x4<f32> = *p_m;
+  let l_m_1 : vec4<f32>   = *p_m_1;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..c45de93
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,23 @@
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[3];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float3x4 tint_symbol(uint4 buffer[3], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float3x4 l_m = tint_symbol(m, 0u);
+  const float4 l_m_1 = asfloat(m[1]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..c45de93
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,23 @@
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[3];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float3x4 tint_symbol(uint4 buffer[3], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float3x4 l_m = tint_symbol(m, 0u);
+  const float4 l_m_1 = asfloat(m[1]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/static_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..0074214
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/static_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,16 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform m_block_ubo {
+  mat3x4 inner;
+} m;
+
+void f() {
+  mat3x4 l_m = m.inner;
+  vec4 l_m_1 = m.inner[1];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/static_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..e48a04b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/static_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,15 @@
+#include <metal_stdlib>
+
+using namespace metal;
+int i() {
+  thread int tint_symbol = 0;
+  tint_symbol = as_type<int>((as_type<uint>(tint_symbol) + as_type<uint>(1)));
+  return tint_symbol;
+}
+
+kernel void f(const constant float3x4* tint_symbol_1 [[buffer(0)]]) {
+  float3x4 const l_m = *(tint_symbol_1);
+  float4 const l_m_1 = (*(tint_symbol_1))[1];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/static_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..e50e62b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/static_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,56 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 30
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %m_block "m_block"
+               OpMemberName %m_block 0 "inner"
+               OpName %m "m"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %f "f"
+               OpDecorate %m_block Block
+               OpMemberDecorate %m_block 0 Offset 0
+               OpMemberDecorate %m_block 0 ColMajor
+               OpMemberDecorate %m_block 0 MatrixStride 16
+               OpDecorate %m NonWritable
+               OpDecorate %m DescriptorSet 0
+               OpDecorate %m Binding 0
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat3v4float = OpTypeMatrix %v4float 3
+    %m_block = OpTypeStruct %mat3v4float
+%_ptr_Uniform_m_block = OpTypePointer Uniform %m_block
+          %m = OpVariable %_ptr_Uniform_m_block Uniform
+        %int = OpTypeInt 32 1
+          %8 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %8
+         %11 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+       %void = OpTypeVoid
+         %18 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_mat3v4float = OpTypePointer Uniform %mat3v4float
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+          %i = OpFunction %int None %11
+         %13 = OpLabel
+         %14 = OpLoad %int %counter
+         %16 = OpIAdd %int %14 %int_1
+               OpStore %counter %16
+         %17 = OpLoad %int %counter
+               OpReturnValue %17
+               OpFunctionEnd
+          %f = OpFunction %void None %18
+         %21 = OpLabel
+         %25 = OpAccessChain %_ptr_Uniform_mat3v4float %m %uint_0
+         %26 = OpLoad %mat3v4float %25
+         %28 = OpAccessChain %_ptr_Uniform_v4float %m %uint_0 %int_1
+         %29 = OpLoad %v4float %28
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/static_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..ecef1a6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/static_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,16 @@
+@group(0) @binding(0) var<uniform> m : mat3x4<f32>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m = &(m);
+  let p_m_1 = &((*(p_m))[1]);
+  let l_m : mat3x4<f32> = *(p_m);
+  let l_m_1 : vec4<f32> = *(p_m_1);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_builtin.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_builtin.wgsl
new file mode 100644
index 0000000..9d0578e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_builtin.wgsl
@@ -0,0 +1,8 @@
+@group(0) @binding(0) var<uniform> u : mat3x4<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+    let t = transpose(u);
+    let l = length(u[1]);
+    let a = abs(u[0].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_builtin.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..619729e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_builtin.wgsl.expected.dxc.hlsl
@@ -0,0 +1,18 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[3];
+};
+
+float3x4 tint_symbol(uint4 buffer[3], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float4x3 t = transpose(tint_symbol(u, 0u));
+  const float l = length(asfloat(u[1]));
+  const float a = abs(asfloat(u[0]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_builtin.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..619729e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_builtin.wgsl.expected.fxc.hlsl
@@ -0,0 +1,18 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[3];
+};
+
+float3x4 tint_symbol(uint4 buffer[3], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float4x3 t = transpose(tint_symbol(u, 0u));
+  const float l = length(asfloat(u[1]));
+  const float a = abs(asfloat(u[0]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_builtin.wgsl.expected.glsl
new file mode 100644
index 0000000..f7f6904
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_builtin.wgsl.expected.glsl
@@ -0,0 +1,17 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat3x4 inner;
+} u;
+
+void f() {
+  mat4x3 t = transpose(u.inner);
+  float l = length(u.inner[1]);
+  float a = abs(u.inner[0].ywxz.x);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_builtin.wgsl.expected.msl
new file mode 100644
index 0000000..78ddda6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_builtin.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f(const constant float3x4* tint_symbol [[buffer(0)]]) {
+  float4x3 const t = transpose(*(tint_symbol));
+  float const l = length((*(tint_symbol))[1]);
+  float const a = fabs(float4((*(tint_symbol))[0]).ywxz[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_builtin.wgsl.expected.spvasm
new file mode 100644
index 0000000..150517c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_builtin.wgsl.expected.spvasm
@@ -0,0 +1,53 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 32
+; Schema: 0
+               OpCapability Shader
+         %20 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat3v4float = OpTypeMatrix %v4float 3
+    %u_block = OpTypeStruct %mat3v4float
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+          %7 = OpTypeFunction %void
+    %v3float = OpTypeVector %float 3
+%mat4v3float = OpTypeMatrix %v3float 4
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_mat3v4float = OpTypePointer Uniform %mat3v4float
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+         %27 = OpConstantNull %int
+          %f = OpFunction %void None %7
+         %10 = OpLabel
+         %17 = OpAccessChain %_ptr_Uniform_mat3v4float %u %uint_0
+         %18 = OpLoad %mat3v4float %17
+         %11 = OpTranspose %mat4v3float %18
+         %24 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %int_1
+         %25 = OpLoad %v4float %24
+         %19 = OpExtInst %float %20 Length %25
+         %28 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %27
+         %29 = OpLoad %v4float %28
+         %30 = OpVectorShuffle %v4float %29 %29 1 3 0 2
+         %31 = OpCompositeExtract %float %30 0
+         %26 = OpExtInst %float %20 FAbs %31
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_builtin.wgsl.expected.wgsl
new file mode 100644
index 0000000..cd3b10d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_builtin.wgsl.expected.wgsl
@@ -0,0 +1,8 @@
+@group(0) @binding(0) var<uniform> u : mat3x4<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let t = transpose(u);
+  let l = length(u[1]);
+  let a = abs(u[0].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_fn.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_fn.wgsl
new file mode 100644
index 0000000..8e98ca7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_fn.wgsl
@@ -0,0 +1,14 @@
+@group(0) @binding(0) var<uniform> u : mat3x4<f32>;
+
+fn a(m : mat3x4<f32>) {}
+fn b(v : vec4<f32>) {}
+fn c(f : f32) {}
+
+@compute @workgroup_size(1)
+fn f() {
+    a(u);
+    b(u[1]);
+    b(u[1].ywxz);
+    c(u[1].x);
+    c(u[1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_fn.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..697aafc
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_fn.wgsl.expected.dxc.hlsl
@@ -0,0 +1,29 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[3];
+};
+
+void a(float3x4 m) {
+}
+
+void b(float4 v) {
+}
+
+void c(float f_1) {
+}
+
+float3x4 tint_symbol(uint4 buffer[3], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(asfloat(u[1]));
+  b(asfloat(u[1]).ywxz);
+  c(asfloat(u[1].x));
+  c(asfloat(u[1]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_fn.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..697aafc
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_fn.wgsl.expected.fxc.hlsl
@@ -0,0 +1,29 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[3];
+};
+
+void a(float3x4 m) {
+}
+
+void b(float4 v) {
+}
+
+void c(float f_1) {
+}
+
+float3x4 tint_symbol(uint4 buffer[3], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(asfloat(u[1]));
+  b(asfloat(u[1]).ywxz);
+  c(asfloat(u[1].x));
+  c(asfloat(u[1]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_fn.wgsl.expected.glsl
new file mode 100644
index 0000000..620404b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_fn.wgsl.expected.glsl
@@ -0,0 +1,28 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat3x4 inner;
+} u;
+
+void a(mat3x4 m) {
+}
+
+void b(vec4 v) {
+}
+
+void c(float f_1) {
+}
+
+void f() {
+  a(u.inner);
+  b(u.inner[1]);
+  b(u.inner[1].ywxz);
+  c(u.inner[1].x);
+  c(u.inner[1].ywxz.x);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_fn.wgsl.expected.msl
new file mode 100644
index 0000000..1097f7e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_fn.wgsl.expected.msl
@@ -0,0 +1,21 @@
+#include <metal_stdlib>
+
+using namespace metal;
+void a(float3x4 m) {
+}
+
+void b(float4 v) {
+}
+
+void c(float f_1) {
+}
+
+kernel void f(const constant float3x4* tint_symbol [[buffer(0)]]) {
+  a(*(tint_symbol));
+  b((*(tint_symbol))[1]);
+  b(float4((*(tint_symbol))[1]).ywxz);
+  c((*(tint_symbol))[1][0]);
+  c(float4((*(tint_symbol))[1]).ywxz[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_fn.wgsl.expected.spvasm
new file mode 100644
index 0000000..2e87c98
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_fn.wgsl.expected.spvasm
@@ -0,0 +1,81 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 48
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %a "a"
+               OpName %m "m"
+               OpName %b "b"
+               OpName %v "v"
+               OpName %c "c"
+               OpName %f_1 "f_1"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat3v4float = OpTypeMatrix %v4float 3
+    %u_block = OpTypeStruct %mat3v4float
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+          %7 = OpTypeFunction %void %mat3v4float
+         %12 = OpTypeFunction %void %v4float
+         %16 = OpTypeFunction %void %float
+         %20 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_mat3v4float = OpTypePointer Uniform %mat3v4float
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+          %a = OpFunction %void None %7
+          %m = OpFunctionParameter %mat3v4float
+         %11 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %b = OpFunction %void None %12
+          %v = OpFunctionParameter %v4float
+         %15 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %c = OpFunction %void None %16
+        %f_1 = OpFunctionParameter %float
+         %19 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %20
+         %22 = OpLabel
+         %27 = OpAccessChain %_ptr_Uniform_mat3v4float %u %uint_0
+         %28 = OpLoad %mat3v4float %27
+         %23 = OpFunctionCall %void %a %28
+         %33 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %int_1
+         %34 = OpLoad %v4float %33
+         %29 = OpFunctionCall %void %b %34
+         %36 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %int_1
+         %37 = OpLoad %v4float %36
+         %38 = OpVectorShuffle %v4float %37 %37 1 3 0 2
+         %35 = OpFunctionCall %void %b %38
+         %41 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %int_1 %uint_0
+         %42 = OpLoad %float %41
+         %39 = OpFunctionCall %void %c %42
+         %44 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %int_1
+         %45 = OpLoad %v4float %44
+         %46 = OpVectorShuffle %v4float %45 %45 1 3 0 2
+         %47 = OpCompositeExtract %float %46 0
+         %43 = OpFunctionCall %void %c %47
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_fn.wgsl.expected.wgsl
new file mode 100644
index 0000000..cb1ecfb
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_fn.wgsl.expected.wgsl
@@ -0,0 +1,19 @@
+@group(0) @binding(0) var<uniform> u : mat3x4<f32>;
+
+fn a(m : mat3x4<f32>) {
+}
+
+fn b(v : vec4<f32>) {
+}
+
+fn c(f : f32) {
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  a(u);
+  b(u[1]);
+  b(u[1].ywxz);
+  c(u[1].x);
+  c(u[1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_private.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_private.wgsl
new file mode 100644
index 0000000..1cfdf67
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_private.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0) var<uniform> u : mat3x4<f32>;
+var<private> p : mat3x4<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[0];
+    p[1] = u[0].ywxz;
+    p[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_private.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..f6518d9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_private.wgsl.expected.dxc.hlsl
@@ -0,0 +1,20 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[3];
+};
+static float3x4 p = float3x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
+
+float3x4 tint_symbol(uint4 buffer[3], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = asfloat(u[0]);
+  p[1] = asfloat(u[0]).ywxz;
+  p[0][1] = asfloat(u[1].x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_private.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..f6518d9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_private.wgsl.expected.fxc.hlsl
@@ -0,0 +1,20 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[3];
+};
+static float3x4 p = float3x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
+
+float3x4 tint_symbol(uint4 buffer[3], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = asfloat(u[0]);
+  p[1] = asfloat(u[0]).ywxz;
+  p[0][1] = asfloat(u[1].x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..ebbbb86
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_private.wgsl.expected.glsl
@@ -0,0 +1,19 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat3x4 inner;
+} u;
+
+mat3x4 p = mat3x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
+void f() {
+  p = u.inner;
+  p[1] = u.inner[0];
+  p[1] = u.inner[0].ywxz;
+  p[0][1] = u.inner[1][0];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..a073777
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_private.wgsl.expected.msl
@@ -0,0 +1,12 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f(const constant float3x4* tint_symbol_1 [[buffer(0)]]) {
+  thread float3x4 tint_symbol = float3x4(0.0f);
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[0];
+  tint_symbol[1] = float4((*(tint_symbol_1))[0]).ywxz;
+  tint_symbol[0][1] = (*(tint_symbol_1))[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_private.wgsl.expected.spvasm
new file mode 100644
index 0000000..82befc1
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_private.wgsl.expected.spvasm
@@ -0,0 +1,62 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 36
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %p "p"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat3v4float = OpTypeMatrix %v4float 3
+    %u_block = OpTypeStruct %mat3v4float
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_Private_mat3v4float = OpTypePointer Private %mat3v4float
+          %9 = OpConstantNull %mat3v4float
+          %p = OpVariable %_ptr_Private_mat3v4float Private %9
+       %void = OpTypeVoid
+         %10 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_mat3v4float = OpTypePointer Uniform %mat3v4float
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Private_v4float = OpTypePointer Private %v4float
+         %23 = OpConstantNull %int
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+%_ptr_Private_float = OpTypePointer Private %float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+          %f = OpFunction %void None %10
+         %13 = OpLabel
+         %17 = OpAccessChain %_ptr_Uniform_mat3v4float %u %uint_0
+         %18 = OpLoad %mat3v4float %17
+               OpStore %p %18
+         %22 = OpAccessChain %_ptr_Private_v4float %p %int_1
+         %25 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %23
+         %26 = OpLoad %v4float %25
+               OpStore %22 %26
+         %27 = OpAccessChain %_ptr_Private_v4float %p %int_1
+         %28 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %23
+         %29 = OpLoad %v4float %28
+         %30 = OpVectorShuffle %v4float %29 %29 1 3 0 2
+               OpStore %27 %30
+         %32 = OpAccessChain %_ptr_Private_float %p %23 %int_1
+         %34 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %int_1 %23
+         %35 = OpLoad %float %34
+               OpStore %32 %35
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..41ffb6b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_private.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> u : mat3x4<f32>;
+
+var<private> p : mat3x4<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[0];
+  p[1] = u[0].ywxz;
+  p[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_storage.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_storage.wgsl
new file mode 100644
index 0000000..1742cf7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_storage.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0) var<uniform> u : mat3x4<f32>;
+@group(0) @binding(1) var<storage, read_write> s : mat3x4<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[0];
+    s[1] = u[0].ywxz;
+    s[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_storage.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..7891cea
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_storage.wgsl.expected.dxc.hlsl
@@ -0,0 +1,26 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[3];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, float3x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+  buffer.Store4((offset + 32u), asuint(value[2u]));
+}
+
+float3x4 tint_symbol_2(uint4 buffer[3], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_2(u, 0u));
+  s.Store4(16u, asuint(asfloat(u[0])));
+  s.Store4(16u, asuint(asfloat(u[0]).ywxz));
+  s.Store(4u, asuint(asfloat(u[1].x)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_storage.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..7891cea
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_storage.wgsl.expected.fxc.hlsl
@@ -0,0 +1,26 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[3];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, float3x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+  buffer.Store4((offset + 32u), asuint(value[2u]));
+}
+
+float3x4 tint_symbol_2(uint4 buffer[3], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_2(u, 0u));
+  s.Store4(16u, asuint(asfloat(u[0])));
+  s.Store4(16u, asuint(asfloat(u[0]).ywxz));
+  s.Store(4u, asuint(asfloat(u[1].x)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..358b0c2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_storage.wgsl.expected.glsl
@@ -0,0 +1,22 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat3x4 inner;
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  mat3x4 inner;
+} s;
+
+void f() {
+  s.inner = u.inner;
+  s.inner[1] = u.inner[0];
+  s.inner[1] = u.inner[0].ywxz;
+  s.inner[0][1] = u.inner[1][0];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..d7903f5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_storage.wgsl.expected.msl
@@ -0,0 +1,11 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f(device float3x4* tint_symbol [[buffer(1)]], const constant float3x4* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[0];
+  (*(tint_symbol))[1] = float4((*(tint_symbol_1))[0]).ywxz;
+  (*(tint_symbol))[0][1] = (*(tint_symbol_1))[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_storage.wgsl.expected.spvasm
new file mode 100644
index 0000000..8ca73c9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_storage.wgsl.expected.spvasm
@@ -0,0 +1,65 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 37
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %s "s"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %s DescriptorSet 0
+               OpDecorate %s Binding 1
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat3v4float = OpTypeMatrix %v4float 3
+    %u_block = OpTypeStruct %mat3v4float
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
+          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+       %void = OpTypeVoid
+          %9 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_mat3v4float = OpTypePointer StorageBuffer %mat3v4float
+%_ptr_Uniform_mat3v4float = OpTypePointer Uniform %mat3v4float
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_v4float = OpTypePointer StorageBuffer %v4float
+         %24 = OpConstantNull %int
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+          %f = OpFunction %void None %9
+         %12 = OpLabel
+         %16 = OpAccessChain %_ptr_StorageBuffer_mat3v4float %s %uint_0
+         %18 = OpAccessChain %_ptr_Uniform_mat3v4float %u %uint_0
+         %19 = OpLoad %mat3v4float %18
+               OpStore %16 %19
+         %23 = OpAccessChain %_ptr_StorageBuffer_v4float %s %uint_0 %int_1
+         %26 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %24
+         %27 = OpLoad %v4float %26
+               OpStore %23 %27
+         %28 = OpAccessChain %_ptr_StorageBuffer_v4float %s %uint_0 %int_1
+         %29 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %24
+         %30 = OpLoad %v4float %29
+         %31 = OpVectorShuffle %v4float %30 %30 1 3 0 2
+               OpStore %28 %31
+         %33 = OpAccessChain %_ptr_StorageBuffer_float %s %uint_0 %24 %int_1
+         %35 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %int_1 %24
+         %36 = OpLoad %float %35
+               OpStore %33 %36
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..4d2e528
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> u : mat3x4<f32>;
+
+@group(0) @binding(1) var<storage, read_write> s : mat3x4<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[0];
+  s[1] = u[0].ywxz;
+  s[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_workgroup.wgsl
new file mode 100644
index 0000000..5266522
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_workgroup.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0) var<uniform> u : mat3x4<f32>;
+var<workgroup> w : mat3x4<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[0];
+    w[1] = u[0].ywxz;
+    w[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_workgroup.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..84b835f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_workgroup.wgsl.expected.dxc.hlsl
@@ -0,0 +1,32 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[3];
+};
+groupshared float3x4 w;
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+float3x4 tint_symbol_2(uint4 buffer[3], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    w = float3x4((0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx);
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = asfloat(u[0]);
+  w[1] = asfloat(u[0]).ywxz;
+  w[0][1] = asfloat(u[1].x);
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_workgroup.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..84b835f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_workgroup.wgsl.expected.fxc.hlsl
@@ -0,0 +1,32 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[3];
+};
+groupshared float3x4 w;
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+float3x4 tint_symbol_2(uint4 buffer[3], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    w = float3x4((0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx);
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = asfloat(u[0]);
+  w[1] = asfloat(u[0]).ywxz;
+  w[0][1] = asfloat(u[1].x);
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..bf3eb87
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,23 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat3x4 inner;
+} u;
+
+shared mat3x4 w;
+void f(uint local_invocation_index) {
+  {
+    w = mat3x4(vec4(0.0f), vec4(0.0f), vec4(0.0f));
+  }
+  barrier();
+  w = u.inner;
+  w[1] = u.inner[0];
+  w[1] = u.inner[0].ywxz;
+  w[0][1] = u.inner[1][0];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..37ed55e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,24 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct tint_symbol_5 {
+  float3x4 w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup float3x4* const tint_symbol, const constant float3x4* const tint_symbol_1) {
+  {
+    *(tint_symbol) = float3x4(float4(0.0f), float4(0.0f), float4(0.0f));
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[0];
+  (*(tint_symbol))[1] = float4((*(tint_symbol_1))[0]).ywxz;
+  (*(tint_symbol))[0][1] = (*(tint_symbol_1))[1][0];
+}
+
+kernel void f(const constant float3x4* tint_symbol_4 [[buffer(0)]], threadgroup tint_symbol_5* tint_symbol_3 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup float3x4* const tint_symbol_2 = &((*(tint_symbol_3)).w);
+  f_inner(local_invocation_index, tint_symbol_2, tint_symbol_4);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_workgroup.wgsl.expected.spvasm
new file mode 100644
index 0000000..7d91714
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_workgroup.wgsl.expected.spvasm
@@ -0,0 +1,80 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 47
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %local_invocation_index_1 "local_invocation_index_1"
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %w "w"
+               OpName %f_inner "f_inner"
+               OpName %local_invocation_index "local_invocation_index"
+               OpName %f "f"
+               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat3v4float = OpTypeMatrix %v4float 3
+    %u_block = OpTypeStruct %mat3v4float
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_Workgroup_mat3v4float = OpTypePointer Workgroup %mat3v4float
+          %w = OpVariable %_ptr_Workgroup_mat3v4float Workgroup
+       %void = OpTypeVoid
+         %12 = OpTypeFunction %void %uint
+         %17 = OpConstantNull %mat3v4float
+     %uint_2 = OpConstant %uint 2
+   %uint_264 = OpConstant %uint 264
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_mat3v4float = OpTypePointer Uniform %mat3v4float
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Workgroup_v4float = OpTypePointer Workgroup %v4float
+         %29 = OpConstantNull %int
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+%_ptr_Workgroup_float = OpTypePointer Workgroup %float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+         %42 = OpTypeFunction %void
+    %f_inner = OpFunction %void None %12
+%local_invocation_index = OpFunctionParameter %uint
+         %16 = OpLabel
+               OpStore %w %17
+               OpControlBarrier %uint_2 %uint_2 %uint_264
+         %23 = OpAccessChain %_ptr_Uniform_mat3v4float %u %uint_0
+         %24 = OpLoad %mat3v4float %23
+               OpStore %w %24
+         %28 = OpAccessChain %_ptr_Workgroup_v4float %w %int_1
+         %31 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %29
+         %32 = OpLoad %v4float %31
+               OpStore %28 %32
+         %33 = OpAccessChain %_ptr_Workgroup_v4float %w %int_1
+         %34 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %29
+         %35 = OpLoad %v4float %34
+         %36 = OpVectorShuffle %v4float %35 %35 1 3 0 2
+               OpStore %33 %36
+         %38 = OpAccessChain %_ptr_Workgroup_float %w %29 %int_1
+         %40 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %int_1 %29
+         %41 = OpLoad %float %40
+               OpStore %38 %41
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %42
+         %44 = OpLabel
+         %46 = OpLoad %uint %local_invocation_index_1
+         %45 = OpFunctionCall %void %f_inner %46
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..05782a8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat3x4_f32/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> u : mat3x4<f32>;
+
+var<workgroup> w : mat3x4<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[0];
+  w[1] = u[0].ywxz;
+  w[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/dynamic_index_via_ptr.wgsl
new file mode 100644
index 0000000..b9a4d8d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/dynamic_index_via_ptr.wgsl
@@ -0,0 +1,15 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> m : mat4x2<f16>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m   = &m;
+  let p_m_i = &((*p_m)[i()]);
+
+  let l_m   : mat4x2<f16> = *p_m;
+  let l_m_i : vec2<f16>   = *p_m_i;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..fe97f69
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,31 @@
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[1];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 4, 2> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const uint scalar_offset_3 = ((offset + 12u)) / 4;
+  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_m_i_save = i();
+  const matrix<float16_t, 4, 2> l_m = tint_symbol(m, 0u);
+  const uint scalar_offset_4 = ((4u * uint(p_m_i_save))) / 4;
+  uint ubo_load_4 = m[scalar_offset_4 / 4][scalar_offset_4 % 4];
+  const vector<float16_t, 2> l_m_i = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..492df55
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,36 @@
+SKIP: FAILED
+
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[1];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 4, 2> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const uint scalar_offset_3 = ((offset + 12u)) / 4;
+  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_m_i_save = i();
+  const matrix<float16_t, 4, 2> l_m = tint_symbol(m, 0u);
+  const uint scalar_offset_4 = ((4u * uint(p_m_i_save))) / 4;
+  uint ubo_load_4 = m[scalar_offset_4 / 4][scalar_offset_4 % 4];
+  const vector<float16_t, 2> l_m_i = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16)));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000013D9C70AA90(11,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..ade941c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,58 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform m_block_std140_ubo {
+  f16vec2 inner_0;
+  f16vec2 inner_1;
+  f16vec2 inner_2;
+  f16vec2 inner_3;
+} m;
+
+int counter = 0;
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+f16mat4x2 load_m_inner() {
+  return f16mat4x2(m.inner_0, m.inner_1, m.inner_2, m.inner_3);
+}
+
+f16vec2 load_m_inner_p0(uint p0) {
+  switch(p0) {
+    case 0u: {
+      return m.inner_0;
+      break;
+    }
+    case 1u: {
+      return m.inner_1;
+      break;
+    }
+    case 2u: {
+      return m.inner_2;
+      break;
+    }
+    case 3u: {
+      return m.inner_3;
+      break;
+    }
+    default: {
+      return f16vec2(0.0hf);
+      break;
+    }
+  }
+}
+
+void f() {
+  f16mat4x2 p_m = load_m_inner();
+  int tint_symbol = i();
+  f16vec2 p_m_i = load_m_inner_p0(uint(tint_symbol));
+  f16mat4x2 l_m = load_m_inner();
+  f16vec2 l_m_i = load_m_inner_p0(uint(tint_symbol));
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..756ba6d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,17 @@
+#include <metal_stdlib>
+
+using namespace metal;
+int i() {
+  thread int tint_symbol_1 = 0;
+  tint_symbol_1 = as_type<int>((as_type<uint>(tint_symbol_1) + as_type<uint>(1)));
+  return tint_symbol_1;
+}
+
+kernel void f(const constant half4x2* tint_symbol_2 [[buffer(0)]]) {
+  int const tint_symbol = i();
+  int const p_m_i_save = tint_symbol;
+  half4x2 const l_m = *(tint_symbol_2);
+  half2 const l_m_i = (*(tint_symbol_2))[p_m_i_save];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..c3c3369
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,111 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 68
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %m_block_std140 "m_block_std140"
+               OpMemberName %m_block_std140 0 "inner_0"
+               OpMemberName %m_block_std140 1 "inner_1"
+               OpMemberName %m_block_std140 2 "inner_2"
+               OpMemberName %m_block_std140 3 "inner_3"
+               OpName %m "m"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %load_m_inner "load_m_inner"
+               OpName %load_m_inner_p0 "load_m_inner_p0"
+               OpName %p0 "p0"
+               OpName %f "f"
+               OpDecorate %m_block_std140 Block
+               OpMemberDecorate %m_block_std140 0 Offset 0
+               OpMemberDecorate %m_block_std140 1 Offset 4
+               OpMemberDecorate %m_block_std140 2 Offset 8
+               OpMemberDecorate %m_block_std140 3 Offset 12
+               OpDecorate %m NonWritable
+               OpDecorate %m DescriptorSet 0
+               OpDecorate %m Binding 0
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+%m_block_std140 = OpTypeStruct %v2half %v2half %v2half %v2half
+%_ptr_Uniform_m_block_std140 = OpTypePointer Uniform %m_block_std140
+          %m = OpVariable %_ptr_Uniform_m_block_std140 Uniform
+        %int = OpTypeInt 32 1
+          %7 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %7
+         %10 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+ %mat4v2half = OpTypeMatrix %v2half 4
+         %17 = OpTypeFunction %mat4v2half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+         %41 = OpTypeFunction %v2half %uint
+         %59 = OpConstantNull %v2half
+       %void = OpTypeVoid
+         %60 = OpTypeFunction %void
+          %i = OpFunction %int None %10
+         %12 = OpLabel
+         %13 = OpLoad %int %counter
+         %15 = OpIAdd %int %13 %int_1
+               OpStore %counter %15
+         %16 = OpLoad %int %counter
+               OpReturnValue %16
+               OpFunctionEnd
+%load_m_inner = OpFunction %mat4v2half None %17
+         %20 = OpLabel
+         %26 = OpAccessChain %_ptr_Uniform_v2half %m %uint_0
+         %27 = OpLoad %v2half %26
+         %30 = OpAccessChain %_ptr_Uniform_v2half %m %uint_1
+         %31 = OpLoad %v2half %30
+         %34 = OpAccessChain %_ptr_Uniform_v2half %m %uint_2
+         %35 = OpLoad %v2half %34
+         %38 = OpAccessChain %_ptr_Uniform_v2half %m %uint_3
+         %39 = OpLoad %v2half %38
+         %40 = OpCompositeConstruct %mat4v2half %27 %31 %35 %39
+               OpReturnValue %40
+               OpFunctionEnd
+%load_m_inner_p0 = OpFunction %v2half None %41
+         %p0 = OpFunctionParameter %uint
+         %44 = OpLabel
+               OpSelectionMerge %45 None
+               OpSwitch %p0 %46 0 %47 1 %48 2 %49 3 %50
+         %47 = OpLabel
+         %51 = OpAccessChain %_ptr_Uniform_v2half %m %uint_0
+         %52 = OpLoad %v2half %51
+               OpReturnValue %52
+         %48 = OpLabel
+         %53 = OpAccessChain %_ptr_Uniform_v2half %m %uint_1
+         %54 = OpLoad %v2half %53
+               OpReturnValue %54
+         %49 = OpLabel
+         %55 = OpAccessChain %_ptr_Uniform_v2half %m %uint_2
+         %56 = OpLoad %v2half %55
+               OpReturnValue %56
+         %50 = OpLabel
+         %57 = OpAccessChain %_ptr_Uniform_v2half %m %uint_3
+         %58 = OpLoad %v2half %57
+               OpReturnValue %58
+         %46 = OpLabel
+               OpReturnValue %59
+         %45 = OpLabel
+               OpReturnValue %59
+               OpFunctionEnd
+          %f = OpFunction %void None %60
+         %63 = OpLabel
+         %64 = OpFunctionCall %int %i
+         %65 = OpFunctionCall %mat4v2half %load_m_inner
+         %67 = OpBitcast %uint %64
+         %66 = OpFunctionCall %v2half %load_m_inner_p0 %67
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..4f04f9e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> m : mat4x2<f16>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m = &(m);
+  let p_m_i = &((*(p_m))[i()]);
+  let l_m : mat4x2<f16> = *(p_m);
+  let l_m_i : vec2<f16> = *(p_m_i);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/static_index_via_ptr.wgsl
new file mode 100644
index 0000000..26076b16
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/static_index_via_ptr.wgsl
@@ -0,0 +1,15 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> m : mat4x2<f16>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m   = &m;
+  let p_m_1 = &((*p_m)[1]);
+
+  let l_m   : mat4x2<f16> = *p_m;
+  let l_m_1 : vec2<f16>   = *p_m_1;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..e56d25a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,29 @@
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[1];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 4, 2> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const uint scalar_offset_3 = ((offset + 12u)) / 4;
+  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 4, 2> l_m = tint_symbol(m, 0u);
+  uint ubo_load_4 = m[0].y;
+  const vector<float16_t, 2> l_m_1 = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..d7d572d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,34 @@
+SKIP: FAILED
+
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[1];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 4, 2> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const uint scalar_offset_3 = ((offset + 12u)) / 4;
+  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 4, 2> l_m = tint_symbol(m, 0u);
+  uint ubo_load_4 = m[0].y;
+  const vector<float16_t, 2> l_m_1 = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16)));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000025078B145D0(11,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/static_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..7c754a6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/static_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,26 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform m_block_std140_ubo {
+  f16vec2 inner_0;
+  f16vec2 inner_1;
+  f16vec2 inner_2;
+  f16vec2 inner_3;
+} m;
+
+f16mat4x2 load_m_inner() {
+  return f16mat4x2(m.inner_0, m.inner_1, m.inner_2, m.inner_3);
+}
+
+void f() {
+  f16mat4x2 p_m = load_m_inner();
+  f16vec2 p_m_1 = m.inner_1;
+  f16mat4x2 l_m = load_m_inner();
+  f16vec2 l_m_1 = m.inner_1;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/static_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..a054f04
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/static_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,15 @@
+#include <metal_stdlib>
+
+using namespace metal;
+int i() {
+  thread int tint_symbol = 0;
+  tint_symbol = as_type<int>((as_type<uint>(tint_symbol) + as_type<uint>(1)));
+  return tint_symbol;
+}
+
+kernel void f(const constant half4x2* tint_symbol_1 [[buffer(0)]]) {
+  half4x2 const l_m = *(tint_symbol_1);
+  half2 const l_m_1 = (*(tint_symbol_1))[1];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/static_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..216db17
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/static_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,80 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 48
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %m_block_std140 "m_block_std140"
+               OpMemberName %m_block_std140 0 "inner_0"
+               OpMemberName %m_block_std140 1 "inner_1"
+               OpMemberName %m_block_std140 2 "inner_2"
+               OpMemberName %m_block_std140 3 "inner_3"
+               OpName %m "m"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %load_m_inner "load_m_inner"
+               OpName %f "f"
+               OpDecorate %m_block_std140 Block
+               OpMemberDecorate %m_block_std140 0 Offset 0
+               OpMemberDecorate %m_block_std140 1 Offset 4
+               OpMemberDecorate %m_block_std140 2 Offset 8
+               OpMemberDecorate %m_block_std140 3 Offset 12
+               OpDecorate %m NonWritable
+               OpDecorate %m DescriptorSet 0
+               OpDecorate %m Binding 0
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+%m_block_std140 = OpTypeStruct %v2half %v2half %v2half %v2half
+%_ptr_Uniform_m_block_std140 = OpTypePointer Uniform %m_block_std140
+          %m = OpVariable %_ptr_Uniform_m_block_std140 Uniform
+        %int = OpTypeInt 32 1
+          %7 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %7
+         %10 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+ %mat4v2half = OpTypeMatrix %v2half 4
+         %17 = OpTypeFunction %mat4v2half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %41 = OpTypeFunction %void
+          %i = OpFunction %int None %10
+         %12 = OpLabel
+         %13 = OpLoad %int %counter
+         %15 = OpIAdd %int %13 %int_1
+               OpStore %counter %15
+         %16 = OpLoad %int %counter
+               OpReturnValue %16
+               OpFunctionEnd
+%load_m_inner = OpFunction %mat4v2half None %17
+         %20 = OpLabel
+         %26 = OpAccessChain %_ptr_Uniform_v2half %m %uint_0
+         %27 = OpLoad %v2half %26
+         %30 = OpAccessChain %_ptr_Uniform_v2half %m %uint_1
+         %31 = OpLoad %v2half %30
+         %34 = OpAccessChain %_ptr_Uniform_v2half %m %uint_2
+         %35 = OpLoad %v2half %34
+         %38 = OpAccessChain %_ptr_Uniform_v2half %m %uint_3
+         %39 = OpLoad %v2half %38
+         %40 = OpCompositeConstruct %mat4v2half %27 %31 %35 %39
+               OpReturnValue %40
+               OpFunctionEnd
+          %f = OpFunction %void None %41
+         %44 = OpLabel
+         %45 = OpFunctionCall %mat4v2half %load_m_inner
+         %46 = OpAccessChain %_ptr_Uniform_v2half %m %uint_1
+         %47 = OpLoad %v2half %46
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/static_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..b7111b4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/static_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> m : mat4x2<f16>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m = &(m);
+  let p_m_1 = &((*(p_m))[1]);
+  let l_m : mat4x2<f16> = *(p_m);
+  let l_m_1 : vec2<f16> = *(p_m_1);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_builtin.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_builtin.wgsl
new file mode 100644
index 0000000..f8e709a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_builtin.wgsl
@@ -0,0 +1,10 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat4x2<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+    let t = transpose(u);
+    let l = length(u[1]);
+    let a = abs(u[0].yx.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_builtin.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..1c208e2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_builtin.wgsl.expected.dxc.hlsl
@@ -0,0 +1,25 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+matrix<float16_t, 4, 2> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const uint scalar_offset_3 = ((offset + 12u)) / 4;
+  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 2, 4> t = transpose(tint_symbol(u, 0u));
+  uint ubo_load_4 = u[0].y;
+  const float16_t l = length(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16))));
+  uint ubo_load_5 = u[0].x;
+  const float16_t a = abs(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_5 & 0xFFFF)), float16_t(f16tof32(ubo_load_5 >> 16))).yx.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_builtin.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..8f7f50f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_builtin.wgsl.expected.fxc.hlsl
@@ -0,0 +1,30 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+matrix<float16_t, 4, 2> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const uint scalar_offset_3 = ((offset + 12u)) / 4;
+  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 2, 4> t = transpose(tint_symbol(u, 0u));
+  uint ubo_load_4 = u[0].y;
+  const float16_t l = length(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16))));
+  uint ubo_load_5 = u[0].x;
+  const float16_t a = abs(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_5 & 0xFFFF)), float16_t(f16tof32(ubo_load_5 >> 16))).yx.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001FEE1A64990(5,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_builtin.wgsl.expected.glsl
new file mode 100644
index 0000000..9038781
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_builtin.wgsl.expected.glsl
@@ -0,0 +1,25 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec2 inner_0;
+  f16vec2 inner_1;
+  f16vec2 inner_2;
+  f16vec2 inner_3;
+} u;
+
+f16mat4x2 load_u_inner() {
+  return f16mat4x2(u.inner_0, u.inner_1, u.inner_2, u.inner_3);
+}
+
+void f() {
+  f16mat2x4 t = transpose(load_u_inner());
+  float16_t l = length(u.inner_1);
+  float16_t a = abs(u.inner_0.yx[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_builtin.wgsl.expected.msl
new file mode 100644
index 0000000..1b137c5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_builtin.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f(const constant half4x2* tint_symbol [[buffer(0)]]) {
+  half2x4 const t = transpose(*(tint_symbol));
+  half const l = length((*(tint_symbol))[1]);
+  half const a = fabs(half2((*(tint_symbol))[0]).yx[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_builtin.wgsl.expected.spvasm
new file mode 100644
index 0000000..22d89d9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_builtin.wgsl.expected.spvasm
@@ -0,0 +1,75 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 48
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+         %39 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpMemberName %u_block_std140 2 "inner_2"
+               OpMemberName %u_block_std140 3 "inner_3"
+               OpName %u "u"
+               OpName %load_u_inner "load_u_inner"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 4
+               OpMemberDecorate %u_block_std140 2 Offset 8
+               OpMemberDecorate %u_block_std140 3 Offset 12
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+%u_block_std140 = OpTypeStruct %v2half %v2half %v2half %v2half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat4v2half = OpTypeMatrix %v2half 4
+          %6 = OpTypeFunction %mat4v2half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %30 = OpTypeFunction %void
+     %v4half = OpTypeVector %half 4
+ %mat2v4half = OpTypeMatrix %v4half 2
+         %46 = OpConstantNull %uint
+%load_u_inner = OpFunction %mat4v2half None %6
+          %9 = OpLabel
+         %15 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0
+         %16 = OpLoad %v2half %15
+         %19 = OpAccessChain %_ptr_Uniform_v2half %u %uint_1
+         %20 = OpLoad %v2half %19
+         %23 = OpAccessChain %_ptr_Uniform_v2half %u %uint_2
+         %24 = OpLoad %v2half %23
+         %27 = OpAccessChain %_ptr_Uniform_v2half %u %uint_3
+         %28 = OpLoad %v2half %27
+         %29 = OpCompositeConstruct %mat4v2half %16 %20 %24 %28
+               OpReturnValue %29
+               OpFunctionEnd
+          %f = OpFunction %void None %30
+         %33 = OpLabel
+         %37 = OpFunctionCall %mat4v2half %load_u_inner
+         %34 = OpTranspose %mat2v4half %37
+         %40 = OpAccessChain %_ptr_Uniform_v2half %u %uint_1
+         %41 = OpLoad %v2half %40
+         %38 = OpExtInst %half %39 Length %41
+         %43 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0
+         %44 = OpLoad %v2half %43
+         %45 = OpVectorShuffle %v2half %44 %44 1 0
+         %47 = OpCompositeExtract %half %45 0
+         %42 = OpExtInst %half %39 FAbs %47
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_builtin.wgsl.expected.wgsl
new file mode 100644
index 0000000..1df8062
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_builtin.wgsl.expected.wgsl
@@ -0,0 +1,10 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat4x2<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let t = transpose(u);
+  let l = length(u[1]);
+  let a = abs(u[0].yx.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_fn.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_fn.wgsl
new file mode 100644
index 0000000..34cf034
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_fn.wgsl
@@ -0,0 +1,16 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat4x2<f16>;
+
+fn a(m : mat4x2<f16>) {}
+fn b(v : vec2<f16>) {}
+fn c(f : f16) {}
+
+@compute @workgroup_size(1)
+fn f() {
+    a(u);
+    b(u[1]);
+    b(u[1].yx);
+    c(u[1].x);
+    c(u[1].yx.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_fn.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..a5ffec0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_fn.wgsl.expected.dxc.hlsl
@@ -0,0 +1,37 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+void a(matrix<float16_t, 4, 2> m) {
+}
+
+void b(vector<float16_t, 2> v) {
+}
+
+void c(float16_t f_1) {
+}
+
+matrix<float16_t, 4, 2> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const uint scalar_offset_3 = ((offset + 12u)) / 4;
+  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  uint ubo_load_4 = u[0].y;
+  b(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16))));
+  uint ubo_load_5 = u[0].y;
+  b(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_5 & 0xFFFF)), float16_t(f16tof32(ubo_load_5 >> 16))).yx);
+  c(float16_t(f16tof32(((u[0].y) & 0xFFFF))));
+  uint ubo_load_6 = u[0].y;
+  c(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_6 & 0xFFFF)), float16_t(f16tof32(ubo_load_6 >> 16))).yx.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_fn.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..1cae909
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_fn.wgsl.expected.fxc.hlsl
@@ -0,0 +1,44 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+void a(matrix<float16_t, 4, 2> m) {
+}
+
+void b(vector<float16_t, 2> v) {
+}
+
+void c(float16_t f_1) {
+}
+
+matrix<float16_t, 4, 2> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const uint scalar_offset_3 = ((offset + 12u)) / 4;
+  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  uint ubo_load_4 = u[0].y;
+  b(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16))));
+  uint ubo_load_5 = u[0].y;
+  b(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_5 & 0xFFFF)), float16_t(f16tof32(ubo_load_5 >> 16))).yx);
+  c(float16_t(f16tof32(((u[0].y) & 0xFFFF))));
+  uint ubo_load_6 = u[0].y;
+  c(vector<float16_t, 2>(float16_t(f16tof32(ubo_load_6 & 0xFFFF)), float16_t(f16tof32(ubo_load_6 >> 16))).yx.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001F4F9D145E0(5,15-23): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001F4F9D145E0(8,15-23): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001F4F9D145E0(11,8-16): error X3000: unrecognized identifier 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_fn.wgsl.expected.glsl
new file mode 100644
index 0000000..d4ed074
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_fn.wgsl.expected.glsl
@@ -0,0 +1,36 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec2 inner_0;
+  f16vec2 inner_1;
+  f16vec2 inner_2;
+  f16vec2 inner_3;
+} u;
+
+void a(f16mat4x2 m) {
+}
+
+void b(f16vec2 v) {
+}
+
+void c(float16_t f_1) {
+}
+
+f16mat4x2 load_u_inner() {
+  return f16mat4x2(u.inner_0, u.inner_1, u.inner_2, u.inner_3);
+}
+
+void f() {
+  a(load_u_inner());
+  b(u.inner_1);
+  b(u.inner_1.yx);
+  c(u.inner_1[0u]);
+  c(u.inner_1.yx[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_fn.wgsl.expected.msl
new file mode 100644
index 0000000..25b867f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_fn.wgsl.expected.msl
@@ -0,0 +1,21 @@
+#include <metal_stdlib>
+
+using namespace metal;
+void a(half4x2 m) {
+}
+
+void b(half2 v) {
+}
+
+void c(half f_1) {
+}
+
+kernel void f(const constant half4x2* tint_symbol [[buffer(0)]]) {
+  a(*(tint_symbol));
+  b((*(tint_symbol))[1]);
+  b(half2((*(tint_symbol))[1]).yx);
+  c((*(tint_symbol))[1][0]);
+  c(half2((*(tint_symbol))[1]).yx[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_fn.wgsl.expected.spvasm
new file mode 100644
index 0000000..8d44eb1
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_fn.wgsl.expected.spvasm
@@ -0,0 +1,104 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 65
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpMemberName %u_block_std140 2 "inner_2"
+               OpMemberName %u_block_std140 3 "inner_3"
+               OpName %u "u"
+               OpName %a "a"
+               OpName %m "m"
+               OpName %b "b"
+               OpName %v "v"
+               OpName %c "c"
+               OpName %f_1 "f_1"
+               OpName %load_u_inner "load_u_inner"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 4
+               OpMemberDecorate %u_block_std140 2 Offset 8
+               OpMemberDecorate %u_block_std140 3 Offset 12
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+%u_block_std140 = OpTypeStruct %v2half %v2half %v2half %v2half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+       %void = OpTypeVoid
+ %mat4v2half = OpTypeMatrix %v2half 4
+          %6 = OpTypeFunction %void %mat4v2half
+         %12 = OpTypeFunction %void %v2half
+         %16 = OpTypeFunction %void %half
+         %20 = OpTypeFunction %mat4v2half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+         %43 = OpTypeFunction %void
+         %56 = OpConstantNull %uint
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+          %a = OpFunction %void None %6
+          %m = OpFunctionParameter %mat4v2half
+         %11 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %b = OpFunction %void None %12
+          %v = OpFunctionParameter %v2half
+         %15 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %c = OpFunction %void None %16
+        %f_1 = OpFunctionParameter %half
+         %19 = OpLabel
+               OpReturn
+               OpFunctionEnd
+%load_u_inner = OpFunction %mat4v2half None %20
+         %22 = OpLabel
+         %28 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0
+         %29 = OpLoad %v2half %28
+         %32 = OpAccessChain %_ptr_Uniform_v2half %u %uint_1
+         %33 = OpLoad %v2half %32
+         %36 = OpAccessChain %_ptr_Uniform_v2half %u %uint_2
+         %37 = OpLoad %v2half %36
+         %40 = OpAccessChain %_ptr_Uniform_v2half %u %uint_3
+         %41 = OpLoad %v2half %40
+         %42 = OpCompositeConstruct %mat4v2half %29 %33 %37 %41
+               OpReturnValue %42
+               OpFunctionEnd
+          %f = OpFunction %void None %43
+         %45 = OpLabel
+         %47 = OpFunctionCall %mat4v2half %load_u_inner
+         %46 = OpFunctionCall %void %a %47
+         %49 = OpAccessChain %_ptr_Uniform_v2half %u %uint_1
+         %50 = OpLoad %v2half %49
+         %48 = OpFunctionCall %void %b %50
+         %52 = OpAccessChain %_ptr_Uniform_v2half %u %uint_1
+         %53 = OpLoad %v2half %52
+         %54 = OpVectorShuffle %v2half %53 %53 1 0
+         %51 = OpFunctionCall %void %b %54
+         %58 = OpAccessChain %_ptr_Uniform_half %u %uint_1 %56
+         %59 = OpLoad %half %58
+         %55 = OpFunctionCall %void %c %59
+         %61 = OpAccessChain %_ptr_Uniform_v2half %u %uint_1
+         %62 = OpLoad %v2half %61
+         %63 = OpVectorShuffle %v2half %62 %62 1 0
+         %64 = OpCompositeExtract %half %63 0
+         %60 = OpFunctionCall %void %c %64
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_fn.wgsl.expected.wgsl
new file mode 100644
index 0000000..5bc57a0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_fn.wgsl.expected.wgsl
@@ -0,0 +1,21 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat4x2<f16>;
+
+fn a(m : mat4x2<f16>) {
+}
+
+fn b(v : vec2<f16>) {
+}
+
+fn c(f : f16) {
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  a(u);
+  b(u[1]);
+  b(u[1].yx);
+  c(u[1].x);
+  c(u[1].yx.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_private.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_private.wgsl
new file mode 100644
index 0000000..558d302
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_private.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat4x2<f16>;
+var<private> p : mat4x2<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[0];
+    p[1] = u[0].yx;
+    p[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_private.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..bbd9415
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_private.wgsl.expected.dxc.hlsl
@@ -0,0 +1,27 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+static matrix<float16_t, 4, 2> p = matrix<float16_t, 4, 2>(float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h));
+
+matrix<float16_t, 4, 2> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const uint scalar_offset_3 = ((offset + 12u)) / 4;
+  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  uint ubo_load_4 = u[0].x;
+  p[1] = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16)));
+  uint ubo_load_5 = u[0].x;
+  p[1] = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_5 & 0xFFFF)), float16_t(f16tof32(ubo_load_5 >> 16))).yx;
+  p[0][1] = float16_t(f16tof32(((u[0].y) & 0xFFFF)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_private.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..04ae2e2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_private.wgsl.expected.fxc.hlsl
@@ -0,0 +1,32 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+static matrix<float16_t, 4, 2> p = matrix<float16_t, 4, 2>(float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h));
+
+matrix<float16_t, 4, 2> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const uint scalar_offset_3 = ((offset + 12u)) / 4;
+  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  uint ubo_load_4 = u[0].x;
+  p[1] = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16)));
+  uint ubo_load_5 = u[0].x;
+  p[1] = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_5 & 0xFFFF)), float16_t(f16tof32(ubo_load_5 >> 16))).yx;
+  p[0][1] = float16_t(f16tof32(((u[0].y) & 0xFFFF)));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001D1582D92D0(4,15-23): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..8c7a28a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_private.wgsl.expected.glsl
@@ -0,0 +1,27 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec2 inner_0;
+  f16vec2 inner_1;
+  f16vec2 inner_2;
+  f16vec2 inner_3;
+} u;
+
+f16mat4x2 p = f16mat4x2(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf);
+f16mat4x2 load_u_inner() {
+  return f16mat4x2(u.inner_0, u.inner_1, u.inner_2, u.inner_3);
+}
+
+void f() {
+  p = load_u_inner();
+  p[1] = u.inner_0;
+  p[1] = u.inner_0.yx;
+  p[0][1] = u.inner_1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..aac8ea7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_private.wgsl.expected.msl
@@ -0,0 +1,12 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f(const constant half4x2* tint_symbol_1 [[buffer(0)]]) {
+  thread half4x2 tint_symbol = half4x2(0.0h);
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[0];
+  tint_symbol[1] = half2((*(tint_symbol_1))[0]).yx;
+  tint_symbol[0][1] = (*(tint_symbol_1))[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_private.wgsl.expected.spvasm
new file mode 100644
index 0000000..cc710ce
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_private.wgsl.expected.spvasm
@@ -0,0 +1,87 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 55
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpMemberName %u_block_std140 2 "inner_2"
+               OpMemberName %u_block_std140 3 "inner_3"
+               OpName %u "u"
+               OpName %p "p"
+               OpName %load_u_inner "load_u_inner"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 4
+               OpMemberDecorate %u_block_std140 2 Offset 8
+               OpMemberDecorate %u_block_std140 3 Offset 12
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+%u_block_std140 = OpTypeStruct %v2half %v2half %v2half %v2half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat4v2half = OpTypeMatrix %v2half 4
+%_ptr_Private_mat4v2half = OpTypePointer Private %mat4v2half
+          %9 = OpConstantNull %mat4v2half
+          %p = OpVariable %_ptr_Private_mat4v2half Private %9
+         %10 = OpTypeFunction %mat4v2half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %33 = OpTypeFunction %void
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Private_v2half = OpTypePointer Private %v2half
+         %48 = OpConstantNull %int
+%_ptr_Private_half = OpTypePointer Private %half
+         %51 = OpConstantNull %uint
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+%load_u_inner = OpFunction %mat4v2half None %10
+         %12 = OpLabel
+         %18 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0
+         %19 = OpLoad %v2half %18
+         %22 = OpAccessChain %_ptr_Uniform_v2half %u %uint_1
+         %23 = OpLoad %v2half %22
+         %26 = OpAccessChain %_ptr_Uniform_v2half %u %uint_2
+         %27 = OpLoad %v2half %26
+         %30 = OpAccessChain %_ptr_Uniform_v2half %u %uint_3
+         %31 = OpLoad %v2half %30
+         %32 = OpCompositeConstruct %mat4v2half %19 %23 %27 %31
+               OpReturnValue %32
+               OpFunctionEnd
+          %f = OpFunction %void None %33
+         %36 = OpLabel
+         %37 = OpFunctionCall %mat4v2half %load_u_inner
+               OpStore %p %37
+         %41 = OpAccessChain %_ptr_Private_v2half %p %int_1
+         %42 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0
+         %43 = OpLoad %v2half %42
+               OpStore %41 %43
+         %44 = OpAccessChain %_ptr_Private_v2half %p %int_1
+         %45 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0
+         %46 = OpLoad %v2half %45
+         %47 = OpVectorShuffle %v2half %46 %46 1 0
+               OpStore %44 %47
+         %50 = OpAccessChain %_ptr_Private_half %p %48 %int_1
+         %53 = OpAccessChain %_ptr_Uniform_half %u %uint_1 %51
+         %54 = OpLoad %half %53
+               OpStore %50 %54
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..af9ce13
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_private.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat4x2<f16>;
+
+var<private> p : mat4x2<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[0];
+  p[1] = u[0].yx;
+  p[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_storage.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_storage.wgsl
new file mode 100644
index 0000000..8d72f90
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_storage.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat4x2<f16>;
+@group(0) @binding(1) var<storage, read_write> s : mat4x2<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[0];
+    s[1] = u[0].yx;
+    s[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_storage.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..df857d0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_storage.wgsl.expected.dxc.hlsl
@@ -0,0 +1,34 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 2> value) {
+  buffer.Store<vector<float16_t, 2> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 4u), value[1u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 8u), value[2u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 12u), value[3u]);
+}
+
+matrix<float16_t, 4, 2> tint_symbol_2(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const uint scalar_offset_3 = ((offset + 12u)) / 4;
+  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_2(u, 0u));
+  uint ubo_load_4 = u[0].x;
+  s.Store<vector<float16_t, 2> >(4u, vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16))));
+  uint ubo_load_5 = u[0].x;
+  s.Store<vector<float16_t, 2> >(4u, vector<float16_t, 2>(float16_t(f16tof32(ubo_load_5 & 0xFFFF)), float16_t(f16tof32(ubo_load_5 >> 16))).yx);
+  s.Store<float16_t>(2u, float16_t(f16tof32(((u[0].y) & 0xFFFF))));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_storage.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..8218a85
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_storage.wgsl.expected.fxc.hlsl
@@ -0,0 +1,40 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 2> value) {
+  buffer.Store<vector<float16_t, 2> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 4u), value[1u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 8u), value[2u]);
+  buffer.Store<vector<float16_t, 2> >((offset + 12u), value[3u]);
+}
+
+matrix<float16_t, 4, 2> tint_symbol_2(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const uint scalar_offset_3 = ((offset + 12u)) / 4;
+  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_2(u, 0u));
+  uint ubo_load_4 = u[0].x;
+  s.Store<vector<float16_t, 2> >(4u, vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16))));
+  uint ubo_load_5 = u[0].x;
+  s.Store<vector<float16_t, 2> >(4u, vector<float16_t, 2>(float16_t(f16tof32(ubo_load_5 & 0xFFFF)), float16_t(f16tof32(ubo_load_5 >> 16))).yx);
+  s.Store<float16_t>(2u, float16_t(f16tof32(((u[0].y) & 0xFFFF))));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x00000252CF939A80(6,66-74): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x00000252CF939A80(7,3-14): error X3018: invalid subscript 'Store'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..b7358af
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_storage.wgsl.expected.glsl
@@ -0,0 +1,30 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec2 inner_0;
+  f16vec2 inner_1;
+  f16vec2 inner_2;
+  f16vec2 inner_3;
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  f16mat4x2 inner;
+} s;
+
+f16mat4x2 load_u_inner() {
+  return f16mat4x2(u.inner_0, u.inner_1, u.inner_2, u.inner_3);
+}
+
+void f() {
+  s.inner = load_u_inner();
+  s.inner[1] = u.inner_0;
+  s.inner[1] = u.inner_0.yx;
+  s.inner[0][1] = u.inner_1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..e3cb6f6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_storage.wgsl.expected.msl
@@ -0,0 +1,11 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f(device half4x2* tint_symbol [[buffer(1)]], const constant half4x2* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[0];
+  (*(tint_symbol))[1] = half2((*(tint_symbol_1))[0]).yx;
+  (*(tint_symbol))[0][1] = (*(tint_symbol_1))[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_storage.wgsl.expected.spvasm
new file mode 100644
index 0000000..8f53935
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_storage.wgsl.expected.spvasm
@@ -0,0 +1,97 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 57
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpMemberName %u_block_std140 2 "inner_2"
+               OpMemberName %u_block_std140 3 "inner_3"
+               OpName %u "u"
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %s "s"
+               OpName %load_u_inner "load_u_inner"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 4
+               OpMemberDecorate %u_block_std140 2 Offset 8
+               OpMemberDecorate %u_block_std140 3 Offset 12
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 4
+               OpDecorate %s DescriptorSet 0
+               OpDecorate %s Binding 1
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+%u_block_std140 = OpTypeStruct %v2half %v2half %v2half %v2half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat4v2half = OpTypeMatrix %v2half 4
+    %u_block = OpTypeStruct %mat4v2half
+%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
+          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+         %10 = OpTypeFunction %mat4v2half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %33 = OpTypeFunction %void
+%_ptr_StorageBuffer_mat4v2half = OpTypePointer StorageBuffer %mat4v2half
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_v2half = OpTypePointer StorageBuffer %v2half
+         %50 = OpConstantNull %int
+%_ptr_StorageBuffer_half = OpTypePointer StorageBuffer %half
+         %53 = OpConstantNull %uint
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+%load_u_inner = OpFunction %mat4v2half None %10
+         %12 = OpLabel
+         %18 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0
+         %19 = OpLoad %v2half %18
+         %22 = OpAccessChain %_ptr_Uniform_v2half %u %uint_1
+         %23 = OpLoad %v2half %22
+         %26 = OpAccessChain %_ptr_Uniform_v2half %u %uint_2
+         %27 = OpLoad %v2half %26
+         %30 = OpAccessChain %_ptr_Uniform_v2half %u %uint_3
+         %31 = OpLoad %v2half %30
+         %32 = OpCompositeConstruct %mat4v2half %19 %23 %27 %31
+               OpReturnValue %32
+               OpFunctionEnd
+          %f = OpFunction %void None %33
+         %36 = OpLabel
+         %38 = OpAccessChain %_ptr_StorageBuffer_mat4v2half %s %uint_0
+         %39 = OpFunctionCall %mat4v2half %load_u_inner
+               OpStore %38 %39
+         %43 = OpAccessChain %_ptr_StorageBuffer_v2half %s %uint_0 %int_1
+         %44 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0
+         %45 = OpLoad %v2half %44
+               OpStore %43 %45
+         %46 = OpAccessChain %_ptr_StorageBuffer_v2half %s %uint_0 %int_1
+         %47 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0
+         %48 = OpLoad %v2half %47
+         %49 = OpVectorShuffle %v2half %48 %48 1 0
+               OpStore %46 %49
+         %52 = OpAccessChain %_ptr_StorageBuffer_half %s %uint_0 %50 %int_1
+         %55 = OpAccessChain %_ptr_Uniform_half %u %uint_1 %53
+         %56 = OpLoad %half %55
+               OpStore %52 %56
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..c58a21e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat4x2<f16>;
+
+@group(0) @binding(1) var<storage, read_write> s : mat4x2<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[0];
+  s[1] = u[0].yx;
+  s[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_workgroup.wgsl
new file mode 100644
index 0000000..a629aa6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_workgroup.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat4x2<f16>;
+var<workgroup> w : mat4x2<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[0];
+    w[1] = u[0].yx;
+    w[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_workgroup.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..a3baa30
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_workgroup.wgsl.expected.dxc.hlsl
@@ -0,0 +1,39 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+groupshared matrix<float16_t, 4, 2> w;
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 4, 2> tint_symbol_2(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const uint scalar_offset_3 = ((offset + 12u)) / 4;
+  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    w = matrix<float16_t, 4, 2>((float16_t(0.0h)).xx, (float16_t(0.0h)).xx, (float16_t(0.0h)).xx, (float16_t(0.0h)).xx);
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  uint ubo_load_4 = u[0].x;
+  w[1] = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16)));
+  uint ubo_load_5 = u[0].x;
+  w[1] = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_5 & 0xFFFF)), float16_t(f16tof32(ubo_load_5 >> 16))).yx;
+  w[0][1] = float16_t(f16tof32(((u[0].y) & 0xFFFF)));
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_workgroup.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..26ab4d8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_workgroup.wgsl.expected.fxc.hlsl
@@ -0,0 +1,44 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+groupshared matrix<float16_t, 4, 2> w;
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 4, 2> tint_symbol_2(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const uint scalar_offset_3 = ((offset + 12u)) / 4;
+  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    w = matrix<float16_t, 4, 2>((float16_t(0.0h)).xx, (float16_t(0.0h)).xx, (float16_t(0.0h)).xx, (float16_t(0.0h)).xx);
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  uint ubo_load_4 = u[0].x;
+  w[1] = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_4 & 0xFFFF)), float16_t(f16tof32(ubo_load_4 >> 16)));
+  uint ubo_load_5 = u[0].x;
+  w[1] = vector<float16_t, 2>(float16_t(f16tof32(ubo_load_5 & 0xFFFF)), float16_t(f16tof32(ubo_load_5 >> 16))).yx;
+  w[0][1] = float16_t(f16tof32(((u[0].y) & 0xFFFF)));
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001DAFCDE42A0(4,20-28): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..931d9c6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,31 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec2 inner_0;
+  f16vec2 inner_1;
+  f16vec2 inner_2;
+  f16vec2 inner_3;
+} u;
+
+shared f16mat4x2 w;
+f16mat4x2 load_u_inner() {
+  return f16mat4x2(u.inner_0, u.inner_1, u.inner_2, u.inner_3);
+}
+
+void f(uint local_invocation_index) {
+  {
+    w = f16mat4x2(f16vec2(0.0hf), f16vec2(0.0hf), f16vec2(0.0hf), f16vec2(0.0hf));
+  }
+  barrier();
+  w = load_u_inner();
+  w[1] = u.inner_0;
+  w[1] = u.inner_0.yx;
+  w[0][1] = u.inner_1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..ccec071
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,24 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct tint_symbol_5 {
+  half4x2 w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup half4x2* const tint_symbol, const constant half4x2* const tint_symbol_1) {
+  {
+    *(tint_symbol) = half4x2(half2(0.0h), half2(0.0h), half2(0.0h), half2(0.0h));
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[0];
+  (*(tint_symbol))[1] = half2((*(tint_symbol_1))[0]).yx;
+  (*(tint_symbol))[0][1] = (*(tint_symbol_1))[1][0];
+}
+
+kernel void f(const constant half4x2* tint_symbol_4 [[buffer(0)]], threadgroup tint_symbol_5* tint_symbol_3 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup half4x2* const tint_symbol_2 = &((*(tint_symbol_3)).w);
+  f_inner(local_invocation_index, tint_symbol_2, tint_symbol_4);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_workgroup.wgsl.expected.spvasm
new file mode 100644
index 0000000..d158053
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_workgroup.wgsl.expected.spvasm
@@ -0,0 +1,104 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 65
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %local_invocation_index_1 "local_invocation_index_1"
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpMemberName %u_block_std140 2 "inner_2"
+               OpMemberName %u_block_std140 3 "inner_3"
+               OpName %u "u"
+               OpName %w "w"
+               OpName %load_u_inner "load_u_inner"
+               OpName %f_inner "f_inner"
+               OpName %local_invocation_index "local_invocation_index"
+               OpName %f "f"
+               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 4
+               OpMemberDecorate %u_block_std140 2 Offset 8
+               OpMemberDecorate %u_block_std140 3 Offset 12
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+%u_block_std140 = OpTypeStruct %v2half %v2half %v2half %v2half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat4v2half = OpTypeMatrix %v2half 4
+%_ptr_Workgroup_mat4v2half = OpTypePointer Workgroup %mat4v2half
+          %w = OpVariable %_ptr_Workgroup_mat4v2half Workgroup
+         %12 = OpTypeFunction %mat4v2half
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %34 = OpTypeFunction %void %uint
+         %39 = OpConstantNull %mat4v2half
+   %uint_264 = OpConstant %uint 264
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Workgroup_v2half = OpTypePointer Workgroup %v2half
+         %53 = OpConstantNull %int
+%_ptr_Workgroup_half = OpTypePointer Workgroup %half
+         %56 = OpConstantNull %uint
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+         %60 = OpTypeFunction %void
+%load_u_inner = OpFunction %mat4v2half None %12
+         %14 = OpLabel
+         %19 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0
+         %20 = OpLoad %v2half %19
+         %23 = OpAccessChain %_ptr_Uniform_v2half %u %uint_1
+         %24 = OpLoad %v2half %23
+         %27 = OpAccessChain %_ptr_Uniform_v2half %u %uint_2
+         %28 = OpLoad %v2half %27
+         %31 = OpAccessChain %_ptr_Uniform_v2half %u %uint_3
+         %32 = OpLoad %v2half %31
+         %33 = OpCompositeConstruct %mat4v2half %20 %24 %28 %32
+               OpReturnValue %33
+               OpFunctionEnd
+    %f_inner = OpFunction %void None %34
+%local_invocation_index = OpFunctionParameter %uint
+         %38 = OpLabel
+               OpStore %w %39
+               OpControlBarrier %uint_2 %uint_2 %uint_264
+         %42 = OpFunctionCall %mat4v2half %load_u_inner
+               OpStore %w %42
+         %46 = OpAccessChain %_ptr_Workgroup_v2half %w %int_1
+         %47 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0
+         %48 = OpLoad %v2half %47
+               OpStore %46 %48
+         %49 = OpAccessChain %_ptr_Workgroup_v2half %w %int_1
+         %50 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0
+         %51 = OpLoad %v2half %50
+         %52 = OpVectorShuffle %v2half %51 %51 1 0
+               OpStore %49 %52
+         %55 = OpAccessChain %_ptr_Workgroup_half %w %53 %int_1
+         %58 = OpAccessChain %_ptr_Uniform_half %u %uint_1 %56
+         %59 = OpLoad %half %58
+               OpStore %55 %59
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %60
+         %62 = OpLabel
+         %64 = OpLoad %uint %local_invocation_index_1
+         %63 = OpFunctionCall %void %f_inner %64
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..75d4a9d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x2_f16/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat4x2<f16>;
+
+var<workgroup> w : mat4x2<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[0];
+  w[1] = u[0].yx;
+  w[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/dynamic_index_via_ptr.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/dynamic_index_via_ptr.wgsl
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/dynamic_index_via_ptr.wgsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/dynamic_index_via_ptr.wgsl.expected.glsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/dynamic_index_via_ptr.wgsl.expected.glsl
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/dynamic_index_via_ptr.wgsl.expected.glsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/dynamic_index_via_ptr.wgsl.expected.msl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/dynamic_index_via_ptr.wgsl.expected.msl
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/dynamic_index_via_ptr.wgsl.expected.msl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/dynamic_index_via_ptr.wgsl.expected.spvasm
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/dynamic_index_via_ptr.wgsl.expected.wgsl
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/static_index_via_ptr.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/static_index_via_ptr.wgsl
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/static_index_via_ptr.wgsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/static_index_via_ptr.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/static_index_via_ptr.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/static_index_via_ptr.wgsl.expected.glsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/static_index_via_ptr.wgsl.expected.glsl
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/static_index_via_ptr.wgsl.expected.glsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/static_index_via_ptr.wgsl.expected.msl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/static_index_via_ptr.wgsl.expected.msl
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/static_index_via_ptr.wgsl.expected.msl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/static_index_via_ptr.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/static_index_via_ptr.wgsl.expected.spvasm
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/static_index_via_ptr.wgsl.expected.spvasm
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/static_index_via_ptr.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/static_index_via_ptr.wgsl.expected.wgsl
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/static_index_via_ptr.wgsl.expected.wgsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/to_builtin.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_builtin.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/to_builtin.wgsl
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_builtin.wgsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_builtin.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/to_builtin.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_builtin.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_builtin.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/to_builtin.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_builtin.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_builtin.wgsl.expected.glsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/to_builtin.wgsl.expected.glsl
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_builtin.wgsl.expected.glsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_builtin.wgsl.expected.msl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/to_builtin.wgsl.expected.msl
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_builtin.wgsl.expected.msl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_builtin.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/to_builtin.wgsl.expected.spvasm
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_builtin.wgsl.expected.spvasm
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_builtin.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/to_builtin.wgsl.expected.wgsl
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_builtin.wgsl.expected.wgsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/to_fn.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_fn.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/to_fn.wgsl
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_fn.wgsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_fn.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/to_fn.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_fn.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_fn.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/to_fn.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_fn.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_fn.wgsl.expected.glsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/to_fn.wgsl.expected.glsl
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_fn.wgsl.expected.glsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_fn.wgsl.expected.msl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/to_fn.wgsl.expected.msl
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_fn.wgsl.expected.msl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_fn.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/to_fn.wgsl.expected.spvasm
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_fn.wgsl.expected.spvasm
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_fn.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/to_fn.wgsl.expected.wgsl
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_fn.wgsl.expected.wgsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/to_private.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_private.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/to_private.wgsl
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_private.wgsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_private.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/to_private.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_private.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_private.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/to_private.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_private.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_private.wgsl.expected.glsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/to_private.wgsl.expected.glsl
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_private.wgsl.expected.glsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_private.wgsl.expected.msl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/to_private.wgsl.expected.msl
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_private.wgsl.expected.msl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_private.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/to_private.wgsl.expected.spvasm
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_private.wgsl.expected.spvasm
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_private.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/to_private.wgsl.expected.wgsl
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_private.wgsl.expected.wgsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/to_storage.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_storage.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/to_storage.wgsl
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_storage.wgsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_storage.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/to_storage.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_storage.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_storage.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/to_storage.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_storage.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_storage.wgsl.expected.glsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/to_storage.wgsl.expected.glsl
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_storage.wgsl.expected.glsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_storage.wgsl.expected.msl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/to_storage.wgsl.expected.msl
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_storage.wgsl.expected.msl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_storage.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/to_storage.wgsl.expected.spvasm
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_storage.wgsl.expected.spvasm
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_storage.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/to_storage.wgsl.expected.wgsl
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_storage.wgsl.expected.wgsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_workgroup.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/to_workgroup.wgsl
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_workgroup.wgsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_workgroup.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/to_workgroup.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_workgroup.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_workgroup.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/to_workgroup.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_workgroup.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_workgroup.wgsl.expected.glsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/to_workgroup.wgsl.expected.glsl
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_workgroup.wgsl.expected.glsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_workgroup.wgsl.expected.msl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/to_workgroup.wgsl.expected.msl
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_workgroup.wgsl.expected.msl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_workgroup.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/to_workgroup.wgsl.expected.spvasm
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_workgroup.wgsl.expected.spvasm
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x2/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_workgroup.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/std140/unnested/mat4x2/to_workgroup.wgsl.expected.wgsl
rename to test/tint/buffer/uniform/std140/unnested/mat4x2_f32/to_workgroup.wgsl.expected.wgsl
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/dynamic_index_via_ptr.wgsl
new file mode 100644
index 0000000..001dc40
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/dynamic_index_via_ptr.wgsl
@@ -0,0 +1,15 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> m : mat4x3<f16>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m   = &m;
+  let p_m_i = &((*p_m)[i()]);
+
+  let l_m   : mat4x3<f16> = *p_m;
+  let l_m_i : vec3<f16>   = *p_m_i;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..d4f64e3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,46 @@
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[2];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 4, 3> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_m_i_save = i();
+  const matrix<float16_t, 4, 3> l_m = tint_symbol(m, 0u);
+  const uint scalar_offset_4 = ((8u * uint(p_m_i_save))) / 4;
+  uint4 ubo_load_9 = m[scalar_offset_4 / 4];
+  uint2 ubo_load_8 = ((scalar_offset_4 & 2) ? ubo_load_9.zw : ubo_load_9.xy);
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  float16_t ubo_load_8_y = f16tof32(ubo_load_8[0] >> 16);
+  const vector<float16_t, 3> l_m_i = vector<float16_t, 3>(ubo_load_8_xz[0], ubo_load_8_y, ubo_load_8_xz[1]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..73d44dc
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,51 @@
+SKIP: FAILED
+
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[2];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 4, 3> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_m_i_save = i();
+  const matrix<float16_t, 4, 3> l_m = tint_symbol(m, 0u);
+  const uint scalar_offset_4 = ((8u * uint(p_m_i_save))) / 4;
+  uint4 ubo_load_9 = m[scalar_offset_4 / 4];
+  uint2 ubo_load_8 = ((scalar_offset_4 & 2) ? ubo_load_9.zw : ubo_load_9.xy);
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  float16_t ubo_load_8_y = f16tof32(ubo_load_8[0] >> 16);
+  const vector<float16_t, 3> l_m_i = vector<float16_t, 3>(ubo_load_8_xz[0], ubo_load_8_y, ubo_load_8_xz[1]);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000029A277BC3D0(11,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..09bc9f3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,58 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform m_block_std140_ubo {
+  f16vec3 inner_0;
+  f16vec3 inner_1;
+  f16vec3 inner_2;
+  f16vec3 inner_3;
+} m;
+
+int counter = 0;
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+f16mat4x3 load_m_inner() {
+  return f16mat4x3(m.inner_0, m.inner_1, m.inner_2, m.inner_3);
+}
+
+f16vec3 load_m_inner_p0(uint p0) {
+  switch(p0) {
+    case 0u: {
+      return m.inner_0;
+      break;
+    }
+    case 1u: {
+      return m.inner_1;
+      break;
+    }
+    case 2u: {
+      return m.inner_2;
+      break;
+    }
+    case 3u: {
+      return m.inner_3;
+      break;
+    }
+    default: {
+      return f16vec3(0.0hf);
+      break;
+    }
+  }
+}
+
+void f() {
+  f16mat4x3 p_m = load_m_inner();
+  int tint_symbol = i();
+  f16vec3 p_m_i = load_m_inner_p0(uint(tint_symbol));
+  f16mat4x3 l_m = load_m_inner();
+  f16vec3 l_m_i = load_m_inner_p0(uint(tint_symbol));
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..3e06cd5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,17 @@
+#include <metal_stdlib>
+
+using namespace metal;
+int i() {
+  thread int tint_symbol_1 = 0;
+  tint_symbol_1 = as_type<int>((as_type<uint>(tint_symbol_1) + as_type<uint>(1)));
+  return tint_symbol_1;
+}
+
+kernel void f(const constant half4x3* tint_symbol_2 [[buffer(0)]]) {
+  int const tint_symbol = i();
+  int const p_m_i_save = tint_symbol;
+  half4x3 const l_m = *(tint_symbol_2);
+  half3 const l_m_i = (*(tint_symbol_2))[p_m_i_save];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..06b5911
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,111 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 68
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %m_block_std140 "m_block_std140"
+               OpMemberName %m_block_std140 0 "inner_0"
+               OpMemberName %m_block_std140 1 "inner_1"
+               OpMemberName %m_block_std140 2 "inner_2"
+               OpMemberName %m_block_std140 3 "inner_3"
+               OpName %m "m"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %load_m_inner "load_m_inner"
+               OpName %load_m_inner_p0 "load_m_inner_p0"
+               OpName %p0 "p0"
+               OpName %f "f"
+               OpDecorate %m_block_std140 Block
+               OpMemberDecorate %m_block_std140 0 Offset 0
+               OpMemberDecorate %m_block_std140 1 Offset 8
+               OpMemberDecorate %m_block_std140 2 Offset 16
+               OpMemberDecorate %m_block_std140 3 Offset 24
+               OpDecorate %m NonWritable
+               OpDecorate %m DescriptorSet 0
+               OpDecorate %m Binding 0
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+%m_block_std140 = OpTypeStruct %v3half %v3half %v3half %v3half
+%_ptr_Uniform_m_block_std140 = OpTypePointer Uniform %m_block_std140
+          %m = OpVariable %_ptr_Uniform_m_block_std140 Uniform
+        %int = OpTypeInt 32 1
+          %7 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %7
+         %10 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+ %mat4v3half = OpTypeMatrix %v3half 4
+         %17 = OpTypeFunction %mat4v3half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+         %41 = OpTypeFunction %v3half %uint
+         %59 = OpConstantNull %v3half
+       %void = OpTypeVoid
+         %60 = OpTypeFunction %void
+          %i = OpFunction %int None %10
+         %12 = OpLabel
+         %13 = OpLoad %int %counter
+         %15 = OpIAdd %int %13 %int_1
+               OpStore %counter %15
+         %16 = OpLoad %int %counter
+               OpReturnValue %16
+               OpFunctionEnd
+%load_m_inner = OpFunction %mat4v3half None %17
+         %20 = OpLabel
+         %26 = OpAccessChain %_ptr_Uniform_v3half %m %uint_0
+         %27 = OpLoad %v3half %26
+         %30 = OpAccessChain %_ptr_Uniform_v3half %m %uint_1
+         %31 = OpLoad %v3half %30
+         %34 = OpAccessChain %_ptr_Uniform_v3half %m %uint_2
+         %35 = OpLoad %v3half %34
+         %38 = OpAccessChain %_ptr_Uniform_v3half %m %uint_3
+         %39 = OpLoad %v3half %38
+         %40 = OpCompositeConstruct %mat4v3half %27 %31 %35 %39
+               OpReturnValue %40
+               OpFunctionEnd
+%load_m_inner_p0 = OpFunction %v3half None %41
+         %p0 = OpFunctionParameter %uint
+         %44 = OpLabel
+               OpSelectionMerge %45 None
+               OpSwitch %p0 %46 0 %47 1 %48 2 %49 3 %50
+         %47 = OpLabel
+         %51 = OpAccessChain %_ptr_Uniform_v3half %m %uint_0
+         %52 = OpLoad %v3half %51
+               OpReturnValue %52
+         %48 = OpLabel
+         %53 = OpAccessChain %_ptr_Uniform_v3half %m %uint_1
+         %54 = OpLoad %v3half %53
+               OpReturnValue %54
+         %49 = OpLabel
+         %55 = OpAccessChain %_ptr_Uniform_v3half %m %uint_2
+         %56 = OpLoad %v3half %55
+               OpReturnValue %56
+         %50 = OpLabel
+         %57 = OpAccessChain %_ptr_Uniform_v3half %m %uint_3
+         %58 = OpLoad %v3half %57
+               OpReturnValue %58
+         %46 = OpLabel
+               OpReturnValue %59
+         %45 = OpLabel
+               OpReturnValue %59
+               OpFunctionEnd
+          %f = OpFunction %void None %60
+         %63 = OpLabel
+         %64 = OpFunctionCall %int %i
+         %65 = OpFunctionCall %mat4v3half %load_m_inner
+         %67 = OpBitcast %uint %64
+         %66 = OpFunctionCall %v3half %load_m_inner_p0 %67
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..90b5ce7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> m : mat4x3<f16>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m = &(m);
+  let p_m_i = &((*(p_m))[i()]);
+  let l_m : mat4x3<f16> = *(p_m);
+  let l_m_i : vec3<f16> = *(p_m_i);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/static_index_via_ptr.wgsl
new file mode 100644
index 0000000..63121b8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/static_index_via_ptr.wgsl
@@ -0,0 +1,15 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> m : mat4x3<f16>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m   = &m;
+  let p_m_1 = &((*p_m)[1]);
+
+  let l_m   : mat4x3<f16> = *p_m;
+  let l_m_1 : vec3<f16>   = *p_m_1;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..46a10de
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,43 @@
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[2];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 4, 3> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 4, 3> l_m = tint_symbol(m, 0u);
+  uint2 ubo_load_8 = m[0].zw;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  float16_t ubo_load_8_y = f16tof32(ubo_load_8[0] >> 16);
+  const vector<float16_t, 3> l_m_1 = vector<float16_t, 3>(ubo_load_8_xz[0], ubo_load_8_y, ubo_load_8_xz[1]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..77207dc
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,48 @@
+SKIP: FAILED
+
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[2];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 4, 3> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 4, 3> l_m = tint_symbol(m, 0u);
+  uint2 ubo_load_8 = m[0].zw;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  float16_t ubo_load_8_y = f16tof32(ubo_load_8[0] >> 16);
+  const vector<float16_t, 3> l_m_1 = vector<float16_t, 3>(ubo_load_8_xz[0], ubo_load_8_y, ubo_load_8_xz[1]);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001D61ABCB8F0(11,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/static_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..f99841d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/static_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,26 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform m_block_std140_ubo {
+  f16vec3 inner_0;
+  f16vec3 inner_1;
+  f16vec3 inner_2;
+  f16vec3 inner_3;
+} m;
+
+f16mat4x3 load_m_inner() {
+  return f16mat4x3(m.inner_0, m.inner_1, m.inner_2, m.inner_3);
+}
+
+void f() {
+  f16mat4x3 p_m = load_m_inner();
+  f16vec3 p_m_1 = m.inner_1;
+  f16mat4x3 l_m = load_m_inner();
+  f16vec3 l_m_1 = m.inner_1;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/static_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..d08b0d9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/static_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,15 @@
+#include <metal_stdlib>
+
+using namespace metal;
+int i() {
+  thread int tint_symbol = 0;
+  tint_symbol = as_type<int>((as_type<uint>(tint_symbol) + as_type<uint>(1)));
+  return tint_symbol;
+}
+
+kernel void f(const constant half4x3* tint_symbol_1 [[buffer(0)]]) {
+  half4x3 const l_m = *(tint_symbol_1);
+  half3 const l_m_1 = (*(tint_symbol_1))[1];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/static_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..1177f6a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/static_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,80 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 48
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %m_block_std140 "m_block_std140"
+               OpMemberName %m_block_std140 0 "inner_0"
+               OpMemberName %m_block_std140 1 "inner_1"
+               OpMemberName %m_block_std140 2 "inner_2"
+               OpMemberName %m_block_std140 3 "inner_3"
+               OpName %m "m"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %load_m_inner "load_m_inner"
+               OpName %f "f"
+               OpDecorate %m_block_std140 Block
+               OpMemberDecorate %m_block_std140 0 Offset 0
+               OpMemberDecorate %m_block_std140 1 Offset 8
+               OpMemberDecorate %m_block_std140 2 Offset 16
+               OpMemberDecorate %m_block_std140 3 Offset 24
+               OpDecorate %m NonWritable
+               OpDecorate %m DescriptorSet 0
+               OpDecorate %m Binding 0
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+%m_block_std140 = OpTypeStruct %v3half %v3half %v3half %v3half
+%_ptr_Uniform_m_block_std140 = OpTypePointer Uniform %m_block_std140
+          %m = OpVariable %_ptr_Uniform_m_block_std140 Uniform
+        %int = OpTypeInt 32 1
+          %7 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %7
+         %10 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+ %mat4v3half = OpTypeMatrix %v3half 4
+         %17 = OpTypeFunction %mat4v3half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %41 = OpTypeFunction %void
+          %i = OpFunction %int None %10
+         %12 = OpLabel
+         %13 = OpLoad %int %counter
+         %15 = OpIAdd %int %13 %int_1
+               OpStore %counter %15
+         %16 = OpLoad %int %counter
+               OpReturnValue %16
+               OpFunctionEnd
+%load_m_inner = OpFunction %mat4v3half None %17
+         %20 = OpLabel
+         %26 = OpAccessChain %_ptr_Uniform_v3half %m %uint_0
+         %27 = OpLoad %v3half %26
+         %30 = OpAccessChain %_ptr_Uniform_v3half %m %uint_1
+         %31 = OpLoad %v3half %30
+         %34 = OpAccessChain %_ptr_Uniform_v3half %m %uint_2
+         %35 = OpLoad %v3half %34
+         %38 = OpAccessChain %_ptr_Uniform_v3half %m %uint_3
+         %39 = OpLoad %v3half %38
+         %40 = OpCompositeConstruct %mat4v3half %27 %31 %35 %39
+               OpReturnValue %40
+               OpFunctionEnd
+          %f = OpFunction %void None %41
+         %44 = OpLabel
+         %45 = OpFunctionCall %mat4v3half %load_m_inner
+         %46 = OpAccessChain %_ptr_Uniform_v3half %m %uint_1
+         %47 = OpLoad %v3half %46
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/static_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..458602c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/static_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> m : mat4x3<f16>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m = &(m);
+  let p_m_1 = &((*(p_m))[1]);
+  let l_m : mat4x3<f16> = *(p_m);
+  let l_m_1 : vec3<f16> = *(p_m_1);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_builtin.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_builtin.wgsl
new file mode 100644
index 0000000..8e8a955
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_builtin.wgsl
@@ -0,0 +1,10 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat4x3<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+    let t = transpose(u);
+    let l = length(u[1]);
+    let a = abs(u[0].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_builtin.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..34e0598
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_builtin.wgsl.expected.dxc.hlsl
@@ -0,0 +1,41 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+
+matrix<float16_t, 4, 3> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 3, 4> t = transpose(tint_symbol(u, 0u));
+  uint2 ubo_load_8 = u[0].zw;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  float16_t ubo_load_8_y = f16tof32(ubo_load_8[0] >> 16);
+  const float16_t l = length(vector<float16_t, 3>(ubo_load_8_xz[0], ubo_load_8_y, ubo_load_8_xz[1]));
+  uint2 ubo_load_9 = u[0].xy;
+  vector<float16_t, 2> ubo_load_9_xz = vector<float16_t, 2>(f16tof32(ubo_load_9 & 0xFFFF));
+  float16_t ubo_load_9_y = f16tof32(ubo_load_9[0] >> 16);
+  const float16_t a = abs(vector<float16_t, 3>(ubo_load_9_xz[0], ubo_load_9_y, ubo_load_9_xz[1]).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_builtin.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..fa56e93
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_builtin.wgsl.expected.fxc.hlsl
@@ -0,0 +1,46 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+
+matrix<float16_t, 4, 3> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 3, 4> t = transpose(tint_symbol(u, 0u));
+  uint2 ubo_load_8 = u[0].zw;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  float16_t ubo_load_8_y = f16tof32(ubo_load_8[0] >> 16);
+  const float16_t l = length(vector<float16_t, 3>(ubo_load_8_xz[0], ubo_load_8_y, ubo_load_8_xz[1]));
+  uint2 ubo_load_9 = u[0].xy;
+  vector<float16_t, 2> ubo_load_9_xz = vector<float16_t, 2>(f16tof32(ubo_load_9 & 0xFFFF));
+  float16_t ubo_load_9_y = f16tof32(ubo_load_9[0] >> 16);
+  const float16_t a = abs(vector<float16_t, 3>(ubo_load_9_xz[0], ubo_load_9_y, ubo_load_9_xz[1]).zxy.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x00000214C6C4DE30(5,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_builtin.wgsl.expected.glsl
new file mode 100644
index 0000000..699e138
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_builtin.wgsl.expected.glsl
@@ -0,0 +1,25 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec3 inner_0;
+  f16vec3 inner_1;
+  f16vec3 inner_2;
+  f16vec3 inner_3;
+} u;
+
+f16mat4x3 load_u_inner() {
+  return f16mat4x3(u.inner_0, u.inner_1, u.inner_2, u.inner_3);
+}
+
+void f() {
+  f16mat3x4 t = transpose(load_u_inner());
+  float16_t l = length(u.inner_1);
+  float16_t a = abs(u.inner_0.zxy[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_builtin.wgsl.expected.msl
new file mode 100644
index 0000000..6bd3adc
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_builtin.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f(const constant half4x3* tint_symbol [[buffer(0)]]) {
+  half3x4 const t = transpose(*(tint_symbol));
+  half const l = length((*(tint_symbol))[1]);
+  half const a = fabs(half3((*(tint_symbol))[0]).zxy[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_builtin.wgsl.expected.spvasm
new file mode 100644
index 0000000..a5c7161
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_builtin.wgsl.expected.spvasm
@@ -0,0 +1,75 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 48
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+         %39 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpMemberName %u_block_std140 2 "inner_2"
+               OpMemberName %u_block_std140 3 "inner_3"
+               OpName %u "u"
+               OpName %load_u_inner "load_u_inner"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 8
+               OpMemberDecorate %u_block_std140 2 Offset 16
+               OpMemberDecorate %u_block_std140 3 Offset 24
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+%u_block_std140 = OpTypeStruct %v3half %v3half %v3half %v3half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat4v3half = OpTypeMatrix %v3half 4
+          %6 = OpTypeFunction %mat4v3half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %30 = OpTypeFunction %void
+     %v4half = OpTypeVector %half 4
+ %mat3v4half = OpTypeMatrix %v4half 3
+         %46 = OpConstantNull %uint
+%load_u_inner = OpFunction %mat4v3half None %6
+          %9 = OpLabel
+         %15 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0
+         %16 = OpLoad %v3half %15
+         %19 = OpAccessChain %_ptr_Uniform_v3half %u %uint_1
+         %20 = OpLoad %v3half %19
+         %23 = OpAccessChain %_ptr_Uniform_v3half %u %uint_2
+         %24 = OpLoad %v3half %23
+         %27 = OpAccessChain %_ptr_Uniform_v3half %u %uint_3
+         %28 = OpLoad %v3half %27
+         %29 = OpCompositeConstruct %mat4v3half %16 %20 %24 %28
+               OpReturnValue %29
+               OpFunctionEnd
+          %f = OpFunction %void None %30
+         %33 = OpLabel
+         %37 = OpFunctionCall %mat4v3half %load_u_inner
+         %34 = OpTranspose %mat3v4half %37
+         %40 = OpAccessChain %_ptr_Uniform_v3half %u %uint_1
+         %41 = OpLoad %v3half %40
+         %38 = OpExtInst %half %39 Length %41
+         %43 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0
+         %44 = OpLoad %v3half %43
+         %45 = OpVectorShuffle %v3half %44 %44 2 0 1
+         %47 = OpCompositeExtract %half %45 0
+         %42 = OpExtInst %half %39 FAbs %47
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_builtin.wgsl.expected.wgsl
new file mode 100644
index 0000000..4443638
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_builtin.wgsl.expected.wgsl
@@ -0,0 +1,10 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat4x3<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let t = transpose(u);
+  let l = length(u[1]);
+  let a = abs(u[0].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_fn.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_fn.wgsl
new file mode 100644
index 0000000..9fd9ba4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_fn.wgsl
@@ -0,0 +1,16 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat4x3<f16>;
+
+fn a(m : mat4x3<f16>) {}
+fn b(v : vec3<f16>) {}
+fn c(f : f16) {}
+
+@compute @workgroup_size(1)
+fn f() {
+    a(u);
+    b(u[1]);
+    b(u[1].zxy);
+    c(u[1].x);
+    c(u[1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_fn.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..778064a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_fn.wgsl.expected.dxc.hlsl
@@ -0,0 +1,55 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+
+void a(matrix<float16_t, 4, 3> m) {
+}
+
+void b(vector<float16_t, 3> v) {
+}
+
+void c(float16_t f_1) {
+}
+
+matrix<float16_t, 4, 3> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  uint2 ubo_load_8 = u[0].zw;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  float16_t ubo_load_8_y = f16tof32(ubo_load_8[0] >> 16);
+  b(vector<float16_t, 3>(ubo_load_8_xz[0], ubo_load_8_y, ubo_load_8_xz[1]));
+  uint2 ubo_load_9 = u[0].zw;
+  vector<float16_t, 2> ubo_load_9_xz = vector<float16_t, 2>(f16tof32(ubo_load_9 & 0xFFFF));
+  float16_t ubo_load_9_y = f16tof32(ubo_load_9[0] >> 16);
+  b(vector<float16_t, 3>(ubo_load_9_xz[0], ubo_load_9_y, ubo_load_9_xz[1]).zxy);
+  c(float16_t(f16tof32(((u[0].z) & 0xFFFF))));
+  uint2 ubo_load_10 = u[0].zw;
+  vector<float16_t, 2> ubo_load_10_xz = vector<float16_t, 2>(f16tof32(ubo_load_10 & 0xFFFF));
+  float16_t ubo_load_10_y = f16tof32(ubo_load_10[0] >> 16);
+  c(vector<float16_t, 3>(ubo_load_10_xz[0], ubo_load_10_y, ubo_load_10_xz[1]).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_fn.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..3cff235
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_fn.wgsl.expected.fxc.hlsl
@@ -0,0 +1,62 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+
+void a(matrix<float16_t, 4, 3> m) {
+}
+
+void b(vector<float16_t, 3> v) {
+}
+
+void c(float16_t f_1) {
+}
+
+matrix<float16_t, 4, 3> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  uint2 ubo_load_8 = u[0].zw;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  float16_t ubo_load_8_y = f16tof32(ubo_load_8[0] >> 16);
+  b(vector<float16_t, 3>(ubo_load_8_xz[0], ubo_load_8_y, ubo_load_8_xz[1]));
+  uint2 ubo_load_9 = u[0].zw;
+  vector<float16_t, 2> ubo_load_9_xz = vector<float16_t, 2>(f16tof32(ubo_load_9 & 0xFFFF));
+  float16_t ubo_load_9_y = f16tof32(ubo_load_9[0] >> 16);
+  b(vector<float16_t, 3>(ubo_load_9_xz[0], ubo_load_9_y, ubo_load_9_xz[1]).zxy);
+  c(float16_t(f16tof32(((u[0].z) & 0xFFFF))));
+  uint2 ubo_load_10 = u[0].zw;
+  vector<float16_t, 2> ubo_load_10_xz = vector<float16_t, 2>(f16tof32(ubo_load_10 & 0xFFFF));
+  float16_t ubo_load_10_y = f16tof32(ubo_load_10[0] >> 16);
+  c(vector<float16_t, 3>(ubo_load_10_xz[0], ubo_load_10_y, ubo_load_10_xz[1]).zxy.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001F16275ECF0(5,15-23): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001F16275ECF0(8,15-23): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001F16275ECF0(11,8-16): error X3000: unrecognized identifier 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_fn.wgsl.expected.glsl
new file mode 100644
index 0000000..a7cd45d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_fn.wgsl.expected.glsl
@@ -0,0 +1,36 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec3 inner_0;
+  f16vec3 inner_1;
+  f16vec3 inner_2;
+  f16vec3 inner_3;
+} u;
+
+void a(f16mat4x3 m) {
+}
+
+void b(f16vec3 v) {
+}
+
+void c(float16_t f_1) {
+}
+
+f16mat4x3 load_u_inner() {
+  return f16mat4x3(u.inner_0, u.inner_1, u.inner_2, u.inner_3);
+}
+
+void f() {
+  a(load_u_inner());
+  b(u.inner_1);
+  b(u.inner_1.zxy);
+  c(u.inner_1[0u]);
+  c(u.inner_1.zxy[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_fn.wgsl.expected.msl
new file mode 100644
index 0000000..84e67e0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_fn.wgsl.expected.msl
@@ -0,0 +1,21 @@
+#include <metal_stdlib>
+
+using namespace metal;
+void a(half4x3 m) {
+}
+
+void b(half3 v) {
+}
+
+void c(half f_1) {
+}
+
+kernel void f(const constant half4x3* tint_symbol [[buffer(0)]]) {
+  a(*(tint_symbol));
+  b((*(tint_symbol))[1]);
+  b(half3((*(tint_symbol))[1]).zxy);
+  c((*(tint_symbol))[1][0]);
+  c(half3((*(tint_symbol))[1]).zxy[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_fn.wgsl.expected.spvasm
new file mode 100644
index 0000000..7ab21d9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_fn.wgsl.expected.spvasm
@@ -0,0 +1,104 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 65
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpMemberName %u_block_std140 2 "inner_2"
+               OpMemberName %u_block_std140 3 "inner_3"
+               OpName %u "u"
+               OpName %a "a"
+               OpName %m "m"
+               OpName %b "b"
+               OpName %v "v"
+               OpName %c "c"
+               OpName %f_1 "f_1"
+               OpName %load_u_inner "load_u_inner"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 8
+               OpMemberDecorate %u_block_std140 2 Offset 16
+               OpMemberDecorate %u_block_std140 3 Offset 24
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+%u_block_std140 = OpTypeStruct %v3half %v3half %v3half %v3half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+       %void = OpTypeVoid
+ %mat4v3half = OpTypeMatrix %v3half 4
+          %6 = OpTypeFunction %void %mat4v3half
+         %12 = OpTypeFunction %void %v3half
+         %16 = OpTypeFunction %void %half
+         %20 = OpTypeFunction %mat4v3half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+         %43 = OpTypeFunction %void
+         %56 = OpConstantNull %uint
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+          %a = OpFunction %void None %6
+          %m = OpFunctionParameter %mat4v3half
+         %11 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %b = OpFunction %void None %12
+          %v = OpFunctionParameter %v3half
+         %15 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %c = OpFunction %void None %16
+        %f_1 = OpFunctionParameter %half
+         %19 = OpLabel
+               OpReturn
+               OpFunctionEnd
+%load_u_inner = OpFunction %mat4v3half None %20
+         %22 = OpLabel
+         %28 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0
+         %29 = OpLoad %v3half %28
+         %32 = OpAccessChain %_ptr_Uniform_v3half %u %uint_1
+         %33 = OpLoad %v3half %32
+         %36 = OpAccessChain %_ptr_Uniform_v3half %u %uint_2
+         %37 = OpLoad %v3half %36
+         %40 = OpAccessChain %_ptr_Uniform_v3half %u %uint_3
+         %41 = OpLoad %v3half %40
+         %42 = OpCompositeConstruct %mat4v3half %29 %33 %37 %41
+               OpReturnValue %42
+               OpFunctionEnd
+          %f = OpFunction %void None %43
+         %45 = OpLabel
+         %47 = OpFunctionCall %mat4v3half %load_u_inner
+         %46 = OpFunctionCall %void %a %47
+         %49 = OpAccessChain %_ptr_Uniform_v3half %u %uint_1
+         %50 = OpLoad %v3half %49
+         %48 = OpFunctionCall %void %b %50
+         %52 = OpAccessChain %_ptr_Uniform_v3half %u %uint_1
+         %53 = OpLoad %v3half %52
+         %54 = OpVectorShuffle %v3half %53 %53 2 0 1
+         %51 = OpFunctionCall %void %b %54
+         %58 = OpAccessChain %_ptr_Uniform_half %u %uint_1 %56
+         %59 = OpLoad %half %58
+         %55 = OpFunctionCall %void %c %59
+         %61 = OpAccessChain %_ptr_Uniform_v3half %u %uint_1
+         %62 = OpLoad %v3half %61
+         %63 = OpVectorShuffle %v3half %62 %62 2 0 1
+         %64 = OpCompositeExtract %half %63 0
+         %60 = OpFunctionCall %void %c %64
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_fn.wgsl.expected.wgsl
new file mode 100644
index 0000000..5e553aa
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_fn.wgsl.expected.wgsl
@@ -0,0 +1,21 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat4x3<f16>;
+
+fn a(m : mat4x3<f16>) {
+}
+
+fn b(v : vec3<f16>) {
+}
+
+fn c(f : f16) {
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  a(u);
+  b(u[1]);
+  b(u[1].zxy);
+  c(u[1].x);
+  c(u[1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_private.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_private.wgsl
new file mode 100644
index 0000000..d971a47
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_private.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat4x3<f16>;
+var<private> p : mat4x3<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[0];
+    p[1] = u[0].zxy;
+    p[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_private.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..a448fe7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_private.wgsl.expected.dxc.hlsl
@@ -0,0 +1,43 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+static matrix<float16_t, 4, 3> p = matrix<float16_t, 4, 3>(float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h));
+
+matrix<float16_t, 4, 3> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  uint2 ubo_load_8 = u[0].xy;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  float16_t ubo_load_8_y = f16tof32(ubo_load_8[0] >> 16);
+  p[1] = vector<float16_t, 3>(ubo_load_8_xz[0], ubo_load_8_y, ubo_load_8_xz[1]);
+  uint2 ubo_load_9 = u[0].xy;
+  vector<float16_t, 2> ubo_load_9_xz = vector<float16_t, 2>(f16tof32(ubo_load_9 & 0xFFFF));
+  float16_t ubo_load_9_y = f16tof32(ubo_load_9[0] >> 16);
+  p[1] = vector<float16_t, 3>(ubo_load_9_xz[0], ubo_load_9_y, ubo_load_9_xz[1]).zxy;
+  p[0][1] = float16_t(f16tof32(((u[0].z) & 0xFFFF)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_private.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..d1183d2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_private.wgsl.expected.fxc.hlsl
@@ -0,0 +1,48 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+static matrix<float16_t, 4, 3> p = matrix<float16_t, 4, 3>(float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h));
+
+matrix<float16_t, 4, 3> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  uint2 ubo_load_8 = u[0].xy;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  float16_t ubo_load_8_y = f16tof32(ubo_load_8[0] >> 16);
+  p[1] = vector<float16_t, 3>(ubo_load_8_xz[0], ubo_load_8_y, ubo_load_8_xz[1]);
+  uint2 ubo_load_9 = u[0].xy;
+  vector<float16_t, 2> ubo_load_9_xz = vector<float16_t, 2>(f16tof32(ubo_load_9 & 0xFFFF));
+  float16_t ubo_load_9_y = f16tof32(ubo_load_9[0] >> 16);
+  p[1] = vector<float16_t, 3>(ubo_load_9_xz[0], ubo_load_9_y, ubo_load_9_xz[1]).zxy;
+  p[0][1] = float16_t(f16tof32(((u[0].z) & 0xFFFF)));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001A61234DB60(4,15-23): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..b00a3ed
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_private.wgsl.expected.glsl
@@ -0,0 +1,27 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec3 inner_0;
+  f16vec3 inner_1;
+  f16vec3 inner_2;
+  f16vec3 inner_3;
+} u;
+
+f16mat4x3 p = f16mat4x3(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf);
+f16mat4x3 load_u_inner() {
+  return f16mat4x3(u.inner_0, u.inner_1, u.inner_2, u.inner_3);
+}
+
+void f() {
+  p = load_u_inner();
+  p[1] = u.inner_0;
+  p[1] = u.inner_0.zxy;
+  p[0][1] = u.inner_1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..5aa938f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_private.wgsl.expected.msl
@@ -0,0 +1,12 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f(const constant half4x3* tint_symbol_1 [[buffer(0)]]) {
+  thread half4x3 tint_symbol = half4x3(0.0h);
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[0];
+  tint_symbol[1] = half3((*(tint_symbol_1))[0]).zxy;
+  tint_symbol[0][1] = (*(tint_symbol_1))[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_private.wgsl.expected.spvasm
new file mode 100644
index 0000000..c733bfd
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_private.wgsl.expected.spvasm
@@ -0,0 +1,87 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 55
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpMemberName %u_block_std140 2 "inner_2"
+               OpMemberName %u_block_std140 3 "inner_3"
+               OpName %u "u"
+               OpName %p "p"
+               OpName %load_u_inner "load_u_inner"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 8
+               OpMemberDecorate %u_block_std140 2 Offset 16
+               OpMemberDecorate %u_block_std140 3 Offset 24
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+%u_block_std140 = OpTypeStruct %v3half %v3half %v3half %v3half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat4v3half = OpTypeMatrix %v3half 4
+%_ptr_Private_mat4v3half = OpTypePointer Private %mat4v3half
+          %9 = OpConstantNull %mat4v3half
+          %p = OpVariable %_ptr_Private_mat4v3half Private %9
+         %10 = OpTypeFunction %mat4v3half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %33 = OpTypeFunction %void
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Private_v3half = OpTypePointer Private %v3half
+         %48 = OpConstantNull %int
+%_ptr_Private_half = OpTypePointer Private %half
+         %51 = OpConstantNull %uint
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+%load_u_inner = OpFunction %mat4v3half None %10
+         %12 = OpLabel
+         %18 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0
+         %19 = OpLoad %v3half %18
+         %22 = OpAccessChain %_ptr_Uniform_v3half %u %uint_1
+         %23 = OpLoad %v3half %22
+         %26 = OpAccessChain %_ptr_Uniform_v3half %u %uint_2
+         %27 = OpLoad %v3half %26
+         %30 = OpAccessChain %_ptr_Uniform_v3half %u %uint_3
+         %31 = OpLoad %v3half %30
+         %32 = OpCompositeConstruct %mat4v3half %19 %23 %27 %31
+               OpReturnValue %32
+               OpFunctionEnd
+          %f = OpFunction %void None %33
+         %36 = OpLabel
+         %37 = OpFunctionCall %mat4v3half %load_u_inner
+               OpStore %p %37
+         %41 = OpAccessChain %_ptr_Private_v3half %p %int_1
+         %42 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0
+         %43 = OpLoad %v3half %42
+               OpStore %41 %43
+         %44 = OpAccessChain %_ptr_Private_v3half %p %int_1
+         %45 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0
+         %46 = OpLoad %v3half %45
+         %47 = OpVectorShuffle %v3half %46 %46 2 0 1
+               OpStore %44 %47
+         %50 = OpAccessChain %_ptr_Private_half %p %48 %int_1
+         %53 = OpAccessChain %_ptr_Uniform_half %u %uint_1 %51
+         %54 = OpLoad %half %53
+               OpStore %50 %54
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..bf1dbf2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_private.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat4x3<f16>;
+
+var<private> p : mat4x3<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[0];
+  p[1] = u[0].zxy;
+  p[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_storage.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_storage.wgsl
new file mode 100644
index 0000000..10ee5e7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_storage.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat4x3<f16>;
+@group(0) @binding(1) var<storage, read_write> s : mat4x3<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[0];
+    s[1] = u[0].zxy;
+    s[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_storage.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..7d09ac6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_storage.wgsl.expected.dxc.hlsl
@@ -0,0 +1,50 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 3> value) {
+  buffer.Store<vector<float16_t, 3> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 8u), value[1u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 16u), value[2u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 24u), value[3u]);
+}
+
+matrix<float16_t, 4, 3> tint_symbol_2(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_2(u, 0u));
+  uint2 ubo_load_8 = u[0].xy;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  float16_t ubo_load_8_y = f16tof32(ubo_load_8[0] >> 16);
+  s.Store<vector<float16_t, 3> >(8u, vector<float16_t, 3>(ubo_load_8_xz[0], ubo_load_8_y, ubo_load_8_xz[1]));
+  uint2 ubo_load_9 = u[0].xy;
+  vector<float16_t, 2> ubo_load_9_xz = vector<float16_t, 2>(f16tof32(ubo_load_9 & 0xFFFF));
+  float16_t ubo_load_9_y = f16tof32(ubo_load_9[0] >> 16);
+  s.Store<vector<float16_t, 3> >(8u, vector<float16_t, 3>(ubo_load_9_xz[0], ubo_load_9_y, ubo_load_9_xz[1]).zxy);
+  s.Store<float16_t>(2u, float16_t(f16tof32(((u[0].z) & 0xFFFF))));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_storage.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..fb2dab0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_storage.wgsl.expected.fxc.hlsl
@@ -0,0 +1,56 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 3> value) {
+  buffer.Store<vector<float16_t, 3> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 8u), value[1u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 16u), value[2u]);
+  buffer.Store<vector<float16_t, 3> >((offset + 24u), value[3u]);
+}
+
+matrix<float16_t, 4, 3> tint_symbol_2(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_2(u, 0u));
+  uint2 ubo_load_8 = u[0].xy;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  float16_t ubo_load_8_y = f16tof32(ubo_load_8[0] >> 16);
+  s.Store<vector<float16_t, 3> >(8u, vector<float16_t, 3>(ubo_load_8_xz[0], ubo_load_8_y, ubo_load_8_xz[1]));
+  uint2 ubo_load_9 = u[0].xy;
+  vector<float16_t, 2> ubo_load_9_xz = vector<float16_t, 2>(f16tof32(ubo_load_9 & 0xFFFF));
+  float16_t ubo_load_9_y = f16tof32(ubo_load_9[0] >> 16);
+  s.Store<vector<float16_t, 3> >(8u, vector<float16_t, 3>(ubo_load_9_xz[0], ubo_load_9_y, ubo_load_9_xz[1]).zxy);
+  s.Store<float16_t>(2u, float16_t(f16tof32(((u[0].z) & 0xFFFF))));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001FD3C2FBCC0(6,66-74): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001FD3C2FBCC0(7,3-14): error X3018: invalid subscript 'Store'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..dd054eb
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_storage.wgsl.expected.glsl
@@ -0,0 +1,30 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec3 inner_0;
+  f16vec3 inner_1;
+  f16vec3 inner_2;
+  f16vec3 inner_3;
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  f16mat4x3 inner;
+} s;
+
+f16mat4x3 load_u_inner() {
+  return f16mat4x3(u.inner_0, u.inner_1, u.inner_2, u.inner_3);
+}
+
+void f() {
+  s.inner = load_u_inner();
+  s.inner[1] = u.inner_0;
+  s.inner[1] = u.inner_0.zxy;
+  s.inner[0][1] = u.inner_1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..cab8651
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_storage.wgsl.expected.msl
@@ -0,0 +1,11 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f(device half4x3* tint_symbol [[buffer(1)]], const constant half4x3* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[0];
+  (*(tint_symbol))[1] = half3((*(tint_symbol_1))[0]).zxy;
+  (*(tint_symbol))[0][1] = (*(tint_symbol_1))[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_storage.wgsl.expected.spvasm
new file mode 100644
index 0000000..d22bb08
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_storage.wgsl.expected.spvasm
@@ -0,0 +1,97 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 57
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpMemberName %u_block_std140 2 "inner_2"
+               OpMemberName %u_block_std140 3 "inner_3"
+               OpName %u "u"
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %s "s"
+               OpName %load_u_inner "load_u_inner"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 8
+               OpMemberDecorate %u_block_std140 2 Offset 16
+               OpMemberDecorate %u_block_std140 3 Offset 24
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 8
+               OpDecorate %s DescriptorSet 0
+               OpDecorate %s Binding 1
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+%u_block_std140 = OpTypeStruct %v3half %v3half %v3half %v3half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat4v3half = OpTypeMatrix %v3half 4
+    %u_block = OpTypeStruct %mat4v3half
+%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
+          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+         %10 = OpTypeFunction %mat4v3half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %33 = OpTypeFunction %void
+%_ptr_StorageBuffer_mat4v3half = OpTypePointer StorageBuffer %mat4v3half
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_v3half = OpTypePointer StorageBuffer %v3half
+         %50 = OpConstantNull %int
+%_ptr_StorageBuffer_half = OpTypePointer StorageBuffer %half
+         %53 = OpConstantNull %uint
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+%load_u_inner = OpFunction %mat4v3half None %10
+         %12 = OpLabel
+         %18 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0
+         %19 = OpLoad %v3half %18
+         %22 = OpAccessChain %_ptr_Uniform_v3half %u %uint_1
+         %23 = OpLoad %v3half %22
+         %26 = OpAccessChain %_ptr_Uniform_v3half %u %uint_2
+         %27 = OpLoad %v3half %26
+         %30 = OpAccessChain %_ptr_Uniform_v3half %u %uint_3
+         %31 = OpLoad %v3half %30
+         %32 = OpCompositeConstruct %mat4v3half %19 %23 %27 %31
+               OpReturnValue %32
+               OpFunctionEnd
+          %f = OpFunction %void None %33
+         %36 = OpLabel
+         %38 = OpAccessChain %_ptr_StorageBuffer_mat4v3half %s %uint_0
+         %39 = OpFunctionCall %mat4v3half %load_u_inner
+               OpStore %38 %39
+         %43 = OpAccessChain %_ptr_StorageBuffer_v3half %s %uint_0 %int_1
+         %44 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0
+         %45 = OpLoad %v3half %44
+               OpStore %43 %45
+         %46 = OpAccessChain %_ptr_StorageBuffer_v3half %s %uint_0 %int_1
+         %47 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0
+         %48 = OpLoad %v3half %47
+         %49 = OpVectorShuffle %v3half %48 %48 2 0 1
+               OpStore %46 %49
+         %52 = OpAccessChain %_ptr_StorageBuffer_half %s %uint_0 %50 %int_1
+         %55 = OpAccessChain %_ptr_Uniform_half %u %uint_1 %53
+         %56 = OpLoad %half %55
+               OpStore %52 %56
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..e556976
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat4x3<f16>;
+
+@group(0) @binding(1) var<storage, read_write> s : mat4x3<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[0];
+  s[1] = u[0].zxy;
+  s[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_workgroup.wgsl
new file mode 100644
index 0000000..258704a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_workgroup.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat4x3<f16>;
+var<workgroup> w : mat4x3<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[0];
+    w[1] = u[0].zxy;
+    w[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_workgroup.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..d577f14
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_workgroup.wgsl.expected.dxc.hlsl
@@ -0,0 +1,55 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+groupshared matrix<float16_t, 4, 3> w;
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 4, 3> tint_symbol_2(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    w = matrix<float16_t, 4, 3>((float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx);
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  uint2 ubo_load_8 = u[0].xy;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  float16_t ubo_load_8_y = f16tof32(ubo_load_8[0] >> 16);
+  w[1] = vector<float16_t, 3>(ubo_load_8_xz[0], ubo_load_8_y, ubo_load_8_xz[1]);
+  uint2 ubo_load_9 = u[0].xy;
+  vector<float16_t, 2> ubo_load_9_xz = vector<float16_t, 2>(f16tof32(ubo_load_9 & 0xFFFF));
+  float16_t ubo_load_9_y = f16tof32(ubo_load_9[0] >> 16);
+  w[1] = vector<float16_t, 3>(ubo_load_9_xz[0], ubo_load_9_y, ubo_load_9_xz[1]).zxy;
+  w[0][1] = float16_t(f16tof32(((u[0].z) & 0xFFFF)));
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_workgroup.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..b5fa2ba
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_workgroup.wgsl.expected.fxc.hlsl
@@ -0,0 +1,60 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+groupshared matrix<float16_t, 4, 3> w;
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 4, 3> tint_symbol_2(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    w = matrix<float16_t, 4, 3>((float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx, (float16_t(0.0h)).xxx);
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  uint2 ubo_load_8 = u[0].xy;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  float16_t ubo_load_8_y = f16tof32(ubo_load_8[0] >> 16);
+  w[1] = vector<float16_t, 3>(ubo_load_8_xz[0], ubo_load_8_y, ubo_load_8_xz[1]);
+  uint2 ubo_load_9 = u[0].xy;
+  vector<float16_t, 2> ubo_load_9_xz = vector<float16_t, 2>(f16tof32(ubo_load_9 & 0xFFFF));
+  float16_t ubo_load_9_y = f16tof32(ubo_load_9[0] >> 16);
+  w[1] = vector<float16_t, 3>(ubo_load_9_xz[0], ubo_load_9_y, ubo_load_9_xz[1]).zxy;
+  w[0][1] = float16_t(f16tof32(((u[0].z) & 0xFFFF)));
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000019BA46EC370(4,20-28): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..4829a28
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,31 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec3 inner_0;
+  f16vec3 inner_1;
+  f16vec3 inner_2;
+  f16vec3 inner_3;
+} u;
+
+shared f16mat4x3 w;
+f16mat4x3 load_u_inner() {
+  return f16mat4x3(u.inner_0, u.inner_1, u.inner_2, u.inner_3);
+}
+
+void f(uint local_invocation_index) {
+  {
+    w = f16mat4x3(f16vec3(0.0hf), f16vec3(0.0hf), f16vec3(0.0hf), f16vec3(0.0hf));
+  }
+  barrier();
+  w = load_u_inner();
+  w[1] = u.inner_0;
+  w[1] = u.inner_0.zxy;
+  w[0][1] = u.inner_1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..6df9ce1
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,24 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct tint_symbol_5 {
+  half4x3 w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup half4x3* const tint_symbol, const constant half4x3* const tint_symbol_1) {
+  {
+    *(tint_symbol) = half4x3(half3(0.0h), half3(0.0h), half3(0.0h), half3(0.0h));
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[0];
+  (*(tint_symbol))[1] = half3((*(tint_symbol_1))[0]).zxy;
+  (*(tint_symbol))[0][1] = (*(tint_symbol_1))[1][0];
+}
+
+kernel void f(const constant half4x3* tint_symbol_4 [[buffer(0)]], threadgroup tint_symbol_5* tint_symbol_3 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup half4x3* const tint_symbol_2 = &((*(tint_symbol_3)).w);
+  f_inner(local_invocation_index, tint_symbol_2, tint_symbol_4);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_workgroup.wgsl.expected.spvasm
new file mode 100644
index 0000000..b29b7c7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_workgroup.wgsl.expected.spvasm
@@ -0,0 +1,104 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 65
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %local_invocation_index_1 "local_invocation_index_1"
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpMemberName %u_block_std140 2 "inner_2"
+               OpMemberName %u_block_std140 3 "inner_3"
+               OpName %u "u"
+               OpName %w "w"
+               OpName %load_u_inner "load_u_inner"
+               OpName %f_inner "f_inner"
+               OpName %local_invocation_index "local_invocation_index"
+               OpName %f "f"
+               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 8
+               OpMemberDecorate %u_block_std140 2 Offset 16
+               OpMemberDecorate %u_block_std140 3 Offset 24
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+%u_block_std140 = OpTypeStruct %v3half %v3half %v3half %v3half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat4v3half = OpTypeMatrix %v3half 4
+%_ptr_Workgroup_mat4v3half = OpTypePointer Workgroup %mat4v3half
+          %w = OpVariable %_ptr_Workgroup_mat4v3half Workgroup
+         %12 = OpTypeFunction %mat4v3half
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %34 = OpTypeFunction %void %uint
+         %39 = OpConstantNull %mat4v3half
+   %uint_264 = OpConstant %uint 264
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Workgroup_v3half = OpTypePointer Workgroup %v3half
+         %53 = OpConstantNull %int
+%_ptr_Workgroup_half = OpTypePointer Workgroup %half
+         %56 = OpConstantNull %uint
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+         %60 = OpTypeFunction %void
+%load_u_inner = OpFunction %mat4v3half None %12
+         %14 = OpLabel
+         %19 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0
+         %20 = OpLoad %v3half %19
+         %23 = OpAccessChain %_ptr_Uniform_v3half %u %uint_1
+         %24 = OpLoad %v3half %23
+         %27 = OpAccessChain %_ptr_Uniform_v3half %u %uint_2
+         %28 = OpLoad %v3half %27
+         %31 = OpAccessChain %_ptr_Uniform_v3half %u %uint_3
+         %32 = OpLoad %v3half %31
+         %33 = OpCompositeConstruct %mat4v3half %20 %24 %28 %32
+               OpReturnValue %33
+               OpFunctionEnd
+    %f_inner = OpFunction %void None %34
+%local_invocation_index = OpFunctionParameter %uint
+         %38 = OpLabel
+               OpStore %w %39
+               OpControlBarrier %uint_2 %uint_2 %uint_264
+         %42 = OpFunctionCall %mat4v3half %load_u_inner
+               OpStore %w %42
+         %46 = OpAccessChain %_ptr_Workgroup_v3half %w %int_1
+         %47 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0
+         %48 = OpLoad %v3half %47
+               OpStore %46 %48
+         %49 = OpAccessChain %_ptr_Workgroup_v3half %w %int_1
+         %50 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0
+         %51 = OpLoad %v3half %50
+         %52 = OpVectorShuffle %v3half %51 %51 2 0 1
+               OpStore %49 %52
+         %55 = OpAccessChain %_ptr_Workgroup_half %w %53 %int_1
+         %58 = OpAccessChain %_ptr_Uniform_half %u %uint_1 %56
+         %59 = OpLoad %half %58
+               OpStore %55 %59
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %60
+         %62 = OpLabel
+         %64 = OpLoad %uint %local_invocation_index_1
+         %63 = OpFunctionCall %void %f_inner %64
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..b6d3724
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f16/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat4x3<f16>;
+
+var<workgroup> w : mat4x3<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[0];
+  w[1] = u[0].zxy;
+  w[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/dynamic_index_via_ptr.wgsl
new file mode 100644
index 0000000..c095f4c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/dynamic_index_via_ptr.wgsl
@@ -0,0 +1,13 @@
+@group(0) @binding(0) var<uniform> m : mat4x3<f32>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m   = &m;
+  let p_m_i = &((*p_m)[i()]);
+
+  let l_m   : mat4x3<f32> = *p_m;
+  let l_m_i : vec3<f32>   = *p_m_i;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..4816aa7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,26 @@
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[4];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float4x3 tint_symbol(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_m_i_save = i();
+  const float4x3 l_m = tint_symbol(m, 0u);
+  const uint scalar_offset_4 = ((16u * uint(p_m_i_save))) / 4;
+  const float3 l_m_i = asfloat(m[scalar_offset_4 / 4].xyz);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..4816aa7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,26 @@
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[4];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float4x3 tint_symbol(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_m_i_save = i();
+  const float4x3 l_m = tint_symbol(m, 0u);
+  const uint scalar_offset_4 = ((16u * uint(p_m_i_save))) / 4;
+  const float3 l_m_i = asfloat(m[scalar_offset_4 / 4].xyz);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..0c54273
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,24 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform m_block_ubo {
+  mat4x3 inner;
+} m;
+
+int counter = 0;
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+void f() {
+  int tint_symbol = i();
+  int p_m_i_save = tint_symbol;
+  mat4x3 l_m = m.inner;
+  vec3 l_m_i = m.inner[p_m_i_save];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..cb87975
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,17 @@
+#include <metal_stdlib>
+
+using namespace metal;
+int i() {
+  thread int tint_symbol_1 = 0;
+  tint_symbol_1 = as_type<int>((as_type<uint>(tint_symbol_1) + as_type<uint>(1)));
+  return tint_symbol_1;
+}
+
+kernel void f(const constant float4x3* tint_symbol_2 [[buffer(0)]]) {
+  int const tint_symbol = i();
+  int const p_m_i_save = tint_symbol;
+  float4x3 const l_m = *(tint_symbol_2);
+  float3 const l_m_i = (*(tint_symbol_2))[p_m_i_save];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..8ef501b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,57 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 31
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %m_block "m_block"
+               OpMemberName %m_block 0 "inner"
+               OpName %m "m"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %f "f"
+               OpDecorate %m_block Block
+               OpMemberDecorate %m_block 0 Offset 0
+               OpMemberDecorate %m_block 0 ColMajor
+               OpMemberDecorate %m_block 0 MatrixStride 16
+               OpDecorate %m NonWritable
+               OpDecorate %m DescriptorSet 0
+               OpDecorate %m Binding 0
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat4v3float = OpTypeMatrix %v3float 4
+    %m_block = OpTypeStruct %mat4v3float
+%_ptr_Uniform_m_block = OpTypePointer Uniform %m_block
+          %m = OpVariable %_ptr_Uniform_m_block Uniform
+        %int = OpTypeInt 32 1
+          %8 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %8
+         %11 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+       %void = OpTypeVoid
+         %18 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_mat4v3float = OpTypePointer Uniform %mat4v3float
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+          %i = OpFunction %int None %11
+         %13 = OpLabel
+         %14 = OpLoad %int %counter
+         %16 = OpIAdd %int %14 %int_1
+               OpStore %counter %16
+         %17 = OpLoad %int %counter
+               OpReturnValue %17
+               OpFunctionEnd
+          %f = OpFunction %void None %18
+         %21 = OpLabel
+         %22 = OpFunctionCall %int %i
+         %26 = OpAccessChain %_ptr_Uniform_mat4v3float %m %uint_0
+         %27 = OpLoad %mat4v3float %26
+         %29 = OpAccessChain %_ptr_Uniform_v3float %m %uint_0 %22
+         %30 = OpLoad %v3float %29
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..7704f9d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,16 @@
+@group(0) @binding(0) var<uniform> m : mat4x3<f32>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m = &(m);
+  let p_m_i = &((*(p_m))[i()]);
+  let l_m : mat4x3<f32> = *(p_m);
+  let l_m_i : vec3<f32> = *(p_m_i);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/static_index_via_ptr.wgsl
new file mode 100644
index 0000000..6b1df2a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/static_index_via_ptr.wgsl
@@ -0,0 +1,13 @@
+@group(0) @binding(0) var<uniform> m : mat4x3<f32>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m   = &m;
+  let p_m_1 = &((*p_m)[1]);
+
+  let l_m   : mat4x3<f32> = *p_m;
+  let l_m_1 : vec3<f32>   = *p_m_1;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..8492882
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,24 @@
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[4];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float4x3 tint_symbol(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float4x3 l_m = tint_symbol(m, 0u);
+  const float3 l_m_1 = asfloat(m[1].xyz);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..8492882
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,24 @@
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[4];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float4x3 tint_symbol(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float4x3 l_m = tint_symbol(m, 0u);
+  const float3 l_m_1 = asfloat(m[1].xyz);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/static_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..6ceeadc
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/static_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,16 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform m_block_ubo {
+  mat4x3 inner;
+} m;
+
+void f() {
+  mat4x3 l_m = m.inner;
+  vec3 l_m_1 = m.inner[1];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/static_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..55af02e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/static_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,15 @@
+#include <metal_stdlib>
+
+using namespace metal;
+int i() {
+  thread int tint_symbol = 0;
+  tint_symbol = as_type<int>((as_type<uint>(tint_symbol) + as_type<uint>(1)));
+  return tint_symbol;
+}
+
+kernel void f(const constant float4x3* tint_symbol_1 [[buffer(0)]]) {
+  float4x3 const l_m = *(tint_symbol_1);
+  float3 const l_m_1 = (*(tint_symbol_1))[1];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/static_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..02ab5ed
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/static_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,56 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 30
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %m_block "m_block"
+               OpMemberName %m_block 0 "inner"
+               OpName %m "m"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %f "f"
+               OpDecorate %m_block Block
+               OpMemberDecorate %m_block 0 Offset 0
+               OpMemberDecorate %m_block 0 ColMajor
+               OpMemberDecorate %m_block 0 MatrixStride 16
+               OpDecorate %m NonWritable
+               OpDecorate %m DescriptorSet 0
+               OpDecorate %m Binding 0
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat4v3float = OpTypeMatrix %v3float 4
+    %m_block = OpTypeStruct %mat4v3float
+%_ptr_Uniform_m_block = OpTypePointer Uniform %m_block
+          %m = OpVariable %_ptr_Uniform_m_block Uniform
+        %int = OpTypeInt 32 1
+          %8 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %8
+         %11 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+       %void = OpTypeVoid
+         %18 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_mat4v3float = OpTypePointer Uniform %mat4v3float
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+          %i = OpFunction %int None %11
+         %13 = OpLabel
+         %14 = OpLoad %int %counter
+         %16 = OpIAdd %int %14 %int_1
+               OpStore %counter %16
+         %17 = OpLoad %int %counter
+               OpReturnValue %17
+               OpFunctionEnd
+          %f = OpFunction %void None %18
+         %21 = OpLabel
+         %25 = OpAccessChain %_ptr_Uniform_mat4v3float %m %uint_0
+         %26 = OpLoad %mat4v3float %25
+         %28 = OpAccessChain %_ptr_Uniform_v3float %m %uint_0 %int_1
+         %29 = OpLoad %v3float %28
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/static_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..9e2d6bd
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/static_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,16 @@
+@group(0) @binding(0) var<uniform> m : mat4x3<f32>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m = &(m);
+  let p_m_1 = &((*(p_m))[1]);
+  let l_m : mat4x3<f32> = *(p_m);
+  let l_m_1 : vec3<f32> = *(p_m_1);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_builtin.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_builtin.wgsl
new file mode 100644
index 0000000..1035979
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_builtin.wgsl
@@ -0,0 +1,8 @@
+@group(0) @binding(0) var<uniform> u : mat4x3<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+    let t = transpose(u);
+    let l = length(u[1]);
+    let a = abs(u[0].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_builtin.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..9e00a15
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_builtin.wgsl.expected.dxc.hlsl
@@ -0,0 +1,19 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+
+float4x3 tint_symbol(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float3x4 t = transpose(tint_symbol(u, 0u));
+  const float l = length(asfloat(u[1].xyz));
+  const float a = abs(asfloat(u[0].xyz).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_builtin.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..9e00a15
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_builtin.wgsl.expected.fxc.hlsl
@@ -0,0 +1,19 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+
+float4x3 tint_symbol(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float3x4 t = transpose(tint_symbol(u, 0u));
+  const float l = length(asfloat(u[1].xyz));
+  const float a = abs(asfloat(u[0].xyz).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_builtin.wgsl.expected.glsl
new file mode 100644
index 0000000..ab382b6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_builtin.wgsl.expected.glsl
@@ -0,0 +1,17 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat4x3 inner;
+} u;
+
+void f() {
+  mat3x4 t = transpose(u.inner);
+  float l = length(u.inner[1]);
+  float a = abs(u.inner[0].zxy.x);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_builtin.wgsl.expected.msl
new file mode 100644
index 0000000..803b6d8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_builtin.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f(const constant float4x3* tint_symbol [[buffer(0)]]) {
+  float3x4 const t = transpose(*(tint_symbol));
+  float const l = length((*(tint_symbol))[1]);
+  float const a = fabs(float3((*(tint_symbol))[0]).zxy[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_builtin.wgsl.expected.spvasm
new file mode 100644
index 0000000..d1dc513
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_builtin.wgsl.expected.spvasm
@@ -0,0 +1,53 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 32
+; Schema: 0
+               OpCapability Shader
+         %20 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat4v3float = OpTypeMatrix %v3float 4
+    %u_block = OpTypeStruct %mat4v3float
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+          %7 = OpTypeFunction %void
+    %v4float = OpTypeVector %float 4
+%mat3v4float = OpTypeMatrix %v4float 3
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_mat4v3float = OpTypePointer Uniform %mat4v3float
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+         %27 = OpConstantNull %int
+          %f = OpFunction %void None %7
+         %10 = OpLabel
+         %17 = OpAccessChain %_ptr_Uniform_mat4v3float %u %uint_0
+         %18 = OpLoad %mat4v3float %17
+         %11 = OpTranspose %mat3v4float %18
+         %24 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %int_1
+         %25 = OpLoad %v3float %24
+         %19 = OpExtInst %float %20 Length %25
+         %28 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %27
+         %29 = OpLoad %v3float %28
+         %30 = OpVectorShuffle %v3float %29 %29 2 0 1
+         %31 = OpCompositeExtract %float %30 0
+         %26 = OpExtInst %float %20 FAbs %31
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_builtin.wgsl.expected.wgsl
new file mode 100644
index 0000000..3ff3ff4
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_builtin.wgsl.expected.wgsl
@@ -0,0 +1,8 @@
+@group(0) @binding(0) var<uniform> u : mat4x3<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let t = transpose(u);
+  let l = length(u[1]);
+  let a = abs(u[0].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_fn.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_fn.wgsl
new file mode 100644
index 0000000..58fb44b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_fn.wgsl
@@ -0,0 +1,14 @@
+@group(0) @binding(0) var<uniform> u : mat4x3<f32>;
+
+fn a(m : mat4x3<f32>) {}
+fn b(v : vec3<f32>) {}
+fn c(f : f32) {}
+
+@compute @workgroup_size(1)
+fn f() {
+    a(u);
+    b(u[1]);
+    b(u[1].zxy);
+    c(u[1].x);
+    c(u[1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_fn.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..67c4557
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_fn.wgsl.expected.dxc.hlsl
@@ -0,0 +1,30 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+
+void a(float4x3 m) {
+}
+
+void b(float3 v) {
+}
+
+void c(float f_1) {
+}
+
+float4x3 tint_symbol(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(asfloat(u[1].xyz));
+  b(asfloat(u[1].xyz).zxy);
+  c(asfloat(u[1].x));
+  c(asfloat(u[1].xyz).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_fn.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..67c4557
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_fn.wgsl.expected.fxc.hlsl
@@ -0,0 +1,30 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+
+void a(float4x3 m) {
+}
+
+void b(float3 v) {
+}
+
+void c(float f_1) {
+}
+
+float4x3 tint_symbol(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(asfloat(u[1].xyz));
+  b(asfloat(u[1].xyz).zxy);
+  c(asfloat(u[1].x));
+  c(asfloat(u[1].xyz).zxy.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_fn.wgsl.expected.glsl
new file mode 100644
index 0000000..ea4d739
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_fn.wgsl.expected.glsl
@@ -0,0 +1,28 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat4x3 inner;
+} u;
+
+void a(mat4x3 m) {
+}
+
+void b(vec3 v) {
+}
+
+void c(float f_1) {
+}
+
+void f() {
+  a(u.inner);
+  b(u.inner[1]);
+  b(u.inner[1].zxy);
+  c(u.inner[1].x);
+  c(u.inner[1].zxy.x);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_fn.wgsl.expected.msl
new file mode 100644
index 0000000..2fdb2d1
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_fn.wgsl.expected.msl
@@ -0,0 +1,21 @@
+#include <metal_stdlib>
+
+using namespace metal;
+void a(float4x3 m) {
+}
+
+void b(float3 v) {
+}
+
+void c(float f_1) {
+}
+
+kernel void f(const constant float4x3* tint_symbol [[buffer(0)]]) {
+  a(*(tint_symbol));
+  b((*(tint_symbol))[1]);
+  b(float3((*(tint_symbol))[1]).zxy);
+  c((*(tint_symbol))[1][0]);
+  c(float3((*(tint_symbol))[1]).zxy[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_fn.wgsl.expected.spvasm
new file mode 100644
index 0000000..6ae3ab6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_fn.wgsl.expected.spvasm
@@ -0,0 +1,81 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 48
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %a "a"
+               OpName %m "m"
+               OpName %b "b"
+               OpName %v "v"
+               OpName %c "c"
+               OpName %f_1 "f_1"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat4v3float = OpTypeMatrix %v3float 4
+    %u_block = OpTypeStruct %mat4v3float
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+          %7 = OpTypeFunction %void %mat4v3float
+         %12 = OpTypeFunction %void %v3float
+         %16 = OpTypeFunction %void %float
+         %20 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_mat4v3float = OpTypePointer Uniform %mat4v3float
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+          %a = OpFunction %void None %7
+          %m = OpFunctionParameter %mat4v3float
+         %11 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %b = OpFunction %void None %12
+          %v = OpFunctionParameter %v3float
+         %15 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %c = OpFunction %void None %16
+        %f_1 = OpFunctionParameter %float
+         %19 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %20
+         %22 = OpLabel
+         %27 = OpAccessChain %_ptr_Uniform_mat4v3float %u %uint_0
+         %28 = OpLoad %mat4v3float %27
+         %23 = OpFunctionCall %void %a %28
+         %33 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %int_1
+         %34 = OpLoad %v3float %33
+         %29 = OpFunctionCall %void %b %34
+         %36 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %int_1
+         %37 = OpLoad %v3float %36
+         %38 = OpVectorShuffle %v3float %37 %37 2 0 1
+         %35 = OpFunctionCall %void %b %38
+         %41 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %int_1 %uint_0
+         %42 = OpLoad %float %41
+         %39 = OpFunctionCall %void %c %42
+         %44 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %int_1
+         %45 = OpLoad %v3float %44
+         %46 = OpVectorShuffle %v3float %45 %45 2 0 1
+         %47 = OpCompositeExtract %float %46 0
+         %43 = OpFunctionCall %void %c %47
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_fn.wgsl.expected.wgsl
new file mode 100644
index 0000000..04612d2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_fn.wgsl.expected.wgsl
@@ -0,0 +1,19 @@
+@group(0) @binding(0) var<uniform> u : mat4x3<f32>;
+
+fn a(m : mat4x3<f32>) {
+}
+
+fn b(v : vec3<f32>) {
+}
+
+fn c(f : f32) {
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  a(u);
+  b(u[1]);
+  b(u[1].zxy);
+  c(u[1].x);
+  c(u[1].zxy.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_private.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_private.wgsl
new file mode 100644
index 0000000..891c736
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_private.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0) var<uniform> u : mat4x3<f32>;
+var<private> p : mat4x3<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[0];
+    p[1] = u[0].zxy;
+    p[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_private.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..e0bec97
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_private.wgsl.expected.dxc.hlsl
@@ -0,0 +1,21 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+static float4x3 p = float4x3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
+
+float4x3 tint_symbol(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = asfloat(u[0].xyz);
+  p[1] = asfloat(u[0].xyz).zxy;
+  p[0][1] = asfloat(u[1].x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_private.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..e0bec97
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_private.wgsl.expected.fxc.hlsl
@@ -0,0 +1,21 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+static float4x3 p = float4x3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
+
+float4x3 tint_symbol(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = asfloat(u[0].xyz);
+  p[1] = asfloat(u[0].xyz).zxy;
+  p[0][1] = asfloat(u[1].x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..2a37a32
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_private.wgsl.expected.glsl
@@ -0,0 +1,19 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat4x3 inner;
+} u;
+
+mat4x3 p = mat4x3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
+void f() {
+  p = u.inner;
+  p[1] = u.inner[0];
+  p[1] = u.inner[0].zxy;
+  p[0][1] = u.inner[1][0];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..904c327
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_private.wgsl.expected.msl
@@ -0,0 +1,12 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f(const constant float4x3* tint_symbol_1 [[buffer(0)]]) {
+  thread float4x3 tint_symbol = float4x3(0.0f);
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[0];
+  tint_symbol[1] = float3((*(tint_symbol_1))[0]).zxy;
+  tint_symbol[0][1] = (*(tint_symbol_1))[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_private.wgsl.expected.spvasm
new file mode 100644
index 0000000..e7b0c0b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_private.wgsl.expected.spvasm
@@ -0,0 +1,62 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 36
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %p "p"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat4v3float = OpTypeMatrix %v3float 4
+    %u_block = OpTypeStruct %mat4v3float
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_Private_mat4v3float = OpTypePointer Private %mat4v3float
+          %9 = OpConstantNull %mat4v3float
+          %p = OpVariable %_ptr_Private_mat4v3float Private %9
+       %void = OpTypeVoid
+         %10 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_mat4v3float = OpTypePointer Uniform %mat4v3float
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Private_v3float = OpTypePointer Private %v3float
+         %23 = OpConstantNull %int
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+%_ptr_Private_float = OpTypePointer Private %float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+          %f = OpFunction %void None %10
+         %13 = OpLabel
+         %17 = OpAccessChain %_ptr_Uniform_mat4v3float %u %uint_0
+         %18 = OpLoad %mat4v3float %17
+               OpStore %p %18
+         %22 = OpAccessChain %_ptr_Private_v3float %p %int_1
+         %25 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %23
+         %26 = OpLoad %v3float %25
+               OpStore %22 %26
+         %27 = OpAccessChain %_ptr_Private_v3float %p %int_1
+         %28 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %23
+         %29 = OpLoad %v3float %28
+         %30 = OpVectorShuffle %v3float %29 %29 2 0 1
+               OpStore %27 %30
+         %32 = OpAccessChain %_ptr_Private_float %p %23 %int_1
+         %34 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %int_1 %23
+         %35 = OpLoad %float %34
+               OpStore %32 %35
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..7eebf15
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_private.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> u : mat4x3<f32>;
+
+var<private> p : mat4x3<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[0];
+  p[1] = u[0].zxy;
+  p[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_storage.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_storage.wgsl
new file mode 100644
index 0000000..64ba3f2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_storage.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0) var<uniform> u : mat4x3<f32>;
+@group(0) @binding(1) var<storage, read_write> s : mat4x3<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[0];
+    s[1] = u[0].zxy;
+    s[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_storage.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..372d7c0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_storage.wgsl.expected.dxc.hlsl
@@ -0,0 +1,28 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, float4x3 value) {
+  buffer.Store3((offset + 0u), asuint(value[0u]));
+  buffer.Store3((offset + 16u), asuint(value[1u]));
+  buffer.Store3((offset + 32u), asuint(value[2u]));
+  buffer.Store3((offset + 48u), asuint(value[3u]));
+}
+
+float4x3 tint_symbol_2(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_2(u, 0u));
+  s.Store3(16u, asuint(asfloat(u[0].xyz)));
+  s.Store3(16u, asuint(asfloat(u[0].xyz).zxy));
+  s.Store(4u, asuint(asfloat(u[1].x)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_storage.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..372d7c0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_storage.wgsl.expected.fxc.hlsl
@@ -0,0 +1,28 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, float4x3 value) {
+  buffer.Store3((offset + 0u), asuint(value[0u]));
+  buffer.Store3((offset + 16u), asuint(value[1u]));
+  buffer.Store3((offset + 32u), asuint(value[2u]));
+  buffer.Store3((offset + 48u), asuint(value[3u]));
+}
+
+float4x3 tint_symbol_2(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_2(u, 0u));
+  s.Store3(16u, asuint(asfloat(u[0].xyz)));
+  s.Store3(16u, asuint(asfloat(u[0].xyz).zxy));
+  s.Store(4u, asuint(asfloat(u[1].x)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..8a91538
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_storage.wgsl.expected.glsl
@@ -0,0 +1,22 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat4x3 inner;
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  mat4x3 inner;
+} s;
+
+void f() {
+  s.inner = u.inner;
+  s.inner[1] = u.inner[0];
+  s.inner[1] = u.inner[0].zxy;
+  s.inner[0][1] = u.inner[1][0];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..b3dcd87
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_storage.wgsl.expected.msl
@@ -0,0 +1,11 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f(device float4x3* tint_symbol [[buffer(1)]], const constant float4x3* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[0];
+  (*(tint_symbol))[1] = float3((*(tint_symbol_1))[0]).zxy;
+  (*(tint_symbol))[0][1] = (*(tint_symbol_1))[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_storage.wgsl.expected.spvasm
new file mode 100644
index 0000000..c6b01ce
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_storage.wgsl.expected.spvasm
@@ -0,0 +1,65 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 37
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %s "s"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %s DescriptorSet 0
+               OpDecorate %s Binding 1
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat4v3float = OpTypeMatrix %v3float 4
+    %u_block = OpTypeStruct %mat4v3float
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
+          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+       %void = OpTypeVoid
+          %9 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_mat4v3float = OpTypePointer StorageBuffer %mat4v3float
+%_ptr_Uniform_mat4v3float = OpTypePointer Uniform %mat4v3float
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_v3float = OpTypePointer StorageBuffer %v3float
+         %24 = OpConstantNull %int
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+          %f = OpFunction %void None %9
+         %12 = OpLabel
+         %16 = OpAccessChain %_ptr_StorageBuffer_mat4v3float %s %uint_0
+         %18 = OpAccessChain %_ptr_Uniform_mat4v3float %u %uint_0
+         %19 = OpLoad %mat4v3float %18
+               OpStore %16 %19
+         %23 = OpAccessChain %_ptr_StorageBuffer_v3float %s %uint_0 %int_1
+         %26 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %24
+         %27 = OpLoad %v3float %26
+               OpStore %23 %27
+         %28 = OpAccessChain %_ptr_StorageBuffer_v3float %s %uint_0 %int_1
+         %29 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %24
+         %30 = OpLoad %v3float %29
+         %31 = OpVectorShuffle %v3float %30 %30 2 0 1
+               OpStore %28 %31
+         %33 = OpAccessChain %_ptr_StorageBuffer_float %s %uint_0 %24 %int_1
+         %35 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %int_1 %24
+         %36 = OpLoad %float %35
+               OpStore %33 %36
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..73926e8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> u : mat4x3<f32>;
+
+@group(0) @binding(1) var<storage, read_write> s : mat4x3<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[0];
+  s[1] = u[0].zxy;
+  s[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_workgroup.wgsl
new file mode 100644
index 0000000..b5e5b2f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_workgroup.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0) var<uniform> u : mat4x3<f32>;
+var<workgroup> w : mat4x3<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[0];
+    w[1] = u[0].zxy;
+    w[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_workgroup.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..fab699a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_workgroup.wgsl.expected.dxc.hlsl
@@ -0,0 +1,33 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+groupshared float4x3 w;
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+float4x3 tint_symbol_2(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    w = float4x3((0.0f).xxx, (0.0f).xxx, (0.0f).xxx, (0.0f).xxx);
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = asfloat(u[0].xyz);
+  w[1] = asfloat(u[0].xyz).zxy;
+  w[0][1] = asfloat(u[1].x);
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_workgroup.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..fab699a
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_workgroup.wgsl.expected.fxc.hlsl
@@ -0,0 +1,33 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+groupshared float4x3 w;
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+float4x3 tint_symbol_2(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    w = float4x3((0.0f).xxx, (0.0f).xxx, (0.0f).xxx, (0.0f).xxx);
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = asfloat(u[0].xyz);
+  w[1] = asfloat(u[0].xyz).zxy;
+  w[0][1] = asfloat(u[1].x);
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..d75121b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,23 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat4x3 inner;
+} u;
+
+shared mat4x3 w;
+void f(uint local_invocation_index) {
+  {
+    w = mat4x3(vec3(0.0f), vec3(0.0f), vec3(0.0f), vec3(0.0f));
+  }
+  barrier();
+  w = u.inner;
+  w[1] = u.inner[0];
+  w[1] = u.inner[0].zxy;
+  w[0][1] = u.inner[1][0];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..ffc9775
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,24 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct tint_symbol_5 {
+  float4x3 w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup float4x3* const tint_symbol, const constant float4x3* const tint_symbol_1) {
+  {
+    *(tint_symbol) = float4x3(float3(0.0f), float3(0.0f), float3(0.0f), float3(0.0f));
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[0];
+  (*(tint_symbol))[1] = float3((*(tint_symbol_1))[0]).zxy;
+  (*(tint_symbol))[0][1] = (*(tint_symbol_1))[1][0];
+}
+
+kernel void f(const constant float4x3* tint_symbol_4 [[buffer(0)]], threadgroup tint_symbol_5* tint_symbol_3 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup float4x3* const tint_symbol_2 = &((*(tint_symbol_3)).w);
+  f_inner(local_invocation_index, tint_symbol_2, tint_symbol_4);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_workgroup.wgsl.expected.spvasm
new file mode 100644
index 0000000..1f5e90b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_workgroup.wgsl.expected.spvasm
@@ -0,0 +1,80 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 47
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %local_invocation_index_1 "local_invocation_index_1"
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %w "w"
+               OpName %f_inner "f_inner"
+               OpName %local_invocation_index "local_invocation_index"
+               OpName %f "f"
+               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat4v3float = OpTypeMatrix %v3float 4
+    %u_block = OpTypeStruct %mat4v3float
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_Workgroup_mat4v3float = OpTypePointer Workgroup %mat4v3float
+          %w = OpVariable %_ptr_Workgroup_mat4v3float Workgroup
+       %void = OpTypeVoid
+         %12 = OpTypeFunction %void %uint
+         %17 = OpConstantNull %mat4v3float
+     %uint_2 = OpConstant %uint 2
+   %uint_264 = OpConstant %uint 264
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_mat4v3float = OpTypePointer Uniform %mat4v3float
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Workgroup_v3float = OpTypePointer Workgroup %v3float
+         %29 = OpConstantNull %int
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+%_ptr_Workgroup_float = OpTypePointer Workgroup %float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+         %42 = OpTypeFunction %void
+    %f_inner = OpFunction %void None %12
+%local_invocation_index = OpFunctionParameter %uint
+         %16 = OpLabel
+               OpStore %w %17
+               OpControlBarrier %uint_2 %uint_2 %uint_264
+         %23 = OpAccessChain %_ptr_Uniform_mat4v3float %u %uint_0
+         %24 = OpLoad %mat4v3float %23
+               OpStore %w %24
+         %28 = OpAccessChain %_ptr_Workgroup_v3float %w %int_1
+         %31 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %29
+         %32 = OpLoad %v3float %31
+               OpStore %28 %32
+         %33 = OpAccessChain %_ptr_Workgroup_v3float %w %int_1
+         %34 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0 %29
+         %35 = OpLoad %v3float %34
+         %36 = OpVectorShuffle %v3float %35 %35 2 0 1
+               OpStore %33 %36
+         %38 = OpAccessChain %_ptr_Workgroup_float %w %29 %int_1
+         %40 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %int_1 %29
+         %41 = OpLoad %float %40
+               OpStore %38 %41
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %42
+         %44 = OpLabel
+         %46 = OpLoad %uint %local_invocation_index_1
+         %45 = OpFunctionCall %void %f_inner %46
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..7099022
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x3_f32/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> u : mat4x3<f32>;
+
+var<workgroup> w : mat4x3<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[0];
+  w[1] = u[0].zxy;
+  w[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/dynamic_index_via_ptr.wgsl
new file mode 100644
index 0000000..21e943d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/dynamic_index_via_ptr.wgsl
@@ -0,0 +1,15 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> m : mat4x4<f16>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m   = &m;
+  let p_m_i = &((*p_m)[i()]);
+
+  let l_m   : mat4x4<f16> = *p_m;
+  let l_m_i : vec4<f16>   = *p_m_i;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..16e4c4f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,46 @@
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[2];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 4, 4> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_m_i_save = i();
+  const matrix<float16_t, 4, 4> l_m = tint_symbol(m, 0u);
+  const uint scalar_offset_4 = ((8u * uint(p_m_i_save))) / 4;
+  uint4 ubo_load_9 = m[scalar_offset_4 / 4];
+  uint2 ubo_load_8 = ((scalar_offset_4 & 2) ? ubo_load_9.zw : ubo_load_9.xy);
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_8_yw = vector<float16_t, 2>(f16tof32(ubo_load_8 >> 16));
+  const vector<float16_t, 4> l_m_i = vector<float16_t, 4>(ubo_load_8_xz[0], ubo_load_8_yw[0], ubo_load_8_xz[1], ubo_load_8_yw[1]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..a85dc45
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,51 @@
+SKIP: FAILED
+
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[2];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 4, 4> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_m_i_save = i();
+  const matrix<float16_t, 4, 4> l_m = tint_symbol(m, 0u);
+  const uint scalar_offset_4 = ((8u * uint(p_m_i_save))) / 4;
+  uint4 ubo_load_9 = m[scalar_offset_4 / 4];
+  uint2 ubo_load_8 = ((scalar_offset_4 & 2) ? ubo_load_9.zw : ubo_load_9.xy);
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_8_yw = vector<float16_t, 2>(f16tof32(ubo_load_8 >> 16));
+  const vector<float16_t, 4> l_m_i = vector<float16_t, 4>(ubo_load_8_xz[0], ubo_load_8_yw[0], ubo_load_8_xz[1], ubo_load_8_yw[1]);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000021737B8AE70(11,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..fd478c5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,58 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform m_block_std140_ubo {
+  f16vec4 inner_0;
+  f16vec4 inner_1;
+  f16vec4 inner_2;
+  f16vec4 inner_3;
+} m;
+
+int counter = 0;
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+f16mat4 load_m_inner() {
+  return f16mat4(m.inner_0, m.inner_1, m.inner_2, m.inner_3);
+}
+
+f16vec4 load_m_inner_p0(uint p0) {
+  switch(p0) {
+    case 0u: {
+      return m.inner_0;
+      break;
+    }
+    case 1u: {
+      return m.inner_1;
+      break;
+    }
+    case 2u: {
+      return m.inner_2;
+      break;
+    }
+    case 3u: {
+      return m.inner_3;
+      break;
+    }
+    default: {
+      return f16vec4(0.0hf);
+      break;
+    }
+  }
+}
+
+void f() {
+  f16mat4 p_m = load_m_inner();
+  int tint_symbol = i();
+  f16vec4 p_m_i = load_m_inner_p0(uint(tint_symbol));
+  f16mat4 l_m = load_m_inner();
+  f16vec4 l_m_i = load_m_inner_p0(uint(tint_symbol));
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..f8948a7
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,17 @@
+#include <metal_stdlib>
+
+using namespace metal;
+int i() {
+  thread int tint_symbol_1 = 0;
+  tint_symbol_1 = as_type<int>((as_type<uint>(tint_symbol_1) + as_type<uint>(1)));
+  return tint_symbol_1;
+}
+
+kernel void f(const constant half4x4* tint_symbol_2 [[buffer(0)]]) {
+  int const tint_symbol = i();
+  int const p_m_i_save = tint_symbol;
+  half4x4 const l_m = *(tint_symbol_2);
+  half4 const l_m_i = (*(tint_symbol_2))[p_m_i_save];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..6e3ae0b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,111 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 68
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %m_block_std140 "m_block_std140"
+               OpMemberName %m_block_std140 0 "inner_0"
+               OpMemberName %m_block_std140 1 "inner_1"
+               OpMemberName %m_block_std140 2 "inner_2"
+               OpMemberName %m_block_std140 3 "inner_3"
+               OpName %m "m"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %load_m_inner "load_m_inner"
+               OpName %load_m_inner_p0 "load_m_inner_p0"
+               OpName %p0 "p0"
+               OpName %f "f"
+               OpDecorate %m_block_std140 Block
+               OpMemberDecorate %m_block_std140 0 Offset 0
+               OpMemberDecorate %m_block_std140 1 Offset 8
+               OpMemberDecorate %m_block_std140 2 Offset 16
+               OpMemberDecorate %m_block_std140 3 Offset 24
+               OpDecorate %m NonWritable
+               OpDecorate %m DescriptorSet 0
+               OpDecorate %m Binding 0
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+%m_block_std140 = OpTypeStruct %v4half %v4half %v4half %v4half
+%_ptr_Uniform_m_block_std140 = OpTypePointer Uniform %m_block_std140
+          %m = OpVariable %_ptr_Uniform_m_block_std140 Uniform
+        %int = OpTypeInt 32 1
+          %7 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %7
+         %10 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+ %mat4v4half = OpTypeMatrix %v4half 4
+         %17 = OpTypeFunction %mat4v4half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+         %41 = OpTypeFunction %v4half %uint
+         %59 = OpConstantNull %v4half
+       %void = OpTypeVoid
+         %60 = OpTypeFunction %void
+          %i = OpFunction %int None %10
+         %12 = OpLabel
+         %13 = OpLoad %int %counter
+         %15 = OpIAdd %int %13 %int_1
+               OpStore %counter %15
+         %16 = OpLoad %int %counter
+               OpReturnValue %16
+               OpFunctionEnd
+%load_m_inner = OpFunction %mat4v4half None %17
+         %20 = OpLabel
+         %26 = OpAccessChain %_ptr_Uniform_v4half %m %uint_0
+         %27 = OpLoad %v4half %26
+         %30 = OpAccessChain %_ptr_Uniform_v4half %m %uint_1
+         %31 = OpLoad %v4half %30
+         %34 = OpAccessChain %_ptr_Uniform_v4half %m %uint_2
+         %35 = OpLoad %v4half %34
+         %38 = OpAccessChain %_ptr_Uniform_v4half %m %uint_3
+         %39 = OpLoad %v4half %38
+         %40 = OpCompositeConstruct %mat4v4half %27 %31 %35 %39
+               OpReturnValue %40
+               OpFunctionEnd
+%load_m_inner_p0 = OpFunction %v4half None %41
+         %p0 = OpFunctionParameter %uint
+         %44 = OpLabel
+               OpSelectionMerge %45 None
+               OpSwitch %p0 %46 0 %47 1 %48 2 %49 3 %50
+         %47 = OpLabel
+         %51 = OpAccessChain %_ptr_Uniform_v4half %m %uint_0
+         %52 = OpLoad %v4half %51
+               OpReturnValue %52
+         %48 = OpLabel
+         %53 = OpAccessChain %_ptr_Uniform_v4half %m %uint_1
+         %54 = OpLoad %v4half %53
+               OpReturnValue %54
+         %49 = OpLabel
+         %55 = OpAccessChain %_ptr_Uniform_v4half %m %uint_2
+         %56 = OpLoad %v4half %55
+               OpReturnValue %56
+         %50 = OpLabel
+         %57 = OpAccessChain %_ptr_Uniform_v4half %m %uint_3
+         %58 = OpLoad %v4half %57
+               OpReturnValue %58
+         %46 = OpLabel
+               OpReturnValue %59
+         %45 = OpLabel
+               OpReturnValue %59
+               OpFunctionEnd
+          %f = OpFunction %void None %60
+         %63 = OpLabel
+         %64 = OpFunctionCall %int %i
+         %65 = OpFunctionCall %mat4v4half %load_m_inner
+         %67 = OpBitcast %uint %64
+         %66 = OpFunctionCall %v4half %load_m_inner_p0 %67
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..0362728
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/dynamic_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> m : mat4x4<f16>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m = &(m);
+  let p_m_i = &((*(p_m))[i()]);
+  let l_m : mat4x4<f16> = *(p_m);
+  let l_m_i : vec4<f16> = *(p_m_i);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/static_index_via_ptr.wgsl
new file mode 100644
index 0000000..a78172e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/static_index_via_ptr.wgsl
@@ -0,0 +1,15 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> m : mat4x4<f16>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m   = &m;
+  let p_m_1 = &((*p_m)[1]);
+
+  let l_m   : mat4x4<f16> = *p_m;
+  let l_m_1 : vec4<f16>   = *p_m_1;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..a841311
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/static_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,43 @@
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[2];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 4, 4> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 4, 4> l_m = tint_symbol(m, 0u);
+  uint2 ubo_load_8 = m[0].zw;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_8_yw = vector<float16_t, 2>(f16tof32(ubo_load_8 >> 16));
+  const vector<float16_t, 4> l_m_1 = vector<float16_t, 4>(ubo_load_8_xz[0], ubo_load_8_yw[0], ubo_load_8_xz[1], ubo_load_8_yw[1]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..6d03956
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/static_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,48 @@
+SKIP: FAILED
+
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[2];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+matrix<float16_t, 4, 4> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 4, 4> l_m = tint_symbol(m, 0u);
+  uint2 ubo_load_8 = m[0].zw;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_8_yw = vector<float16_t, 2>(f16tof32(ubo_load_8 >> 16));
+  const vector<float16_t, 4> l_m_1 = vector<float16_t, 4>(ubo_load_8_xz[0], ubo_load_8_yw[0], ubo_load_8_xz[1], ubo_load_8_yw[1]);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000002055528A940(11,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/static_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..4175a0d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/static_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,26 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform m_block_std140_ubo {
+  f16vec4 inner_0;
+  f16vec4 inner_1;
+  f16vec4 inner_2;
+  f16vec4 inner_3;
+} m;
+
+f16mat4 load_m_inner() {
+  return f16mat4(m.inner_0, m.inner_1, m.inner_2, m.inner_3);
+}
+
+void f() {
+  f16mat4 p_m = load_m_inner();
+  f16vec4 p_m_1 = m.inner_1;
+  f16mat4 l_m = load_m_inner();
+  f16vec4 l_m_1 = m.inner_1;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/static_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..6e62a9c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/static_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,15 @@
+#include <metal_stdlib>
+
+using namespace metal;
+int i() {
+  thread int tint_symbol = 0;
+  tint_symbol = as_type<int>((as_type<uint>(tint_symbol) + as_type<uint>(1)));
+  return tint_symbol;
+}
+
+kernel void f(const constant half4x4* tint_symbol_1 [[buffer(0)]]) {
+  half4x4 const l_m = *(tint_symbol_1);
+  half4 const l_m_1 = (*(tint_symbol_1))[1];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/static_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..1c9316c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/static_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,80 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 48
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %m_block_std140 "m_block_std140"
+               OpMemberName %m_block_std140 0 "inner_0"
+               OpMemberName %m_block_std140 1 "inner_1"
+               OpMemberName %m_block_std140 2 "inner_2"
+               OpMemberName %m_block_std140 3 "inner_3"
+               OpName %m "m"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %load_m_inner "load_m_inner"
+               OpName %f "f"
+               OpDecorate %m_block_std140 Block
+               OpMemberDecorate %m_block_std140 0 Offset 0
+               OpMemberDecorate %m_block_std140 1 Offset 8
+               OpMemberDecorate %m_block_std140 2 Offset 16
+               OpMemberDecorate %m_block_std140 3 Offset 24
+               OpDecorate %m NonWritable
+               OpDecorate %m DescriptorSet 0
+               OpDecorate %m Binding 0
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+%m_block_std140 = OpTypeStruct %v4half %v4half %v4half %v4half
+%_ptr_Uniform_m_block_std140 = OpTypePointer Uniform %m_block_std140
+          %m = OpVariable %_ptr_Uniform_m_block_std140 Uniform
+        %int = OpTypeInt 32 1
+          %7 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %7
+         %10 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+ %mat4v4half = OpTypeMatrix %v4half 4
+         %17 = OpTypeFunction %mat4v4half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %41 = OpTypeFunction %void
+          %i = OpFunction %int None %10
+         %12 = OpLabel
+         %13 = OpLoad %int %counter
+         %15 = OpIAdd %int %13 %int_1
+               OpStore %counter %15
+         %16 = OpLoad %int %counter
+               OpReturnValue %16
+               OpFunctionEnd
+%load_m_inner = OpFunction %mat4v4half None %17
+         %20 = OpLabel
+         %26 = OpAccessChain %_ptr_Uniform_v4half %m %uint_0
+         %27 = OpLoad %v4half %26
+         %30 = OpAccessChain %_ptr_Uniform_v4half %m %uint_1
+         %31 = OpLoad %v4half %30
+         %34 = OpAccessChain %_ptr_Uniform_v4half %m %uint_2
+         %35 = OpLoad %v4half %34
+         %38 = OpAccessChain %_ptr_Uniform_v4half %m %uint_3
+         %39 = OpLoad %v4half %38
+         %40 = OpCompositeConstruct %mat4v4half %27 %31 %35 %39
+               OpReturnValue %40
+               OpFunctionEnd
+          %f = OpFunction %void None %41
+         %44 = OpLabel
+         %45 = OpFunctionCall %mat4v4half %load_m_inner
+         %46 = OpAccessChain %_ptr_Uniform_v4half %m %uint_1
+         %47 = OpLoad %v4half %46
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/static_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..5ee7934
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/static_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> m : mat4x4<f16>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m = &(m);
+  let p_m_1 = &((*(p_m))[1]);
+  let l_m : mat4x4<f16> = *(p_m);
+  let l_m_1 : vec4<f16> = *(p_m_1);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_builtin.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_builtin.wgsl
new file mode 100644
index 0000000..2cd0d33
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_builtin.wgsl
@@ -0,0 +1,10 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat4x4<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+    let t = transpose(u);
+    let l = length(u[1]);
+    let a = abs(u[0].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_builtin.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..cd3f135
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_builtin.wgsl.expected.dxc.hlsl
@@ -0,0 +1,41 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+
+matrix<float16_t, 4, 4> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 4, 4> t = transpose(tint_symbol(u, 0u));
+  uint2 ubo_load_8 = u[0].zw;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_8_yw = vector<float16_t, 2>(f16tof32(ubo_load_8 >> 16));
+  const float16_t l = length(vector<float16_t, 4>(ubo_load_8_xz[0], ubo_load_8_yw[0], ubo_load_8_xz[1], ubo_load_8_yw[1]));
+  uint2 ubo_load_9 = u[0].xy;
+  vector<float16_t, 2> ubo_load_9_xz = vector<float16_t, 2>(f16tof32(ubo_load_9 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_9_yw = vector<float16_t, 2>(f16tof32(ubo_load_9 >> 16));
+  const float16_t a = abs(vector<float16_t, 4>(ubo_load_9_xz[0], ubo_load_9_yw[0], ubo_load_9_xz[1], ubo_load_9_yw[1]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_builtin.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..cb0cc66
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_builtin.wgsl.expected.fxc.hlsl
@@ -0,0 +1,46 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+
+matrix<float16_t, 4, 4> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const matrix<float16_t, 4, 4> t = transpose(tint_symbol(u, 0u));
+  uint2 ubo_load_8 = u[0].zw;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_8_yw = vector<float16_t, 2>(f16tof32(ubo_load_8 >> 16));
+  const float16_t l = length(vector<float16_t, 4>(ubo_load_8_xz[0], ubo_load_8_yw[0], ubo_load_8_xz[1], ubo_load_8_yw[1]));
+  uint2 ubo_load_9 = u[0].xy;
+  vector<float16_t, 2> ubo_load_9_xz = vector<float16_t, 2>(f16tof32(ubo_load_9 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_9_yw = vector<float16_t, 2>(f16tof32(ubo_load_9 >> 16));
+  const float16_t a = abs(vector<float16_t, 4>(ubo_load_9_xz[0], ubo_load_9_yw[0], ubo_load_9_xz[1], ubo_load_9_yw[1]).ywxz.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000023EC1BAE110(5,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_builtin.wgsl.expected.glsl
new file mode 100644
index 0000000..bdf7c59
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_builtin.wgsl.expected.glsl
@@ -0,0 +1,25 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec4 inner_0;
+  f16vec4 inner_1;
+  f16vec4 inner_2;
+  f16vec4 inner_3;
+} u;
+
+f16mat4 load_u_inner() {
+  return f16mat4(u.inner_0, u.inner_1, u.inner_2, u.inner_3);
+}
+
+void f() {
+  f16mat4 t = transpose(load_u_inner());
+  float16_t l = length(u.inner_1);
+  float16_t a = abs(u.inner_0.ywxz[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_builtin.wgsl.expected.msl
new file mode 100644
index 0000000..f05f8a0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_builtin.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f(const constant half4x4* tint_symbol [[buffer(0)]]) {
+  half4x4 const t = transpose(*(tint_symbol));
+  half const l = length((*(tint_symbol))[1]);
+  half const a = fabs(half4((*(tint_symbol))[0]).ywxz[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_builtin.wgsl.expected.spvasm
new file mode 100644
index 0000000..8175c9c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_builtin.wgsl.expected.spvasm
@@ -0,0 +1,73 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 46
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+         %37 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpMemberName %u_block_std140 2 "inner_2"
+               OpMemberName %u_block_std140 3 "inner_3"
+               OpName %u "u"
+               OpName %load_u_inner "load_u_inner"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 8
+               OpMemberDecorate %u_block_std140 2 Offset 16
+               OpMemberDecorate %u_block_std140 3 Offset 24
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+%u_block_std140 = OpTypeStruct %v4half %v4half %v4half %v4half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat4v4half = OpTypeMatrix %v4half 4
+          %6 = OpTypeFunction %mat4v4half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %30 = OpTypeFunction %void
+         %44 = OpConstantNull %uint
+%load_u_inner = OpFunction %mat4v4half None %6
+          %9 = OpLabel
+         %15 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0
+         %16 = OpLoad %v4half %15
+         %19 = OpAccessChain %_ptr_Uniform_v4half %u %uint_1
+         %20 = OpLoad %v4half %19
+         %23 = OpAccessChain %_ptr_Uniform_v4half %u %uint_2
+         %24 = OpLoad %v4half %23
+         %27 = OpAccessChain %_ptr_Uniform_v4half %u %uint_3
+         %28 = OpLoad %v4half %27
+         %29 = OpCompositeConstruct %mat4v4half %16 %20 %24 %28
+               OpReturnValue %29
+               OpFunctionEnd
+          %f = OpFunction %void None %30
+         %33 = OpLabel
+         %35 = OpFunctionCall %mat4v4half %load_u_inner
+         %34 = OpTranspose %mat4v4half %35
+         %38 = OpAccessChain %_ptr_Uniform_v4half %u %uint_1
+         %39 = OpLoad %v4half %38
+         %36 = OpExtInst %half %37 Length %39
+         %41 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0
+         %42 = OpLoad %v4half %41
+         %43 = OpVectorShuffle %v4half %42 %42 1 3 0 2
+         %45 = OpCompositeExtract %half %43 0
+         %40 = OpExtInst %half %37 FAbs %45
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_builtin.wgsl.expected.wgsl
new file mode 100644
index 0000000..aafbef5
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_builtin.wgsl.expected.wgsl
@@ -0,0 +1,10 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat4x4<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let t = transpose(u);
+  let l = length(u[1]);
+  let a = abs(u[0].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_fn.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_fn.wgsl
new file mode 100644
index 0000000..47a7a69
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_fn.wgsl
@@ -0,0 +1,16 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat4x4<f16>;
+
+fn a(m : mat4x4<f16>) {}
+fn b(v : vec4<f16>) {}
+fn c(f : f16) {}
+
+@compute @workgroup_size(1)
+fn f() {
+    a(u);
+    b(u[1]);
+    b(u[1].ywxz);
+    c(u[1].x);
+    c(u[1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_fn.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..01d30aef
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_fn.wgsl.expected.dxc.hlsl
@@ -0,0 +1,55 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+
+void a(matrix<float16_t, 4, 4> m) {
+}
+
+void b(vector<float16_t, 4> v) {
+}
+
+void c(float16_t f_1) {
+}
+
+matrix<float16_t, 4, 4> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  uint2 ubo_load_8 = u[0].zw;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_8_yw = vector<float16_t, 2>(f16tof32(ubo_load_8 >> 16));
+  b(vector<float16_t, 4>(ubo_load_8_xz[0], ubo_load_8_yw[0], ubo_load_8_xz[1], ubo_load_8_yw[1]));
+  uint2 ubo_load_9 = u[0].zw;
+  vector<float16_t, 2> ubo_load_9_xz = vector<float16_t, 2>(f16tof32(ubo_load_9 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_9_yw = vector<float16_t, 2>(f16tof32(ubo_load_9 >> 16));
+  b(vector<float16_t, 4>(ubo_load_9_xz[0], ubo_load_9_yw[0], ubo_load_9_xz[1], ubo_load_9_yw[1]).ywxz);
+  c(float16_t(f16tof32(((u[0].z) & 0xFFFF))));
+  uint2 ubo_load_10 = u[0].zw;
+  vector<float16_t, 2> ubo_load_10_xz = vector<float16_t, 2>(f16tof32(ubo_load_10 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_10_yw = vector<float16_t, 2>(f16tof32(ubo_load_10 >> 16));
+  c(vector<float16_t, 4>(ubo_load_10_xz[0], ubo_load_10_yw[0], ubo_load_10_xz[1], ubo_load_10_yw[1]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_fn.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..212ddb2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_fn.wgsl.expected.fxc.hlsl
@@ -0,0 +1,62 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+
+void a(matrix<float16_t, 4, 4> m) {
+}
+
+void b(vector<float16_t, 4> v) {
+}
+
+void c(float16_t f_1) {
+}
+
+matrix<float16_t, 4, 4> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  uint2 ubo_load_8 = u[0].zw;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_8_yw = vector<float16_t, 2>(f16tof32(ubo_load_8 >> 16));
+  b(vector<float16_t, 4>(ubo_load_8_xz[0], ubo_load_8_yw[0], ubo_load_8_xz[1], ubo_load_8_yw[1]));
+  uint2 ubo_load_9 = u[0].zw;
+  vector<float16_t, 2> ubo_load_9_xz = vector<float16_t, 2>(f16tof32(ubo_load_9 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_9_yw = vector<float16_t, 2>(f16tof32(ubo_load_9 >> 16));
+  b(vector<float16_t, 4>(ubo_load_9_xz[0], ubo_load_9_yw[0], ubo_load_9_xz[1], ubo_load_9_yw[1]).ywxz);
+  c(float16_t(f16tof32(((u[0].z) & 0xFFFF))));
+  uint2 ubo_load_10 = u[0].zw;
+  vector<float16_t, 2> ubo_load_10_xz = vector<float16_t, 2>(f16tof32(ubo_load_10 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_10_yw = vector<float16_t, 2>(f16tof32(ubo_load_10 >> 16));
+  c(vector<float16_t, 4>(ubo_load_10_xz[0], ubo_load_10_yw[0], ubo_load_10_xz[1], ubo_load_10_yw[1]).ywxz.x);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001E1E337D1E0(5,15-23): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001E1E337D1E0(8,15-23): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001E1E337D1E0(11,8-16): error X3000: unrecognized identifier 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_fn.wgsl.expected.glsl
new file mode 100644
index 0000000..113ee01
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_fn.wgsl.expected.glsl
@@ -0,0 +1,36 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec4 inner_0;
+  f16vec4 inner_1;
+  f16vec4 inner_2;
+  f16vec4 inner_3;
+} u;
+
+void a(f16mat4 m) {
+}
+
+void b(f16vec4 v) {
+}
+
+void c(float16_t f_1) {
+}
+
+f16mat4 load_u_inner() {
+  return f16mat4(u.inner_0, u.inner_1, u.inner_2, u.inner_3);
+}
+
+void f() {
+  a(load_u_inner());
+  b(u.inner_1);
+  b(u.inner_1.ywxz);
+  c(u.inner_1[0u]);
+  c(u.inner_1.ywxz[0u]);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_fn.wgsl.expected.msl
new file mode 100644
index 0000000..d2d7153
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_fn.wgsl.expected.msl
@@ -0,0 +1,21 @@
+#include <metal_stdlib>
+
+using namespace metal;
+void a(half4x4 m) {
+}
+
+void b(half4 v) {
+}
+
+void c(half f_1) {
+}
+
+kernel void f(const constant half4x4* tint_symbol [[buffer(0)]]) {
+  a(*(tint_symbol));
+  b((*(tint_symbol))[1]);
+  b(half4((*(tint_symbol))[1]).ywxz);
+  c((*(tint_symbol))[1][0]);
+  c(half4((*(tint_symbol))[1]).ywxz[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_fn.wgsl.expected.spvasm
new file mode 100644
index 0000000..34680c6
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_fn.wgsl.expected.spvasm
@@ -0,0 +1,104 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 65
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpMemberName %u_block_std140 2 "inner_2"
+               OpMemberName %u_block_std140 3 "inner_3"
+               OpName %u "u"
+               OpName %a "a"
+               OpName %m "m"
+               OpName %b "b"
+               OpName %v "v"
+               OpName %c "c"
+               OpName %f_1 "f_1"
+               OpName %load_u_inner "load_u_inner"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 8
+               OpMemberDecorate %u_block_std140 2 Offset 16
+               OpMemberDecorate %u_block_std140 3 Offset 24
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+%u_block_std140 = OpTypeStruct %v4half %v4half %v4half %v4half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+       %void = OpTypeVoid
+ %mat4v4half = OpTypeMatrix %v4half 4
+          %6 = OpTypeFunction %void %mat4v4half
+         %12 = OpTypeFunction %void %v4half
+         %16 = OpTypeFunction %void %half
+         %20 = OpTypeFunction %mat4v4half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+         %43 = OpTypeFunction %void
+         %56 = OpConstantNull %uint
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+          %a = OpFunction %void None %6
+          %m = OpFunctionParameter %mat4v4half
+         %11 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %b = OpFunction %void None %12
+          %v = OpFunctionParameter %v4half
+         %15 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %c = OpFunction %void None %16
+        %f_1 = OpFunctionParameter %half
+         %19 = OpLabel
+               OpReturn
+               OpFunctionEnd
+%load_u_inner = OpFunction %mat4v4half None %20
+         %22 = OpLabel
+         %28 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0
+         %29 = OpLoad %v4half %28
+         %32 = OpAccessChain %_ptr_Uniform_v4half %u %uint_1
+         %33 = OpLoad %v4half %32
+         %36 = OpAccessChain %_ptr_Uniform_v4half %u %uint_2
+         %37 = OpLoad %v4half %36
+         %40 = OpAccessChain %_ptr_Uniform_v4half %u %uint_3
+         %41 = OpLoad %v4half %40
+         %42 = OpCompositeConstruct %mat4v4half %29 %33 %37 %41
+               OpReturnValue %42
+               OpFunctionEnd
+          %f = OpFunction %void None %43
+         %45 = OpLabel
+         %47 = OpFunctionCall %mat4v4half %load_u_inner
+         %46 = OpFunctionCall %void %a %47
+         %49 = OpAccessChain %_ptr_Uniform_v4half %u %uint_1
+         %50 = OpLoad %v4half %49
+         %48 = OpFunctionCall %void %b %50
+         %52 = OpAccessChain %_ptr_Uniform_v4half %u %uint_1
+         %53 = OpLoad %v4half %52
+         %54 = OpVectorShuffle %v4half %53 %53 1 3 0 2
+         %51 = OpFunctionCall %void %b %54
+         %58 = OpAccessChain %_ptr_Uniform_half %u %uint_1 %56
+         %59 = OpLoad %half %58
+         %55 = OpFunctionCall %void %c %59
+         %61 = OpAccessChain %_ptr_Uniform_v4half %u %uint_1
+         %62 = OpLoad %v4half %61
+         %63 = OpVectorShuffle %v4half %62 %62 1 3 0 2
+         %64 = OpCompositeExtract %half %63 0
+         %60 = OpFunctionCall %void %c %64
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_fn.wgsl.expected.wgsl
new file mode 100644
index 0000000..c99345b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_fn.wgsl.expected.wgsl
@@ -0,0 +1,21 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat4x4<f16>;
+
+fn a(m : mat4x4<f16>) {
+}
+
+fn b(v : vec4<f16>) {
+}
+
+fn c(f : f16) {
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  a(u);
+  b(u[1]);
+  b(u[1].ywxz);
+  c(u[1].x);
+  c(u[1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_private.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_private.wgsl
new file mode 100644
index 0000000..964be33
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_private.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat4x4<f16>;
+var<private> p : mat4x4<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[0];
+    p[1] = u[0].ywxz;
+    p[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_private.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..686f794
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_private.wgsl.expected.dxc.hlsl
@@ -0,0 +1,43 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+static matrix<float16_t, 4, 4> p = matrix<float16_t, 4, 4>(float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h));
+
+matrix<float16_t, 4, 4> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  uint2 ubo_load_8 = u[0].xy;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_8_yw = vector<float16_t, 2>(f16tof32(ubo_load_8 >> 16));
+  p[1] = vector<float16_t, 4>(ubo_load_8_xz[0], ubo_load_8_yw[0], ubo_load_8_xz[1], ubo_load_8_yw[1]);
+  uint2 ubo_load_9 = u[0].xy;
+  vector<float16_t, 2> ubo_load_9_xz = vector<float16_t, 2>(f16tof32(ubo_load_9 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_9_yw = vector<float16_t, 2>(f16tof32(ubo_load_9 >> 16));
+  p[1] = vector<float16_t, 4>(ubo_load_9_xz[0], ubo_load_9_yw[0], ubo_load_9_xz[1], ubo_load_9_yw[1]).ywxz;
+  p[0][1] = float16_t(f16tof32(((u[0].z) & 0xFFFF)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_private.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..7bb4eda
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_private.wgsl.expected.fxc.hlsl
@@ -0,0 +1,48 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+static matrix<float16_t, 4, 4> p = matrix<float16_t, 4, 4>(float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h), float16_t(0.0h));
+
+matrix<float16_t, 4, 4> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  uint2 ubo_load_8 = u[0].xy;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_8_yw = vector<float16_t, 2>(f16tof32(ubo_load_8 >> 16));
+  p[1] = vector<float16_t, 4>(ubo_load_8_xz[0], ubo_load_8_yw[0], ubo_load_8_xz[1], ubo_load_8_yw[1]);
+  uint2 ubo_load_9 = u[0].xy;
+  vector<float16_t, 2> ubo_load_9_xz = vector<float16_t, 2>(f16tof32(ubo_load_9 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_9_yw = vector<float16_t, 2>(f16tof32(ubo_load_9 >> 16));
+  p[1] = vector<float16_t, 4>(ubo_load_9_xz[0], ubo_load_9_yw[0], ubo_load_9_xz[1], ubo_load_9_yw[1]).ywxz;
+  p[0][1] = float16_t(f16tof32(((u[0].z) & 0xFFFF)));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001F1E6D79B60(4,15-23): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..5d0c395
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_private.wgsl.expected.glsl
@@ -0,0 +1,27 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec4 inner_0;
+  f16vec4 inner_1;
+  f16vec4 inner_2;
+  f16vec4 inner_3;
+} u;
+
+f16mat4 p = f16mat4(0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf, 0.0hf);
+f16mat4 load_u_inner() {
+  return f16mat4(u.inner_0, u.inner_1, u.inner_2, u.inner_3);
+}
+
+void f() {
+  p = load_u_inner();
+  p[1] = u.inner_0;
+  p[1] = u.inner_0.ywxz;
+  p[0][1] = u.inner_1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..7d4af8b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_private.wgsl.expected.msl
@@ -0,0 +1,12 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f(const constant half4x4* tint_symbol_1 [[buffer(0)]]) {
+  thread half4x4 tint_symbol = half4x4(0.0h);
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[0];
+  tint_symbol[1] = half4((*(tint_symbol_1))[0]).ywxz;
+  tint_symbol[0][1] = (*(tint_symbol_1))[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_private.wgsl.expected.spvasm
new file mode 100644
index 0000000..afb9628
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_private.wgsl.expected.spvasm
@@ -0,0 +1,87 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 55
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpMemberName %u_block_std140 2 "inner_2"
+               OpMemberName %u_block_std140 3 "inner_3"
+               OpName %u "u"
+               OpName %p "p"
+               OpName %load_u_inner "load_u_inner"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 8
+               OpMemberDecorate %u_block_std140 2 Offset 16
+               OpMemberDecorate %u_block_std140 3 Offset 24
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+%u_block_std140 = OpTypeStruct %v4half %v4half %v4half %v4half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat4v4half = OpTypeMatrix %v4half 4
+%_ptr_Private_mat4v4half = OpTypePointer Private %mat4v4half
+          %9 = OpConstantNull %mat4v4half
+          %p = OpVariable %_ptr_Private_mat4v4half Private %9
+         %10 = OpTypeFunction %mat4v4half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %33 = OpTypeFunction %void
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Private_v4half = OpTypePointer Private %v4half
+         %48 = OpConstantNull %int
+%_ptr_Private_half = OpTypePointer Private %half
+         %51 = OpConstantNull %uint
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+%load_u_inner = OpFunction %mat4v4half None %10
+         %12 = OpLabel
+         %18 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0
+         %19 = OpLoad %v4half %18
+         %22 = OpAccessChain %_ptr_Uniform_v4half %u %uint_1
+         %23 = OpLoad %v4half %22
+         %26 = OpAccessChain %_ptr_Uniform_v4half %u %uint_2
+         %27 = OpLoad %v4half %26
+         %30 = OpAccessChain %_ptr_Uniform_v4half %u %uint_3
+         %31 = OpLoad %v4half %30
+         %32 = OpCompositeConstruct %mat4v4half %19 %23 %27 %31
+               OpReturnValue %32
+               OpFunctionEnd
+          %f = OpFunction %void None %33
+         %36 = OpLabel
+         %37 = OpFunctionCall %mat4v4half %load_u_inner
+               OpStore %p %37
+         %41 = OpAccessChain %_ptr_Private_v4half %p %int_1
+         %42 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0
+         %43 = OpLoad %v4half %42
+               OpStore %41 %43
+         %44 = OpAccessChain %_ptr_Private_v4half %p %int_1
+         %45 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0
+         %46 = OpLoad %v4half %45
+         %47 = OpVectorShuffle %v4half %46 %46 1 3 0 2
+               OpStore %44 %47
+         %50 = OpAccessChain %_ptr_Private_half %p %48 %int_1
+         %53 = OpAccessChain %_ptr_Uniform_half %u %uint_1 %51
+         %54 = OpLoad %half %53
+               OpStore %50 %54
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..d5db396
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_private.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat4x4<f16>;
+
+var<private> p : mat4x4<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[0];
+  p[1] = u[0].ywxz;
+  p[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_storage.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_storage.wgsl
new file mode 100644
index 0000000..4eeb003
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_storage.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat4x4<f16>;
+@group(0) @binding(1) var<storage, read_write> s : mat4x4<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[0];
+    s[1] = u[0].ywxz;
+    s[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_storage.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..ab84a62
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_storage.wgsl.expected.dxc.hlsl
@@ -0,0 +1,50 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 4> value) {
+  buffer.Store<vector<float16_t, 4> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 8u), value[1u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 16u), value[2u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 24u), value[3u]);
+}
+
+matrix<float16_t, 4, 4> tint_symbol_2(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_2(u, 0u));
+  uint2 ubo_load_8 = u[0].xy;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_8_yw = vector<float16_t, 2>(f16tof32(ubo_load_8 >> 16));
+  s.Store<vector<float16_t, 4> >(8u, vector<float16_t, 4>(ubo_load_8_xz[0], ubo_load_8_yw[0], ubo_load_8_xz[1], ubo_load_8_yw[1]));
+  uint2 ubo_load_9 = u[0].xy;
+  vector<float16_t, 2> ubo_load_9_xz = vector<float16_t, 2>(f16tof32(ubo_load_9 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_9_yw = vector<float16_t, 2>(f16tof32(ubo_load_9 >> 16));
+  s.Store<vector<float16_t, 4> >(8u, vector<float16_t, 4>(ubo_load_9_xz[0], ubo_load_9_yw[0], ubo_load_9_xz[1], ubo_load_9_yw[1]).ywxz);
+  s.Store<float16_t>(2u, float16_t(f16tof32(((u[0].z) & 0xFFFF))));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_storage.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..f709acf
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_storage.wgsl.expected.fxc.hlsl
@@ -0,0 +1,56 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, matrix<float16_t, 4, 4> value) {
+  buffer.Store<vector<float16_t, 4> >((offset + 0u), value[0u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 8u), value[1u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 16u), value[2u]);
+  buffer.Store<vector<float16_t, 4> >((offset + 24u), value[3u]);
+}
+
+matrix<float16_t, 4, 4> tint_symbol_2(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_2(u, 0u));
+  uint2 ubo_load_8 = u[0].xy;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_8_yw = vector<float16_t, 2>(f16tof32(ubo_load_8 >> 16));
+  s.Store<vector<float16_t, 4> >(8u, vector<float16_t, 4>(ubo_load_8_xz[0], ubo_load_8_yw[0], ubo_load_8_xz[1], ubo_load_8_yw[1]));
+  uint2 ubo_load_9 = u[0].xy;
+  vector<float16_t, 2> ubo_load_9_xz = vector<float16_t, 2>(f16tof32(ubo_load_9 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_9_yw = vector<float16_t, 2>(f16tof32(ubo_load_9 >> 16));
+  s.Store<vector<float16_t, 4> >(8u, vector<float16_t, 4>(ubo_load_9_xz[0], ubo_load_9_yw[0], ubo_load_9_xz[1], ubo_load_9_yw[1]).ywxz);
+  s.Store<float16_t>(2u, float16_t(f16tof32(((u[0].z) & 0xFFFF))));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000017A08509500(6,66-74): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000017A08509500(7,3-14): error X3018: invalid subscript 'Store'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..0d01706
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_storage.wgsl.expected.glsl
@@ -0,0 +1,30 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec4 inner_0;
+  f16vec4 inner_1;
+  f16vec4 inner_2;
+  f16vec4 inner_3;
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  f16mat4 inner;
+} s;
+
+f16mat4 load_u_inner() {
+  return f16mat4(u.inner_0, u.inner_1, u.inner_2, u.inner_3);
+}
+
+void f() {
+  s.inner = load_u_inner();
+  s.inner[1] = u.inner_0;
+  s.inner[1] = u.inner_0.ywxz;
+  s.inner[0][1] = u.inner_1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..4530643
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_storage.wgsl.expected.msl
@@ -0,0 +1,11 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f(device half4x4* tint_symbol [[buffer(1)]], const constant half4x4* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[0];
+  (*(tint_symbol))[1] = half4((*(tint_symbol_1))[0]).ywxz;
+  (*(tint_symbol))[0][1] = (*(tint_symbol_1))[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_storage.wgsl.expected.spvasm
new file mode 100644
index 0000000..95d5fea
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_storage.wgsl.expected.spvasm
@@ -0,0 +1,97 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 57
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpMemberName %u_block_std140 2 "inner_2"
+               OpMemberName %u_block_std140 3 "inner_3"
+               OpName %u "u"
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %s "s"
+               OpName %load_u_inner "load_u_inner"
+               OpName %f "f"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 8
+               OpMemberDecorate %u_block_std140 2 Offset 16
+               OpMemberDecorate %u_block_std140 3 Offset 24
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 8
+               OpDecorate %s DescriptorSet 0
+               OpDecorate %s Binding 1
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+%u_block_std140 = OpTypeStruct %v4half %v4half %v4half %v4half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat4v4half = OpTypeMatrix %v4half 4
+    %u_block = OpTypeStruct %mat4v4half
+%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
+          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+         %10 = OpTypeFunction %mat4v4half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %33 = OpTypeFunction %void
+%_ptr_StorageBuffer_mat4v4half = OpTypePointer StorageBuffer %mat4v4half
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_v4half = OpTypePointer StorageBuffer %v4half
+         %50 = OpConstantNull %int
+%_ptr_StorageBuffer_half = OpTypePointer StorageBuffer %half
+         %53 = OpConstantNull %uint
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+%load_u_inner = OpFunction %mat4v4half None %10
+         %12 = OpLabel
+         %18 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0
+         %19 = OpLoad %v4half %18
+         %22 = OpAccessChain %_ptr_Uniform_v4half %u %uint_1
+         %23 = OpLoad %v4half %22
+         %26 = OpAccessChain %_ptr_Uniform_v4half %u %uint_2
+         %27 = OpLoad %v4half %26
+         %30 = OpAccessChain %_ptr_Uniform_v4half %u %uint_3
+         %31 = OpLoad %v4half %30
+         %32 = OpCompositeConstruct %mat4v4half %19 %23 %27 %31
+               OpReturnValue %32
+               OpFunctionEnd
+          %f = OpFunction %void None %33
+         %36 = OpLabel
+         %38 = OpAccessChain %_ptr_StorageBuffer_mat4v4half %s %uint_0
+         %39 = OpFunctionCall %mat4v4half %load_u_inner
+               OpStore %38 %39
+         %43 = OpAccessChain %_ptr_StorageBuffer_v4half %s %uint_0 %int_1
+         %44 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0
+         %45 = OpLoad %v4half %44
+               OpStore %43 %45
+         %46 = OpAccessChain %_ptr_StorageBuffer_v4half %s %uint_0 %int_1
+         %47 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0
+         %48 = OpLoad %v4half %47
+         %49 = OpVectorShuffle %v4half %48 %48 1 3 0 2
+               OpStore %46 %49
+         %52 = OpAccessChain %_ptr_StorageBuffer_half %s %uint_0 %50 %int_1
+         %55 = OpAccessChain %_ptr_Uniform_half %u %uint_1 %53
+         %56 = OpLoad %half %55
+               OpStore %52 %56
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..e7a3faa
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat4x4<f16>;
+
+@group(0) @binding(1) var<storage, read_write> s : mat4x4<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[0];
+  s[1] = u[0].ywxz;
+  s[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_workgroup.wgsl
new file mode 100644
index 0000000..3018a0f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_workgroup.wgsl
@@ -0,0 +1,12 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat4x4<f16>;
+var<workgroup> w : mat4x4<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[0];
+    w[1] = u[0].ywxz;
+    w[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_workgroup.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..3cf441e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_workgroup.wgsl.expected.dxc.hlsl
@@ -0,0 +1,55 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+groupshared matrix<float16_t, 4, 4> w;
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 4, 4> tint_symbol_2(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    w = matrix<float16_t, 4, 4>((float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx);
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  uint2 ubo_load_8 = u[0].xy;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_8_yw = vector<float16_t, 2>(f16tof32(ubo_load_8 >> 16));
+  w[1] = vector<float16_t, 4>(ubo_load_8_xz[0], ubo_load_8_yw[0], ubo_load_8_xz[1], ubo_load_8_yw[1]);
+  uint2 ubo_load_9 = u[0].xy;
+  vector<float16_t, 2> ubo_load_9_xz = vector<float16_t, 2>(f16tof32(ubo_load_9 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_9_yw = vector<float16_t, 2>(f16tof32(ubo_load_9 >> 16));
+  w[1] = vector<float16_t, 4>(ubo_load_9_xz[0], ubo_load_9_yw[0], ubo_load_9_xz[1], ubo_load_9_yw[1]).ywxz;
+  w[0][1] = float16_t(f16tof32(((u[0].z) & 0xFFFF)));
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_workgroup.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..ca75021
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_workgroup.wgsl.expected.fxc.hlsl
@@ -0,0 +1,60 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+groupshared matrix<float16_t, 4, 4> w;
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+matrix<float16_t, 4, 4> tint_symbol_2(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    w = matrix<float16_t, 4, 4>((float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx);
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  uint2 ubo_load_8 = u[0].xy;
+  vector<float16_t, 2> ubo_load_8_xz = vector<float16_t, 2>(f16tof32(ubo_load_8 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_8_yw = vector<float16_t, 2>(f16tof32(ubo_load_8 >> 16));
+  w[1] = vector<float16_t, 4>(ubo_load_8_xz[0], ubo_load_8_yw[0], ubo_load_8_xz[1], ubo_load_8_yw[1]);
+  uint2 ubo_load_9 = u[0].xy;
+  vector<float16_t, 2> ubo_load_9_xz = vector<float16_t, 2>(f16tof32(ubo_load_9 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_9_yw = vector<float16_t, 2>(f16tof32(ubo_load_9 >> 16));
+  w[1] = vector<float16_t, 4>(ubo_load_9_xz[0], ubo_load_9_yw[0], ubo_load_9_xz[1], ubo_load_9_yw[1]).ywxz;
+  w[0][1] = float16_t(f16tof32(((u[0].z) & 0xFFFF)));
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x00000234396001A0(4,20-28): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..18b9337
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,31 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec4 inner_0;
+  f16vec4 inner_1;
+  f16vec4 inner_2;
+  f16vec4 inner_3;
+} u;
+
+shared f16mat4 w;
+f16mat4 load_u_inner() {
+  return f16mat4(u.inner_0, u.inner_1, u.inner_2, u.inner_3);
+}
+
+void f(uint local_invocation_index) {
+  {
+    w = f16mat4(f16vec4(0.0hf), f16vec4(0.0hf), f16vec4(0.0hf), f16vec4(0.0hf));
+  }
+  barrier();
+  w = load_u_inner();
+  w[1] = u.inner_0;
+  w[1] = u.inner_0.ywxz;
+  w[0][1] = u.inner_1[0u];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..57392de
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,24 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct tint_symbol_5 {
+  half4x4 w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup half4x4* const tint_symbol, const constant half4x4* const tint_symbol_1) {
+  {
+    *(tint_symbol) = half4x4(half4(0.0h), half4(0.0h), half4(0.0h), half4(0.0h));
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[0];
+  (*(tint_symbol))[1] = half4((*(tint_symbol_1))[0]).ywxz;
+  (*(tint_symbol))[0][1] = (*(tint_symbol_1))[1][0];
+}
+
+kernel void f(const constant half4x4* tint_symbol_4 [[buffer(0)]], threadgroup tint_symbol_5* tint_symbol_3 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup half4x4* const tint_symbol_2 = &((*(tint_symbol_3)).w);
+  f_inner(local_invocation_index, tint_symbol_2, tint_symbol_4);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_workgroup.wgsl.expected.spvasm
new file mode 100644
index 0000000..c26e2ab
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_workgroup.wgsl.expected.spvasm
@@ -0,0 +1,104 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 65
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %local_invocation_index_1 "local_invocation_index_1"
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpMemberName %u_block_std140 2 "inner_2"
+               OpMemberName %u_block_std140 3 "inner_3"
+               OpName %u "u"
+               OpName %w "w"
+               OpName %load_u_inner "load_u_inner"
+               OpName %f_inner "f_inner"
+               OpName %local_invocation_index "local_invocation_index"
+               OpName %f "f"
+               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 8
+               OpMemberDecorate %u_block_std140 2 Offset 16
+               OpMemberDecorate %u_block_std140 3 Offset 24
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+%u_block_std140 = OpTypeStruct %v4half %v4half %v4half %v4half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat4v4half = OpTypeMatrix %v4half 4
+%_ptr_Workgroup_mat4v4half = OpTypePointer Workgroup %mat4v4half
+          %w = OpVariable %_ptr_Workgroup_mat4v4half Workgroup
+         %12 = OpTypeFunction %mat4v4half
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %34 = OpTypeFunction %void %uint
+         %39 = OpConstantNull %mat4v4half
+   %uint_264 = OpConstant %uint 264
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Workgroup_v4half = OpTypePointer Workgroup %v4half
+         %53 = OpConstantNull %int
+%_ptr_Workgroup_half = OpTypePointer Workgroup %half
+         %56 = OpConstantNull %uint
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+         %60 = OpTypeFunction %void
+%load_u_inner = OpFunction %mat4v4half None %12
+         %14 = OpLabel
+         %19 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0
+         %20 = OpLoad %v4half %19
+         %23 = OpAccessChain %_ptr_Uniform_v4half %u %uint_1
+         %24 = OpLoad %v4half %23
+         %27 = OpAccessChain %_ptr_Uniform_v4half %u %uint_2
+         %28 = OpLoad %v4half %27
+         %31 = OpAccessChain %_ptr_Uniform_v4half %u %uint_3
+         %32 = OpLoad %v4half %31
+         %33 = OpCompositeConstruct %mat4v4half %20 %24 %28 %32
+               OpReturnValue %33
+               OpFunctionEnd
+    %f_inner = OpFunction %void None %34
+%local_invocation_index = OpFunctionParameter %uint
+         %38 = OpLabel
+               OpStore %w %39
+               OpControlBarrier %uint_2 %uint_2 %uint_264
+         %42 = OpFunctionCall %mat4v4half %load_u_inner
+               OpStore %w %42
+         %46 = OpAccessChain %_ptr_Workgroup_v4half %w %int_1
+         %47 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0
+         %48 = OpLoad %v4half %47
+               OpStore %46 %48
+         %49 = OpAccessChain %_ptr_Workgroup_v4half %w %int_1
+         %50 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0
+         %51 = OpLoad %v4half %50
+         %52 = OpVectorShuffle %v4half %51 %51 1 3 0 2
+               OpStore %49 %52
+         %55 = OpAccessChain %_ptr_Workgroup_half %w %53 %int_1
+         %58 = OpAccessChain %_ptr_Uniform_half %u %uint_1 %56
+         %59 = OpLoad %half %58
+               OpStore %55 %59
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %60
+         %62 = OpLabel
+         %64 = OpLoad %uint %local_invocation_index_1
+         %63 = OpFunctionCall %void %f_inner %64
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..75f45fe
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f16/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,13 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat4x4<f16>;
+
+var<workgroup> w : mat4x4<f16>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[0];
+  w[1] = u[0].ywxz;
+  w[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/dynamic_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/dynamic_index_via_ptr.wgsl
new file mode 100644
index 0000000..09d34f3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/dynamic_index_via_ptr.wgsl
@@ -0,0 +1,13 @@
+@group(0) @binding(0) var<uniform> m : mat4x4<f32>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m   = &m;
+  let p_m_i = &((*p_m)[i()]);
+
+  let l_m   : mat4x4<f32> = *p_m;
+  let l_m_i : vec4<f32>   = *p_m_i;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..ea3e8b8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,26 @@
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[4];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float4x4 tint_symbol(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]), asfloat(buffer[scalar_offset_3 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_m_i_save = i();
+  const float4x4 l_m = tint_symbol(m, 0u);
+  const uint scalar_offset_4 = ((16u * uint(p_m_i_save))) / 4;
+  const float4 l_m_i = asfloat(m[scalar_offset_4 / 4]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..ea3e8b8
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,26 @@
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[4];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float4x4 tint_symbol(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]), asfloat(buffer[scalar_offset_3 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const int p_m_i_save = i();
+  const float4x4 l_m = tint_symbol(m, 0u);
+  const uint scalar_offset_4 = ((16u * uint(p_m_i_save))) / 4;
+  const float4 l_m_i = asfloat(m[scalar_offset_4 / 4]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..37b6cda
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,24 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform m_block_ubo {
+  mat4 inner;
+} m;
+
+int counter = 0;
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+void f() {
+  int tint_symbol = i();
+  int p_m_i_save = tint_symbol;
+  mat4 l_m = m.inner;
+  vec4 l_m_i = m.inner[p_m_i_save];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..084622b
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,17 @@
+#include <metal_stdlib>
+
+using namespace metal;
+int i() {
+  thread int tint_symbol_1 = 0;
+  tint_symbol_1 = as_type<int>((as_type<uint>(tint_symbol_1) + as_type<uint>(1)));
+  return tint_symbol_1;
+}
+
+kernel void f(const constant float4x4* tint_symbol_2 [[buffer(0)]]) {
+  int const tint_symbol = i();
+  int const p_m_i_save = tint_symbol;
+  float4x4 const l_m = *(tint_symbol_2);
+  float4 const l_m_i = (*(tint_symbol_2))[p_m_i_save];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..c010265
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,57 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 31
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %m_block "m_block"
+               OpMemberName %m_block 0 "inner"
+               OpName %m "m"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %f "f"
+               OpDecorate %m_block Block
+               OpMemberDecorate %m_block 0 Offset 0
+               OpMemberDecorate %m_block 0 ColMajor
+               OpMemberDecorate %m_block 0 MatrixStride 16
+               OpDecorate %m NonWritable
+               OpDecorate %m DescriptorSet 0
+               OpDecorate %m Binding 0
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat4v4float = OpTypeMatrix %v4float 4
+    %m_block = OpTypeStruct %mat4v4float
+%_ptr_Uniform_m_block = OpTypePointer Uniform %m_block
+          %m = OpVariable %_ptr_Uniform_m_block Uniform
+        %int = OpTypeInt 32 1
+          %8 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %8
+         %11 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+       %void = OpTypeVoid
+         %18 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+          %i = OpFunction %int None %11
+         %13 = OpLabel
+         %14 = OpLoad %int %counter
+         %16 = OpIAdd %int %14 %int_1
+               OpStore %counter %16
+         %17 = OpLoad %int %counter
+               OpReturnValue %17
+               OpFunctionEnd
+          %f = OpFunction %void None %18
+         %21 = OpLabel
+         %22 = OpFunctionCall %int %i
+         %26 = OpAccessChain %_ptr_Uniform_mat4v4float %m %uint_0
+         %27 = OpLoad %mat4v4float %26
+         %29 = OpAccessChain %_ptr_Uniform_v4float %m %uint_0 %22
+         %30 = OpLoad %v4float %29
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..6654dab
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/dynamic_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,16 @@
+@group(0) @binding(0) var<uniform> m : mat4x4<f32>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m = &(m);
+  let p_m_i = &((*(p_m))[i()]);
+  let l_m : mat4x4<f32> = *(p_m);
+  let l_m_i : vec4<f32> = *(p_m_i);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/static_index_via_ptr.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/static_index_via_ptr.wgsl
new file mode 100644
index 0000000..2c0c99d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/static_index_via_ptr.wgsl
@@ -0,0 +1,13 @@
+@group(0) @binding(0) var<uniform> m : mat4x4<f32>;
+
+var<private> counter = 0;
+fn i() -> i32 { counter++; return counter; }
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m   = &m;
+  let p_m_1 = &((*p_m)[1]);
+
+  let l_m   : mat4x4<f32> = *p_m;
+  let l_m_1 : vec4<f32>   = *p_m_1;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..8ae2c10
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/static_index_via_ptr.wgsl.expected.dxc.hlsl
@@ -0,0 +1,24 @@
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[4];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float4x4 tint_symbol(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]), asfloat(buffer[scalar_offset_3 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float4x4 l_m = tint_symbol(m, 0u);
+  const float4 l_m_1 = asfloat(m[1]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..8ae2c10
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/static_index_via_ptr.wgsl.expected.fxc.hlsl
@@ -0,0 +1,24 @@
+cbuffer cbuffer_m : register(b0, space0) {
+  uint4 m[4];
+};
+static int counter = 0;
+
+int i() {
+  counter = (counter + 1);
+  return counter;
+}
+
+float4x4 tint_symbol(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]), asfloat(buffer[scalar_offset_3 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float4x4 l_m = tint_symbol(m, 0u);
+  const float4 l_m_1 = asfloat(m[1]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/static_index_via_ptr.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/static_index_via_ptr.wgsl.expected.glsl
new file mode 100644
index 0000000..e9fc87c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/static_index_via_ptr.wgsl.expected.glsl
@@ -0,0 +1,16 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform m_block_ubo {
+  mat4 inner;
+} m;
+
+void f() {
+  mat4 l_m = m.inner;
+  vec4 l_m_1 = m.inner[1];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/static_index_via_ptr.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/static_index_via_ptr.wgsl.expected.msl
new file mode 100644
index 0000000..8118193
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/static_index_via_ptr.wgsl.expected.msl
@@ -0,0 +1,15 @@
+#include <metal_stdlib>
+
+using namespace metal;
+int i() {
+  thread int tint_symbol = 0;
+  tint_symbol = as_type<int>((as_type<uint>(tint_symbol) + as_type<uint>(1)));
+  return tint_symbol;
+}
+
+kernel void f(const constant float4x4* tint_symbol_1 [[buffer(0)]]) {
+  float4x4 const l_m = *(tint_symbol_1);
+  float4 const l_m_1 = (*(tint_symbol_1))[1];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/static_index_via_ptr.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/static_index_via_ptr.wgsl.expected.spvasm
new file mode 100644
index 0000000..e4d3f30
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/static_index_via_ptr.wgsl.expected.spvasm
@@ -0,0 +1,56 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 30
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %m_block "m_block"
+               OpMemberName %m_block 0 "inner"
+               OpName %m "m"
+               OpName %counter "counter"
+               OpName %i "i"
+               OpName %f "f"
+               OpDecorate %m_block Block
+               OpMemberDecorate %m_block 0 Offset 0
+               OpMemberDecorate %m_block 0 ColMajor
+               OpMemberDecorate %m_block 0 MatrixStride 16
+               OpDecorate %m NonWritable
+               OpDecorate %m DescriptorSet 0
+               OpDecorate %m Binding 0
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat4v4float = OpTypeMatrix %v4float 4
+    %m_block = OpTypeStruct %mat4v4float
+%_ptr_Uniform_m_block = OpTypePointer Uniform %m_block
+          %m = OpVariable %_ptr_Uniform_m_block Uniform
+        %int = OpTypeInt 32 1
+          %8 = OpConstantNull %int
+%_ptr_Private_int = OpTypePointer Private %int
+    %counter = OpVariable %_ptr_Private_int Private %8
+         %11 = OpTypeFunction %int
+      %int_1 = OpConstant %int 1
+       %void = OpTypeVoid
+         %18 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+          %i = OpFunction %int None %11
+         %13 = OpLabel
+         %14 = OpLoad %int %counter
+         %16 = OpIAdd %int %14 %int_1
+               OpStore %counter %16
+         %17 = OpLoad %int %counter
+               OpReturnValue %17
+               OpFunctionEnd
+          %f = OpFunction %void None %18
+         %21 = OpLabel
+         %25 = OpAccessChain %_ptr_Uniform_mat4v4float %m %uint_0
+         %26 = OpLoad %mat4v4float %25
+         %28 = OpAccessChain %_ptr_Uniform_v4float %m %uint_0 %int_1
+         %29 = OpLoad %v4float %28
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/static_index_via_ptr.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/static_index_via_ptr.wgsl.expected.wgsl
new file mode 100644
index 0000000..7729038
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/static_index_via_ptr.wgsl.expected.wgsl
@@ -0,0 +1,16 @@
+@group(0) @binding(0) var<uniform> m : mat4x4<f32>;
+
+var<private> counter = 0;
+
+fn i() -> i32 {
+  counter++;
+  return counter;
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  let p_m = &(m);
+  let p_m_1 = &((*(p_m))[1]);
+  let l_m : mat4x4<f32> = *(p_m);
+  let l_m_1 : vec4<f32> = *(p_m_1);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_builtin.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_builtin.wgsl
new file mode 100644
index 0000000..396c963
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_builtin.wgsl
@@ -0,0 +1,8 @@
+@group(0) @binding(0) var<uniform> u : mat4x4<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+    let t = transpose(u);
+    let l = length(u[1]);
+    let a = abs(u[0].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_builtin.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_builtin.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..7642211
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_builtin.wgsl.expected.dxc.hlsl
@@ -0,0 +1,19 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+
+float4x4 tint_symbol(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]), asfloat(buffer[scalar_offset_3 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float4x4 t = transpose(tint_symbol(u, 0u));
+  const float l = length(asfloat(u[1]));
+  const float a = abs(asfloat(u[0]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_builtin.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_builtin.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..7642211
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_builtin.wgsl.expected.fxc.hlsl
@@ -0,0 +1,19 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+
+float4x4 tint_symbol(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]), asfloat(buffer[scalar_offset_3 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  const float4x4 t = transpose(tint_symbol(u, 0u));
+  const float l = length(asfloat(u[1]));
+  const float a = abs(asfloat(u[0]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_builtin.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_builtin.wgsl.expected.glsl
new file mode 100644
index 0000000..98ccccb
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_builtin.wgsl.expected.glsl
@@ -0,0 +1,17 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat4 inner;
+} u;
+
+void f() {
+  mat4 t = transpose(u.inner);
+  float l = length(u.inner[1]);
+  float a = abs(u.inner[0].ywxz.x);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_builtin.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_builtin.wgsl.expected.msl
new file mode 100644
index 0000000..61a809d
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_builtin.wgsl.expected.msl
@@ -0,0 +1,10 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f(const constant float4x4* tint_symbol [[buffer(0)]]) {
+  float4x4 const t = transpose(*(tint_symbol));
+  float const l = length((*(tint_symbol))[1]);
+  float const a = fabs(float4((*(tint_symbol))[0]).ywxz[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_builtin.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_builtin.wgsl.expected.spvasm
new file mode 100644
index 0000000..c026f19
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_builtin.wgsl.expected.spvasm
@@ -0,0 +1,51 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 30
+; Schema: 0
+               OpCapability Shader
+         %18 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat4v4float = OpTypeMatrix %v4float 4
+    %u_block = OpTypeStruct %mat4v4float
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+          %7 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+         %25 = OpConstantNull %int
+          %f = OpFunction %void None %7
+         %10 = OpLabel
+         %15 = OpAccessChain %_ptr_Uniform_mat4v4float %u %uint_0
+         %16 = OpLoad %mat4v4float %15
+         %11 = OpTranspose %mat4v4float %16
+         %22 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %int_1
+         %23 = OpLoad %v4float %22
+         %17 = OpExtInst %float %18 Length %23
+         %26 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %25
+         %27 = OpLoad %v4float %26
+         %28 = OpVectorShuffle %v4float %27 %27 1 3 0 2
+         %29 = OpCompositeExtract %float %28 0
+         %24 = OpExtInst %float %18 FAbs %29
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_builtin.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_builtin.wgsl.expected.wgsl
new file mode 100644
index 0000000..2bf8fea
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_builtin.wgsl.expected.wgsl
@@ -0,0 +1,8 @@
+@group(0) @binding(0) var<uniform> u : mat4x4<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+  let t = transpose(u);
+  let l = length(u[1]);
+  let a = abs(u[0].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_fn.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_fn.wgsl
new file mode 100644
index 0000000..f149495
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_fn.wgsl
@@ -0,0 +1,14 @@
+@group(0) @binding(0) var<uniform> u : mat4x4<f32>;
+
+fn a(m : mat4x4<f32>) {}
+fn b(v : vec4<f32>) {}
+fn c(f : f32) {}
+
+@compute @workgroup_size(1)
+fn f() {
+    a(u);
+    b(u[1]);
+    b(u[1].ywxz);
+    c(u[1].x);
+    c(u[1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_fn.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_fn.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..b70e101
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_fn.wgsl.expected.dxc.hlsl
@@ -0,0 +1,30 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+
+void a(float4x4 m) {
+}
+
+void b(float4 v) {
+}
+
+void c(float f_1) {
+}
+
+float4x4 tint_symbol(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]), asfloat(buffer[scalar_offset_3 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(asfloat(u[1]));
+  b(asfloat(u[1]).ywxz);
+  c(asfloat(u[1].x));
+  c(asfloat(u[1]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_fn.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_fn.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..b70e101
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_fn.wgsl.expected.fxc.hlsl
@@ -0,0 +1,30 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+
+void a(float4x4 m) {
+}
+
+void b(float4 v) {
+}
+
+void c(float f_1) {
+}
+
+float4x4 tint_symbol(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]), asfloat(buffer[scalar_offset_3 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  a(tint_symbol(u, 0u));
+  b(asfloat(u[1]));
+  b(asfloat(u[1]).ywxz);
+  c(asfloat(u[1].x));
+  c(asfloat(u[1]).ywxz.x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_fn.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_fn.wgsl.expected.glsl
new file mode 100644
index 0000000..2e2bb64
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_fn.wgsl.expected.glsl
@@ -0,0 +1,28 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat4 inner;
+} u;
+
+void a(mat4 m) {
+}
+
+void b(vec4 v) {
+}
+
+void c(float f_1) {
+}
+
+void f() {
+  a(u.inner);
+  b(u.inner[1]);
+  b(u.inner[1].ywxz);
+  c(u.inner[1].x);
+  c(u.inner[1].ywxz.x);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_fn.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_fn.wgsl.expected.msl
new file mode 100644
index 0000000..8a08412
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_fn.wgsl.expected.msl
@@ -0,0 +1,21 @@
+#include <metal_stdlib>
+
+using namespace metal;
+void a(float4x4 m) {
+}
+
+void b(float4 v) {
+}
+
+void c(float f_1) {
+}
+
+kernel void f(const constant float4x4* tint_symbol [[buffer(0)]]) {
+  a(*(tint_symbol));
+  b((*(tint_symbol))[1]);
+  b(float4((*(tint_symbol))[1]).ywxz);
+  c((*(tint_symbol))[1][0]);
+  c(float4((*(tint_symbol))[1]).ywxz[0]);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_fn.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_fn.wgsl.expected.spvasm
new file mode 100644
index 0000000..ba20788
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_fn.wgsl.expected.spvasm
@@ -0,0 +1,81 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 48
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %a "a"
+               OpName %m "m"
+               OpName %b "b"
+               OpName %v "v"
+               OpName %c "c"
+               OpName %f_1 "f_1"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat4v4float = OpTypeMatrix %v4float 4
+    %u_block = OpTypeStruct %mat4v4float
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+          %7 = OpTypeFunction %void %mat4v4float
+         %12 = OpTypeFunction %void %v4float
+         %16 = OpTypeFunction %void %float
+         %20 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+          %a = OpFunction %void None %7
+          %m = OpFunctionParameter %mat4v4float
+         %11 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %b = OpFunction %void None %12
+          %v = OpFunctionParameter %v4float
+         %15 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %c = OpFunction %void None %16
+        %f_1 = OpFunctionParameter %float
+         %19 = OpLabel
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %20
+         %22 = OpLabel
+         %27 = OpAccessChain %_ptr_Uniform_mat4v4float %u %uint_0
+         %28 = OpLoad %mat4v4float %27
+         %23 = OpFunctionCall %void %a %28
+         %33 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %int_1
+         %34 = OpLoad %v4float %33
+         %29 = OpFunctionCall %void %b %34
+         %36 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %int_1
+         %37 = OpLoad %v4float %36
+         %38 = OpVectorShuffle %v4float %37 %37 1 3 0 2
+         %35 = OpFunctionCall %void %b %38
+         %41 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %int_1 %uint_0
+         %42 = OpLoad %float %41
+         %39 = OpFunctionCall %void %c %42
+         %44 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %int_1
+         %45 = OpLoad %v4float %44
+         %46 = OpVectorShuffle %v4float %45 %45 1 3 0 2
+         %47 = OpCompositeExtract %float %46 0
+         %43 = OpFunctionCall %void %c %47
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_fn.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_fn.wgsl.expected.wgsl
new file mode 100644
index 0000000..eb33f7c
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_fn.wgsl.expected.wgsl
@@ -0,0 +1,19 @@
+@group(0) @binding(0) var<uniform> u : mat4x4<f32>;
+
+fn a(m : mat4x4<f32>) {
+}
+
+fn b(v : vec4<f32>) {
+}
+
+fn c(f : f32) {
+}
+
+@compute @workgroup_size(1)
+fn f() {
+  a(u);
+  b(u[1]);
+  b(u[1].ywxz);
+  c(u[1].x);
+  c(u[1].ywxz.x);
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_private.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_private.wgsl
new file mode 100644
index 0000000..36f4c15
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_private.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0) var<uniform> u : mat4x4<f32>;
+var<private> p : mat4x4<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+    p = u;
+    p[1] = u[0];
+    p[1] = u[0].ywxz;
+    p[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_private.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_private.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..7679686
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_private.wgsl.expected.dxc.hlsl
@@ -0,0 +1,21 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+static float4x4 p = float4x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
+
+float4x4 tint_symbol(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]), asfloat(buffer[scalar_offset_3 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = asfloat(u[0]);
+  p[1] = asfloat(u[0]).ywxz;
+  p[0][1] = asfloat(u[1].x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_private.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_private.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..7679686
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_private.wgsl.expected.fxc.hlsl
@@ -0,0 +1,21 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+static float4x4 p = float4x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
+
+float4x4 tint_symbol(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]), asfloat(buffer[scalar_offset_3 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  p = tint_symbol(u, 0u);
+  p[1] = asfloat(u[0]);
+  p[1] = asfloat(u[0]).ywxz;
+  p[0][1] = asfloat(u[1].x);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_private.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_private.wgsl.expected.glsl
new file mode 100644
index 0000000..a45b304
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_private.wgsl.expected.glsl
@@ -0,0 +1,19 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat4 inner;
+} u;
+
+mat4 p = mat4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
+void f() {
+  p = u.inner;
+  p[1] = u.inner[0];
+  p[1] = u.inner[0].ywxz;
+  p[0][1] = u.inner[1][0];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_private.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_private.wgsl.expected.msl
new file mode 100644
index 0000000..1230ff9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_private.wgsl.expected.msl
@@ -0,0 +1,12 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f(const constant float4x4* tint_symbol_1 [[buffer(0)]]) {
+  thread float4x4 tint_symbol = float4x4(0.0f);
+  tint_symbol = *(tint_symbol_1);
+  tint_symbol[1] = (*(tint_symbol_1))[0];
+  tint_symbol[1] = float4((*(tint_symbol_1))[0]).ywxz;
+  tint_symbol[0][1] = (*(tint_symbol_1))[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_private.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_private.wgsl.expected.spvasm
new file mode 100644
index 0000000..ea0d486
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_private.wgsl.expected.spvasm
@@ -0,0 +1,62 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 36
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %p "p"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat4v4float = OpTypeMatrix %v4float 4
+    %u_block = OpTypeStruct %mat4v4float
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_Private_mat4v4float = OpTypePointer Private %mat4v4float
+          %9 = OpConstantNull %mat4v4float
+          %p = OpVariable %_ptr_Private_mat4v4float Private %9
+       %void = OpTypeVoid
+         %10 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Private_v4float = OpTypePointer Private %v4float
+         %23 = OpConstantNull %int
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+%_ptr_Private_float = OpTypePointer Private %float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+          %f = OpFunction %void None %10
+         %13 = OpLabel
+         %17 = OpAccessChain %_ptr_Uniform_mat4v4float %u %uint_0
+         %18 = OpLoad %mat4v4float %17
+               OpStore %p %18
+         %22 = OpAccessChain %_ptr_Private_v4float %p %int_1
+         %25 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %23
+         %26 = OpLoad %v4float %25
+               OpStore %22 %26
+         %27 = OpAccessChain %_ptr_Private_v4float %p %int_1
+         %28 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %23
+         %29 = OpLoad %v4float %28
+         %30 = OpVectorShuffle %v4float %29 %29 1 3 0 2
+               OpStore %27 %30
+         %32 = OpAccessChain %_ptr_Private_float %p %23 %int_1
+         %34 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %int_1 %23
+         %35 = OpLoad %float %34
+               OpStore %32 %35
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_private.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_private.wgsl.expected.wgsl
new file mode 100644
index 0000000..7c0e888
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_private.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> u : mat4x4<f32>;
+
+var<private> p : mat4x4<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+  p = u;
+  p[1] = u[0];
+  p[1] = u[0].ywxz;
+  p[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_storage.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_storage.wgsl
new file mode 100644
index 0000000..801c31f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_storage.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0) var<uniform> u : mat4x4<f32>;
+@group(0) @binding(1) var<storage, read_write> s : mat4x4<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+    s = u;
+    s[1] = u[0];
+    s[1] = u[0].ywxz;
+    s[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_storage.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_storage.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..cd27df0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_storage.wgsl.expected.dxc.hlsl
@@ -0,0 +1,28 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, float4x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+  buffer.Store4((offset + 32u), asuint(value[2u]));
+  buffer.Store4((offset + 48u), asuint(value[3u]));
+}
+
+float4x4 tint_symbol_2(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]), asfloat(buffer[scalar_offset_3 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_2(u, 0u));
+  s.Store4(16u, asuint(asfloat(u[0])));
+  s.Store4(16u, asuint(asfloat(u[0]).ywxz));
+  s.Store(4u, asuint(asfloat(u[1].x)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_storage.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_storage.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..cd27df0
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_storage.wgsl.expected.fxc.hlsl
@@ -0,0 +1,28 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+RWByteAddressBuffer s : register(u1, space0);
+
+void tint_symbol(RWByteAddressBuffer buffer, uint offset, float4x4 value) {
+  buffer.Store4((offset + 0u), asuint(value[0u]));
+  buffer.Store4((offset + 16u), asuint(value[1u]));
+  buffer.Store4((offset + 32u), asuint(value[2u]));
+  buffer.Store4((offset + 48u), asuint(value[3u]));
+}
+
+float4x4 tint_symbol_2(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]), asfloat(buffer[scalar_offset_3 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void f() {
+  tint_symbol(s, 0u, tint_symbol_2(u, 0u));
+  s.Store4(16u, asuint(asfloat(u[0])));
+  s.Store4(16u, asuint(asfloat(u[0]).ywxz));
+  s.Store(4u, asuint(asfloat(u[1].x)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_storage.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_storage.wgsl.expected.glsl
new file mode 100644
index 0000000..d8d07fb
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_storage.wgsl.expected.glsl
@@ -0,0 +1,22 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat4 inner;
+} u;
+
+layout(binding = 1, std430) buffer u_block_ssbo {
+  mat4 inner;
+} s;
+
+void f() {
+  s.inner = u.inner;
+  s.inner[1] = u.inner[0];
+  s.inner[1] = u.inner[0].ywxz;
+  s.inner[0][1] = u.inner[1][0];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f();
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_storage.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_storage.wgsl.expected.msl
new file mode 100644
index 0000000..c3e6062
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_storage.wgsl.expected.msl
@@ -0,0 +1,11 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void f(device float4x4* tint_symbol [[buffer(1)]], const constant float4x4* tint_symbol_1 [[buffer(0)]]) {
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[0];
+  (*(tint_symbol))[1] = float4((*(tint_symbol_1))[0]).ywxz;
+  (*(tint_symbol))[0][1] = (*(tint_symbol_1))[1][0];
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_storage.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_storage.wgsl.expected.spvasm
new file mode 100644
index 0000000..ade3b6f
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_storage.wgsl.expected.spvasm
@@ -0,0 +1,65 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 37
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f"
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %s "s"
+               OpName %f "f"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpDecorate %s DescriptorSet 0
+               OpDecorate %s Binding 1
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat4v4float = OpTypeMatrix %v4float 4
+    %u_block = OpTypeStruct %mat4v4float
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_StorageBuffer_u_block = OpTypePointer StorageBuffer %u_block
+          %s = OpVariable %_ptr_StorageBuffer_u_block StorageBuffer
+       %void = OpTypeVoid
+          %9 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_mat4v4float = OpTypePointer StorageBuffer %mat4v4float
+%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_StorageBuffer_v4float = OpTypePointer StorageBuffer %v4float
+         %24 = OpConstantNull %int
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+          %f = OpFunction %void None %9
+         %12 = OpLabel
+         %16 = OpAccessChain %_ptr_StorageBuffer_mat4v4float %s %uint_0
+         %18 = OpAccessChain %_ptr_Uniform_mat4v4float %u %uint_0
+         %19 = OpLoad %mat4v4float %18
+               OpStore %16 %19
+         %23 = OpAccessChain %_ptr_StorageBuffer_v4float %s %uint_0 %int_1
+         %26 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %24
+         %27 = OpLoad %v4float %26
+               OpStore %23 %27
+         %28 = OpAccessChain %_ptr_StorageBuffer_v4float %s %uint_0 %int_1
+         %29 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %24
+         %30 = OpLoad %v4float %29
+         %31 = OpVectorShuffle %v4float %30 %30 1 3 0 2
+               OpStore %28 %31
+         %33 = OpAccessChain %_ptr_StorageBuffer_float %s %uint_0 %24 %int_1
+         %35 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %int_1 %24
+         %36 = OpLoad %float %35
+               OpStore %33 %36
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_storage.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_storage.wgsl.expected.wgsl
new file mode 100644
index 0000000..f21e4d9
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_storage.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> u : mat4x4<f32>;
+
+@group(0) @binding(1) var<storage, read_write> s : mat4x4<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+  s = u;
+  s[1] = u[0];
+  s[1] = u[0].ywxz;
+  s[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_workgroup.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_workgroup.wgsl
new file mode 100644
index 0000000..b629c9e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_workgroup.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(0) var<uniform> u : mat4x4<f32>;
+var<workgroup> w : mat4x4<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+    w = u;
+    w[1] = u[0];
+    w[1] = u[0].ywxz;
+    w[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_workgroup.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_workgroup.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..eb1a4f3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_workgroup.wgsl.expected.dxc.hlsl
@@ -0,0 +1,33 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+groupshared float4x4 w;
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+float4x4 tint_symbol_2(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]), asfloat(buffer[scalar_offset_3 / 4]));
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    w = float4x4((0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx);
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = asfloat(u[0]);
+  w[1] = asfloat(u[0]).ywxz;
+  w[0][1] = asfloat(u[1].x);
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_workgroup.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_workgroup.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..eb1a4f3
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_workgroup.wgsl.expected.fxc.hlsl
@@ -0,0 +1,33 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+groupshared float4x4 w;
+
+struct tint_symbol_1 {
+  uint local_invocation_index : SV_GroupIndex;
+};
+
+float4x4 tint_symbol_2(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]), asfloat(buffer[scalar_offset_3 / 4]));
+}
+
+void f_inner(uint local_invocation_index) {
+  {
+    w = float4x4((0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx);
+  }
+  GroupMemoryBarrierWithGroupSync();
+  w = tint_symbol_2(u, 0u);
+  w[1] = asfloat(u[0]);
+  w[1] = asfloat(u[0]).ywxz;
+  w[0][1] = asfloat(u[1].x);
+}
+
+[numthreads(1, 1, 1)]
+void f(tint_symbol_1 tint_symbol) {
+  f_inner(tint_symbol.local_invocation_index);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_workgroup.wgsl.expected.glsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_workgroup.wgsl.expected.glsl
new file mode 100644
index 0000000..2039627
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_workgroup.wgsl.expected.glsl
@@ -0,0 +1,23 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat4 inner;
+} u;
+
+shared mat4 w;
+void f(uint local_invocation_index) {
+  {
+    w = mat4(vec4(0.0f), vec4(0.0f), vec4(0.0f), vec4(0.0f));
+  }
+  barrier();
+  w = u.inner;
+  w[1] = u.inner[0];
+  w[1] = u.inner[0].ywxz;
+  w[0][1] = u.inner[1][0];
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  f(gl_LocalInvocationIndex);
+  return;
+}
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_workgroup.wgsl.expected.msl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_workgroup.wgsl.expected.msl
new file mode 100644
index 0000000..172975e
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_workgroup.wgsl.expected.msl
@@ -0,0 +1,24 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct tint_symbol_5 {
+  float4x4 w;
+};
+
+void f_inner(uint local_invocation_index, threadgroup float4x4* const tint_symbol, const constant float4x4* const tint_symbol_1) {
+  {
+    *(tint_symbol) = float4x4(float4(0.0f), float4(0.0f), float4(0.0f), float4(0.0f));
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+  *(tint_symbol) = *(tint_symbol_1);
+  (*(tint_symbol))[1] = (*(tint_symbol_1))[0];
+  (*(tint_symbol))[1] = float4((*(tint_symbol_1))[0]).ywxz;
+  (*(tint_symbol))[0][1] = (*(tint_symbol_1))[1][0];
+}
+
+kernel void f(const constant float4x4* tint_symbol_4 [[buffer(0)]], threadgroup tint_symbol_5* tint_symbol_3 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup float4x4* const tint_symbol_2 = &((*(tint_symbol_3)).w);
+  f_inner(local_invocation_index, tint_symbol_2, tint_symbol_4);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_workgroup.wgsl.expected.spvasm b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_workgroup.wgsl.expected.spvasm
new file mode 100644
index 0000000..d8f1b17
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_workgroup.wgsl.expected.spvasm
@@ -0,0 +1,80 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 47
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %f "f" %local_invocation_index_1
+               OpExecutionMode %f LocalSize 1 1 1
+               OpName %local_invocation_index_1 "local_invocation_index_1"
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %w "w"
+               OpName %f_inner "f_inner"
+               OpName %local_invocation_index "local_invocation_index"
+               OpName %f "f"
+               OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat4v4float = OpTypeMatrix %v4float 4
+    %u_block = OpTypeStruct %mat4v4float
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+%_ptr_Workgroup_mat4v4float = OpTypePointer Workgroup %mat4v4float
+          %w = OpVariable %_ptr_Workgroup_mat4v4float Workgroup
+       %void = OpTypeVoid
+         %12 = OpTypeFunction %void %uint
+         %17 = OpConstantNull %mat4v4float
+     %uint_2 = OpConstant %uint 2
+   %uint_264 = OpConstant %uint 264
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%_ptr_Workgroup_v4float = OpTypePointer Workgroup %v4float
+         %29 = OpConstantNull %int
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+%_ptr_Workgroup_float = OpTypePointer Workgroup %float
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+         %42 = OpTypeFunction %void
+    %f_inner = OpFunction %void None %12
+%local_invocation_index = OpFunctionParameter %uint
+         %16 = OpLabel
+               OpStore %w %17
+               OpControlBarrier %uint_2 %uint_2 %uint_264
+         %23 = OpAccessChain %_ptr_Uniform_mat4v4float %u %uint_0
+         %24 = OpLoad %mat4v4float %23
+               OpStore %w %24
+         %28 = OpAccessChain %_ptr_Workgroup_v4float %w %int_1
+         %31 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %29
+         %32 = OpLoad %v4float %31
+               OpStore %28 %32
+         %33 = OpAccessChain %_ptr_Workgroup_v4float %w %int_1
+         %34 = OpAccessChain %_ptr_Uniform_v4float %u %uint_0 %29
+         %35 = OpLoad %v4float %34
+         %36 = OpVectorShuffle %v4float %35 %35 1 3 0 2
+               OpStore %33 %36
+         %38 = OpAccessChain %_ptr_Workgroup_float %w %29 %int_1
+         %40 = OpAccessChain %_ptr_Uniform_float %u %uint_0 %int_1 %29
+         %41 = OpLoad %float %40
+               OpStore %38 %41
+               OpReturn
+               OpFunctionEnd
+          %f = OpFunction %void None %42
+         %44 = OpLabel
+         %46 = OpLoad %uint %local_invocation_index_1
+         %45 = OpFunctionCall %void %f_inner %46
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_workgroup.wgsl.expected.wgsl b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_workgroup.wgsl.expected.wgsl
new file mode 100644
index 0000000..5bc17b2
--- /dev/null
+++ b/test/tint/buffer/uniform/std140/unnested/mat4x4_f32/to_workgroup.wgsl.expected.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(0) var<uniform> u : mat4x4<f32>;
+
+var<workgroup> w : mat4x4<f32>;
+
+@compute @workgroup_size(1)
+fn f() {
+  w = u;
+  w[1] = u[0];
+  w[1] = u[0].ywxz;
+  w[0][1] = u[1][0];
+}
diff --git a/test/tint/buffer/uniform/types/array.wgsl b/test/tint/buffer/uniform/types/array.wgsl
deleted file mode 100644
index 90a400c..0000000
--- a/test/tint/buffer/uniform/types/array.wgsl
+++ /dev/null
@@ -1,7 +0,0 @@
-@group(0) @binding(0)
-var<uniform> u : array<vec4<f32>, 4>;
-
-@compute @workgroup_size(1)
-fn main() {
-  let x = u;
-}
diff --git a/test/tint/buffer/uniform/types/array.wgsl.expected.glsl b/test/tint/buffer/uniform/types/array.wgsl.expected.glsl
deleted file mode 100644
index c3f6dce..0000000
--- a/test/tint/buffer/uniform/types/array.wgsl.expected.glsl
+++ /dev/null
@@ -1,15 +0,0 @@
-#version 310 es
-
-layout(binding = 0, std140) uniform u_block_ubo {
-  vec4 inner[4];
-} u;
-
-void tint_symbol() {
-  vec4 x[4] = u.inner;
-}
-
-layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
-void main() {
-  tint_symbol();
-  return;
-}
diff --git a/test/tint/buffer/uniform/types/array.wgsl.expected.msl b/test/tint/buffer/uniform/types/array.wgsl.expected.msl
deleted file mode 100644
index 730f4b1..0000000
--- a/test/tint/buffer/uniform/types/array.wgsl.expected.msl
+++ /dev/null
@@ -1,21 +0,0 @@
-#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];
-};
-
-kernel void tint_symbol(const constant tint_array<float4, 4>* tint_symbol_1 [[buffer(0)]]) {
-  tint_array<float4, 4> const x = *(tint_symbol_1);
-  return;
-}
-
diff --git a/test/tint/buffer/uniform/types/array.wgsl.expected.spvasm b/test/tint/buffer/uniform/types/array.wgsl.expected.spvasm
deleted file mode 100644
index ef26f1d..0000000
--- a/test/tint/buffer/uniform/types/array.wgsl.expected.spvasm
+++ /dev/null
@@ -1,37 +0,0 @@
-; SPIR-V
-; Version: 1.3
-; Generator: Google Tint Compiler; 0
-; Bound: 17
-; Schema: 0
-               OpCapability Shader
-               OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %main "main"
-               OpExecutionMode %main LocalSize 1 1 1
-               OpName %u_block "u_block"
-               OpMemberName %u_block 0 "inner"
-               OpName %u "u"
-               OpName %main "main"
-               OpDecorate %u_block Block
-               OpMemberDecorate %u_block 0 Offset 0
-               OpDecorate %_arr_v4float_uint_4 ArrayStride 16
-               OpDecorate %u NonWritable
-               OpDecorate %u DescriptorSet 0
-               OpDecorate %u Binding 0
-      %float = OpTypeFloat 32
-    %v4float = OpTypeVector %float 4
-       %uint = OpTypeInt 32 0
-     %uint_4 = OpConstant %uint 4
-%_arr_v4float_uint_4 = OpTypeArray %v4float %uint_4
-    %u_block = OpTypeStruct %_arr_v4float_uint_4
-%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
-          %u = OpVariable %_ptr_Uniform_u_block Uniform
-       %void = OpTypeVoid
-          %9 = OpTypeFunction %void
-     %uint_0 = OpConstant %uint 0
-%_ptr_Uniform__arr_v4float_uint_4 = OpTypePointer Uniform %_arr_v4float_uint_4
-       %main = OpFunction %void None %9
-         %12 = OpLabel
-         %15 = OpAccessChain %_ptr_Uniform__arr_v4float_uint_4 %u %uint_0
-         %16 = OpLoad %_arr_v4float_uint_4 %15
-               OpReturn
-               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/types/array.wgsl.expected.wgsl b/test/tint/buffer/uniform/types/array.wgsl.expected.wgsl
deleted file mode 100644
index 8c2b5f0..0000000
--- a/test/tint/buffer/uniform/types/array.wgsl.expected.wgsl
+++ /dev/null
@@ -1,6 +0,0 @@
-@group(0) @binding(0) var<uniform> u : array<vec4<f32>, 4>;
-
-@compute @workgroup_size(1)
-fn main() {
-  let x = u;
-}
diff --git a/test/tint/buffer/uniform/types/f16.wgsl b/test/tint/buffer/uniform/types/f16.wgsl
new file mode 100644
index 0000000..6b0d2c8
--- /dev/null
+++ b/test/tint/buffer/uniform/types/f16.wgsl
@@ -0,0 +1,9 @@
+enable f16;
+
+@group(0) @binding(0)
+var<uniform> u : f16;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/f16.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/types/f16.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..5ced784
--- /dev/null
+++ b/test/tint/buffer/uniform/types/f16.wgsl.expected.dxc.hlsl
@@ -0,0 +1,9 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+[numthreads(1, 1, 1)]
+void main() {
+  const float16_t x = float16_t(f16tof32(((u[0].x) & 0xFFFF)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/f16.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/types/f16.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..063ca53
--- /dev/null
+++ b/test/tint/buffer/uniform/types/f16.wgsl.expected.fxc.hlsl
@@ -0,0 +1,14 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+[numthreads(1, 1, 1)]
+void main() {
+  const float16_t x = float16_t(f16tof32(((u[0].x) & 0xFFFF)));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001B3B36433A0(7,9-17): error X3000: unrecognized identifier 'float16_t'
+
diff --git a/test/tint/buffer/uniform/types/f16.wgsl.expected.glsl b/test/tint/buffer/uniform/types/f16.wgsl.expected.glsl
new file mode 100644
index 0000000..079f7c1
--- /dev/null
+++ b/test/tint/buffer/uniform/types/f16.wgsl.expected.glsl
@@ -0,0 +1,16 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  float16_t inner;
+} u;
+
+void tint_symbol() {
+  float16_t x = u.inner;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol();
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/f16.wgsl.expected.msl b/test/tint/buffer/uniform/types/f16.wgsl.expected.msl
new file mode 100644
index 0000000..e48371e
--- /dev/null
+++ b/test/tint/buffer/uniform/types/f16.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(const constant half* tint_symbol_1 [[buffer(0)]]) {
+  half const x = *(tint_symbol_1);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/types/f16.wgsl.expected.spvasm b/test/tint/buffer/uniform/types/f16.wgsl.expected.spvasm
new file mode 100644
index 0000000..1765e3b
--- /dev/null
+++ b/test/tint/buffer/uniform/types/f16.wgsl.expected.spvasm
@@ -0,0 +1,37 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 14
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %main "main"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %half = OpTypeFloat 16
+    %u_block = OpTypeStruct %half
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+          %5 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_half = OpTypePointer Uniform %half
+       %main = OpFunction %void None %5
+          %8 = OpLabel
+         %12 = OpAccessChain %_ptr_Uniform_half %u %uint_0
+         %13 = OpLoad %half %12
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/types/f16.wgsl.expected.wgsl b/test/tint/buffer/uniform/types/f16.wgsl.expected.wgsl
new file mode 100644
index 0000000..671d079
--- /dev/null
+++ b/test/tint/buffer/uniform/types/f16.wgsl.expected.wgsl
@@ -0,0 +1,8 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : f16;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/mat2x2_f16.wgsl b/test/tint/buffer/uniform/types/mat2x2_f16.wgsl
new file mode 100644
index 0000000..78602cc
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat2x2_f16.wgsl
@@ -0,0 +1,9 @@
+enable f16;
+
+@group(0) @binding(0)
+var<uniform> u : mat2x2<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/mat2x2_f16.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/types/mat2x2_f16.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..cb72d73
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat2x2_f16.wgsl.expected.dxc.hlsl
@@ -0,0 +1,17 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+matrix<float16_t, 2, 2> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  return matrix<float16_t, 2, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  const matrix<float16_t, 2, 2> x = tint_symbol(u, 0u);
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/mat2x2_f16.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/types/mat2x2_f16.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..f5360c9
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat2x2_f16.wgsl.expected.fxc.hlsl
@@ -0,0 +1,22 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+matrix<float16_t, 2, 2> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  return matrix<float16_t, 2, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  const matrix<float16_t, 2, 2> x = tint_symbol(u, 0u);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000017F74BE8F50(5,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/types/mat2x2_f16.wgsl.expected.glsl b/test/tint/buffer/uniform/types/mat2x2_f16.wgsl.expected.glsl
new file mode 100644
index 0000000..2bfde1c
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat2x2_f16.wgsl.expected.glsl
@@ -0,0 +1,21 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec2 inner_0;
+  f16vec2 inner_1;
+} u;
+
+f16mat2 load_u_inner() {
+  return f16mat2(u.inner_0, u.inner_1);
+}
+
+void tint_symbol() {
+  f16mat2 x = load_u_inner();
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol();
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/mat2x2_f16.wgsl.expected.msl b/test/tint/buffer/uniform/types/mat2x2_f16.wgsl.expected.msl
new file mode 100644
index 0000000..ada512c
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat2x2_f16.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(const constant half2x2* tint_symbol_1 [[buffer(0)]]) {
+  half2x2 const x = *(tint_symbol_1);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/types/mat2x2_f16.wgsl.expected.spvasm b/test/tint/buffer/uniform/types/mat2x2_f16.wgsl.expected.spvasm
new file mode 100644
index 0000000..a350fc2
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat2x2_f16.wgsl.expected.spvasm
@@ -0,0 +1,52 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 27
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpName %u "u"
+               OpName %load_u_inner "load_u_inner"
+               OpName %main "main"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 4
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+%u_block_std140 = OpTypeStruct %v2half %v2half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat2v2half = OpTypeMatrix %v2half 2
+          %6 = OpTypeFunction %mat2v2half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+     %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %22 = OpTypeFunction %void
+%load_u_inner = OpFunction %mat2v2half None %6
+          %9 = OpLabel
+         %15 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0
+         %16 = OpLoad %v2half %15
+         %19 = OpAccessChain %_ptr_Uniform_v2half %u %uint_1
+         %20 = OpLoad %v2half %19
+         %21 = OpCompositeConstruct %mat2v2half %16 %20
+               OpReturnValue %21
+               OpFunctionEnd
+       %main = OpFunction %void None %22
+         %25 = OpLabel
+         %26 = OpFunctionCall %mat2v2half %load_u_inner
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/types/mat2x2_f16.wgsl.expected.wgsl b/test/tint/buffer/uniform/types/mat2x2_f16.wgsl.expected.wgsl
new file mode 100644
index 0000000..b6eac28
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat2x2_f16.wgsl.expected.wgsl
@@ -0,0 +1,8 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat2x2<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/mat2x2.wgsl b/test/tint/buffer/uniform/types/mat2x2_f32.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/types/mat2x2.wgsl
rename to test/tint/buffer/uniform/types/mat2x2_f32.wgsl
diff --git a/test/tint/buffer/uniform/types/mat2x2.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/types/mat2x2_f32.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/types/mat2x2.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/uniform/types/mat2x2_f32.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/uniform/types/mat2x2.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/types/mat2x2_f32.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/types/mat2x2.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/uniform/types/mat2x2_f32.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/uniform/types/mat2x2.wgsl.expected.glsl b/test/tint/buffer/uniform/types/mat2x2_f32.wgsl.expected.glsl
similarity index 100%
rename from test/tint/buffer/uniform/types/mat2x2.wgsl.expected.glsl
rename to test/tint/buffer/uniform/types/mat2x2_f32.wgsl.expected.glsl
diff --git a/test/tint/buffer/uniform/types/mat2x2.wgsl.expected.msl b/test/tint/buffer/uniform/types/mat2x2_f32.wgsl.expected.msl
similarity index 100%
rename from test/tint/buffer/uniform/types/mat2x2.wgsl.expected.msl
rename to test/tint/buffer/uniform/types/mat2x2_f32.wgsl.expected.msl
diff --git a/test/tint/buffer/uniform/types/mat2x2.wgsl.expected.spvasm b/test/tint/buffer/uniform/types/mat2x2_f32.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/uniform/types/mat2x2.wgsl.expected.spvasm
rename to test/tint/buffer/uniform/types/mat2x2_f32.wgsl.expected.spvasm
diff --git a/test/tint/buffer/uniform/types/mat2x2.wgsl.expected.wgsl b/test/tint/buffer/uniform/types/mat2x2_f32.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/types/mat2x2.wgsl.expected.wgsl
rename to test/tint/buffer/uniform/types/mat2x2_f32.wgsl.expected.wgsl
diff --git a/test/tint/buffer/uniform/types/mat2x3_f16.wgsl b/test/tint/buffer/uniform/types/mat2x3_f16.wgsl
new file mode 100644
index 0000000..9b92a38
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat2x3_f16.wgsl
@@ -0,0 +1,9 @@
+enable f16;
+
+@group(0) @binding(0)
+var<uniform> u : mat2x3<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/mat2x3_f16.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/types/mat2x3_f16.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..ee623a0
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat2x3_f16.wgsl.expected.dxc.hlsl
@@ -0,0 +1,23 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+matrix<float16_t, 2, 3> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  const matrix<float16_t, 2, 3> x = tint_symbol(u, 0u);
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/mat2x3_f16.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/types/mat2x3_f16.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..cda8557
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat2x3_f16.wgsl.expected.fxc.hlsl
@@ -0,0 +1,28 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+matrix<float16_t, 2, 3> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  return matrix<float16_t, 2, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  const matrix<float16_t, 2, 3> x = tint_symbol(u, 0u);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x00000248395CA260(5,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/types/mat2x3_f16.wgsl.expected.glsl b/test/tint/buffer/uniform/types/mat2x3_f16.wgsl.expected.glsl
new file mode 100644
index 0000000..4e6f41a
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat2x3_f16.wgsl.expected.glsl
@@ -0,0 +1,21 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec3 inner_0;
+  f16vec3 inner_1;
+} u;
+
+f16mat2x3 load_u_inner() {
+  return f16mat2x3(u.inner_0, u.inner_1);
+}
+
+void tint_symbol() {
+  f16mat2x3 x = load_u_inner();
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol();
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/mat2x3_f16.wgsl.expected.msl b/test/tint/buffer/uniform/types/mat2x3_f16.wgsl.expected.msl
new file mode 100644
index 0000000..58a4bff
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat2x3_f16.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(const constant half2x3* tint_symbol_1 [[buffer(0)]]) {
+  half2x3 const x = *(tint_symbol_1);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/types/mat2x3_f16.wgsl.expected.spvasm b/test/tint/buffer/uniform/types/mat2x3_f16.wgsl.expected.spvasm
new file mode 100644
index 0000000..0ed7fbe
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat2x3_f16.wgsl.expected.spvasm
@@ -0,0 +1,52 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 27
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpName %u "u"
+               OpName %load_u_inner "load_u_inner"
+               OpName %main "main"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 8
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+%u_block_std140 = OpTypeStruct %v3half %v3half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat2v3half = OpTypeMatrix %v3half 2
+          %6 = OpTypeFunction %mat2v3half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+     %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %22 = OpTypeFunction %void
+%load_u_inner = OpFunction %mat2v3half None %6
+          %9 = OpLabel
+         %15 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0
+         %16 = OpLoad %v3half %15
+         %19 = OpAccessChain %_ptr_Uniform_v3half %u %uint_1
+         %20 = OpLoad %v3half %19
+         %21 = OpCompositeConstruct %mat2v3half %16 %20
+               OpReturnValue %21
+               OpFunctionEnd
+       %main = OpFunction %void None %22
+         %25 = OpLabel
+         %26 = OpFunctionCall %mat2v3half %load_u_inner
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/types/mat2x3_f16.wgsl.expected.wgsl b/test/tint/buffer/uniform/types/mat2x3_f16.wgsl.expected.wgsl
new file mode 100644
index 0000000..73c789b
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat2x3_f16.wgsl.expected.wgsl
@@ -0,0 +1,8 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat2x3<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/mat2x3.wgsl b/test/tint/buffer/uniform/types/mat2x3_f32.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/types/mat2x3.wgsl
rename to test/tint/buffer/uniform/types/mat2x3_f32.wgsl
diff --git a/test/tint/buffer/uniform/types/mat2x3.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/types/mat2x3_f32.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/types/mat2x3.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/uniform/types/mat2x3_f32.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/uniform/types/mat2x3.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/types/mat2x3_f32.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/types/mat2x3.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/uniform/types/mat2x3_f32.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/uniform/types/mat2x3.wgsl.expected.glsl b/test/tint/buffer/uniform/types/mat2x3_f32.wgsl.expected.glsl
similarity index 100%
rename from test/tint/buffer/uniform/types/mat2x3.wgsl.expected.glsl
rename to test/tint/buffer/uniform/types/mat2x3_f32.wgsl.expected.glsl
diff --git a/test/tint/buffer/uniform/types/mat2x3.wgsl.expected.msl b/test/tint/buffer/uniform/types/mat2x3_f32.wgsl.expected.msl
similarity index 100%
rename from test/tint/buffer/uniform/types/mat2x3.wgsl.expected.msl
rename to test/tint/buffer/uniform/types/mat2x3_f32.wgsl.expected.msl
diff --git a/test/tint/buffer/uniform/types/mat2x3.wgsl.expected.spvasm b/test/tint/buffer/uniform/types/mat2x3_f32.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/uniform/types/mat2x3.wgsl.expected.spvasm
rename to test/tint/buffer/uniform/types/mat2x3_f32.wgsl.expected.spvasm
diff --git a/test/tint/buffer/uniform/types/mat2x3.wgsl.expected.wgsl b/test/tint/buffer/uniform/types/mat2x3_f32.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/types/mat2x3.wgsl.expected.wgsl
rename to test/tint/buffer/uniform/types/mat2x3_f32.wgsl.expected.wgsl
diff --git a/test/tint/buffer/uniform/types/mat2x4_f16.wgsl b/test/tint/buffer/uniform/types/mat2x4_f16.wgsl
new file mode 100644
index 0000000..b6b79c5
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat2x4_f16.wgsl
@@ -0,0 +1,9 @@
+enable f16;
+
+@group(0) @binding(0)
+var<uniform> u : mat2x4<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/mat2x4_f16.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/types/mat2x4_f16.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..c891507
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat2x4_f16.wgsl.expected.dxc.hlsl
@@ -0,0 +1,23 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+matrix<float16_t, 2, 4> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  const matrix<float16_t, 2, 4> x = tint_symbol(u, 0u);
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/mat2x4_f16.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/types/mat2x4_f16.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..8f306c1
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat2x4_f16.wgsl.expected.fxc.hlsl
@@ -0,0 +1,28 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+matrix<float16_t, 2, 4> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  const matrix<float16_t, 2, 4> x = tint_symbol(u, 0u);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000010C86099F60(5,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/types/mat2x4_f16.wgsl.expected.glsl b/test/tint/buffer/uniform/types/mat2x4_f16.wgsl.expected.glsl
new file mode 100644
index 0000000..5a472a1
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat2x4_f16.wgsl.expected.glsl
@@ -0,0 +1,21 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec4 inner_0;
+  f16vec4 inner_1;
+} u;
+
+f16mat2x4 load_u_inner() {
+  return f16mat2x4(u.inner_0, u.inner_1);
+}
+
+void tint_symbol() {
+  f16mat2x4 x = load_u_inner();
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol();
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/mat2x4_f16.wgsl.expected.msl b/test/tint/buffer/uniform/types/mat2x4_f16.wgsl.expected.msl
new file mode 100644
index 0000000..932aa83
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat2x4_f16.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(const constant half2x4* tint_symbol_1 [[buffer(0)]]) {
+  half2x4 const x = *(tint_symbol_1);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/types/mat2x4_f16.wgsl.expected.spvasm b/test/tint/buffer/uniform/types/mat2x4_f16.wgsl.expected.spvasm
new file mode 100644
index 0000000..6ffde9e
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat2x4_f16.wgsl.expected.spvasm
@@ -0,0 +1,52 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 27
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpName %u "u"
+               OpName %load_u_inner "load_u_inner"
+               OpName %main "main"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 8
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+%u_block_std140 = OpTypeStruct %v4half %v4half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat2v4half = OpTypeMatrix %v4half 2
+          %6 = OpTypeFunction %mat2v4half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+     %uint_1 = OpConstant %uint 1
+       %void = OpTypeVoid
+         %22 = OpTypeFunction %void
+%load_u_inner = OpFunction %mat2v4half None %6
+          %9 = OpLabel
+         %15 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0
+         %16 = OpLoad %v4half %15
+         %19 = OpAccessChain %_ptr_Uniform_v4half %u %uint_1
+         %20 = OpLoad %v4half %19
+         %21 = OpCompositeConstruct %mat2v4half %16 %20
+               OpReturnValue %21
+               OpFunctionEnd
+       %main = OpFunction %void None %22
+         %25 = OpLabel
+         %26 = OpFunctionCall %mat2v4half %load_u_inner
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/types/mat2x4_f16.wgsl.expected.wgsl b/test/tint/buffer/uniform/types/mat2x4_f16.wgsl.expected.wgsl
new file mode 100644
index 0000000..d6ff764
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat2x4_f16.wgsl.expected.wgsl
@@ -0,0 +1,8 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat2x4<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/mat2x4_f32.wgsl b/test/tint/buffer/uniform/types/mat2x4_f32.wgsl
new file mode 100644
index 0000000..1847020
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat2x4_f32.wgsl
@@ -0,0 +1,7 @@
+@group(0) @binding(0)
+var<uniform> u : mat2x4<f32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/mat2x4_f32.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/types/mat2x4_f32.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..cead0e2
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat2x4_f32.wgsl.expected.dxc.hlsl
@@ -0,0 +1,15 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+
+float2x4 tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  const float2x4 x = tint_symbol(u, 0u);
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/mat2x4_f32.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/types/mat2x4_f32.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..cead0e2
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat2x4_f32.wgsl.expected.fxc.hlsl
@@ -0,0 +1,15 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+
+float2x4 tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  const float2x4 x = tint_symbol(u, 0u);
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/mat2x4_f32.wgsl.expected.glsl b/test/tint/buffer/uniform/types/mat2x4_f32.wgsl.expected.glsl
new file mode 100644
index 0000000..c476a7f
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat2x4_f32.wgsl.expected.glsl
@@ -0,0 +1,15 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat2x4 inner;
+} u;
+
+void tint_symbol() {
+  mat2x4 x = u.inner;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol();
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/mat2x4_f32.wgsl.expected.msl b/test/tint/buffer/uniform/types/mat2x4_f32.wgsl.expected.msl
new file mode 100644
index 0000000..b5c1099
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat2x4_f32.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(const constant float2x4* tint_symbol_1 [[buffer(0)]]) {
+  float2x4 const x = *(tint_symbol_1);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/types/mat2x4_f32.wgsl.expected.spvasm b/test/tint/buffer/uniform/types/mat2x4_f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..9da8a2f
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat2x4_f32.wgsl.expected.spvasm
@@ -0,0 +1,37 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 16
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %main "main"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat2v4float = OpTypeMatrix %v4float 2
+    %u_block = OpTypeStruct %mat2v4float
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+          %7 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_mat2v4float = OpTypePointer Uniform %mat2v4float
+       %main = OpFunction %void None %7
+         %10 = OpLabel
+         %14 = OpAccessChain %_ptr_Uniform_mat2v4float %u %uint_0
+         %15 = OpLoad %mat2v4float %14
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/types/mat2x4_f32.wgsl.expected.wgsl b/test/tint/buffer/uniform/types/mat2x4_f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..368e8b0
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat2x4_f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+@group(0) @binding(0) var<uniform> u : mat2x4<f32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/mat3x2_f16.wgsl b/test/tint/buffer/uniform/types/mat3x2_f16.wgsl
new file mode 100644
index 0000000..5f158a3
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat3x2_f16.wgsl
@@ -0,0 +1,9 @@
+enable f16;
+
+@group(0) @binding(0)
+var<uniform> u : mat3x2<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/mat3x2_f16.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/types/mat3x2_f16.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..704945f
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat3x2_f16.wgsl.expected.dxc.hlsl
@@ -0,0 +1,19 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+matrix<float16_t, 3, 2> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  return matrix<float16_t, 3, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  const matrix<float16_t, 3, 2> x = tint_symbol(u, 0u);
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/mat3x2_f16.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/types/mat3x2_f16.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..32c5415
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat3x2_f16.wgsl.expected.fxc.hlsl
@@ -0,0 +1,24 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+matrix<float16_t, 3, 2> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  return matrix<float16_t, 3, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  const matrix<float16_t, 3, 2> x = tint_symbol(u, 0u);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000014294788E00(5,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/types/mat3x2_f16.wgsl.expected.glsl b/test/tint/buffer/uniform/types/mat3x2_f16.wgsl.expected.glsl
new file mode 100644
index 0000000..766b477
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat3x2_f16.wgsl.expected.glsl
@@ -0,0 +1,22 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec2 inner_0;
+  f16vec2 inner_1;
+  f16vec2 inner_2;
+} u;
+
+f16mat3x2 load_u_inner() {
+  return f16mat3x2(u.inner_0, u.inner_1, u.inner_2);
+}
+
+void tint_symbol() {
+  f16mat3x2 x = load_u_inner();
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol();
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/mat3x2_f16.wgsl.expected.msl b/test/tint/buffer/uniform/types/mat3x2_f16.wgsl.expected.msl
new file mode 100644
index 0000000..f5c897d
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat3x2_f16.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(const constant half3x2* tint_symbol_1 [[buffer(0)]]) {
+  half3x2 const x = *(tint_symbol_1);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/types/mat3x2_f16.wgsl.expected.spvasm b/test/tint/buffer/uniform/types/mat3x2_f16.wgsl.expected.spvasm
new file mode 100644
index 0000000..a365da4
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat3x2_f16.wgsl.expected.spvasm
@@ -0,0 +1,57 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 31
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpMemberName %u_block_std140 2 "inner_2"
+               OpName %u "u"
+               OpName %load_u_inner "load_u_inner"
+               OpName %main "main"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 4
+               OpMemberDecorate %u_block_std140 2 Offset 8
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+%u_block_std140 = OpTypeStruct %v2half %v2half %v2half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat3v2half = OpTypeMatrix %v2half 3
+          %6 = OpTypeFunction %mat3v2half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+       %void = OpTypeVoid
+         %26 = OpTypeFunction %void
+%load_u_inner = OpFunction %mat3v2half None %6
+          %9 = OpLabel
+         %15 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0
+         %16 = OpLoad %v2half %15
+         %19 = OpAccessChain %_ptr_Uniform_v2half %u %uint_1
+         %20 = OpLoad %v2half %19
+         %23 = OpAccessChain %_ptr_Uniform_v2half %u %uint_2
+         %24 = OpLoad %v2half %23
+         %25 = OpCompositeConstruct %mat3v2half %16 %20 %24
+               OpReturnValue %25
+               OpFunctionEnd
+       %main = OpFunction %void None %26
+         %29 = OpLabel
+         %30 = OpFunctionCall %mat3v2half %load_u_inner
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/types/mat3x2_f16.wgsl.expected.wgsl b/test/tint/buffer/uniform/types/mat3x2_f16.wgsl.expected.wgsl
new file mode 100644
index 0000000..512b9ac
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat3x2_f16.wgsl.expected.wgsl
@@ -0,0 +1,8 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat3x2<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/mat3x2.wgsl b/test/tint/buffer/uniform/types/mat3x2_f32.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/types/mat3x2.wgsl
rename to test/tint/buffer/uniform/types/mat3x2_f32.wgsl
diff --git a/test/tint/buffer/uniform/types/mat3x2.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/types/mat3x2_f32.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/types/mat3x2.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/uniform/types/mat3x2_f32.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/uniform/types/mat3x2.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/types/mat3x2_f32.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/types/mat3x2.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/uniform/types/mat3x2_f32.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/uniform/types/mat3x2.wgsl.expected.glsl b/test/tint/buffer/uniform/types/mat3x2_f32.wgsl.expected.glsl
similarity index 100%
rename from test/tint/buffer/uniform/types/mat3x2.wgsl.expected.glsl
rename to test/tint/buffer/uniform/types/mat3x2_f32.wgsl.expected.glsl
diff --git a/test/tint/buffer/uniform/types/mat3x2.wgsl.expected.msl b/test/tint/buffer/uniform/types/mat3x2_f32.wgsl.expected.msl
similarity index 100%
rename from test/tint/buffer/uniform/types/mat3x2.wgsl.expected.msl
rename to test/tint/buffer/uniform/types/mat3x2_f32.wgsl.expected.msl
diff --git a/test/tint/buffer/uniform/types/mat3x2.wgsl.expected.spvasm b/test/tint/buffer/uniform/types/mat3x2_f32.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/uniform/types/mat3x2.wgsl.expected.spvasm
rename to test/tint/buffer/uniform/types/mat3x2_f32.wgsl.expected.spvasm
diff --git a/test/tint/buffer/uniform/types/mat3x2.wgsl.expected.wgsl b/test/tint/buffer/uniform/types/mat3x2_f32.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/types/mat3x2.wgsl.expected.wgsl
rename to test/tint/buffer/uniform/types/mat3x2_f32.wgsl.expected.wgsl
diff --git a/test/tint/buffer/uniform/types/mat3x3_f16.wgsl b/test/tint/buffer/uniform/types/mat3x3_f16.wgsl
new file mode 100644
index 0000000..967f0cd
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat3x3_f16.wgsl
@@ -0,0 +1,9 @@
+enable f16;
+
+@group(0) @binding(0)
+var<uniform> u : mat3x3<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/mat3x3_f16.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/types/mat3x3_f16.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..04db7e6
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat3x3_f16.wgsl.expected.dxc.hlsl
@@ -0,0 +1,28 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+
+matrix<float16_t, 3, 3> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  return matrix<float16_t, 3, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  const matrix<float16_t, 3, 3> x = tint_symbol(u, 0u);
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/mat3x3_f16.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/types/mat3x3_f16.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..6b5696d
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat3x3_f16.wgsl.expected.fxc.hlsl
@@ -0,0 +1,33 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+
+matrix<float16_t, 3, 3> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  return matrix<float16_t, 3, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  const matrix<float16_t, 3, 3> x = tint_symbol(u, 0u);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x00000231800429A0(5,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/types/mat3x3_f16.wgsl.expected.glsl b/test/tint/buffer/uniform/types/mat3x3_f16.wgsl.expected.glsl
new file mode 100644
index 0000000..17d202d
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat3x3_f16.wgsl.expected.glsl
@@ -0,0 +1,22 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec3 inner_0;
+  f16vec3 inner_1;
+  f16vec3 inner_2;
+} u;
+
+f16mat3 load_u_inner() {
+  return f16mat3(u.inner_0, u.inner_1, u.inner_2);
+}
+
+void tint_symbol() {
+  f16mat3 x = load_u_inner();
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol();
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/mat3x3_f16.wgsl.expected.msl b/test/tint/buffer/uniform/types/mat3x3_f16.wgsl.expected.msl
new file mode 100644
index 0000000..060a4ff
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat3x3_f16.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(const constant half3x3* tint_symbol_1 [[buffer(0)]]) {
+  half3x3 const x = *(tint_symbol_1);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/types/mat3x3_f16.wgsl.expected.spvasm b/test/tint/buffer/uniform/types/mat3x3_f16.wgsl.expected.spvasm
new file mode 100644
index 0000000..044aa6c
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat3x3_f16.wgsl.expected.spvasm
@@ -0,0 +1,57 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 31
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpMemberName %u_block_std140 2 "inner_2"
+               OpName %u "u"
+               OpName %load_u_inner "load_u_inner"
+               OpName %main "main"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 8
+               OpMemberDecorate %u_block_std140 2 Offset 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+%u_block_std140 = OpTypeStruct %v3half %v3half %v3half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat3v3half = OpTypeMatrix %v3half 3
+          %6 = OpTypeFunction %mat3v3half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+       %void = OpTypeVoid
+         %26 = OpTypeFunction %void
+%load_u_inner = OpFunction %mat3v3half None %6
+          %9 = OpLabel
+         %15 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0
+         %16 = OpLoad %v3half %15
+         %19 = OpAccessChain %_ptr_Uniform_v3half %u %uint_1
+         %20 = OpLoad %v3half %19
+         %23 = OpAccessChain %_ptr_Uniform_v3half %u %uint_2
+         %24 = OpLoad %v3half %23
+         %25 = OpCompositeConstruct %mat3v3half %16 %20 %24
+               OpReturnValue %25
+               OpFunctionEnd
+       %main = OpFunction %void None %26
+         %29 = OpLabel
+         %30 = OpFunctionCall %mat3v3half %load_u_inner
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/types/mat3x3_f16.wgsl.expected.wgsl b/test/tint/buffer/uniform/types/mat3x3_f16.wgsl.expected.wgsl
new file mode 100644
index 0000000..c7b7675
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat3x3_f16.wgsl.expected.wgsl
@@ -0,0 +1,8 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat3x3<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/mat3x3_f32.wgsl b/test/tint/buffer/uniform/types/mat3x3_f32.wgsl
new file mode 100644
index 0000000..a67f2fa
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat3x3_f32.wgsl
@@ -0,0 +1,7 @@
+@group(0) @binding(0)
+var<uniform> u : mat3x3<f32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/mat3x3_f32.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/types/mat3x3_f32.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..310ff04
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat3x3_f32.wgsl.expected.dxc.hlsl
@@ -0,0 +1,16 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[3];
+};
+
+float3x3 tint_symbol(uint4 buffer[3], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  const float3x3 x = tint_symbol(u, 0u);
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/mat3x3_f32.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/types/mat3x3_f32.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..310ff04
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat3x3_f32.wgsl.expected.fxc.hlsl
@@ -0,0 +1,16 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[3];
+};
+
+float3x3 tint_symbol(uint4 buffer[3], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  const float3x3 x = tint_symbol(u, 0u);
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/mat3x3_f32.wgsl.expected.glsl b/test/tint/buffer/uniform/types/mat3x3_f32.wgsl.expected.glsl
new file mode 100644
index 0000000..5b15b84
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat3x3_f32.wgsl.expected.glsl
@@ -0,0 +1,15 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat3 inner;
+} u;
+
+void tint_symbol() {
+  mat3 x = u.inner;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol();
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/mat3x3_f32.wgsl.expected.msl b/test/tint/buffer/uniform/types/mat3x3_f32.wgsl.expected.msl
new file mode 100644
index 0000000..328708c
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat3x3_f32.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(const constant float3x3* tint_symbol_1 [[buffer(0)]]) {
+  float3x3 const x = *(tint_symbol_1);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/types/mat3x3_f32.wgsl.expected.spvasm b/test/tint/buffer/uniform/types/mat3x3_f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..18970bc
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat3x3_f32.wgsl.expected.spvasm
@@ -0,0 +1,37 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 16
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %main "main"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+    %u_block = OpTypeStruct %mat3v3float
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+          %7 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_mat3v3float = OpTypePointer Uniform %mat3v3float
+       %main = OpFunction %void None %7
+         %10 = OpLabel
+         %14 = OpAccessChain %_ptr_Uniform_mat3v3float %u %uint_0
+         %15 = OpLoad %mat3v3float %14
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/types/mat3x3_f32.wgsl.expected.wgsl b/test/tint/buffer/uniform/types/mat3x3_f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..e56c0b6
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat3x3_f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+@group(0) @binding(0) var<uniform> u : mat3x3<f32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/mat3x4_f16.wgsl b/test/tint/buffer/uniform/types/mat3x4_f16.wgsl
new file mode 100644
index 0000000..3830f33
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat3x4_f16.wgsl
@@ -0,0 +1,9 @@
+enable f16;
+
+@group(0) @binding(0)
+var<uniform> u : mat3x4<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/mat3x4_f16.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/types/mat3x4_f16.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..a13d689
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat3x4_f16.wgsl.expected.dxc.hlsl
@@ -0,0 +1,28 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+
+matrix<float16_t, 3, 4> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  return matrix<float16_t, 3, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  const matrix<float16_t, 3, 4> x = tint_symbol(u, 0u);
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/mat3x4_f16.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/types/mat3x4_f16.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..b410283
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat3x4_f16.wgsl.expected.fxc.hlsl
@@ -0,0 +1,33 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+
+matrix<float16_t, 3, 4> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  return matrix<float16_t, 3, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  const matrix<float16_t, 3, 4> x = tint_symbol(u, 0u);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001E049208950(5,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/types/mat3x4_f16.wgsl.expected.glsl b/test/tint/buffer/uniform/types/mat3x4_f16.wgsl.expected.glsl
new file mode 100644
index 0000000..2cb7a29
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat3x4_f16.wgsl.expected.glsl
@@ -0,0 +1,22 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec4 inner_0;
+  f16vec4 inner_1;
+  f16vec4 inner_2;
+} u;
+
+f16mat3x4 load_u_inner() {
+  return f16mat3x4(u.inner_0, u.inner_1, u.inner_2);
+}
+
+void tint_symbol() {
+  f16mat3x4 x = load_u_inner();
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol();
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/mat3x4_f16.wgsl.expected.msl b/test/tint/buffer/uniform/types/mat3x4_f16.wgsl.expected.msl
new file mode 100644
index 0000000..e28cf69
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat3x4_f16.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(const constant half3x4* tint_symbol_1 [[buffer(0)]]) {
+  half3x4 const x = *(tint_symbol_1);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/types/mat3x4_f16.wgsl.expected.spvasm b/test/tint/buffer/uniform/types/mat3x4_f16.wgsl.expected.spvasm
new file mode 100644
index 0000000..22a1399
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat3x4_f16.wgsl.expected.spvasm
@@ -0,0 +1,57 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 31
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpMemberName %u_block_std140 2 "inner_2"
+               OpName %u "u"
+               OpName %load_u_inner "load_u_inner"
+               OpName %main "main"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 8
+               OpMemberDecorate %u_block_std140 2 Offset 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+%u_block_std140 = OpTypeStruct %v4half %v4half %v4half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat3v4half = OpTypeMatrix %v4half 3
+          %6 = OpTypeFunction %mat3v4half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+       %void = OpTypeVoid
+         %26 = OpTypeFunction %void
+%load_u_inner = OpFunction %mat3v4half None %6
+          %9 = OpLabel
+         %15 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0
+         %16 = OpLoad %v4half %15
+         %19 = OpAccessChain %_ptr_Uniform_v4half %u %uint_1
+         %20 = OpLoad %v4half %19
+         %23 = OpAccessChain %_ptr_Uniform_v4half %u %uint_2
+         %24 = OpLoad %v4half %23
+         %25 = OpCompositeConstruct %mat3v4half %16 %20 %24
+               OpReturnValue %25
+               OpFunctionEnd
+       %main = OpFunction %void None %26
+         %29 = OpLabel
+         %30 = OpFunctionCall %mat3v4half %load_u_inner
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/types/mat3x4_f16.wgsl.expected.wgsl b/test/tint/buffer/uniform/types/mat3x4_f16.wgsl.expected.wgsl
new file mode 100644
index 0000000..0047e5a
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat3x4_f16.wgsl.expected.wgsl
@@ -0,0 +1,8 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat3x4<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/mat3x4_f32.wgsl b/test/tint/buffer/uniform/types/mat3x4_f32.wgsl
new file mode 100644
index 0000000..ab5dda1
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat3x4_f32.wgsl
@@ -0,0 +1,7 @@
+@group(0) @binding(0)
+var<uniform> u : mat3x4<f32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/mat3x4_f32.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/types/mat3x4_f32.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..4a409e5
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat3x4_f32.wgsl.expected.dxc.hlsl
@@ -0,0 +1,16 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[3];
+};
+
+float3x4 tint_symbol(uint4 buffer[3], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  const float3x4 x = tint_symbol(u, 0u);
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/mat3x4_f32.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/types/mat3x4_f32.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..4a409e5
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat3x4_f32.wgsl.expected.fxc.hlsl
@@ -0,0 +1,16 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[3];
+};
+
+float3x4 tint_symbol(uint4 buffer[3], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  const float3x4 x = tint_symbol(u, 0u);
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/mat3x4_f32.wgsl.expected.glsl b/test/tint/buffer/uniform/types/mat3x4_f32.wgsl.expected.glsl
new file mode 100644
index 0000000..318b5f4
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat3x4_f32.wgsl.expected.glsl
@@ -0,0 +1,15 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat3x4 inner;
+} u;
+
+void tint_symbol() {
+  mat3x4 x = u.inner;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol();
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/mat3x4_f32.wgsl.expected.msl b/test/tint/buffer/uniform/types/mat3x4_f32.wgsl.expected.msl
new file mode 100644
index 0000000..5cebcd4
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat3x4_f32.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(const constant float3x4* tint_symbol_1 [[buffer(0)]]) {
+  float3x4 const x = *(tint_symbol_1);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/types/mat3x4_f32.wgsl.expected.spvasm b/test/tint/buffer/uniform/types/mat3x4_f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..6d7f26a
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat3x4_f32.wgsl.expected.spvasm
@@ -0,0 +1,37 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 16
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %main "main"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%mat3v4float = OpTypeMatrix %v4float 3
+    %u_block = OpTypeStruct %mat3v4float
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+          %7 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_mat3v4float = OpTypePointer Uniform %mat3v4float
+       %main = OpFunction %void None %7
+         %10 = OpLabel
+         %14 = OpAccessChain %_ptr_Uniform_mat3v4float %u %uint_0
+         %15 = OpLoad %mat3v4float %14
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/types/mat3x4_f32.wgsl.expected.wgsl b/test/tint/buffer/uniform/types/mat3x4_f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..97fea4f
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat3x4_f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+@group(0) @binding(0) var<uniform> u : mat3x4<f32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/mat4x2_f16.wgsl b/test/tint/buffer/uniform/types/mat4x2_f16.wgsl
new file mode 100644
index 0000000..04f5a9a
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat4x2_f16.wgsl
@@ -0,0 +1,9 @@
+enable f16;
+
+@group(0) @binding(0)
+var<uniform> u : mat4x2<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/mat4x2_f16.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/types/mat4x2_f16.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..4f03c89
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat4x2_f16.wgsl.expected.dxc.hlsl
@@ -0,0 +1,21 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+matrix<float16_t, 4, 2> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const uint scalar_offset_3 = ((offset + 12u)) / 4;
+  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  const matrix<float16_t, 4, 2> x = tint_symbol(u, 0u);
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/mat4x2_f16.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/types/mat4x2_f16.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..a5f251c
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat4x2_f16.wgsl.expected.fxc.hlsl
@@ -0,0 +1,26 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+matrix<float16_t, 4, 2> tint_symbol(uint4 buffer[1], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint ubo_load = buffer[scalar_offset / 4][scalar_offset % 4];
+  const uint scalar_offset_1 = ((offset + 4u)) / 4;
+  uint ubo_load_1 = buffer[scalar_offset_1 / 4][scalar_offset_1 % 4];
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint ubo_load_2 = buffer[scalar_offset_2 / 4][scalar_offset_2 % 4];
+  const uint scalar_offset_3 = ((offset + 12u)) / 4;
+  uint ubo_load_3 = buffer[scalar_offset_3 / 4][scalar_offset_3 % 4];
+  return matrix<float16_t, 4, 2>(vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_1 & 0xFFFF)), float16_t(f16tof32(ubo_load_1 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_2 & 0xFFFF)), float16_t(f16tof32(ubo_load_2 >> 16))), vector<float16_t, 2>(float16_t(f16tof32(ubo_load_3 & 0xFFFF)), float16_t(f16tof32(ubo_load_3 >> 16))));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  const matrix<float16_t, 4, 2> x = tint_symbol(u, 0u);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000017761DC8170(5,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/types/mat4x2_f16.wgsl.expected.glsl b/test/tint/buffer/uniform/types/mat4x2_f16.wgsl.expected.glsl
new file mode 100644
index 0000000..faa76d2
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat4x2_f16.wgsl.expected.glsl
@@ -0,0 +1,23 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec2 inner_0;
+  f16vec2 inner_1;
+  f16vec2 inner_2;
+  f16vec2 inner_3;
+} u;
+
+f16mat4x2 load_u_inner() {
+  return f16mat4x2(u.inner_0, u.inner_1, u.inner_2, u.inner_3);
+}
+
+void tint_symbol() {
+  f16mat4x2 x = load_u_inner();
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol();
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/mat4x2_f16.wgsl.expected.msl b/test/tint/buffer/uniform/types/mat4x2_f16.wgsl.expected.msl
new file mode 100644
index 0000000..37a617d
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat4x2_f16.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(const constant half4x2* tint_symbol_1 [[buffer(0)]]) {
+  half4x2 const x = *(tint_symbol_1);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/types/mat4x2_f16.wgsl.expected.spvasm b/test/tint/buffer/uniform/types/mat4x2_f16.wgsl.expected.spvasm
new file mode 100644
index 0000000..61763c4
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat4x2_f16.wgsl.expected.spvasm
@@ -0,0 +1,62 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 35
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpMemberName %u_block_std140 2 "inner_2"
+               OpMemberName %u_block_std140 3 "inner_3"
+               OpName %u "u"
+               OpName %load_u_inner "load_u_inner"
+               OpName %main "main"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 4
+               OpMemberDecorate %u_block_std140 2 Offset 8
+               OpMemberDecorate %u_block_std140 3 Offset 12
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+%u_block_std140 = OpTypeStruct %v2half %v2half %v2half %v2half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat4v2half = OpTypeMatrix %v2half 4
+          %6 = OpTypeFunction %mat4v2half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %30 = OpTypeFunction %void
+%load_u_inner = OpFunction %mat4v2half None %6
+          %9 = OpLabel
+         %15 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0
+         %16 = OpLoad %v2half %15
+         %19 = OpAccessChain %_ptr_Uniform_v2half %u %uint_1
+         %20 = OpLoad %v2half %19
+         %23 = OpAccessChain %_ptr_Uniform_v2half %u %uint_2
+         %24 = OpLoad %v2half %23
+         %27 = OpAccessChain %_ptr_Uniform_v2half %u %uint_3
+         %28 = OpLoad %v2half %27
+         %29 = OpCompositeConstruct %mat4v2half %16 %20 %24 %28
+               OpReturnValue %29
+               OpFunctionEnd
+       %main = OpFunction %void None %30
+         %33 = OpLabel
+         %34 = OpFunctionCall %mat4v2half %load_u_inner
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/types/mat4x2_f16.wgsl.expected.wgsl b/test/tint/buffer/uniform/types/mat4x2_f16.wgsl.expected.wgsl
new file mode 100644
index 0000000..fe2c66b
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat4x2_f16.wgsl.expected.wgsl
@@ -0,0 +1,8 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat4x2<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/mat4x2_f32.wgsl b/test/tint/buffer/uniform/types/mat4x2_f32.wgsl
new file mode 100644
index 0000000..94291b1
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat4x2_f32.wgsl
@@ -0,0 +1,7 @@
+@group(0) @binding(0)
+var<uniform> u : mat4x2<f32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/mat4x2_f32.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/types/mat4x2_f32.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..a6278e9
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat4x2_f32.wgsl.expected.dxc.hlsl
@@ -0,0 +1,21 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+
+float4x2 tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_3 / 4];
+  return float4x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)), asfloat(((scalar_offset_3 & 2) ? ubo_load_3.zw : ubo_load_3.xy)));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  const float4x2 x = tint_symbol(u, 0u);
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/mat4x2_f32.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/types/mat4x2_f32.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..a6278e9
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat4x2_f32.wgsl.expected.fxc.hlsl
@@ -0,0 +1,21 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+
+float4x2 tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load = buffer[scalar_offset / 4];
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset_1 / 4];
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_2 = buffer[scalar_offset_2 / 4];
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_3 / 4];
+  return float4x2(asfloat(((scalar_offset & 2) ? ubo_load.zw : ubo_load.xy)), asfloat(((scalar_offset_1 & 2) ? ubo_load_1.zw : ubo_load_1.xy)), asfloat(((scalar_offset_2 & 2) ? ubo_load_2.zw : ubo_load_2.xy)), asfloat(((scalar_offset_3 & 2) ? ubo_load_3.zw : ubo_load_3.xy)));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  const float4x2 x = tint_symbol(u, 0u);
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/mat4x2_f32.wgsl.expected.glsl b/test/tint/buffer/uniform/types/mat4x2_f32.wgsl.expected.glsl
new file mode 100644
index 0000000..aaaf7e5
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat4x2_f32.wgsl.expected.glsl
@@ -0,0 +1,22 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  vec2 inner_0;
+  vec2 inner_1;
+  vec2 inner_2;
+  vec2 inner_3;
+} u;
+
+mat4x2 load_u_inner() {
+  return mat4x2(u.inner_0, u.inner_1, u.inner_2, u.inner_3);
+}
+
+void tint_symbol() {
+  mat4x2 x = load_u_inner();
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol();
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/mat4x2_f32.wgsl.expected.msl b/test/tint/buffer/uniform/types/mat4x2_f32.wgsl.expected.msl
new file mode 100644
index 0000000..9c68fb1
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat4x2_f32.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(const constant float4x2* tint_symbol_1 [[buffer(0)]]) {
+  float4x2 const x = *(tint_symbol_1);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/types/mat4x2_f32.wgsl.expected.spvasm b/test/tint/buffer/uniform/types/mat4x2_f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..c9e3140
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat4x2_f32.wgsl.expected.spvasm
@@ -0,0 +1,58 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 35
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpMemberName %u_block_std140 2 "inner_2"
+               OpMemberName %u_block_std140 3 "inner_3"
+               OpName %u "u"
+               OpName %load_u_inner "load_u_inner"
+               OpName %main "main"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 8
+               OpMemberDecorate %u_block_std140 2 Offset 16
+               OpMemberDecorate %u_block_std140 3 Offset 24
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+      %float = OpTypeFloat 32
+    %v2float = OpTypeVector %float 2
+%u_block_std140 = OpTypeStruct %v2float %v2float %v2float %v2float
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+%mat4v2float = OpTypeMatrix %v2float 4
+          %6 = OpTypeFunction %mat4v2float
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %30 = OpTypeFunction %void
+%load_u_inner = OpFunction %mat4v2float None %6
+          %9 = OpLabel
+         %15 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0
+         %16 = OpLoad %v2float %15
+         %19 = OpAccessChain %_ptr_Uniform_v2float %u %uint_1
+         %20 = OpLoad %v2float %19
+         %23 = OpAccessChain %_ptr_Uniform_v2float %u %uint_2
+         %24 = OpLoad %v2float %23
+         %27 = OpAccessChain %_ptr_Uniform_v2float %u %uint_3
+         %28 = OpLoad %v2float %27
+         %29 = OpCompositeConstruct %mat4v2float %16 %20 %24 %28
+               OpReturnValue %29
+               OpFunctionEnd
+       %main = OpFunction %void None %30
+         %33 = OpLabel
+         %34 = OpFunctionCall %mat4v2float %load_u_inner
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/types/mat4x2_f32.wgsl.expected.wgsl b/test/tint/buffer/uniform/types/mat4x2_f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..4dee7ee
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat4x2_f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+@group(0) @binding(0) var<uniform> u : mat4x2<f32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/mat4x3_f16.wgsl b/test/tint/buffer/uniform/types/mat4x3_f16.wgsl
new file mode 100644
index 0000000..526ef36
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat4x3_f16.wgsl
@@ -0,0 +1,9 @@
+enable f16;
+
+@group(0) @binding(0)
+var<uniform> u : mat4x3<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/mat4x3_f16.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/types/mat4x3_f16.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..5acbef9
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat4x3_f16.wgsl.expected.dxc.hlsl
@@ -0,0 +1,33 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+
+matrix<float16_t, 4, 3> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  const matrix<float16_t, 4, 3> x = tint_symbol(u, 0u);
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/mat4x3_f16.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/types/mat4x3_f16.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..804c81e
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat4x3_f16.wgsl.expected.fxc.hlsl
@@ -0,0 +1,38 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+
+matrix<float16_t, 4, 3> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  float16_t ubo_load_2_y = f16tof32(ubo_load_2[0] >> 16);
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  float16_t ubo_load_6_y = f16tof32(ubo_load_6[0] >> 16);
+  return matrix<float16_t, 4, 3>(vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]), vector<float16_t, 3>(ubo_load_2_xz[0], ubo_load_2_y, ubo_load_2_xz[1]), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), vector<float16_t, 3>(ubo_load_6_xz[0], ubo_load_6_y, ubo_load_6_xz[1]));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  const matrix<float16_t, 4, 3> x = tint_symbol(u, 0u);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x00000184D1079D40(5,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/types/mat4x3_f16.wgsl.expected.glsl b/test/tint/buffer/uniform/types/mat4x3_f16.wgsl.expected.glsl
new file mode 100644
index 0000000..03ff053
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat4x3_f16.wgsl.expected.glsl
@@ -0,0 +1,23 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec3 inner_0;
+  f16vec3 inner_1;
+  f16vec3 inner_2;
+  f16vec3 inner_3;
+} u;
+
+f16mat4x3 load_u_inner() {
+  return f16mat4x3(u.inner_0, u.inner_1, u.inner_2, u.inner_3);
+}
+
+void tint_symbol() {
+  f16mat4x3 x = load_u_inner();
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol();
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/mat4x3_f16.wgsl.expected.msl b/test/tint/buffer/uniform/types/mat4x3_f16.wgsl.expected.msl
new file mode 100644
index 0000000..199ceee
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat4x3_f16.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(const constant half4x3* tint_symbol_1 [[buffer(0)]]) {
+  half4x3 const x = *(tint_symbol_1);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/types/mat4x3_f16.wgsl.expected.spvasm b/test/tint/buffer/uniform/types/mat4x3_f16.wgsl.expected.spvasm
new file mode 100644
index 0000000..1d0fe82
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat4x3_f16.wgsl.expected.spvasm
@@ -0,0 +1,62 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 35
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpMemberName %u_block_std140 2 "inner_2"
+               OpMemberName %u_block_std140 3 "inner_3"
+               OpName %u "u"
+               OpName %load_u_inner "load_u_inner"
+               OpName %main "main"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 8
+               OpMemberDecorate %u_block_std140 2 Offset 16
+               OpMemberDecorate %u_block_std140 3 Offset 24
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+%u_block_std140 = OpTypeStruct %v3half %v3half %v3half %v3half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat4v3half = OpTypeMatrix %v3half 4
+          %6 = OpTypeFunction %mat4v3half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %30 = OpTypeFunction %void
+%load_u_inner = OpFunction %mat4v3half None %6
+          %9 = OpLabel
+         %15 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0
+         %16 = OpLoad %v3half %15
+         %19 = OpAccessChain %_ptr_Uniform_v3half %u %uint_1
+         %20 = OpLoad %v3half %19
+         %23 = OpAccessChain %_ptr_Uniform_v3half %u %uint_2
+         %24 = OpLoad %v3half %23
+         %27 = OpAccessChain %_ptr_Uniform_v3half %u %uint_3
+         %28 = OpLoad %v3half %27
+         %29 = OpCompositeConstruct %mat4v3half %16 %20 %24 %28
+               OpReturnValue %29
+               OpFunctionEnd
+       %main = OpFunction %void None %30
+         %33 = OpLabel
+         %34 = OpFunctionCall %mat4v3half %load_u_inner
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/types/mat4x3_f16.wgsl.expected.wgsl b/test/tint/buffer/uniform/types/mat4x3_f16.wgsl.expected.wgsl
new file mode 100644
index 0000000..43c4a43
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat4x3_f16.wgsl.expected.wgsl
@@ -0,0 +1,8 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat4x3<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/mat4x3_f32.wgsl b/test/tint/buffer/uniform/types/mat4x3_f32.wgsl
new file mode 100644
index 0000000..d8cd5b4
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat4x3_f32.wgsl
@@ -0,0 +1,7 @@
+@group(0) @binding(0)
+var<uniform> u : mat4x3<f32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/mat4x3_f32.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/types/mat4x3_f32.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..044877c
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat4x3_f32.wgsl.expected.dxc.hlsl
@@ -0,0 +1,17 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+
+float4x3 tint_symbol(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  const float4x3 x = tint_symbol(u, 0u);
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/mat4x3_f32.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/types/mat4x3_f32.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..044877c
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat4x3_f32.wgsl.expected.fxc.hlsl
@@ -0,0 +1,17 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+
+float4x3 tint_symbol(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  const uint scalar_offset_2 = ((offset + 32u)) / 4;
+  const uint scalar_offset_3 = ((offset + 48u)) / 4;
+  return float4x3(asfloat(buffer[scalar_offset / 4].xyz), asfloat(buffer[scalar_offset_1 / 4].xyz), asfloat(buffer[scalar_offset_2 / 4].xyz), asfloat(buffer[scalar_offset_3 / 4].xyz));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  const float4x3 x = tint_symbol(u, 0u);
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/mat4x3_f32.wgsl.expected.glsl b/test/tint/buffer/uniform/types/mat4x3_f32.wgsl.expected.glsl
new file mode 100644
index 0000000..0cffe2d
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat4x3_f32.wgsl.expected.glsl
@@ -0,0 +1,15 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  mat4x3 inner;
+} u;
+
+void tint_symbol() {
+  mat4x3 x = u.inner;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol();
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/mat4x3_f32.wgsl.expected.msl b/test/tint/buffer/uniform/types/mat4x3_f32.wgsl.expected.msl
new file mode 100644
index 0000000..482db1c
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat4x3_f32.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(const constant float4x3* tint_symbol_1 [[buffer(0)]]) {
+  float4x3 const x = *(tint_symbol_1);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/types/mat4x3_f32.wgsl.expected.spvasm b/test/tint/buffer/uniform/types/mat4x3_f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..d96eb83
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat4x3_f32.wgsl.expected.spvasm
@@ -0,0 +1,37 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 16
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %main "main"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %u_block 0 ColMajor
+               OpMemberDecorate %u_block 0 MatrixStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%mat4v3float = OpTypeMatrix %v3float 4
+    %u_block = OpTypeStruct %mat4v3float
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+          %7 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_mat4v3float = OpTypePointer Uniform %mat4v3float
+       %main = OpFunction %void None %7
+         %10 = OpLabel
+         %14 = OpAccessChain %_ptr_Uniform_mat4v3float %u %uint_0
+         %15 = OpLoad %mat4v3float %14
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/types/mat4x3_f32.wgsl.expected.wgsl b/test/tint/buffer/uniform/types/mat4x3_f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..d177f74
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat4x3_f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+@group(0) @binding(0) var<uniform> u : mat4x3<f32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/mat4x4_f16.wgsl b/test/tint/buffer/uniform/types/mat4x4_f16.wgsl
new file mode 100644
index 0000000..f30a48e
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat4x4_f16.wgsl
@@ -0,0 +1,9 @@
+enable f16;
+
+@group(0) @binding(0)
+var<uniform> u : mat4x4<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/mat4x4_f16.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/types/mat4x4_f16.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..a0e9f1b5
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat4x4_f16.wgsl.expected.dxc.hlsl
@@ -0,0 +1,33 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+
+matrix<float16_t, 4, 4> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  const matrix<float16_t, 4, 4> x = tint_symbol(u, 0u);
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/mat4x4_f16.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/types/mat4x4_f16.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..8b29f19
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat4x4_f16.wgsl.expected.fxc.hlsl
@@ -0,0 +1,38 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+
+matrix<float16_t, 4, 4> tint_symbol(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  const uint scalar_offset_2 = ((offset + 16u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_4_yw = vector<float16_t, 2>(f16tof32(ubo_load_4 >> 16));
+  const uint scalar_offset_3 = ((offset + 24u)) / 4;
+  uint4 ubo_load_7 = buffer[scalar_offset_3 / 4];
+  uint2 ubo_load_6 = ((scalar_offset_3 & 2) ? ubo_load_7.zw : ubo_load_7.xy);
+  vector<float16_t, 2> ubo_load_6_xz = vector<float16_t, 2>(f16tof32(ubo_load_6 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_6_yw = vector<float16_t, 2>(f16tof32(ubo_load_6 >> 16));
+  return matrix<float16_t, 4, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]), vector<float16_t, 4>(ubo_load_4_xz[0], ubo_load_4_yw[0], ubo_load_4_xz[1], ubo_load_4_yw[1]), vector<float16_t, 4>(ubo_load_6_xz[0], ubo_load_6_yw[0], ubo_load_6_xz[1], ubo_load_6_yw[1]));
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  const matrix<float16_t, 4, 4> x = tint_symbol(u, 0u);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000014CB93FB460(5,8-16): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/types/mat4x4_f16.wgsl.expected.glsl b/test/tint/buffer/uniform/types/mat4x4_f16.wgsl.expected.glsl
new file mode 100644
index 0000000..e84101c
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat4x4_f16.wgsl.expected.glsl
@@ -0,0 +1,23 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  f16vec4 inner_0;
+  f16vec4 inner_1;
+  f16vec4 inner_2;
+  f16vec4 inner_3;
+} u;
+
+f16mat4 load_u_inner() {
+  return f16mat4(u.inner_0, u.inner_1, u.inner_2, u.inner_3);
+}
+
+void tint_symbol() {
+  f16mat4 x = load_u_inner();
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol();
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/mat4x4_f16.wgsl.expected.msl b/test/tint/buffer/uniform/types/mat4x4_f16.wgsl.expected.msl
new file mode 100644
index 0000000..aad6510
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat4x4_f16.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(const constant half4x4* tint_symbol_1 [[buffer(0)]]) {
+  half4x4 const x = *(tint_symbol_1);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/types/mat4x4_f16.wgsl.expected.spvasm b/test/tint/buffer/uniform/types/mat4x4_f16.wgsl.expected.spvasm
new file mode 100644
index 0000000..0dc3bce
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat4x4_f16.wgsl.expected.spvasm
@@ -0,0 +1,62 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 35
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner_0"
+               OpMemberName %u_block_std140 1 "inner_1"
+               OpMemberName %u_block_std140 2 "inner_2"
+               OpMemberName %u_block_std140 3 "inner_3"
+               OpName %u "u"
+               OpName %load_u_inner "load_u_inner"
+               OpName %main "main"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %u_block_std140 1 Offset 8
+               OpMemberDecorate %u_block_std140 2 Offset 16
+               OpMemberDecorate %u_block_std140 3 Offset 24
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+%u_block_std140 = OpTypeStruct %v4half %v4half %v4half %v4half
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat4v4half = OpTypeMatrix %v4half 4
+          %6 = OpTypeFunction %mat4v4half
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+     %uint_1 = OpConstant %uint 1
+     %uint_2 = OpConstant %uint 2
+     %uint_3 = OpConstant %uint 3
+       %void = OpTypeVoid
+         %30 = OpTypeFunction %void
+%load_u_inner = OpFunction %mat4v4half None %6
+          %9 = OpLabel
+         %15 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0
+         %16 = OpLoad %v4half %15
+         %19 = OpAccessChain %_ptr_Uniform_v4half %u %uint_1
+         %20 = OpLoad %v4half %19
+         %23 = OpAccessChain %_ptr_Uniform_v4half %u %uint_2
+         %24 = OpLoad %v4half %23
+         %27 = OpAccessChain %_ptr_Uniform_v4half %u %uint_3
+         %28 = OpLoad %v4half %27
+         %29 = OpCompositeConstruct %mat4v4half %16 %20 %24 %28
+               OpReturnValue %29
+               OpFunctionEnd
+       %main = OpFunction %void None %30
+         %33 = OpLabel
+         %34 = OpFunctionCall %mat4v4half %load_u_inner
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/types/mat4x4_f16.wgsl.expected.wgsl b/test/tint/buffer/uniform/types/mat4x4_f16.wgsl.expected.wgsl
new file mode 100644
index 0000000..0186b40
--- /dev/null
+++ b/test/tint/buffer/uniform/types/mat4x4_f16.wgsl.expected.wgsl
@@ -0,0 +1,8 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : mat4x4<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/mat4x4.wgsl b/test/tint/buffer/uniform/types/mat4x4_f32.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/types/mat4x4.wgsl
rename to test/tint/buffer/uniform/types/mat4x4_f32.wgsl
diff --git a/test/tint/buffer/uniform/types/mat4x4.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/types/mat4x4_f32.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/types/mat4x4.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/uniform/types/mat4x4_f32.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/uniform/types/mat4x4.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/types/mat4x4_f32.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/types/mat4x4.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/uniform/types/mat4x4_f32.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/uniform/types/mat4x4.wgsl.expected.glsl b/test/tint/buffer/uniform/types/mat4x4_f32.wgsl.expected.glsl
similarity index 100%
rename from test/tint/buffer/uniform/types/mat4x4.wgsl.expected.glsl
rename to test/tint/buffer/uniform/types/mat4x4_f32.wgsl.expected.glsl
diff --git a/test/tint/buffer/uniform/types/mat4x4.wgsl.expected.msl b/test/tint/buffer/uniform/types/mat4x4_f32.wgsl.expected.msl
similarity index 100%
rename from test/tint/buffer/uniform/types/mat4x4.wgsl.expected.msl
rename to test/tint/buffer/uniform/types/mat4x4_f32.wgsl.expected.msl
diff --git a/test/tint/buffer/uniform/types/mat4x4.wgsl.expected.spvasm b/test/tint/buffer/uniform/types/mat4x4_f32.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/uniform/types/mat4x4.wgsl.expected.spvasm
rename to test/tint/buffer/uniform/types/mat4x4_f32.wgsl.expected.spvasm
diff --git a/test/tint/buffer/uniform/types/mat4x4.wgsl.expected.wgsl b/test/tint/buffer/uniform/types/mat4x4_f32.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/types/mat4x4.wgsl.expected.wgsl
rename to test/tint/buffer/uniform/types/mat4x4_f32.wgsl.expected.wgsl
diff --git a/test/tint/buffer/uniform/types/struct.wgsl b/test/tint/buffer/uniform/types/struct.wgsl
deleted file mode 100644
index c50edb3..0000000
--- a/test/tint/buffer/uniform/types/struct.wgsl
+++ /dev/null
@@ -1,14 +0,0 @@
-struct Inner {
-  f : f32,
-};
-struct S {
-  inner : Inner,
-};
-
-@group(0) @binding(0)
-var<uniform> u : S;
-
-@compute @workgroup_size(1)
-fn main() {
-  let x = u;
-}
diff --git a/test/tint/buffer/uniform/types/struct.wgsl.expected.glsl b/test/tint/buffer/uniform/types/struct.wgsl.expected.glsl
deleted file mode 100644
index b717d8c..0000000
--- a/test/tint/buffer/uniform/types/struct.wgsl.expected.glsl
+++ /dev/null
@@ -1,26 +0,0 @@
-#version 310 es
-
-struct Inner {
-  float f;
-  uint pad;
-  uint pad_1;
-  uint pad_2;
-};
-
-struct S {
-  Inner inner;
-};
-
-layout(binding = 0, std140) uniform u_block_ubo {
-  S inner;
-} u;
-
-void tint_symbol() {
-  S x = u.inner;
-}
-
-layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
-void main() {
-  tint_symbol();
-  return;
-}
diff --git a/test/tint/buffer/uniform/types/struct.wgsl.expected.msl b/test/tint/buffer/uniform/types/struct.wgsl.expected.msl
deleted file mode 100644
index 41e3ae3..0000000
--- a/test/tint/buffer/uniform/types/struct.wgsl.expected.msl
+++ /dev/null
@@ -1,16 +0,0 @@
-#include <metal_stdlib>
-
-using namespace metal;
-struct Inner {
-  /* 0x0000 */ float f;
-};
-
-struct S {
-  /* 0x0000 */ Inner inner;
-};
-
-kernel void tint_symbol(const constant S* tint_symbol_1 [[buffer(0)]]) {
-  S const x = *(tint_symbol_1);
-  return;
-}
-
diff --git a/test/tint/buffer/uniform/types/struct.wgsl.expected.spvasm b/test/tint/buffer/uniform/types/struct.wgsl.expected.spvasm
deleted file mode 100644
index 9c63d49..0000000
--- a/test/tint/buffer/uniform/types/struct.wgsl.expected.spvasm
+++ /dev/null
@@ -1,41 +0,0 @@
-; SPIR-V
-; Version: 1.3
-; Generator: Google Tint Compiler; 0
-; Bound: 16
-; Schema: 0
-               OpCapability Shader
-               OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %main "main"
-               OpExecutionMode %main LocalSize 1 1 1
-               OpName %u_block "u_block"
-               OpMemberName %u_block 0 "inner"
-               OpName %S "S"
-               OpMemberName %S 0 "inner"
-               OpName %Inner "Inner"
-               OpMemberName %Inner 0 "f"
-               OpName %u "u"
-               OpName %main "main"
-               OpDecorate %u_block Block
-               OpMemberDecorate %u_block 0 Offset 0
-               OpMemberDecorate %S 0 Offset 0
-               OpMemberDecorate %Inner 0 Offset 0
-               OpDecorate %u NonWritable
-               OpDecorate %u DescriptorSet 0
-               OpDecorate %u Binding 0
-      %float = OpTypeFloat 32
-      %Inner = OpTypeStruct %float
-          %S = OpTypeStruct %Inner
-    %u_block = OpTypeStruct %S
-%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
-          %u = OpVariable %_ptr_Uniform_u_block Uniform
-       %void = OpTypeVoid
-          %7 = OpTypeFunction %void
-       %uint = OpTypeInt 32 0
-     %uint_0 = OpConstant %uint 0
-%_ptr_Uniform_S = OpTypePointer Uniform %S
-       %main = OpFunction %void None %7
-         %10 = OpLabel
-         %14 = OpAccessChain %_ptr_Uniform_S %u %uint_0
-         %15 = OpLoad %S %14
-               OpReturn
-               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/types/struct.wgsl.expected.wgsl b/test/tint/buffer/uniform/types/struct.wgsl.expected.wgsl
deleted file mode 100644
index 552be2c..0000000
--- a/test/tint/buffer/uniform/types/struct.wgsl.expected.wgsl
+++ /dev/null
@@ -1,14 +0,0 @@
-struct Inner {
-  f : f32,
-}
-
-struct S {
-  inner : Inner,
-}
-
-@group(0) @binding(0) var<uniform> u : S;
-
-@compute @workgroup_size(1)
-fn main() {
-  let x = u;
-}
diff --git a/test/tint/buffer/uniform/types/struct_f16.wgsl b/test/tint/buffer/uniform/types/struct_f16.wgsl
new file mode 100644
index 0000000..a2610fd
--- /dev/null
+++ b/test/tint/buffer/uniform/types/struct_f16.wgsl
@@ -0,0 +1,18 @@
+enable f16;
+
+struct Inner {
+  scalar_f16 : f16,
+  vec3_f16 : vec3<f16>,
+  mat2x4_f16 : mat2x4<f16>,
+};
+struct S {
+  inner : Inner,
+};
+
+@group(0) @binding(0)
+var<uniform> u : S;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/struct_f16.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/types/struct_f16.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..0ee746e
--- /dev/null
+++ b/test/tint/buffer/uniform/types/struct_f16.wgsl.expected.dxc.hlsl
@@ -0,0 +1,49 @@
+struct Inner {
+  float16_t scalar_f16;
+  vector<float16_t, 3> vec3_f16;
+  matrix<float16_t, 2, 4> mat2x4_f16;
+};
+struct S {
+  Inner inner;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+
+matrix<float16_t, 2, 4> tint_symbol_4(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+Inner tint_symbol_1(uint4 buffer[2], uint offset) {
+  const uint scalar_offset_bytes = ((offset + 0u));
+  const uint scalar_offset_index = scalar_offset_bytes / 4;
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const Inner tint_symbol_6 = {float16_t(f16tof32(((buffer[scalar_offset_index / 4][scalar_offset_index % 4] >> (scalar_offset_bytes % 4 == 0 ? 0 : 16)) & 0xFFFF))), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), tint_symbol_4(buffer, (offset + 16u))};
+  return tint_symbol_6;
+}
+
+S tint_symbol(uint4 buffer[2], uint offset) {
+  const S tint_symbol_7 = {tint_symbol_1(buffer, (offset + 0u))};
+  return tint_symbol_7;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  const S x = tint_symbol(u, 0u);
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/struct_f16.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/types/struct_f16.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..1c11433
--- /dev/null
+++ b/test/tint/buffer/uniform/types/struct_f16.wgsl.expected.fxc.hlsl
@@ -0,0 +1,54 @@
+SKIP: FAILED
+
+struct Inner {
+  float16_t scalar_f16;
+  vector<float16_t, 3> vec3_f16;
+  matrix<float16_t, 2, 4> mat2x4_f16;
+};
+struct S {
+  Inner inner;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[2];
+};
+
+matrix<float16_t, 2, 4> tint_symbol_4(uint4 buffer[2], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  uint4 ubo_load_1 = buffer[scalar_offset / 4];
+  uint2 ubo_load = ((scalar_offset & 2) ? ubo_load_1.zw : ubo_load_1.xy);
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const uint scalar_offset_1 = ((offset + 8u)) / 4;
+  uint4 ubo_load_3 = buffer[scalar_offset_1 / 4];
+  uint2 ubo_load_2 = ((scalar_offset_1 & 2) ? ubo_load_3.zw : ubo_load_3.xy);
+  vector<float16_t, 2> ubo_load_2_xz = vector<float16_t, 2>(f16tof32(ubo_load_2 & 0xFFFF));
+  vector<float16_t, 2> ubo_load_2_yw = vector<float16_t, 2>(f16tof32(ubo_load_2 >> 16));
+  return matrix<float16_t, 2, 4>(vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]), vector<float16_t, 4>(ubo_load_2_xz[0], ubo_load_2_yw[0], ubo_load_2_xz[1], ubo_load_2_yw[1]));
+}
+
+Inner tint_symbol_1(uint4 buffer[2], uint offset) {
+  const uint scalar_offset_bytes = ((offset + 0u));
+  const uint scalar_offset_index = scalar_offset_bytes / 4;
+  const uint scalar_offset_2 = ((offset + 8u)) / 4;
+  uint4 ubo_load_5 = buffer[scalar_offset_2 / 4];
+  uint2 ubo_load_4 = ((scalar_offset_2 & 2) ? ubo_load_5.zw : ubo_load_5.xy);
+  vector<float16_t, 2> ubo_load_4_xz = vector<float16_t, 2>(f16tof32(ubo_load_4 & 0xFFFF));
+  float16_t ubo_load_4_y = f16tof32(ubo_load_4[0] >> 16);
+  const Inner tint_symbol_6 = {float16_t(f16tof32(((buffer[scalar_offset_index / 4][scalar_offset_index % 4] >> (scalar_offset_bytes % 4 == 0 ? 0 : 16)) & 0xFFFF))), vector<float16_t, 3>(ubo_load_4_xz[0], ubo_load_4_y, ubo_load_4_xz[1]), tint_symbol_4(buffer, (offset + 16u))};
+  return tint_symbol_6;
+}
+
+S tint_symbol(uint4 buffer[2], uint offset) {
+  const S tint_symbol_7 = {tint_symbol_1(buffer, (offset + 0u))};
+  return tint_symbol_7;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  const S x = tint_symbol(u, 0u);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x0000019B8F8CCCD0(2,3-11): error X3000: unrecognized identifier 'float16_t'
+
diff --git a/test/tint/buffer/uniform/types/struct_f16.wgsl.expected.glsl b/test/tint/buffer/uniform/types/struct_f16.wgsl.expected.glsl
new file mode 100644
index 0000000..0f63a58
--- /dev/null
+++ b/test/tint/buffer/uniform/types/struct_f16.wgsl.expected.glsl
@@ -0,0 +1,47 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+struct Inner {
+  float16_t scalar_f16;
+  uint pad;
+  f16vec3 vec3_f16;
+  f16mat2x4 mat2x4_f16;
+};
+
+struct Inner_std140 {
+  float16_t scalar_f16;
+  uint pad;
+  f16vec3 vec3_f16;
+  f16vec4 mat2x4_f16_0;
+  f16vec4 mat2x4_f16_1;
+};
+
+struct S {
+  Inner inner;
+};
+
+struct S_std140 {
+  Inner_std140 inner;
+};
+
+layout(binding = 0, std140) uniform u_block_std140_ubo {
+  S_std140 inner;
+} u;
+
+Inner conv_Inner(Inner_std140 val) {
+  return Inner(val.scalar_f16, val.pad, val.vec3_f16, f16mat2x4(val.mat2x4_f16_0, val.mat2x4_f16_1));
+}
+
+S conv_S(S_std140 val) {
+  return S(conv_Inner(val.inner));
+}
+
+void tint_symbol() {
+  S x = conv_S(u.inner);
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol();
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/struct_f16.wgsl.expected.msl b/test/tint/buffer/uniform/types/struct_f16.wgsl.expected.msl
new file mode 100644
index 0000000..fd9b0f2
--- /dev/null
+++ b/test/tint/buffer/uniform/types/struct_f16.wgsl.expected.msl
@@ -0,0 +1,33 @@
+#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 Inner {
+  /* 0x0000 */ half scalar_f16;
+  /* 0x0002 */ tint_array<int8_t, 6> tint_pad;
+  /* 0x0008 */ packed_half3 vec3_f16;
+  /* 0x000e */ tint_array<int8_t, 2> tint_pad_1;
+  /* 0x0010 */ half2x4 mat2x4_f16;
+};
+
+struct S {
+  /* 0x0000 */ Inner inner;
+};
+
+kernel void tint_symbol(const constant S* tint_symbol_1 [[buffer(0)]]) {
+  S const x = *(tint_symbol_1);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/types/struct_f16.wgsl.expected.spvasm b/test/tint/buffer/uniform/types/struct_f16.wgsl.expected.spvasm
new file mode 100644
index 0000000..00afa20
--- /dev/null
+++ b/test/tint/buffer/uniform/types/struct_f16.wgsl.expected.spvasm
@@ -0,0 +1,94 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 39
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %u_block_std140 "u_block_std140"
+               OpMemberName %u_block_std140 0 "inner"
+               OpName %S_std140 "S_std140"
+               OpMemberName %S_std140 0 "inner"
+               OpName %Inner_std140 "Inner_std140"
+               OpMemberName %Inner_std140 0 "scalar_f16"
+               OpMemberName %Inner_std140 1 "vec3_f16"
+               OpMemberName %Inner_std140 2 "mat2x4_f16_0"
+               OpMemberName %Inner_std140 3 "mat2x4_f16_1"
+               OpName %u "u"
+               OpName %Inner "Inner"
+               OpMemberName %Inner 0 "scalar_f16"
+               OpMemberName %Inner 1 "vec3_f16"
+               OpMemberName %Inner 2 "mat2x4_f16"
+               OpName %conv_Inner "conv_Inner"
+               OpName %val "val"
+               OpName %S "S"
+               OpMemberName %S 0 "inner"
+               OpName %conv_S "conv_S"
+               OpName %val_0 "val"
+               OpName %main "main"
+               OpDecorate %u_block_std140 Block
+               OpMemberDecorate %u_block_std140 0 Offset 0
+               OpMemberDecorate %S_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 0 Offset 0
+               OpMemberDecorate %Inner_std140 1 Offset 8
+               OpMemberDecorate %Inner_std140 2 Offset 16
+               OpMemberDecorate %Inner_std140 3 Offset 24
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+               OpMemberDecorate %Inner 0 Offset 0
+               OpMemberDecorate %Inner 1 Offset 8
+               OpMemberDecorate %Inner 2 Offset 16
+               OpMemberDecorate %Inner 2 ColMajor
+               OpMemberDecorate %Inner 2 MatrixStride 8
+               OpMemberDecorate %S 0 Offset 0
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+     %v4half = OpTypeVector %half 4
+%Inner_std140 = OpTypeStruct %half %v3half %v4half %v4half
+   %S_std140 = OpTypeStruct %Inner_std140
+%u_block_std140 = OpTypeStruct %S_std140
+%_ptr_Uniform_u_block_std140 = OpTypePointer Uniform %u_block_std140
+          %u = OpVariable %_ptr_Uniform_u_block_std140 Uniform
+ %mat2v4half = OpTypeMatrix %v4half 2
+      %Inner = OpTypeStruct %half %v3half %mat2v4half
+          %9 = OpTypeFunction %Inner %Inner_std140
+          %S = OpTypeStruct %Inner
+         %21 = OpTypeFunction %S %S_std140
+       %void = OpTypeVoid
+         %29 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_S_std140 = OpTypePointer Uniform %S_std140
+ %conv_Inner = OpFunction %Inner None %9
+        %val = OpFunctionParameter %Inner_std140
+         %14 = OpLabel
+         %15 = OpCompositeExtract %half %val 0
+         %16 = OpCompositeExtract %v3half %val 1
+         %17 = OpCompositeExtract %v4half %val 2
+         %18 = OpCompositeExtract %v4half %val 3
+         %19 = OpCompositeConstruct %mat2v4half %17 %18
+         %20 = OpCompositeConstruct %Inner %15 %16 %19
+               OpReturnValue %20
+               OpFunctionEnd
+     %conv_S = OpFunction %S None %21
+      %val_0 = OpFunctionParameter %S_std140
+         %25 = OpLabel
+         %27 = OpCompositeExtract %Inner_std140 %val_0 0
+         %26 = OpFunctionCall %Inner %conv_Inner %27
+         %28 = OpCompositeConstruct %S %26
+               OpReturnValue %28
+               OpFunctionEnd
+       %main = OpFunction %void None %29
+         %32 = OpLabel
+         %37 = OpAccessChain %_ptr_Uniform_S_std140 %u %uint_0
+         %38 = OpLoad %S_std140 %37
+         %33 = OpFunctionCall %S %conv_S %38
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/types/struct_f16.wgsl.expected.wgsl b/test/tint/buffer/uniform/types/struct_f16.wgsl.expected.wgsl
new file mode 100644
index 0000000..1e2dd4e
--- /dev/null
+++ b/test/tint/buffer/uniform/types/struct_f16.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+enable f16;
+
+struct Inner {
+  scalar_f16 : f16,
+  vec3_f16 : vec3<f16>,
+  mat2x4_f16 : mat2x4<f16>,
+}
+
+struct S {
+  inner : Inner,
+}
+
+@group(0) @binding(0) var<uniform> u : S;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/struct_f32.wgsl b/test/tint/buffer/uniform/types/struct_f32.wgsl
new file mode 100644
index 0000000..3620fec
--- /dev/null
+++ b/test/tint/buffer/uniform/types/struct_f32.wgsl
@@ -0,0 +1,16 @@
+struct Inner {
+  scalar_f32 : f32,
+  vec3_f32 : vec3<f32>,
+  mat2x4_f32 : mat2x4<f32>,
+};
+struct S {
+  inner : Inner,
+};
+
+@group(0) @binding(0)
+var<uniform> u : S;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/struct_f32.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/types/struct_f32.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..c6a6891
--- /dev/null
+++ b/test/tint/buffer/uniform/types/struct_f32.wgsl.expected.dxc.hlsl
@@ -0,0 +1,36 @@
+struct Inner {
+  float scalar_f32;
+  float3 vec3_f32;
+  float2x4 mat2x4_f32;
+};
+struct S {
+  Inner inner;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+
+float2x4 tint_symbol_4(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+Inner tint_symbol_1(uint4 buffer[4], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 16u)) / 4;
+  const Inner tint_symbol_6 = {asfloat(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), asfloat(buffer[scalar_offset_3 / 4].xyz), tint_symbol_4(buffer, (offset + 32u))};
+  return tint_symbol_6;
+}
+
+S tint_symbol(uint4 buffer[4], uint offset) {
+  const S tint_symbol_7 = {tint_symbol_1(buffer, (offset + 0u))};
+  return tint_symbol_7;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  const S x = tint_symbol(u, 0u);
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/struct_f32.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/types/struct_f32.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..c6a6891
--- /dev/null
+++ b/test/tint/buffer/uniform/types/struct_f32.wgsl.expected.fxc.hlsl
@@ -0,0 +1,36 @@
+struct Inner {
+  float scalar_f32;
+  float3 vec3_f32;
+  float2x4 mat2x4_f32;
+};
+struct S {
+  Inner inner;
+};
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[4];
+};
+
+float2x4 tint_symbol_4(uint4 buffer[4], uint offset) {
+  const uint scalar_offset = ((offset + 0u)) / 4;
+  const uint scalar_offset_1 = ((offset + 16u)) / 4;
+  return float2x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]));
+}
+
+Inner tint_symbol_1(uint4 buffer[4], uint offset) {
+  const uint scalar_offset_2 = ((offset + 0u)) / 4;
+  const uint scalar_offset_3 = ((offset + 16u)) / 4;
+  const Inner tint_symbol_6 = {asfloat(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), asfloat(buffer[scalar_offset_3 / 4].xyz), tint_symbol_4(buffer, (offset + 32u))};
+  return tint_symbol_6;
+}
+
+S tint_symbol(uint4 buffer[4], uint offset) {
+  const S tint_symbol_7 = {tint_symbol_1(buffer, (offset + 0u))};
+  return tint_symbol_7;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+  const S x = tint_symbol(u, 0u);
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/struct_f32.wgsl.expected.glsl b/test/tint/buffer/uniform/types/struct_f32.wgsl.expected.glsl
new file mode 100644
index 0000000..b5a022d
--- /dev/null
+++ b/test/tint/buffer/uniform/types/struct_f32.wgsl.expected.glsl
@@ -0,0 +1,29 @@
+#version 310 es
+
+struct Inner {
+  float scalar_f32;
+  uint pad;
+  uint pad_1;
+  uint pad_2;
+  vec3 vec3_f32;
+  uint pad_3;
+  mat2x4 mat2x4_f32;
+};
+
+struct S {
+  Inner inner;
+};
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  S inner;
+} u;
+
+void tint_symbol() {
+  S x = u.inner;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol();
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/struct_f32.wgsl.expected.msl b/test/tint/buffer/uniform/types/struct_f32.wgsl.expected.msl
new file mode 100644
index 0000000..ae03b60
--- /dev/null
+++ b/test/tint/buffer/uniform/types/struct_f32.wgsl.expected.msl
@@ -0,0 +1,33 @@
+#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 Inner {
+  /* 0x0000 */ float scalar_f32;
+  /* 0x0004 */ tint_array<int8_t, 12> tint_pad;
+  /* 0x0010 */ packed_float3 vec3_f32;
+  /* 0x001c */ tint_array<int8_t, 4> tint_pad_1;
+  /* 0x0020 */ float2x4 mat2x4_f32;
+};
+
+struct S {
+  /* 0x0000 */ Inner inner;
+};
+
+kernel void tint_symbol(const constant S* tint_symbol_1 [[buffer(0)]]) {
+  S const x = *(tint_symbol_1);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/types/struct_f32.wgsl.expected.spvasm b/test/tint/buffer/uniform/types/struct_f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..b7e94dd
--- /dev/null
+++ b/test/tint/buffer/uniform/types/struct_f32.wgsl.expected.spvasm
@@ -0,0 +1,50 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 19
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %S "S"
+               OpMemberName %S 0 "inner"
+               OpName %Inner "Inner"
+               OpMemberName %Inner 0 "scalar_f32"
+               OpMemberName %Inner 1 "vec3_f32"
+               OpMemberName %Inner 2 "mat2x4_f32"
+               OpName %u "u"
+               OpName %main "main"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpMemberDecorate %S 0 Offset 0
+               OpMemberDecorate %Inner 0 Offset 0
+               OpMemberDecorate %Inner 1 Offset 16
+               OpMemberDecorate %Inner 2 Offset 32
+               OpMemberDecorate %Inner 2 ColMajor
+               OpMemberDecorate %Inner 2 MatrixStride 16
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+    %v4float = OpTypeVector %float 4
+%mat2v4float = OpTypeMatrix %v4float 2
+      %Inner = OpTypeStruct %float %v3float %mat2v4float
+          %S = OpTypeStruct %Inner
+    %u_block = OpTypeStruct %S
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+         %10 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_S = OpTypePointer Uniform %S
+       %main = OpFunction %void None %10
+         %13 = OpLabel
+         %17 = OpAccessChain %_ptr_Uniform_S %u %uint_0
+         %18 = OpLoad %S %17
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/types/struct_f32.wgsl.expected.wgsl b/test/tint/buffer/uniform/types/struct_f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..9658b07
--- /dev/null
+++ b/test/tint/buffer/uniform/types/struct_f32.wgsl.expected.wgsl
@@ -0,0 +1,16 @@
+struct Inner {
+  scalar_f32 : f32,
+  vec3_f32 : vec3<f32>,
+  mat2x4_f32 : mat2x4<f32>,
+}
+
+struct S {
+  inner : Inner,
+}
+
+@group(0) @binding(0) var<uniform> u : S;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/vec2_f16.wgsl b/test/tint/buffer/uniform/types/vec2_f16.wgsl
new file mode 100644
index 0000000..17cb8b7
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec2_f16.wgsl
@@ -0,0 +1,9 @@
+enable f16;
+
+@group(0) @binding(0)
+var<uniform> u : vec2<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/vec2_f16.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/types/vec2_f16.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..6449cb7
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec2_f16.wgsl.expected.dxc.hlsl
@@ -0,0 +1,10 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+[numthreads(1, 1, 1)]
+void main() {
+  uint ubo_load = u[0].x;
+  const vector<float16_t, 2> x = vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16)));
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/vec2_f16.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/types/vec2_f16.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..f8f7aad
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec2_f16.wgsl.expected.fxc.hlsl
@@ -0,0 +1,15 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+[numthreads(1, 1, 1)]
+void main() {
+  uint ubo_load = u[0].x;
+  const vector<float16_t, 2> x = vector<float16_t, 2>(float16_t(f16tof32(ubo_load & 0xFFFF)), float16_t(f16tof32(ubo_load >> 16)));
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x00000244450436F0(8,16-24): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/types/vec2_f16.wgsl.expected.glsl b/test/tint/buffer/uniform/types/vec2_f16.wgsl.expected.glsl
new file mode 100644
index 0000000..99cbb53
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec2_f16.wgsl.expected.glsl
@@ -0,0 +1,16 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  f16vec2 inner;
+} u;
+
+void tint_symbol() {
+  f16vec2 x = u.inner;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol();
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/vec2_f16.wgsl.expected.msl b/test/tint/buffer/uniform/types/vec2_f16.wgsl.expected.msl
new file mode 100644
index 0000000..80341d9
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec2_f16.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(const constant half2* tint_symbol_1 [[buffer(0)]]) {
+  half2 const x = *(tint_symbol_1);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/types/vec2_f16.wgsl.expected.spvasm b/test/tint/buffer/uniform/types/vec2_f16.wgsl.expected.spvasm
new file mode 100644
index 0000000..73bbc7e
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec2_f16.wgsl.expected.spvasm
@@ -0,0 +1,38 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 15
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %main "main"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %half = OpTypeFloat 16
+     %v2half = OpTypeVector %half 2
+    %u_block = OpTypeStruct %v2half
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+          %6 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v2half = OpTypePointer Uniform %v2half
+       %main = OpFunction %void None %6
+          %9 = OpLabel
+         %13 = OpAccessChain %_ptr_Uniform_v2half %u %uint_0
+         %14 = OpLoad %v2half %13
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/types/vec2_f16.wgsl.expected.wgsl b/test/tint/buffer/uniform/types/vec2_f16.wgsl.expected.wgsl
new file mode 100644
index 0000000..9f30580
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec2_f16.wgsl.expected.wgsl
@@ -0,0 +1,8 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : vec2<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/vec2_f32.wgsl b/test/tint/buffer/uniform/types/vec2_f32.wgsl
new file mode 100644
index 0000000..4648a8d
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec2_f32.wgsl
@@ -0,0 +1,7 @@
+@group(0) @binding(0)
+var<uniform> u : vec2<f32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/vec2_f32.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/types/vec2_f32.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..06f83a5
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec2_f32.wgsl.expected.dxc.hlsl
@@ -0,0 +1,9 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+[numthreads(1, 1, 1)]
+void main() {
+  const float2 x = asfloat(u[0].xy);
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/vec2_f32.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/types/vec2_f32.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..06f83a5
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec2_f32.wgsl.expected.fxc.hlsl
@@ -0,0 +1,9 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+[numthreads(1, 1, 1)]
+void main() {
+  const float2 x = asfloat(u[0].xy);
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/vec2_f32.wgsl.expected.glsl b/test/tint/buffer/uniform/types/vec2_f32.wgsl.expected.glsl
new file mode 100644
index 0000000..39bd9ac
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec2_f32.wgsl.expected.glsl
@@ -0,0 +1,15 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  vec2 inner;
+} u;
+
+void tint_symbol() {
+  vec2 x = u.inner;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol();
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/vec2_f32.wgsl.expected.msl b/test/tint/buffer/uniform/types/vec2_f32.wgsl.expected.msl
new file mode 100644
index 0000000..f2e48b1
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec2_f32.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(const constant float2* tint_symbol_1 [[buffer(0)]]) {
+  float2 const x = *(tint_symbol_1);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/types/vec2_f32.wgsl.expected.spvasm b/test/tint/buffer/uniform/types/vec2_f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..ba6ed42
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec2_f32.wgsl.expected.spvasm
@@ -0,0 +1,34 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 15
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %main "main"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+      %float = OpTypeFloat 32
+    %v2float = OpTypeVector %float 2
+    %u_block = OpTypeStruct %v2float
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+          %6 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
+       %main = OpFunction %void None %6
+          %9 = OpLabel
+         %13 = OpAccessChain %_ptr_Uniform_v2float %u %uint_0
+         %14 = OpLoad %v2float %13
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/types/vec2_f32.wgsl.expected.wgsl b/test/tint/buffer/uniform/types/vec2_f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..d9315ab
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec2_f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+@group(0) @binding(0) var<uniform> u : vec2<f32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/vec2.wgsl b/test/tint/buffer/uniform/types/vec2_i32.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/types/vec2.wgsl
rename to test/tint/buffer/uniform/types/vec2_i32.wgsl
diff --git a/test/tint/buffer/uniform/types/vec2.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/types/vec2_i32.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/types/vec2.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/uniform/types/vec2_i32.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/uniform/types/vec2.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/types/vec2_i32.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/types/vec2.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/uniform/types/vec2_i32.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/uniform/types/vec2.wgsl.expected.glsl b/test/tint/buffer/uniform/types/vec2_i32.wgsl.expected.glsl
similarity index 100%
rename from test/tint/buffer/uniform/types/vec2.wgsl.expected.glsl
rename to test/tint/buffer/uniform/types/vec2_i32.wgsl.expected.glsl
diff --git a/test/tint/buffer/uniform/types/vec2.wgsl.expected.msl b/test/tint/buffer/uniform/types/vec2_i32.wgsl.expected.msl
similarity index 100%
rename from test/tint/buffer/uniform/types/vec2.wgsl.expected.msl
rename to test/tint/buffer/uniform/types/vec2_i32.wgsl.expected.msl
diff --git a/test/tint/buffer/uniform/types/vec2.wgsl.expected.spvasm b/test/tint/buffer/uniform/types/vec2_i32.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/uniform/types/vec2.wgsl.expected.spvasm
rename to test/tint/buffer/uniform/types/vec2_i32.wgsl.expected.spvasm
diff --git a/test/tint/buffer/uniform/types/vec2.wgsl.expected.wgsl b/test/tint/buffer/uniform/types/vec2_i32.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/types/vec2.wgsl.expected.wgsl
rename to test/tint/buffer/uniform/types/vec2_i32.wgsl.expected.wgsl
diff --git a/test/tint/buffer/uniform/types/vec2_u32.wgsl b/test/tint/buffer/uniform/types/vec2_u32.wgsl
new file mode 100644
index 0000000..ccccb3a
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec2_u32.wgsl
@@ -0,0 +1,7 @@
+@group(0) @binding(0)
+var<uniform> u : vec2<u32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/vec2_u32.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/types/vec2_u32.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..c96708b
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec2_u32.wgsl.expected.dxc.hlsl
@@ -0,0 +1,9 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+[numthreads(1, 1, 1)]
+void main() {
+  const uint2 x = u[0].xy;
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/vec2_u32.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/types/vec2_u32.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..c96708b
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec2_u32.wgsl.expected.fxc.hlsl
@@ -0,0 +1,9 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+[numthreads(1, 1, 1)]
+void main() {
+  const uint2 x = u[0].xy;
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/vec2_u32.wgsl.expected.glsl b/test/tint/buffer/uniform/types/vec2_u32.wgsl.expected.glsl
new file mode 100644
index 0000000..32eedc5
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec2_u32.wgsl.expected.glsl
@@ -0,0 +1,15 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  uvec2 inner;
+} u;
+
+void tint_symbol() {
+  uvec2 x = u.inner;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol();
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/vec2_u32.wgsl.expected.msl b/test/tint/buffer/uniform/types/vec2_u32.wgsl.expected.msl
new file mode 100644
index 0000000..44fcfb2
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec2_u32.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(const constant uint2* tint_symbol_1 [[buffer(0)]]) {
+  uint2 const x = *(tint_symbol_1);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/types/vec2_u32.wgsl.expected.spvasm b/test/tint/buffer/uniform/types/vec2_u32.wgsl.expected.spvasm
new file mode 100644
index 0000000..e8cfed9
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec2_u32.wgsl.expected.spvasm
@@ -0,0 +1,33 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 14
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %main "main"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+    %u_block = OpTypeStruct %v2uint
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+          %6 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v2uint = OpTypePointer Uniform %v2uint
+       %main = OpFunction %void None %6
+          %9 = OpLabel
+         %12 = OpAccessChain %_ptr_Uniform_v2uint %u %uint_0
+         %13 = OpLoad %v2uint %12
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/types/vec2_u32.wgsl.expected.wgsl b/test/tint/buffer/uniform/types/vec2_u32.wgsl.expected.wgsl
new file mode 100644
index 0000000..d2a992c
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec2_u32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+@group(0) @binding(0) var<uniform> u : vec2<u32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/vec3_f16.wgsl b/test/tint/buffer/uniform/types/vec3_f16.wgsl
new file mode 100644
index 0000000..a1eee50
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec3_f16.wgsl
@@ -0,0 +1,9 @@
+enable f16;
+
+@group(0) @binding(0)
+var<uniform> u : vec3<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/vec3_f16.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/types/vec3_f16.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..be2f0a95
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec3_f16.wgsl.expected.dxc.hlsl
@@ -0,0 +1,12 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+[numthreads(1, 1, 1)]
+void main() {
+  uint2 ubo_load = u[0].xy;
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const vector<float16_t, 3> x = vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/vec3_f16.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/types/vec3_f16.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..52d3b87
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec3_f16.wgsl.expected.fxc.hlsl
@@ -0,0 +1,19 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+[numthreads(1, 1, 1)]
+void main() {
+  uint2 ubo_load = u[0].xy;
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  float16_t ubo_load_y = f16tof32(ubo_load[0] >> 16);
+  const vector<float16_t, 3> x = vector<float16_t, 3>(ubo_load_xz[0], ubo_load_y, ubo_load_xz[1]);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001734B456BC0(8,10-18): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001734B456BC0(9,3-11): error X3000: unrecognized identifier 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001734B456BC0(9,13-22): error X3000: unrecognized identifier 'ubo_load_y'
+
diff --git a/test/tint/buffer/uniform/types/vec3_f16.wgsl.expected.glsl b/test/tint/buffer/uniform/types/vec3_f16.wgsl.expected.glsl
new file mode 100644
index 0000000..c1eb385
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec3_f16.wgsl.expected.glsl
@@ -0,0 +1,16 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  f16vec3 inner;
+} u;
+
+void tint_symbol() {
+  f16vec3 x = u.inner;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol();
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/vec3_f16.wgsl.expected.msl b/test/tint/buffer/uniform/types/vec3_f16.wgsl.expected.msl
new file mode 100644
index 0000000..ce6a7ba
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec3_f16.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(const constant half3* tint_symbol_1 [[buffer(0)]]) {
+  half3 const x = *(tint_symbol_1);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/types/vec3_f16.wgsl.expected.spvasm b/test/tint/buffer/uniform/types/vec3_f16.wgsl.expected.spvasm
new file mode 100644
index 0000000..c0115b9
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec3_f16.wgsl.expected.spvasm
@@ -0,0 +1,38 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 15
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %main "main"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %half = OpTypeFloat 16
+     %v3half = OpTypeVector %half 3
+    %u_block = OpTypeStruct %v3half
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+          %6 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v3half = OpTypePointer Uniform %v3half
+       %main = OpFunction %void None %6
+          %9 = OpLabel
+         %13 = OpAccessChain %_ptr_Uniform_v3half %u %uint_0
+         %14 = OpLoad %v3half %13
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/types/vec3_f16.wgsl.expected.wgsl b/test/tint/buffer/uniform/types/vec3_f16.wgsl.expected.wgsl
new file mode 100644
index 0000000..aecf4fc
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec3_f16.wgsl.expected.wgsl
@@ -0,0 +1,8 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : vec3<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/vec3_f32.wgsl b/test/tint/buffer/uniform/types/vec3_f32.wgsl
new file mode 100644
index 0000000..eea6ffb
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec3_f32.wgsl
@@ -0,0 +1,7 @@
+@group(0) @binding(0)
+var<uniform> u : vec3<f32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/vec3_f32.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/types/vec3_f32.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..bd50e30
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec3_f32.wgsl.expected.dxc.hlsl
@@ -0,0 +1,9 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+[numthreads(1, 1, 1)]
+void main() {
+  const float3 x = asfloat(u[0].xyz);
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/vec3_f32.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/types/vec3_f32.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..bd50e30
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec3_f32.wgsl.expected.fxc.hlsl
@@ -0,0 +1,9 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+[numthreads(1, 1, 1)]
+void main() {
+  const float3 x = asfloat(u[0].xyz);
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/vec3_f32.wgsl.expected.glsl b/test/tint/buffer/uniform/types/vec3_f32.wgsl.expected.glsl
new file mode 100644
index 0000000..8d178e7
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec3_f32.wgsl.expected.glsl
@@ -0,0 +1,15 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  vec3 inner;
+} u;
+
+void tint_symbol() {
+  vec3 x = u.inner;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol();
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/vec3_f32.wgsl.expected.msl b/test/tint/buffer/uniform/types/vec3_f32.wgsl.expected.msl
new file mode 100644
index 0000000..b354a26
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec3_f32.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(const constant float3* tint_symbol_1 [[buffer(0)]]) {
+  float3 const x = *(tint_symbol_1);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/types/vec3_f32.wgsl.expected.spvasm b/test/tint/buffer/uniform/types/vec3_f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..1399f22
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec3_f32.wgsl.expected.spvasm
@@ -0,0 +1,34 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 15
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %main "main"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+    %u_block = OpTypeStruct %v3float
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+          %6 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
+       %main = OpFunction %void None %6
+          %9 = OpLabel
+         %13 = OpAccessChain %_ptr_Uniform_v3float %u %uint_0
+         %14 = OpLoad %v3float %13
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/types/vec3_f32.wgsl.expected.wgsl b/test/tint/buffer/uniform/types/vec3_f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..fd8b627
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec3_f32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+@group(0) @binding(0) var<uniform> u : vec3<f32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/vec3_i32.wgsl b/test/tint/buffer/uniform/types/vec3_i32.wgsl
new file mode 100644
index 0000000..5221b76
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec3_i32.wgsl
@@ -0,0 +1,7 @@
+@group(0) @binding(0)
+var<uniform> u : vec3<i32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/vec3_i32.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/types/vec3_i32.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..f49da65
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec3_i32.wgsl.expected.dxc.hlsl
@@ -0,0 +1,9 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+[numthreads(1, 1, 1)]
+void main() {
+  const int3 x = asint(u[0].xyz);
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/vec3_i32.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/types/vec3_i32.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..f49da65
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec3_i32.wgsl.expected.fxc.hlsl
@@ -0,0 +1,9 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+[numthreads(1, 1, 1)]
+void main() {
+  const int3 x = asint(u[0].xyz);
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/vec3_i32.wgsl.expected.glsl b/test/tint/buffer/uniform/types/vec3_i32.wgsl.expected.glsl
new file mode 100644
index 0000000..e0eb3c4
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec3_i32.wgsl.expected.glsl
@@ -0,0 +1,15 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  ivec3 inner;
+} u;
+
+void tint_symbol() {
+  ivec3 x = u.inner;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol();
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/vec3_i32.wgsl.expected.msl b/test/tint/buffer/uniform/types/vec3_i32.wgsl.expected.msl
new file mode 100644
index 0000000..e014902
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec3_i32.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(const constant int3* tint_symbol_1 [[buffer(0)]]) {
+  int3 const x = *(tint_symbol_1);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/types/vec3_i32.wgsl.expected.spvasm b/test/tint/buffer/uniform/types/vec3_i32.wgsl.expected.spvasm
new file mode 100644
index 0000000..5da4eb3
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec3_i32.wgsl.expected.spvasm
@@ -0,0 +1,34 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 15
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %main "main"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+        %int = OpTypeInt 32 1
+      %v3int = OpTypeVector %int 3
+    %u_block = OpTypeStruct %v3int
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+          %6 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v3int = OpTypePointer Uniform %v3int
+       %main = OpFunction %void None %6
+          %9 = OpLabel
+         %13 = OpAccessChain %_ptr_Uniform_v3int %u %uint_0
+         %14 = OpLoad %v3int %13
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/types/vec3_i32.wgsl.expected.wgsl b/test/tint/buffer/uniform/types/vec3_i32.wgsl.expected.wgsl
new file mode 100644
index 0000000..db38609
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec3_i32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+@group(0) @binding(0) var<uniform> u : vec3<i32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/vec3.wgsl b/test/tint/buffer/uniform/types/vec3_u32.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/types/vec3.wgsl
rename to test/tint/buffer/uniform/types/vec3_u32.wgsl
diff --git a/test/tint/buffer/uniform/types/vec3.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/types/vec3_u32.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/types/vec3.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/uniform/types/vec3_u32.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/uniform/types/vec3.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/types/vec3_u32.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/types/vec3.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/uniform/types/vec3_u32.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/uniform/types/vec3.wgsl.expected.glsl b/test/tint/buffer/uniform/types/vec3_u32.wgsl.expected.glsl
similarity index 100%
rename from test/tint/buffer/uniform/types/vec3.wgsl.expected.glsl
rename to test/tint/buffer/uniform/types/vec3_u32.wgsl.expected.glsl
diff --git a/test/tint/buffer/uniform/types/vec3.wgsl.expected.msl b/test/tint/buffer/uniform/types/vec3_u32.wgsl.expected.msl
similarity index 100%
rename from test/tint/buffer/uniform/types/vec3.wgsl.expected.msl
rename to test/tint/buffer/uniform/types/vec3_u32.wgsl.expected.msl
diff --git a/test/tint/buffer/uniform/types/vec3.wgsl.expected.spvasm b/test/tint/buffer/uniform/types/vec3_u32.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/uniform/types/vec3.wgsl.expected.spvasm
rename to test/tint/buffer/uniform/types/vec3_u32.wgsl.expected.spvasm
diff --git a/test/tint/buffer/uniform/types/vec3.wgsl.expected.wgsl b/test/tint/buffer/uniform/types/vec3_u32.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/types/vec3.wgsl.expected.wgsl
rename to test/tint/buffer/uniform/types/vec3_u32.wgsl.expected.wgsl
diff --git a/test/tint/buffer/uniform/types/vec4_f16.wgsl b/test/tint/buffer/uniform/types/vec4_f16.wgsl
new file mode 100644
index 0000000..bf93dc0
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec4_f16.wgsl
@@ -0,0 +1,9 @@
+enable f16;
+
+@group(0) @binding(0)
+var<uniform> u : vec4<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/vec4_f16.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/types/vec4_f16.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..b4d4152
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec4_f16.wgsl.expected.dxc.hlsl
@@ -0,0 +1,12 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+[numthreads(1, 1, 1)]
+void main() {
+  uint2 ubo_load = u[0].xy;
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const vector<float16_t, 4> x = vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/vec4_f16.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/types/vec4_f16.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..525facb
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec4_f16.wgsl.expected.fxc.hlsl
@@ -0,0 +1,19 @@
+SKIP: FAILED
+
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+[numthreads(1, 1, 1)]
+void main() {
+  uint2 ubo_load = u[0].xy;
+  vector<float16_t, 2> ubo_load_xz = vector<float16_t, 2>(f16tof32(ubo_load & 0xFFFF));
+  vector<float16_t, 2> ubo_load_yw = vector<float16_t, 2>(f16tof32(ubo_load >> 16));
+  const vector<float16_t, 4> x = vector<float16_t, 4>(ubo_load_xz[0], ubo_load_yw[0], ubo_load_xz[1], ubo_load_yw[1]);
+  return;
+}
+FXC validation failure:
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001D83CC52880(8,10-18): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001D83CC52880(9,10-18): error X3000: syntax error: unexpected token 'float16_t'
+D:\Projects\RampUp\dawn\test\tint\buffer\Shader@0x000001D83CC52880(10,16-24): error X3000: syntax error: unexpected token 'float16_t'
+
diff --git a/test/tint/buffer/uniform/types/vec4_f16.wgsl.expected.glsl b/test/tint/buffer/uniform/types/vec4_f16.wgsl.expected.glsl
new file mode 100644
index 0000000..4b67acc
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec4_f16.wgsl.expected.glsl
@@ -0,0 +1,16 @@
+#version 310 es
+#extension GL_AMD_gpu_shader_half_float : require
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  f16vec4 inner;
+} u;
+
+void tint_symbol() {
+  f16vec4 x = u.inner;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol();
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/vec4_f16.wgsl.expected.msl b/test/tint/buffer/uniform/types/vec4_f16.wgsl.expected.msl
new file mode 100644
index 0000000..d8a8bfc
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec4_f16.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(const constant half4* tint_symbol_1 [[buffer(0)]]) {
+  half4 const x = *(tint_symbol_1);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/types/vec4_f16.wgsl.expected.spvasm b/test/tint/buffer/uniform/types/vec4_f16.wgsl.expected.spvasm
new file mode 100644
index 0000000..454bc06
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec4_f16.wgsl.expected.spvasm
@@ -0,0 +1,38 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 15
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float16
+               OpCapability UniformAndStorageBuffer16BitAccess
+               OpCapability StorageBuffer16BitAccess
+               OpCapability StorageInputOutput16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %main "main"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %half = OpTypeFloat 16
+     %v4half = OpTypeVector %half 4
+    %u_block = OpTypeStruct %v4half
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+          %6 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v4half = OpTypePointer Uniform %v4half
+       %main = OpFunction %void None %6
+          %9 = OpLabel
+         %13 = OpAccessChain %_ptr_Uniform_v4half %u %uint_0
+         %14 = OpLoad %v4half %13
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/types/vec4_f16.wgsl.expected.wgsl b/test/tint/buffer/uniform/types/vec4_f16.wgsl.expected.wgsl
new file mode 100644
index 0000000..5fb6d20
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec4_f16.wgsl.expected.wgsl
@@ -0,0 +1,8 @@
+enable f16;
+
+@group(0) @binding(0) var<uniform> u : vec4<f16>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/vec4.wgsl b/test/tint/buffer/uniform/types/vec4_f32.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/types/vec4.wgsl
rename to test/tint/buffer/uniform/types/vec4_f32.wgsl
diff --git a/test/tint/buffer/uniform/types/vec4.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/types/vec4_f32.wgsl.expected.dxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/types/vec4.wgsl.expected.dxc.hlsl
rename to test/tint/buffer/uniform/types/vec4_f32.wgsl.expected.dxc.hlsl
diff --git a/test/tint/buffer/uniform/types/vec4.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/types/vec4_f32.wgsl.expected.fxc.hlsl
similarity index 100%
rename from test/tint/buffer/uniform/types/vec4.wgsl.expected.fxc.hlsl
rename to test/tint/buffer/uniform/types/vec4_f32.wgsl.expected.fxc.hlsl
diff --git a/test/tint/buffer/uniform/types/vec4.wgsl.expected.glsl b/test/tint/buffer/uniform/types/vec4_f32.wgsl.expected.glsl
similarity index 100%
rename from test/tint/buffer/uniform/types/vec4.wgsl.expected.glsl
rename to test/tint/buffer/uniform/types/vec4_f32.wgsl.expected.glsl
diff --git a/test/tint/buffer/uniform/types/vec4.wgsl.expected.msl b/test/tint/buffer/uniform/types/vec4_f32.wgsl.expected.msl
similarity index 100%
rename from test/tint/buffer/uniform/types/vec4.wgsl.expected.msl
rename to test/tint/buffer/uniform/types/vec4_f32.wgsl.expected.msl
diff --git a/test/tint/buffer/uniform/types/vec4.wgsl.expected.spvasm b/test/tint/buffer/uniform/types/vec4_f32.wgsl.expected.spvasm
similarity index 100%
rename from test/tint/buffer/uniform/types/vec4.wgsl.expected.spvasm
rename to test/tint/buffer/uniform/types/vec4_f32.wgsl.expected.spvasm
diff --git a/test/tint/buffer/uniform/types/vec4.wgsl.expected.wgsl b/test/tint/buffer/uniform/types/vec4_f32.wgsl.expected.wgsl
similarity index 100%
rename from test/tint/buffer/uniform/types/vec4.wgsl.expected.wgsl
rename to test/tint/buffer/uniform/types/vec4_f32.wgsl.expected.wgsl
diff --git a/test/tint/buffer/uniform/types/vec4_i32.wgsl b/test/tint/buffer/uniform/types/vec4_i32.wgsl
new file mode 100644
index 0000000..aa8c5b1
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec4_i32.wgsl
@@ -0,0 +1,7 @@
+@group(0) @binding(0)
+var<uniform> u : vec4<i32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/vec4_i32.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/types/vec4_i32.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..a3efa9b
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec4_i32.wgsl.expected.dxc.hlsl
@@ -0,0 +1,9 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+[numthreads(1, 1, 1)]
+void main() {
+  const int4 x = asint(u[0]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/vec4_i32.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/types/vec4_i32.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..a3efa9b
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec4_i32.wgsl.expected.fxc.hlsl
@@ -0,0 +1,9 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+[numthreads(1, 1, 1)]
+void main() {
+  const int4 x = asint(u[0]);
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/vec4_i32.wgsl.expected.glsl b/test/tint/buffer/uniform/types/vec4_i32.wgsl.expected.glsl
new file mode 100644
index 0000000..2b41fc8
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec4_i32.wgsl.expected.glsl
@@ -0,0 +1,15 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  ivec4 inner;
+} u;
+
+void tint_symbol() {
+  ivec4 x = u.inner;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol();
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/vec4_i32.wgsl.expected.msl b/test/tint/buffer/uniform/types/vec4_i32.wgsl.expected.msl
new file mode 100644
index 0000000..7bc39f7
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec4_i32.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(const constant int4* tint_symbol_1 [[buffer(0)]]) {
+  int4 const x = *(tint_symbol_1);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/types/vec4_i32.wgsl.expected.spvasm b/test/tint/buffer/uniform/types/vec4_i32.wgsl.expected.spvasm
new file mode 100644
index 0000000..95a491e
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec4_i32.wgsl.expected.spvasm
@@ -0,0 +1,34 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 15
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %main "main"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+        %int = OpTypeInt 32 1
+      %v4int = OpTypeVector %int 4
+    %u_block = OpTypeStruct %v4int
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+          %6 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v4int = OpTypePointer Uniform %v4int
+       %main = OpFunction %void None %6
+          %9 = OpLabel
+         %13 = OpAccessChain %_ptr_Uniform_v4int %u %uint_0
+         %14 = OpLoad %v4int %13
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/types/vec4_i32.wgsl.expected.wgsl b/test/tint/buffer/uniform/types/vec4_i32.wgsl.expected.wgsl
new file mode 100644
index 0000000..ec8838c
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec4_i32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+@group(0) @binding(0) var<uniform> u : vec4<i32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/vec4_u32.wgsl b/test/tint/buffer/uniform/types/vec4_u32.wgsl
new file mode 100644
index 0000000..a01c90e
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec4_u32.wgsl
@@ -0,0 +1,7 @@
+@group(0) @binding(0)
+var<uniform> u : vec4<u32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}
diff --git a/test/tint/buffer/uniform/types/vec4_u32.wgsl.expected.dxc.hlsl b/test/tint/buffer/uniform/types/vec4_u32.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..686add5
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec4_u32.wgsl.expected.dxc.hlsl
@@ -0,0 +1,9 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+[numthreads(1, 1, 1)]
+void main() {
+  const uint4 x = u[0];
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/vec4_u32.wgsl.expected.fxc.hlsl b/test/tint/buffer/uniform/types/vec4_u32.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..686add5
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec4_u32.wgsl.expected.fxc.hlsl
@@ -0,0 +1,9 @@
+cbuffer cbuffer_u : register(b0, space0) {
+  uint4 u[1];
+};
+
+[numthreads(1, 1, 1)]
+void main() {
+  const uint4 x = u[0];
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/vec4_u32.wgsl.expected.glsl b/test/tint/buffer/uniform/types/vec4_u32.wgsl.expected.glsl
new file mode 100644
index 0000000..84be7e2
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec4_u32.wgsl.expected.glsl
@@ -0,0 +1,15 @@
+#version 310 es
+
+layout(binding = 0, std140) uniform u_block_ubo {
+  uvec4 inner;
+} u;
+
+void tint_symbol() {
+  uvec4 x = u.inner;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  tint_symbol();
+  return;
+}
diff --git a/test/tint/buffer/uniform/types/vec4_u32.wgsl.expected.msl b/test/tint/buffer/uniform/types/vec4_u32.wgsl.expected.msl
new file mode 100644
index 0000000..e7c1bfe
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec4_u32.wgsl.expected.msl
@@ -0,0 +1,8 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol(const constant uint4* tint_symbol_1 [[buffer(0)]]) {
+  uint4 const x = *(tint_symbol_1);
+  return;
+}
+
diff --git a/test/tint/buffer/uniform/types/vec4_u32.wgsl.expected.spvasm b/test/tint/buffer/uniform/types/vec4_u32.wgsl.expected.spvasm
new file mode 100644
index 0000000..a48eca4
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec4_u32.wgsl.expected.spvasm
@@ -0,0 +1,33 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 14
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %u_block "u_block"
+               OpMemberName %u_block 0 "inner"
+               OpName %u "u"
+               OpName %main "main"
+               OpDecorate %u_block Block
+               OpMemberDecorate %u_block 0 Offset 0
+               OpDecorate %u NonWritable
+               OpDecorate %u DescriptorSet 0
+               OpDecorate %u Binding 0
+       %uint = OpTypeInt 32 0
+     %v4uint = OpTypeVector %uint 4
+    %u_block = OpTypeStruct %v4uint
+%_ptr_Uniform_u_block = OpTypePointer Uniform %u_block
+          %u = OpVariable %_ptr_Uniform_u_block Uniform
+       %void = OpTypeVoid
+          %6 = OpTypeFunction %void
+     %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_v4uint = OpTypePointer Uniform %v4uint
+       %main = OpFunction %void None %6
+          %9 = OpLabel
+         %12 = OpAccessChain %_ptr_Uniform_v4uint %u %uint_0
+         %13 = OpLoad %v4uint %12
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/buffer/uniform/types/vec4_u32.wgsl.expected.wgsl b/test/tint/buffer/uniform/types/vec4_u32.wgsl.expected.wgsl
new file mode 100644
index 0000000..92c2b03
--- /dev/null
+++ b/test/tint/buffer/uniform/types/vec4_u32.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+@group(0) @binding(0) var<uniform> u : vec4<u32>;
+
+@compute @workgroup_size(1)
+fn main() {
+  let x = u;
+}