[spirv-reader] Emit multi-component swizzles

When translating OpVectorShuffle, emit swizzles for contiguous
sequences of components from the same vector, and elide the type
constructor if the whole shuffle instruction maps to a single swizzle.

Change-Id: I7685de9c003149864b028676b7a79fe9365c4665
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/137840
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: James Price <jrprice@google.com>
Reviewed-by: David Neto <dneto@google.com>
Auto-Submit: James Price <jrprice@google.com>
diff --git a/src/tint/reader/spirv/function.cc b/src/tint/reader/spirv/function.cc
index c78b9a0..1ac22c1 100644
--- a/src/tint/reader/spirv/function.cc
+++ b/src/tint/reader/spirv/function.cc
@@ -4693,40 +4693,68 @@
     const auto vec0_len = type_mgr_->GetType(vec0.type_id())->AsVector()->element_count();
     const auto vec1_len = type_mgr_->GetType(vec1.type_id())->AsVector()->element_count();
 
-    // Idiomatic vector accessors.
+    // Helper to get the name for the component index `i`.
+    auto component_name = [](uint32_t i) {
+        constexpr const char* names[] = {"x", "y", "z", "w"};
+        TINT_ASSERT(Reader, i < 4);
+        return names[i];
+    };
 
-    // Generate an ast::TypeInitializer expression.
+    // Build a swizzle for each consecutive set of indices that fall within the same vector.
     // Assume the literal indices are valid, and there is a valid number of them.
     auto source = GetSourceForInst(inst);
     const Vector* result_type = As<Vector>(parser_impl_.ConvertType(inst.type_id()));
+    uint32_t last_vec_id = 0u;
+    std::string swizzle;
     ExpressionList values;
     for (uint32_t i = 2; i < inst.NumInOperands(); ++i) {
-        const auto index = inst.GetSingleWordInOperand(i);
+        // Select the source vector and determine the index within it.
+        uint32_t vec_id = 0u;
+        uint32_t index = inst.GetSingleWordInOperand(i);
         if (index < vec0_len) {
-            auto expr = MakeExpression(vec0_id);
-            if (!expr) {
-                return {};
-            }
-            values.Push(create<ast::MemberAccessorExpression>(source, expr.expr, Swizzle(index)));
+            vec_id = vec0_id;
         } else if (index < vec0_len + vec1_len) {
-            const auto sub_index = index - vec0_len;
-            TINT_ASSERT(Reader, sub_index < kMaxVectorLen);
-            auto expr = MakeExpression(vec1_id);
-            if (!expr) {
-                return {};
-            }
-            values.Push(
-                create<ast::MemberAccessorExpression>(source, expr.expr, Swizzle(sub_index)));
+            vec_id = vec1_id;
+            index -= vec0_len;
+            TINT_ASSERT(Reader, index < kMaxVectorLen);
         } else if (index == 0xFFFFFFFF) {
-            // By rule, this maps to OpUndef.  Instead, make it zero.
-            values.Push(parser_impl_.MakeNullValue(result_type->type));
+            // By rule, this maps to OpUndef. Instead, take the first component of the first vector.
+            vec_id = vec0_id;
+            index = 0u;
         } else {
             Fail() << "invalid vectorshuffle ID %" << inst.result_id()
                    << ": index too large: " << index;
             return {};
         }
+
+        if (vec_id != last_vec_id && !swizzle.empty()) {
+            // The source vector has changed, so emit the swizzle so far.
+            auto expr = MakeExpression(last_vec_id);
+            if (!expr) {
+                return {};
+            }
+            values.Push(builder_.MemberAccessor(source, expr.expr, builder_.Ident(swizzle)));
+            swizzle.clear();
+        }
+        swizzle += component_name(index);
+        last_vec_id = vec_id;
     }
