reader/spirv: Partially handle MatrixStride on matrix arrays

SPIR-V spec states:
> Each structure-type member that is a matrix or array-of-matrices must have be decorated with a MatrixStride Decoration

As already pointed out in https://dawn-review.googlesource.com/c/tint/+/59840, we were not handling arrays-of-matrices.
To do this correctly, we need the ast::StrideDecoration to be placed on the Matrix type, which is a much bigger change to support.
For now, chase the type, and error if we have a custom MatrixStride on an array of matrices, otherwise drop the decoration.

Bug: tint:1049
Fixed: tint:1088
Change-Id: Idcb75b3df88040836a03a14e0ca402ebee7be9a7
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/60923
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: David Neto <dneto@google.com>
Commit-Queue: David Neto <dneto@google.com>
Auto-Submit: Ben Clayton <bclayton@google.com>
diff --git a/src/reader/spirv/parser_impl.cc b/src/reader/spirv/parser_impl.cc
index de9fe80..43886bd 100644
--- a/src/reader/spirv/parser_impl.cc
+++ b/src/reader/spirv/parser_impl.cc
@@ -487,11 +487,22 @@
         return {};
       }
       uint32_t stride = decoration[1];
-      uint32_t natural_stride = 0;
-      if (auto* mat = member_ty->As<Matrix>()) {
-        natural_stride = (mat->rows == 2) ? 8 : 16;
+      auto* ty = member_ty->UnwrapAlias();
+      while (auto* arr = ty->As<Array>()) {
+        ty = arr->type->UnwrapAlias();
       }
+      auto* mat = ty->As<Matrix>();
+      if (!mat) {
+        Fail() << "MatrixStride cannot be applied to type " << ty->String();
+        return {};
+      }
+      uint32_t natural_stride = (mat->rows == 2) ? 8 : 16;
       if (stride == natural_stride) {
+        return {};  // Decoration matches the natural stride for the matrix
+      }
+      if (!member_ty->Is<Matrix>()) {
+        Fail() << "custom matrix strides not currently supported on array of "
+                  "matrices";
         return {};
       }
       return {
diff --git a/src/reader/spirv/parser_type.h b/src/reader/spirv/parser_type.h
index 0db8aee..e82a0df 100644
--- a/src/reader/spirv/parser_type.h
+++ b/src/reader/spirv/parser_type.h
@@ -80,7 +80,10 @@
   /// @returns true if this type is an unsigned scalar or vector
   bool IsUnsignedScalarOrVector() const;
 
-#ifndef NDEBUG
+#ifdef NDEBUG
+  /// @returns "<no-type-info>", for debug purposes only
+  std::string String() const { return "<no-type-info>"; }
+#else
   /// @returns a string representation of the type, for debug purposes only
   virtual std::string String() const = 0;
 #endif  // NDEBUG
diff --git a/test/bug/tint/1088.spvasm b/test/bug/tint/1088.spvasm
new file mode 100644
index 0000000..d68575c
--- /dev/null
+++ b/test/bug/tint/1088.spvasm
@@ -0,0 +1,149 @@
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 8
+; Bound: 91
+; Schema: 0
+                            OpCapability Shader
+                       %1 = OpExtInstImport "GLSL.std.450"
+                            OpMemoryModel Logical GLSL450
+                            OpEntryPoint Vertex %main "main" %position %__0 %vUV %uv %normal
+                            OpSource GLSL 450
+                            OpName %main "main"
+                            OpName %q "q"
+                            OpName %position "position"
+                            OpName %p "p"
+                            OpName %LeftOver "LeftOver"
+                            OpMemberName %LeftOver 0 "worldViewProjection"
+                            OpMemberName %LeftOver 1 "time"
+                            OpMemberName %LeftOver 2 "test2"
+                            OpMemberName %LeftOver 3 "test"
+                            OpName %_ ""
+                            OpName %gl_PerVertex "gl_PerVertex"
+                            OpMemberName %gl_PerVertex 0 "gl_Position"
+                            OpMemberName %gl_PerVertex 1 "gl_PointSize"
+                            OpMemberName %gl_PerVertex 2 "gl_ClipDistance"
+                            OpMemberName %gl_PerVertex 3 "gl_CullDistance"
+                            OpName %__0 ""
+                            OpName %vUV "vUV"
+                            OpName %uv "uv"
+                            OpName %normal "normal"
+                            OpDecorate %position Location 0
+                            OpDecorate %_arr_mat4v4float_uint_2 ArrayStride 64
+                            OpDecorate %_arr_float_uint_4 ArrayStride 16
+                            OpMemberDecorate %LeftOver 0 ColMajor
+                            OpMemberDecorate %LeftOver 0 Offset 0
+                            OpMemberDecorate %LeftOver 0 MatrixStride 16
+                            OpMemberDecorate %LeftOver 1 Offset 64
+                            OpMemberDecorate %LeftOver 2 ColMajor
+                            OpMemberDecorate %LeftOver 2 Offset 80
+                            OpMemberDecorate %LeftOver 2 MatrixStride 16
+                            OpMemberDecorate %LeftOver 3 Offset 208
+                            OpDecorate %LeftOver Block
+                            OpDecorate %_ DescriptorSet 2
+                            OpDecorate %_ Binding 2
+                            OpMemberDecorate %gl_PerVertex 0 BuiltIn Position
+                            OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize
+                            OpMemberDecorate %gl_PerVertex 2 BuiltIn ClipDistance
+                            OpMemberDecorate %gl_PerVertex 3 BuiltIn CullDistance
+                            OpDecorate %gl_PerVertex Block
+                            OpDecorate %vUV Location 0
+                            OpDecorate %uv Location 2
+                            OpDecorate %normal Location 1
+                    %void = OpTypeVoid
+                       %3 = OpTypeFunction %void
+                   %float = OpTypeFloat 32
+                 %v4float = OpTypeVector %float 4
+   %_ptr_Function_v4float = OpTypePointer Function %v4float
+                 %v3float = OpTypeVector %float 3
+      %_ptr_Input_v3float = OpTypePointer Input %v3float
+                %position = OpVariable %_ptr_Input_v3float Input
+                 %float_1 = OpConstant %float 1
+   %_ptr_Function_v3float = OpTypePointer Function %v3float
+                    %uint = OpTypeInt 32 0
+                  %uint_0 = OpConstant %uint 0
+     %_ptr_Function_float = OpTypePointer Function %float
+             %mat4v4float = OpTypeMatrix %v4float 4
+                  %uint_2 = OpConstant %uint 2
+ %_arr_mat4v4float_uint_2 = OpTypeArray %mat4v4float %uint_2
+                  %uint_4 = OpConstant %uint 4
+       %_arr_float_uint_4 = OpTypeArray %float %uint_4
+                %LeftOver = OpTypeStruct %mat4v4float %float %_arr_mat4v4float_uint_2 %_arr_float_uint_4
+   %_ptr_Uniform_LeftOver = OpTypePointer Uniform %LeftOver
+                       %_ = OpVariable %_ptr_Uniform_LeftOver Uniform
+                     %int = OpTypeInt 32 1
+                   %int_3 = OpConstant %int 3
+                   %int_0 = OpConstant %int 0
+      %_ptr_Uniform_float = OpTypePointer Uniform %float
+                  %uint_1 = OpConstant %uint 1
+        %_ptr_Input_float = OpTypePointer Input %float
+                   %int_1 = OpConstant %int 1
+                 %float_4 = OpConstant %float 4
+       %_arr_float_uint_1 = OpTypeArray %float %uint_1
+            %gl_PerVertex = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1
+%_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex
+                     %__0 = OpVariable %_ptr_Output_gl_PerVertex Output
+%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float
+     %_ptr_Output_v4float = OpTypePointer Output %v4float
+                 %v2float = OpTypeVector %float 2
+     %_ptr_Output_v2float = OpTypePointer Output %v2float
+                     %vUV = OpVariable %_ptr_Output_v2float Output
+      %_ptr_Input_v2float = OpTypePointer Input %v2float
+                      %uv = OpVariable %_ptr_Input_v2float Input
+                %float_n1 = OpConstant %float -1
+       %_ptr_Output_float = OpTypePointer Output %float
+                  %normal = OpVariable %_ptr_Input_v3float Input
+                    %main = OpFunction %void None %3
+                       %5 = OpLabel
+                       %q = OpVariable %_ptr_Function_v4float Function
+                       %p = OpVariable %_ptr_Function_v3float Function
+                      %13 = OpLoad %v3float %position
+                      %15 = OpCompositeExtract %float %13 0
+                      %16 = OpCompositeExtract %float %13 1
+                      %17 = OpCompositeExtract %float %13 2
+                      %18 = OpCompositeConstruct %v4float %15 %16 %17 %float_1
+                            OpStore %q %18
+                      %21 = OpLoad %v4float %q
+                      %22 = OpVectorShuffle %v3float %21 %21 0 1 2
+                            OpStore %p %22
+                      %26 = OpAccessChain %_ptr_Function_float %p %uint_0
+                      %27 = OpLoad %float %26
+                      %40 = OpAccessChain %_ptr_Uniform_float %_ %int_3 %int_0
+                      %41 = OpLoad %float %40
+                      %44 = OpAccessChain %_ptr_Input_float %position %uint_1
+                      %45 = OpLoad %float %44
+                      %46 = OpFMul %float %41 %45
+                      %48 = OpAccessChain %_ptr_Uniform_float %_ %int_1
+                      %49 = OpLoad %float %48
+                      %50 = OpFAdd %float %46 %49
+                      %51 = OpExtInst %float %1 Sin %50
+                      %52 = OpFAdd %float %27 %51
+                      %53 = OpAccessChain %_ptr_Function_float %p %uint_0
+                            OpStore %53 %52
+                      %54 = OpAccessChain %_ptr_Function_float %p %uint_1
+                      %55 = OpLoad %float %54
+                      %56 = OpAccessChain %_ptr_Uniform_float %_ %int_1
+                      %57 = OpLoad %float %56
+                      %59 = OpFAdd %float %57 %float_4
+                      %60 = OpExtInst %float %1 Sin %59
+                      %61 = OpFAdd %float %55 %60
+                      %62 = OpAccessChain %_ptr_Function_float %p %uint_1
+                            OpStore %62 %61
+                      %68 = OpAccessChain %_ptr_Uniform_mat4v4float %_ %int_0
+                      %69 = OpLoad %mat4v4float %68
+                      %70 = OpLoad %v3float %p
+                      %71 = OpCompositeExtract %float %70 0
+                      %72 = OpCompositeExtract %float %70 1
+                      %73 = OpCompositeExtract %float %70 2
+                      %74 = OpCompositeConstruct %v4float %71 %72 %73 %float_1
+                      %75 = OpMatrixTimesVector %v4float %69 %74
+                      %77 = OpAccessChain %_ptr_Output_v4float %__0 %int_0
+                            OpStore %77 %75
+                      %83 = OpLoad %v2float %uv
+                            OpStore %vUV %83
+                      %86 = OpAccessChain %_ptr_Output_float %__0 %int_0 %uint_1
+                      %87 = OpLoad %float %86
+                      %88 = OpFMul %float %87 %float_n1
+                      %89 = OpAccessChain %_ptr_Output_float %__0 %int_0 %uint_1
+                            OpStore %89 %88
+                            OpReturn
+                            OpFunctionEnd
diff --git a/test/bug/tint/1088.spvasm.expected.hlsl b/test/bug/tint/1088.spvasm.expected.hlsl
new file mode 100644
index 0000000..a77d6dc
--- /dev/null
+++ b/test/bug/tint/1088.spvasm.expected.hlsl
@@ -0,0 +1,68 @@
+static float3 position = float3(0.0f, 0.0f, 0.0f);
+cbuffer cbuffer_x_14 : register(b2, space2) {
+  uint4 x_14[17];
+};
+static float2 vUV = float2(0.0f, 0.0f);
+static float2 uv = float2(0.0f, 0.0f);
+static float3 normal = float3(0.0f, 0.0f, 0.0f);
+static float4 gl_Position = float4(0.0f, 0.0f, 0.0f, 0.0f);
+
+float4x4 tint_symbol_5(uint4 buffer[17], 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 main_1() {
+  float4 q = float4(0.0f, 0.0f, 0.0f, 0.0f);
+  float3 p = float3(0.0f, 0.0f, 0.0f);
+  const float3 x_13 = position;
+  q = float4(x_13.x, x_13.y, x_13.z, 1.0f);
+  const float4 x_21 = q;
+  p = float3(x_21.x, x_21.y, x_21.z);
+  const float x_27 = p.x;
+  const uint scalar_offset_4 = ((208u + (16u * uint(0)))) / 4;
+  const float x_41 = asfloat(x_14[scalar_offset_4 / 4][scalar_offset_4 % 4]);
+  const float x_45 = position.y;
+  const float x_49 = asfloat(x_14[4].x);
+  p.x = (x_27 + sin(((x_41 * x_45) + x_49)));
+  const float x_55 = p.y;
+  const float x_57 = asfloat(x_14[4].x);
+  p.y = (x_55 + sin((x_57 + 4.0f)));
+  const float4x4 x_69 = tint_symbol_5(x_14, 0u);
+  const float3 x_70 = p;
+  gl_Position = mul(float4(x_70.x, x_70.y, x_70.z, 1.0f), x_69);
+  vUV = uv;
+  const float x_87 = gl_Position.y;
+  gl_Position.y = (x_87 * -1.0f);
+  return;
+}
+
+struct main_out {
+  float4 gl_Position;
+  float2 vUV_1;
+};
+struct tint_symbol_1 {
+  float3 position_param : TEXCOORD0;
+  float3 normal_param : TEXCOORD1;
+  float2 uv_param : TEXCOORD2;
+};
+struct tint_symbol_2 {
+  float2 vUV_1 : TEXCOORD0;
+  float4 gl_Position : SV_Position;
+};
+
+tint_symbol_2 main(tint_symbol_1 tint_symbol) {
+  const float3 position_param = tint_symbol.position_param;
+  const float2 uv_param = tint_symbol.uv_param;
+  const float3 normal_param = tint_symbol.normal_param;
+  position = position_param;
+  uv = uv_param;
+  normal = normal_param;
+  main_1();
+  const main_out tint_symbol_3 = {gl_Position, vUV};
+  const tint_symbol_2 tint_symbol_7 = {tint_symbol_3.vUV_1, tint_symbol_3.gl_Position};
+  return tint_symbol_7;
+}
diff --git a/test/bug/tint/1088.spvasm.expected.msl b/test/bug/tint/1088.spvasm.expected.msl
new file mode 100644
index 0000000..2e9e3da
--- /dev/null
+++ b/test/bug/tint/1088.spvasm.expected.msl
@@ -0,0 +1,77 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct tint_array_wrapper {
+  /* 0x0000 */ float4x4 arr[2];
+};
+struct tint_padded_array_element {
+  /* 0x0000 */ float el;
+  /* 0x0004 */ int8_t tint_pad[12];
+};
+struct tint_array_wrapper_1 {
+  /* 0x0000 */ tint_padded_array_element arr[4];
+};
+struct LeftOver {
+  /* 0x0000 */ float4x4 worldViewProjection;
+  /* 0x0040 */ float time;
+  /* 0x0044 */ int8_t tint_pad_1[12];
+  /* 0x0050 */ tint_array_wrapper test2;
+  /* 0x00d0 */ tint_array_wrapper_1 test;
+};
+struct main_out {
+  float4 gl_Position;
+  float2 vUV_1;
+};
+struct tint_symbol_2 {
+  float3 position_param [[attribute(0)]];
+  float3 normal_param [[attribute(1)]];
+  float2 uv_param [[attribute(2)]];
+};
+struct tint_symbol_3 {
+  float2 vUV_1 [[user(locn0)]];
+  float4 gl_Position [[position]];
+};
+
+void main_1(constant LeftOver& x_14, thread float3* const tint_symbol_6, thread float4* const tint_symbol_7, thread float2* const tint_symbol_8, thread float2* const tint_symbol_9) {
+  float4 q = 0.0f;
+  float3 p = 0.0f;
+  float3 const x_13 = *(tint_symbol_6);
+  q = float4(x_13.x, x_13.y, x_13.z, 1.0f);
+  float4 const x_21 = q;
+  p = float3(x_21.x, x_21.y, x_21.z);
+  float const x_27 = p.x;
+  float const x_41 = x_14.test.arr[0].el;
+  float const x_45 = (*(tint_symbol_6)).y;
+  float const x_49 = x_14.time;
+  p.x = (x_27 + sin(((x_41 * x_45) + x_49)));
+  float const x_55 = p.y;
+  float const x_57 = x_14.time;
+  p.y = (x_55 + sin((x_57 + 4.0f)));
+  float4x4 const x_69 = x_14.worldViewProjection;
+  float3 const x_70 = p;
+  *(tint_symbol_7) = (x_69 * float4(x_70.x, x_70.y, x_70.z, 1.0f));
+  float2 const x_83 = *(tint_symbol_8);
+  *(tint_symbol_9) = x_83;
+  float const x_87 = (*(tint_symbol_7)).y;
+  (*(tint_symbol_7)).y = (x_87 * -1.0f);
+  return;
+}
+
+vertex tint_symbol_3 tint_symbol(tint_symbol_2 tint_symbol_1 [[stage_in]], constant LeftOver& x_14 [[buffer(2)]]) {
+  thread float3 tint_symbol_10 = 0.0f;
+  thread float2 tint_symbol_11 = 0.0f;
+  thread float3 tint_symbol_12 = 0.0f;
+  thread float4 tint_symbol_13 = 0.0f;
+  thread float2 tint_symbol_14 = 0.0f;
+  float3 const position_param = tint_symbol_1.position_param;
+  float2 const uv_param = tint_symbol_1.uv_param;
+  float3 const normal_param = tint_symbol_1.normal_param;
+  tint_symbol_10 = position_param;
+  tint_symbol_11 = uv_param;
+  tint_symbol_12 = normal_param;
+  main_1(x_14, &(tint_symbol_10), &(tint_symbol_13), &(tint_symbol_11), &(tint_symbol_14));
+  main_out const tint_symbol_4 = {.gl_Position=tint_symbol_13, .vUV_1=tint_symbol_14};
+  tint_symbol_3 const tint_symbol_5 = {.vUV_1=tint_symbol_4.vUV_1, .gl_Position=tint_symbol_4.gl_Position};
+  return tint_symbol_5;
+}
+
diff --git a/test/bug/tint/1088.spvasm.expected.spvasm b/test/bug/tint/1088.spvasm.expected.spvasm
new file mode 100644
index 0000000..aef2a82
--- /dev/null
+++ b/test/bug/tint/1088.spvasm.expected.spvasm
@@ -0,0 +1,193 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 119
+; Schema: 0
+               OpCapability Shader
+         %74 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Vertex %main "main" %tint_pointsize %tint_symbol %tint_symbol_1 %tint_symbol_2 %tint_symbol_4 %tint_symbol_5
+               OpName %tint_pointsize "tint_pointsize"
+               OpName %position "position"
+               OpName %LeftOver "LeftOver"
+               OpMemberName %LeftOver 0 "worldViewProjection"
+               OpMemberName %LeftOver 1 "time"
+               OpMemberName %LeftOver 2 "test2"
+               OpMemberName %LeftOver 3 "test"
+               OpName %x_14 "x_14"
+               OpName %vUV "vUV"
+               OpName %uv "uv"
+               OpName %normal "normal"
+               OpName %gl_Position "gl_Position"
+               OpName %tint_symbol "tint_symbol"
+               OpName %tint_symbol_1 "tint_symbol_1"
+               OpName %tint_symbol_2 "tint_symbol_2"
+               OpName %tint_symbol_4 "tint_symbol_4"
+               OpName %tint_symbol_5 "tint_symbol_5"
+               OpName %main_1 "main_1"
+               OpName %q "q"
+               OpName %p "p"
+               OpName %main_out "main_out"
+               OpMemberName %main_out 0 "gl_Position"
+               OpMemberName %main_out 1 "vUV_1"
+               OpName %tint_symbol_6 "tint_symbol_6"
+               OpName %tint_symbol_3 "tint_symbol_3"
+               OpName %main "main"
+               OpDecorate %tint_pointsize BuiltIn PointSize
+               OpDecorate %LeftOver Block
+               OpMemberDecorate %LeftOver 0 Offset 0
+               OpMemberDecorate %LeftOver 0 ColMajor
+               OpMemberDecorate %LeftOver 0 MatrixStride 16
+               OpMemberDecorate %LeftOver 1 Offset 64
+               OpMemberDecorate %LeftOver 2 Offset 80
+               OpMemberDecorate %LeftOver 2 ColMajor
+               OpMemberDecorate %LeftOver 2 MatrixStride 16
+               OpDecorate %_arr_mat4v4float_uint_2 ArrayStride 64
+               OpMemberDecorate %LeftOver 3 Offset 208
+               OpDecorate %_arr_float_uint_4 ArrayStride 16
+               OpDecorate %x_14 NonWritable
+               OpDecorate %x_14 DescriptorSet 2
+               OpDecorate %x_14 Binding 2
+               OpDecorate %tint_symbol Location 0
+               OpDecorate %tint_symbol_1 Location 2
+               OpDecorate %tint_symbol_2 Location 1
+               OpDecorate %tint_symbol_4 BuiltIn Position
+               OpDecorate %tint_symbol_5 Location 0
+               OpMemberDecorate %main_out 0 Offset 0
+               OpMemberDecorate %main_out 1 Offset 16
+      %float = OpTypeFloat 32
+%_ptr_Output_float = OpTypePointer Output %float
+          %4 = OpConstantNull %float
+%tint_pointsize = OpVariable %_ptr_Output_float Output %4
+    %v3float = OpTypeVector %float 3
+%_ptr_Private_v3float = OpTypePointer Private %v3float
+          %8 = OpConstantNull %v3float
+   %position = OpVariable %_ptr_Private_v3float Private %8
+    %v4float = OpTypeVector %float 4
+%mat4v4float = OpTypeMatrix %v4float 4
+       %uint = OpTypeInt 32 0
+     %uint_2 = OpConstant %uint 2
+%_arr_mat4v4float_uint_2 = OpTypeArray %mat4v4float %uint_2
+     %uint_4 = OpConstant %uint 4
+%_arr_float_uint_4 = OpTypeArray %float %uint_4
+   %LeftOver = OpTypeStruct %mat4v4float %float %_arr_mat4v4float_uint_2 %_arr_float_uint_4
+%_ptr_Uniform_LeftOver = OpTypePointer Uniform %LeftOver
+       %x_14 = OpVariable %_ptr_Uniform_LeftOver Uniform
+    %v2float = OpTypeVector %float 2
+%_ptr_Private_v2float = OpTypePointer Private %v2float
+         %22 = OpConstantNull %v2float
+        %vUV = OpVariable %_ptr_Private_v2float Private %22
+         %uv = OpVariable %_ptr_Private_v2float Private %22
+     %normal = OpVariable %_ptr_Private_v3float Private %8
+%_ptr_Private_v4float = OpTypePointer Private %v4float
+         %27 = OpConstantNull %v4float
+%gl_Position = OpVariable %_ptr_Private_v4float Private %27
+%_ptr_Input_v3float = OpTypePointer Input %v3float
+%tint_symbol = OpVariable %_ptr_Input_v3float Input
+%_ptr_Input_v2float = OpTypePointer Input %v2float
+%tint_symbol_1 = OpVariable %_ptr_Input_v2float Input
+%tint_symbol_2 = OpVariable %_ptr_Input_v3float Input
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+%tint_symbol_4 = OpVariable %_ptr_Output_v4float Output %27
+%_ptr_Output_v2float = OpTypePointer Output %v2float
+%tint_symbol_5 = OpVariable %_ptr_Output_v2float Output %22
+       %void = OpTypeVoid
+         %37 = OpTypeFunction %void
+%_ptr_Function_v4float = OpTypePointer Function %v4float
+%_ptr_Function_v3float = OpTypePointer Function %v3float
+    %float_1 = OpConstant %float 1
+     %uint_0 = OpConstant %uint 0
+%_ptr_Function_float = OpTypePointer Function %float
+     %uint_3 = OpConstant %uint 3
+        %int = OpTypeInt 32 1
+      %int_0 = OpConstant %int 0
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+     %uint_1 = OpConstant %uint 1
+%_ptr_Private_float = OpTypePointer Private %float
+    %float_4 = OpConstant %float 4
+%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float
+   %float_n1 = OpConstant %float -1
+   %main_out = OpTypeStruct %v4float %v2float
+        %102 = OpTypeFunction %void %main_out
+     %main_1 = OpFunction %void None %37
+         %40 = OpLabel
+          %q = OpVariable %_ptr_Function_v4float Function %27
+          %p = OpVariable %_ptr_Function_v3float Function %8
+         %45 = OpLoad %v3float %position
+         %46 = OpCompositeExtract %float %45 0
+         %47 = OpCompositeExtract %float %45 1
+         %48 = OpCompositeExtract %float %45 2
+         %50 = OpCompositeConstruct %v4float %46 %47 %48 %float_1
+               OpStore %q %50
+         %51 = OpLoad %v4float %q
+         %52 = OpCompositeExtract %float %51 0
+         %53 = OpCompositeExtract %float %51 1
+         %54 = OpCompositeExtract %float %51 2
+         %55 = OpCompositeConstruct %v3float %52 %53 %54
+               OpStore %p %55
+         %58 = OpAccessChain %_ptr_Function_float %p %uint_0
+         %59 = OpLoad %float %58
+         %64 = OpAccessChain %_ptr_Uniform_float %x_14 %uint_3 %int_0
+         %65 = OpLoad %float %64
+         %68 = OpAccessChain %_ptr_Private_float %position %uint_1
+         %69 = OpLoad %float %68
+         %70 = OpAccessChain %_ptr_Uniform_float %x_14 %uint_1
+         %71 = OpLoad %float %70
+         %72 = OpAccessChain %_ptr_Function_float %p %uint_0
+         %75 = OpFMul %float %65 %69
+         %76 = OpFAdd %float %75 %71
+         %73 = OpExtInst %float %74 Sin %76
+         %77 = OpFAdd %float %59 %73
+               OpStore %72 %77
+         %78 = OpAccessChain %_ptr_Function_float %p %uint_1
+         %79 = OpLoad %float %78
+         %80 = OpAccessChain %_ptr_Uniform_float %x_14 %uint_1
+         %81 = OpLoad %float %80
+         %82 = OpAccessChain %_ptr_Function_float %p %uint_1
+         %85 = OpFAdd %float %81 %float_4
+         %83 = OpExtInst %float %74 Sin %85
+         %86 = OpFAdd %float %79 %83
+               OpStore %82 %86
+         %88 = OpAccessChain %_ptr_Uniform_mat4v4float %x_14 %uint_0
+         %89 = OpLoad %mat4v4float %88
+         %90 = OpLoad %v3float %p
+         %91 = OpCompositeExtract %float %90 0
+         %92 = OpCompositeExtract %float %90 1
+         %93 = OpCompositeExtract %float %90 2
+         %94 = OpCompositeConstruct %v4float %91 %92 %93 %float_1
+         %95 = OpMatrixTimesVector %v4float %89 %94
+               OpStore %gl_Position %95
+         %96 = OpLoad %v2float %uv
+               OpStore %vUV %96
+         %97 = OpAccessChain %_ptr_Private_float %gl_Position %uint_1
+         %98 = OpLoad %float %97
+         %99 = OpAccessChain %_ptr_Private_float %gl_Position %uint_1
+        %101 = OpFMul %float %98 %float_n1
+               OpStore %99 %101
+               OpReturn
+               OpFunctionEnd
+%tint_symbol_6 = OpFunction %void None %102
+%tint_symbol_3 = OpFunctionParameter %main_out
+        %106 = OpLabel
+        %107 = OpCompositeExtract %v4float %tint_symbol_3 0
+               OpStore %tint_symbol_4 %107
+        %108 = OpCompositeExtract %v2float %tint_symbol_3 1
+               OpStore %tint_symbol_5 %108
+               OpReturn
+               OpFunctionEnd
+       %main = OpFunction %void None %37
+        %110 = OpLabel
+               OpStore %tint_pointsize %float_1
+        %111 = OpLoad %v3float %tint_symbol
+               OpStore %position %111
+        %112 = OpLoad %v2float %tint_symbol_1
+               OpStore %uv %112
+        %113 = OpLoad %v3float %tint_symbol_2
+               OpStore %normal %113
+        %114 = OpFunctionCall %void %main_1
+        %116 = OpLoad %v4float %gl_Position
+        %117 = OpLoad %v2float %vUV
+        %118 = OpCompositeConstruct %main_out %116 %117
+        %115 = OpFunctionCall %void %tint_symbol_6 %118
+               OpReturn
+               OpFunctionEnd
diff --git a/test/bug/tint/1088.spvasm.expected.wgsl b/test/bug/tint/1088.spvasm.expected.wgsl
new file mode 100644
index 0000000..347b3c6
--- /dev/null
+++ b/test/bug/tint/1088.spvasm.expected.wgsl
@@ -0,0 +1,66 @@
+type Arr = [[stride(64)]] array<mat4x4<f32>, 2>;
+
+type Arr_1 = [[stride(16)]] array<f32, 4>;
+
+[[block]]
+struct LeftOver {
+  worldViewProjection : mat4x4<f32>;
+  time : f32;
+  [[size(12)]]
+  padding : u32;
+  test2 : Arr;
+  test : Arr_1;
+};
+
+var<private> position : vec3<f32>;
+
+[[group(2), binding(2)]] var<uniform> x_14 : LeftOver;
+
+var<private> vUV : vec2<f32>;
+
+var<private> uv : vec2<f32>;
+
+var<private> normal : vec3<f32>;
+
+var<private> gl_Position : vec4<f32>;
+
+fn main_1() {
+  var q : vec4<f32>;
+  var p : vec3<f32>;
+  let x_13 : vec3<f32> = position;
+  q = vec4<f32>(x_13.x, x_13.y, x_13.z, 1.0);
+  let x_21 : vec4<f32> = q;
+  p = vec3<f32>(x_21.x, x_21.y, x_21.z);
+  let x_27 : f32 = p.x;
+  let x_41 : f32 = x_14.test[0];
+  let x_45 : f32 = position.y;
+  let x_49 : f32 = x_14.time;
+  p.x = (x_27 + sin(((x_41 * x_45) + x_49)));
+  let x_55 : f32 = p.y;
+  let x_57 : f32 = x_14.time;
+  p.y = (x_55 + sin((x_57 + 4.0)));
+  let x_69 : mat4x4<f32> = x_14.worldViewProjection;
+  let x_70 : vec3<f32> = p;
+  gl_Position = (x_69 * vec4<f32>(x_70.x, x_70.y, x_70.z, 1.0));
+  let x_83 : vec2<f32> = uv;
+  vUV = x_83;
+  let x_87 : f32 = gl_Position.y;
+  gl_Position.y = (x_87 * -1.0);
+  return;
+}
+
+struct main_out {
+  [[builtin(position)]]
+  gl_Position : vec4<f32>;
+  [[location(0)]]
+  vUV_1 : vec2<f32>;
+};
+
+[[stage(vertex)]]
+fn main([[location(0)]] position_param : vec3<f32>, [[location(2)]] uv_param : vec2<f32>, [[location(1)]] normal_param : vec3<f32>) -> main_out {
+  position = position_param;
+  uv = uv_param;
+  normal = normal_param;
+  main_1();
+  return main_out(gl_Position, vUV);
+}