-    return {result_type, builder_.Call(source, result_type->Build(builder_), std::move(values))};
+
+    // Emit the final swizzle.
+    auto expr = MakeExpression(last_vec_id);
+    if (!expr) {
+        return {};
+    }
+    values.Push(builder_.MemberAccessor(source, expr.expr, builder_.Ident(swizzle)));
+
+    if (values.Length() == 1) {
+        // There's only one swizzle, so just return it.
+        return {result_type, values[0]};
+    } else {
+        // There's multiple swizzles, so generate a type constructor expression to combine them.
+        return {result_type,
+                builder_.Call(source, result_type->Build(builder_), std::move(values))};
+    }
 }
 
 bool FunctionEmitter::RegisterSpecialBuiltInVariables() {
diff --git a/src/tint/reader/spirv/function_composite_test.cc b/src/tint/reader/spirv/function_composite_test.cc
index 442d6fc..e81025b 100644
--- a/src/tint/reader/spirv/function_composite_test.cc
+++ b/src/tint/reader/spirv/function_composite_test.cc
@@ -779,7 +779,46 @@
     EXPECT_TRUE(fe.EmitBody()) << p->error();
     auto ast_body = fe.ast_body();
     EXPECT_THAT(test::ToString(p->program(), ast_body),
-                HasSubstr("let x_10 = vec4u(x_2.y, x_2.x, x_1.y, x_1.x);"));
+                HasSubstr("let x_10 = vec4u(x_2.yx, x_1.yx);"));
+}
+
+TEST_F(SpvParserTest_VectorShuffle, FunctionScopeOperands_UseBoth_Swizzle) {
+    // Use the same vector for both source operands.
+    const auto assembly = Preamble() + R"(
+     %100 = OpFunction %void None %voidfn
+     %entry = OpLabel
+     %1 = OpCopyObject %v2uint %v2uint_3_4
+     %10 = OpVectorShuffle %v4uint %1 %1 1 0 2 3
+     OpReturn
+     OpFunctionEnd
+)";
+
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr("let x_10 = x_1.yxxy;"));
+}
+
+TEST_F(SpvParserTest_VectorShuffle, FunctionScopeOperands_UseOne_Swizzle) {
+    // Only use the first vector operand.
+    const auto assembly = Preamble() + R"(
+     %100 = OpFunction %void None %voidfn
+     %entry = OpLabel
+     %1 = OpCopyObject %v2uint %v2uint_3_4
+     %2 = OpUndef %v2uint
+     %10 = OpVectorShuffle %v4uint %1 %2 1 0 0 1
+     OpReturn
+     OpFunctionEnd
+)";
+
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr("let x_10 = x_1.yxxy;"));
 }
 
 TEST_F(SpvParserTest_VectorShuffle, ConstantOperands_UseBoth) {
@@ -796,11 +835,8 @@
     auto fe = p->function_emitter(100);
     EXPECT_TRUE(fe.EmitBody()) << p->error();
     auto ast_body = fe.ast_body();
-    EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr("let x_10 = vec4u("
-                                                                  "vec2u(4u, 3u).y, "
-                                                                  "vec2u(4u, 3u).x, "
-                                                                  "vec2u(3u, 4u).y, "
-                                                                  "vec2u(3u, 4u).x);"));
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_10 = vec4u(vec2u(4u, 3u).yx, vec2u(3u, 4u).yx);"));
 }
 
 TEST_F(SpvParserTest_VectorShuffle, ConstantOperands_AllOnesMapToNull) {
@@ -818,7 +854,7 @@
     auto fe = p->function_emitter(100);
     EXPECT_TRUE(fe.EmitBody()) << p->error();
     auto ast_body = fe.ast_body();
-    EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr("let x_10 = vec2u(0u, x_1.y);"));
+    EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr("let x_10 = x_1.xy;"));
 }
 
 TEST_F(SpvParserTest_VectorShuffle, FunctionScopeOperands_MixedInputOperandSizes) {
diff --git a/test/tint/access/let/vector.spvasm.expected.wgsl b/test/tint/access/let/vector.spvasm.expected.wgsl
index da53bac..d7cf7f3 100644
--- a/test/tint/access/let/vector.spvasm.expected.wgsl
+++ b/test/tint/access/let/vector.spvasm.expected.wgsl
@@ -2,8 +2,8 @@
 
 fn main_1() {
   let x_11 = x_10.y;
-  let x_13 = vec2f(x_10.x, x_10.z);
-  let x_14 = vec3f(x_10.x, x_10.z, x_10.y);
+  let x_13 = x_10.xz;
+  let x_14 = x_10.xzy;
   return;
 }
 
diff --git a/test/tint/access/var/vector.spvasm.expected.dxc.hlsl b/test/tint/access/var/vector.spvasm.expected.dxc.hlsl
index cc8ef6b..bd44142 100644
--- a/test/tint/access/var/vector.spvasm.expected.dxc.hlsl
+++ b/test/tint/access/var/vector.spvasm.expected.dxc.hlsl
@@ -2,9 +2,9 @@
   float3 v = (0.0f).xxx;
   const float x_14 = v.y;
   const float3 x_16 = v;
-  const float2 x_17 = float2(x_16.x, x_16.z);
+  const float2 x_17 = x_16.xz;
   const float3 x_18 = v;
-  const float3 x_19 = float3(x_18.x, x_18.z, x_18.y);
+  const float3 x_19 = x_18.xzy;
   return;
 }
 
diff --git a/test/tint/access/var/vector.spvasm.expected.fxc.hlsl b/test/tint/access/var/vector.spvasm.expected.fxc.hlsl
index cc8ef6b..bd44142 100644
--- a/test/tint/access/var/vector.spvasm.expected.fxc.hlsl
+++ b/test/tint/access/var/vector.spvasm.expected.fxc.hlsl
@@ -2,9 +2,9 @@
   float3 v = (0.0f).xxx;
   const float x_14 = v.y;
   const float3 x_16 = v;
-  const float2 x_17 = float2(x_16.x, x_16.z);
+  const float2 x_17 = x_16.xz;
   const float3 x_18 = v;
-  const float3 x_19 = float3(x_18.x, x_18.z, x_18.y);
+  const float3 x_19 = x_18.xzy;
   return;
 }
 
diff --git a/test/tint/access/var/vector.spvasm.expected.glsl b/test/tint/access/var/vector.spvasm.expected.glsl
index fb15d08..559f22e 100644
--- a/test/tint/access/var/vector.spvasm.expected.glsl
+++ b/test/tint/access/var/vector.spvasm.expected.glsl
@@ -4,9 +4,9 @@
   vec3 v = vec3(0.0f);
   float x_14 = v.y;
   vec3 x_16 = v;
-  vec2 x_17 = vec2(x_16.x, x_16.z);
+  vec2 x_17 = x_16.xz;
   vec3 x_18 = v;
-  vec3 x_19 = vec3(x_18.x, x_18.z, x_18.y);
+  vec3 x_19 = x_18.xzy;
   return;
 }
 
diff --git a/test/tint/access/var/vector.spvasm.expected.msl b/test/tint/access/var/vector.spvasm.expected.msl
index fa7b3bc..e846bd0 100644
--- a/test/tint/access/var/vector.spvasm.expected.msl
+++ b/test/tint/access/var/vector.spvasm.expected.msl
@@ -5,9 +5,9 @@
   float3 v = float3(0.0f);
   float const x_14 = v[1];
   float3 const x_16 = v;
-  float2 const x_17 = float2(x_16[0], x_16[2]);
+  float2 const x_17 = x_16.xz;
   float3 const x_18 = v;
-  float3 const x_19 = float3(x_18[0], x_18[2], x_18[1]);
+  float3 const x_19 = x_18.xzy;
   return;
 }
 
diff --git a/test/tint/access/var/vector.spvasm.expected.spvasm b/test/tint/access/var/vector.spvasm.expected.spvasm
index 1ecdce9..e064ab5 100644
--- a/test/tint/access/var/vector.spvasm.expected.spvasm
+++ b/test/tint/access/var/vector.spvasm.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 28
+; Bound: 23
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -27,18 +27,13 @@
          %13 = OpAccessChain %_ptr_Function_float %v %uint_1
          %14 = OpLoad %float %13
          %15 = OpLoad %v3float %v
-         %17 = OpCompositeExtract %float %15 0
-         %18 = OpCompositeExtract %float %15 2
-         %19 = OpCompositeConstruct %v2float %17 %18
-         %20 = OpLoad %v3float %v
-         %21 = OpCompositeExtract %float %20 0
-         %22 = OpCompositeExtract %float %20 2
-         %23 = OpCompositeExtract %float %20 1
-         %24 = OpCompositeConstruct %v3float %21 %22 %23
+         %17 = OpVectorShuffle %v2float %15 %15 0 2
+         %18 = OpLoad %v3float %v
+         %19 = OpVectorShuffle %v3float %18 %18 0 2 1
                OpReturn
                OpFunctionEnd
        %main = OpFunction %void None %1
-         %26 = OpLabel
-         %27 = OpFunctionCall %void %main_1
+         %21 = OpLabel
+         %22 = OpFunctionCall %void %main_1
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/access/var/vector.spvasm.expected.wgsl b/test/tint/access/var/vector.spvasm.expected.wgsl
index 80a5198..855a881 100644
--- a/test/tint/access/var/vector.spvasm.expected.wgsl
+++ b/test/tint/access/var/vector.spvasm.expected.wgsl
@@ -2,9 +2,9 @@
   var v = vec3f();
   let x_14 = v.y;
   let x_16 = v;
-  let x_17 = vec2f(x_16.x, x_16.z);
+  let x_17 = x_16.xz;
   let x_18 = v;
-  let x_19 = vec3f(x_18.x, x_18.z, x_18.y);
+  let x_19 = x_18.xzy;
   return;
 }
 
diff --git a/test/tint/bug/tint/1088.spvasm.expected.dxc.hlsl b/test/tint/bug/tint/1088.spvasm.expected.dxc.hlsl
index 4884747..86d8120 100644
--- a/test/tint/bug/tint/1088.spvasm.expected.dxc.hlsl
+++ b/test/tint/bug/tint/1088.spvasm.expected.dxc.hlsl
@@ -21,7 +21,7 @@
   const float3 x_13 = position_1;
   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);
+  p = x_21.xyz;
   const float x_27 = p.x;
   const float x_41 = asfloat(x_14[13].x);
   const float x_45 = position_1.y;
diff --git a/test/tint/bug/tint/1088.spvasm.expected.fxc.hlsl b/test/tint/bug/tint/1088.spvasm.expected.fxc.hlsl
index 4884747..86d8120 100644
--- a/test/tint/bug/tint/1088.spvasm.expected.fxc.hlsl
+++ b/test/tint/bug/tint/1088.spvasm.expected.fxc.hlsl
@@ -21,7 +21,7 @@
   const float3 x_13 = position_1;
   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);
+  p = x_21.xyz;
   const float x_27 = p.x;
   const float x_41 = asfloat(x_14[13].x);
   const float x_45 = position_1.y;
diff --git a/test/tint/bug/tint/1088.spvasm.expected.glsl b/test/tint/bug/tint/1088.spvasm.expected.glsl
index 678a63e..3213493 100644
--- a/test/tint/bug/tint/1088.spvasm.expected.glsl
+++ b/test/tint/bug/tint/1088.spvasm.expected.glsl
@@ -36,7 +36,7 @@
   vec3 x_13 = position_1;
   q = vec4(x_13.x, x_13.y, x_13.z, 1.0f);
   vec4 x_21 = q;
-  p = vec3(x_21.x, x_21.y, x_21.z);
+  p = x_21.xyz;
   float x_27 = p.x;
   float x_41 = x_14.inner.test[0].el;
   float x_45 = position_1.y;
diff --git a/test/tint/bug/tint/1088.spvasm.expected.msl b/test/tint/bug/tint/1088.spvasm.expected.msl
index cd127ac..20b80cd 100644
--- a/test/tint/bug/tint/1088.spvasm.expected.msl
+++ b/test/tint/bug/tint/1088.spvasm.expected.msl
@@ -41,7 +41,7 @@
   float3 const x_13 = (*(tint_private_vars)).position_1;
   q = float4(x_13[0], x_13[1], x_13[2], 1.0f);
   float4 const x_21 = q;
-  p = float3(x_21[0], x_21[1], x_21[2]);
+  p = x_21.xyz;
   float const x_27 = p[0];
   float const x_41 = (*(tint_symbol_5)).test[0].el;
   float const x_45 = (*(tint_private_vars)).position_1[1];
diff --git a/test/tint/bug/tint/1088.spvasm.expected.spvasm b/test/tint/bug/tint/1088.spvasm.expected.spvasm
index 10fa5cb..e6a807c 100644
--- a/test/tint/bug/tint/1088.spvasm.expected.spvasm
+++ b/test/tint/bug/tint/1088.spvasm.expected.spvasm
@@ -1,10 +1,10 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 123
+; Bound: 120
 ; Schema: 0
                OpCapability Shader
-         %76 = OpExtInstImport "GLSL.std.450"
+         %73 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
                OpEntryPoint Vertex %main "main" %position_1_param_1 %uv_param_1 %normal_param_1 %gl_Position_1 %vUV_1_1 %vertex_point_size
                OpName %position_1_param_1 "position_1_param_1"
@@ -110,7 +110,7 @@
 %_ptr_Function_float = OpTypePointer Function %float
      %uint_3 = OpConstant %uint 3
         %int = OpTypeInt 32 1
-         %64 = OpConstantNull %int
+         %61 = OpConstantNull %int
 %_ptr_Uniform_float = OpTypePointer Uniform %float
      %uint_1 = OpConstant %uint 1
 %_ptr_Private_float = OpTypePointer Private %float
@@ -118,7 +118,7 @@
 %_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float
    %float_n1 = OpConstant %float -1
    %main_out = OpTypeStruct %v4float %v2float
-        %104 = OpTypeFunction %main_out %v3float %v2float %v3float
+        %101 = OpTypeFunction %main_out %v3float %v2float %v3float
      %main_1 = OpFunction %void None %39
          %42 = OpLabel
           %q = OpVariable %_ptr_Function_v4float Function %12
@@ -130,76 +130,73 @@
          %52 = OpCompositeConstruct %v4float %48 %49 %50 %float_1
                OpStore %q %52
          %53 = OpLoad %v4float %q
-         %54 = OpCompositeExtract %float %53 0
-         %55 = OpCompositeExtract %float %53 1
-         %56 = OpCompositeExtract %float %53 2
-         %57 = OpCompositeConstruct %v3float %54 %55 %56
-               OpStore %p %57
-         %60 = OpAccessChain %_ptr_Function_float %p %uint_0
-         %61 = OpLoad %float %60
-         %66 = OpAccessChain %_ptr_Uniform_float %x_14 %uint_0 %uint_3 %64 %uint_0
-         %67 = OpLoad %float %66
-         %70 = OpAccessChain %_ptr_Private_float %position_1 %uint_1
-         %71 = OpLoad %float %70
-         %72 = OpAccessChain %_ptr_Uniform_float %x_14 %uint_0 %uint_1
-         %73 = OpLoad %float %72
-         %74 = OpAccessChain %_ptr_Function_float %p %uint_0
-         %77 = OpFMul %float %67 %71
-         %78 = OpFAdd %float %77 %73
-         %75 = OpExtInst %float %76 Sin %78
-         %79 = OpFAdd %float %61 %75
-               OpStore %74 %79
-         %80 = OpAccessChain %_ptr_Function_float %p %uint_1
-         %81 = OpLoad %float %80
-         %82 = OpAccessChain %_ptr_Uniform_float %x_14 %uint_0 %uint_1
-         %83 = OpLoad %float %82
-         %84 = OpAccessChain %_ptr_Function_float %p %uint_1
-         %87 = OpFAdd %float %83 %float_4
-         %85 = OpExtInst %float %76 Sin %87
-         %88 = OpFAdd %float %81 %85
-               OpStore %84 %88
-         %90 = OpAccessChain %_ptr_Uniform_mat4v4float %x_14 %uint_0 %uint_0
-         %91 = OpLoad %mat4v4float %90
-         %92 = OpLoad %v3float %p
-         %93 = OpCompositeExtract %float %92 0
-         %94 = OpCompositeExtract %float %92 1
-         %95 = OpCompositeExtract %float %92 2
-         %96 = OpCompositeConstruct %v4float %93 %94 %95 %float_1
-         %97 = OpMatrixTimesVector %v4float %91 %96
-               OpStore %gl_Position %97
-         %98 = OpLoad %v2float %uv
-               OpStore %vUV %98
-         %99 = OpAccessChain %_ptr_Private_float %gl_Position %uint_1
-        %100 = OpLoad %float %99
-        %101 = OpAccessChain %_ptr_Private_float %gl_Position %uint_1
-        %103 = OpFMul %float %100 %float_n1
-               OpStore %101 %103
+         %54 = OpVectorShuffle %v3float %53 %53 0 1 2
+               OpStore %p %54
+         %57 = OpAccessChain %_ptr_Function_float %p %uint_0
+         %58 = OpLoad %float %57
+         %63 = OpAccessChain %_ptr_Uniform_float %x_14 %uint_0 %uint_3 %61 %uint_0
+         %64 = OpLoad %float %63
+         %67 = OpAccessChain %_ptr_Private_float %position_1 %uint_1
+         %68 = OpLoad %float %67
+         %69 = OpAccessChain %_ptr_Uniform_float %x_14 %uint_0 %uint_1
+         %70 = OpLoad %float %69
+         %71 = OpAccessChain %_ptr_Function_float %p %uint_0
+         %74 = OpFMul %float %64 %68
+         %75 = OpFAdd %float %74 %70
+         %72 = OpExtInst %float %73 Sin %75
+         %76 = OpFAdd %float %58 %72
+               OpStore %71 %76
+         %77 = OpAccessChain %_ptr_Function_float %p %uint_1
+         %78 = OpLoad %float %77
+         %79 = OpAccessChain %_ptr_Uniform_float %x_14 %uint_0 %uint_1
+         %80 = OpLoad %float %79
+         %81 = OpAccessChain %_ptr_Function_float %p %uint_1
+         %84 = OpFAdd %float %80 %float_4
+         %82 = OpExtInst %float %73 Sin %84
+         %85 = OpFAdd %float %78 %82
+               OpStore %81 %85
+         %87 = OpAccessChain %_ptr_Uniform_mat4v4float %x_14 %uint_0 %uint_0
+         %88 = OpLoad %mat4v4float %87
+         %89 = OpLoad %v3float %p
+         %90 = OpCompositeExtract %float %89 0
+         %91 = OpCompositeExtract %float %89 1
+         %92 = OpCompositeExtract %float %89 2
+         %93 = OpCompositeConstruct %v4float %90 %91 %92 %float_1
+         %94 = OpMatrixTimesVector %v4float %88 %93
+               OpStore %gl_Position %94
+         %95 = OpLoad %v2float %uv
+               OpStore %vUV %95
+         %96 = OpAccessChain %_ptr_Private_float %gl_Position %uint_1
+         %97 = OpLoad %float %96
+         %98 = OpAccessChain %_ptr_Private_float %gl_Position %uint_1
+        %100 = OpFMul %float %97 %float_n1
+               OpStore %98 %100
                OpReturn
                OpFunctionEnd
- %main_inner = OpFunction %main_out None %104
+ %main_inner = OpFunction %main_out None %101
 %position_1_param = OpFunctionParameter %v3float
    %uv_param = OpFunctionParameter %v2float
 %normal_param = OpFunctionParameter %v3float
-        %110 = OpLabel
+        %107 = OpLabel
                OpStore %position_1 %position_1_param
                OpStore %uv %uv_param
                OpStore %normal %normal_param
-        %111 = OpFunctionCall %void %main_1
-        %112 = OpLoad %v4float %gl_Position
-        %113 = OpLoad %v2float %vUV
-        %114 = OpCompositeConstruct %main_out %112 %113
-               OpReturnValue %114
+        %108 = OpFunctionCall %void %main_1
+        %109 = OpLoad %v4float %gl_Position
+        %110 = OpLoad %v2float %vUV
+        %111 = OpCompositeConstruct %main_out %109 %110
+               OpReturnValue %111
                OpFunctionEnd
        %main = OpFunction %void None %39
-        %116 = OpLabel
-        %118 = OpLoad %v3float %position_1_param_1
-        %119 = OpLoad %v2float %uv_param_1
-        %120 = OpLoad %v3float %normal_param_1
-        %117 = OpFunctionCall %main_out %main_inner %118 %119 %120
-        %121 = OpCompositeExtract %v4float %117 0
-               OpStore %gl_Position_1 %121
-        %122 = OpCompositeExtract %v2float %117 1
-               OpStore %vUV_1_1 %122
+        %113 = OpLabel
+        %115 = OpLoad %v3float %position_1_param_1
+        %116 = OpLoad %v2float %uv_param_1
+        %117 = OpLoad %v3float %normal_param_1
+        %114 = OpFunctionCall %main_out %main_inner %115 %116 %117
+        %118 = OpCompositeExtract %v4float %114 0
+               OpStore %gl_Position_1 %118
+        %119 = OpCompositeExtract %v2float %114 1
+               OpStore %vUV_1_1 %119
                OpStore %vertex_point_size %float_1
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/bug/tint/1088.spvasm.expected.wgsl b/test/tint/bug/tint/1088.spvasm.expected.wgsl
index 235d3aa..824c971 100644
--- a/test/tint/bug/tint/1088.spvasm.expected.wgsl
+++ b/test/tint/bug/tint/1088.spvasm.expected.wgsl
@@ -36,7 +36,7 @@
   let x_13 = position_1;
   q = vec4f(x_13.x, x_13.y, x_13.z, 1.0f);
   let x_21 = q;
-  p = vec3f(x_21.x, x_21.y, x_21.z);
+  p = x_21.xyz;
   let x_27 = p.x;
   let x_41 = x_14.test[0i].el;
   let x_45 = position_1.y;