Use an id count to clamp ID in subgroupShuffle.

When doing a subgroupSuffle, use a subgroup count instead of the
subgroup size builtin. This gives a tighter bound on the actual number
of subgroups being invoked.

Bug: 435246627
Change-Id: Ifb3bb1cef635c32c65ff2595e3ac2e82f7429dc4
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/333515
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: dan sinclair <dsinclair@chromium.org>
diff --git a/src/tint/lang/spirv/writer/raise/builtin_polyfill.cc b/src/tint/lang/spirv/writer/raise/builtin_polyfill.cc
index b900049..07524a8 100644
--- a/src/tint/lang/spirv/writer/raise/builtin_polyfill.cc
+++ b/src/tint/lang/spirv/writer/raise/builtin_polyfill.cc
@@ -186,6 +186,8 @@
 
     /// Module-scoped variable for subgroup size mask.
     core::ir::Var* subgroup_size_mask_ = nullptr;
+    /// Module-scoped variable for the last active subgroup id.
+    core::ir::Var* subgroup_last_id_ = nullptr;
 
     /// Process the module.
     void Process() {
@@ -248,11 +250,14 @@
                     case core::BuiltinFn::kSubgroupBroadcast:
                         worklist.push_back([this, builtin] { SubgroupBroadcast(builtin); });
                         break;
-                    case core::BuiltinFn::kSubgroupShuffle:
+                    case core::BuiltinFn::kSubgroupShuffle: {
+                        worklist.push_back([this, builtin] { SubgroupShuffle(builtin); });
+                        break;
+                    }
                     case core::BuiltinFn::kSubgroupShuffleDown:
                     case core::BuiltinFn::kSubgroupShuffleUp:
                     case core::BuiltinFn::kSubgroupShuffleXor: {
-                        worklist.push_back([this, builtin] { SubgroupShuffle(builtin); });
+                        worklist.push_back([this, builtin] { SubgroupShuffleDirection(builtin); });
                         break;
                     }
                     case core::BuiltinFn::kTextureDimensions:
@@ -368,11 +373,18 @@
             construct->SetArg(0, value);
         }
 
-        if (subgroup_size_mask_) {
+        if (subgroup_size_mask_ || subgroup_last_id_) {
             for (auto func : ir.functions) {
-                if (func->IsEntryPoint()) {
+                if (!func->IsEntryPoint()) {
+                    continue;
+                }
+
+                if (subgroup_size_mask_) {
                     SetSubgroupSizeMaskForEntryPoint(func);
                 }
+                if (subgroup_last_id_) {
+                    SetSubgroupLastIdForEntryPoint(func);
+                }
             }
         }
     }
@@ -411,6 +423,14 @@
         });
     }
 
+    /// Set the subgroup_last_id_ variable from an entry point.
+    void SetSubgroupLastIdForEntryPoint(core::ir::Function* ep) {
+        b.InsertBefore(ep->Block()->Front(), [&] {
+            core::ir::Instruction* count = b.Call(ty.u32(), core::BuiltinFn::kSubgroupAdd, 1_u);
+            b.Store(subgroup_last_id_, b.Subtract(count, 1_u));
+        });
+    }
+
     /// Create a literal operand.
     /// @param value the literal value
     /// @returns the literal operand
@@ -1300,8 +1320,7 @@
         ir.properties.Add(core::ir::Property::kAllowAnyInputAttachmentIndexType);
     }
 
-    /// Handles SubgroupShuffle(), SubgroupShuffleDown(), SubgroupShuffleUp(), SubgroupShuffleXor()
-    /// builtins.
+    /// Handles SubgroupShuffle() builtin.
     /// @param builtin the builtin call instruction
     void SubgroupShuffle(core::ir::CoreBuiltinCall* builtin) {
         TINT_IR_ASSERT(ir, builtin->Args().size() == 2);
@@ -1317,6 +1336,37 @@
 
         /// Polyfill a `subgroupShuffleX` builtin call with one that has clamped the arg2 param
         auto* shuffle_id = builtin->Args()[1];
+        if (!subgroup_last_id_) {
+            b.Append(ir.root_block, [&] {
+                subgroup_last_id_ =
+                    b.Var<core::AddressSpace::kPrivate, u32>("tint_subgroup_last_id");
+            });
+        }
+        b.InsertBefore(builtin, [&] {
+            auto* last_id = b.Load(subgroup_last_id_);
+            auto* clamp_via_min = b.Min(shuffle_id, last_id);
+            builtin->SetArg(1, clamp_via_min->Result());
+        });
+    }
+
+    /// Handles SubgroupShuffleDown(), SubgroupShuffleUp(), SubgroupShuffleXor() builtins.
+    /// @param builtin the builtin call instruction
+    /// TODO(548610177): This should be updated to use a stricter bounds for the `b.And`, similar to
+    /// what SubgroupShuffle above does, but tailored for the specific up/down/xor variant.
+    void SubgroupShuffleDirection(core::ir::CoreBuiltinCall* builtin) {
+        TINT_IR_ASSERT(ir, builtin->Args().size() == 2);
+        // The second argument is either 'id' , 'delta', or 'mask'.
+        // All must be bound by [0, subgroup_size)
+        auto* arg2 = builtin->Args()[1];
+        // arg2 must be an unsigned integer scalar, so bitcast if necessary.
+        if (arg2->Type()->IsSignedIntegerScalar()) {
+            auto* cast = b.Bitcast(ty.u32(), arg2);
+            cast->InsertBefore(builtin);
+            builtin->SetArg(1, cast->Result());
+        }
+
+        /// Polyfill a `subgroupShuffleX` builtin call with one that has clamped the arg2 param
+        auto* shuffle_id = builtin->Args()[1];
         if (!subgroup_size_mask_) {
             b.Append(ir.root_block, [&] {
                 subgroup_size_mask_ =
diff --git a/src/tint/lang/spirv/writer/raise/builtin_polyfill_test.cc b/src/tint/lang/spirv/writer/raise/builtin_polyfill_test.cc
index 51745b1..59403b2 100644
--- a/src/tint/lang/spirv/writer/raise/builtin_polyfill_test.cc
+++ b/src/tint/lang/spirv/writer/raise/builtin_polyfill_test.cc
@@ -4192,16 +4192,17 @@
 
     auto* expect = R"(
 $B1: {  # root
-  %tint_subgroup_size_mask:ptr<private, u32, read_write> = var undef
+  %tint_subgroup_last_id:ptr<private, u32, read_write> = var undef
 }
 
-%foo = @fragment func(%tint_subgroup_size:u32 [@subgroup_size]):void {
+%foo = @fragment func():void {
   $B2: {
-    %4:u32 = sub %tint_subgroup_size, 1u
-    store %tint_subgroup_size_mask, %4
+    %3:u32 = subgroupAdd 1u
+    %4:u32 = sub %3, 1u
+    store %tint_subgroup_last_id, %4
     %5:u32 = bitcast<u32> 1i
-    %6:u32 = load %tint_subgroup_size_mask
-    %7:u32 = and %5, %6
+    %6:u32 = load %tint_subgroup_last_id
+    %7:u32 = min %5, %6
     %8:i32 = subgroupShuffle 1i, %7
     %a:i32 = let %8
     ret
@@ -4239,18 +4240,19 @@
 
     auto* expect = R"(
 $B1: {  # root
-  %tint_subgroup_size_mask:ptr<private, u32, read_write> = var undef
+  %tint_subgroup_last_id:ptr<private, u32, read_write> = var undef
 }
 
 %foo = @fragment func(%my_subgroup_size:u32 [@subgroup_size]):void {
   $B2: {
-    %4:u32 = sub %my_subgroup_size, 1u
-    store %tint_subgroup_size_mask, %4
-    %5:u32 = bitcast<u32> 1i
-    %6:u32 = load %tint_subgroup_size_mask
-    %7:u32 = and %5, %6
-    %8:i32 = subgroupShuffle 1i, %7
-    %a:i32 = let %8
+    %4:u32 = subgroupAdd 1u
+    %5:u32 = sub %4, 1u
+    store %tint_subgroup_last_id, %5
+    %6:u32 = bitcast<u32> 1i
+    %7:u32 = load %tint_subgroup_last_id
+    %8:u32 = min %6, %7
+    %9:i32 = subgroupShuffle 1i, %8
+    %a:i32 = let %9
     ret
   }
 }
@@ -4303,17 +4305,17 @@
 }
 
 $B1: {  # root
-  %tint_subgroup_size_mask:ptr<private, u32, read_write> = var undef
+  %tint_subgroup_last_id:ptr<private, u32, read_write> = var undef
 }
 
 %foo = @fragment func(%inputs:S):void {
   $B2: {
-    %4:u32 = access %inputs, 0u
+    %4:u32 = subgroupAdd 1u
     %5:u32 = sub %4, 1u
-    store %tint_subgroup_size_mask, %5
+    store %tint_subgroup_last_id, %5
     %6:u32 = bitcast<u32> 1i
-    %7:u32 = load %tint_subgroup_size_mask
-    %8:u32 = and %6, %7
+    %7:u32 = load %tint_subgroup_last_id
+    %8:u32 = min %6, %7
     %9:i32 = subgroupShuffle 1i, %8
     %a:i32 = let %9
     ret
@@ -5526,18 +5528,19 @@
 )";
     auto* expect = R"(
 $B1: {  # root
-  %tint_subgroup_size_mask:ptr<private, u32, read_write> = var undef
+  %tint_subgroup_last_id:ptr<private, u32, read_write> = var undef
 }
 
-%foo = @fragment func(%tint_subgroup_size:u32 [@subgroup_size]):void {
+%foo = @fragment func():void {
   $B2: {
-    %4:u32 = sub %tint_subgroup_size, 1u
-    store %tint_subgroup_size_mask, %4
+    %3:u32 = subgroupAdd 1u
+    %4:u32 = sub %3, 1u
+    store %tint_subgroup_last_id, %4
     %arg1:i32 = let 1i
     %arg2:i32 = let 1i
     %7:u32 = bitcast<u32> %arg2
-    %8:u32 = load %tint_subgroup_size_mask
-    %9:u32 = and %7, %8
+    %8:u32 = load %tint_subgroup_last_id
+    %9:u32 = min %7, %8
     %10:i32 = subgroupShuffle %arg1, %9
     %a:i32 = let %10
     ret
@@ -5574,17 +5577,18 @@
 )";
     auto* expect = R"(
 $B1: {  # root
-  %tint_subgroup_size_mask:ptr<private, u32, read_write> = var undef
+  %tint_subgroup_last_id:ptr<private, u32, read_write> = var undef
 }
 
-%foo = @fragment func(%tint_subgroup_size:u32 [@subgroup_size]):void {
+%foo = @fragment func():void {
   $B2: {
-    %4:u32 = sub %tint_subgroup_size, 1u
-    store %tint_subgroup_size_mask, %4
+    %3:u32 = subgroupAdd 1u
+    %4:u32 = sub %3, 1u
+    store %tint_subgroup_last_id, %4
     %arg1:u32 = let 1u
     %arg2:u32 = let 1u
-    %7:u32 = load %tint_subgroup_size_mask
-    %8:u32 = and %arg2, %7
+    %7:u32 = load %tint_subgroup_last_id
+    %8:u32 = min %arg2, %7
     %9:u32 = subgroupShuffle %arg1, %8
     %a:u32 = let %9
     ret
@@ -5621,17 +5625,18 @@
 )";
     auto* expect = R"(
 $B1: {  # root
-  %tint_subgroup_size_mask:ptr<private, u32, read_write> = var undef
+  %tint_subgroup_last_id:ptr<private, u32, read_write> = var undef
 }
 
-%foo = @fragment func(%tint_subgroup_size:u32 [@subgroup_size]):void {
+%foo = @fragment func():void {
   $B2: {
-    %4:u32 = sub %tint_subgroup_size, 1u
-    store %tint_subgroup_size_mask, %4
+    %3:u32 = subgroupAdd 1u
+    %4:u32 = sub %3, 1u
+    store %tint_subgroup_last_id, %4
     %arg1:f32 = let 1.0f
     %arg2:u32 = let 1u
-    %7:u32 = load %tint_subgroup_size_mask
-    %8:u32 = and %arg2, %7
+    %7:u32 = load %tint_subgroup_last_id
+    %8:u32 = min %arg2, %7
     %9:f32 = subgroupShuffle %arg1, %8
     %a:f32 = let %9
     ret
@@ -5668,17 +5673,18 @@
 )";
     auto* expect = R"(
 $B1: {  # root
-  %tint_subgroup_size_mask:ptr<private, u32, read_write> = var undef
+  %tint_subgroup_last_id:ptr<private, u32, read_write> = var undef
 }
 
-%foo = @fragment func(%tint_subgroup_size:u32 [@subgroup_size]):void {
+%foo = @fragment func():void {
   $B2: {
-    %4:u32 = sub %tint_subgroup_size, 1u
-    store %tint_subgroup_size_mask, %4
+    %3:u32 = subgroupAdd 1u
+    %4:u32 = sub %3, 1u
+    store %tint_subgroup_last_id, %4
     %arg1:vec2<f32> = let vec2<f32>(1.0f)
     %arg2:u32 = let 1u
-    %7:u32 = load %tint_subgroup_size_mask
-    %8:u32 = and %arg2, %7
+    %7:u32 = load %tint_subgroup_last_id
+    %8:u32 = min %arg2, %7
     %9:vec2<f32> = subgroupShuffle %arg1, %8
     %a:vec2<f32> = let %9
     ret
diff --git a/test/tint/builtins/gen/literal/subgroupShuffle/030422.wgsl.expected.spvasm b/test/tint/builtins/gen/literal/subgroupShuffle/030422.wgsl.expected.spvasm
index fc8da8f..a383268 100644
--- a/test/tint/builtins/gen/literal/subgroupShuffle/030422.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/literal/subgroupShuffle/030422.wgsl.expected.spvasm
@@ -4,30 +4,26 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 41
+; Bound: 35
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %17 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_030422 "subgroupShuffle_030422"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
       %float = OpTypeFloat 32
 %prevent_dce_block = OpTypeStruct %float
 %_ptr_StorageBuffer_prevent_dce_block = OpTypePointer StorageBuffer %prevent_dce_block
@@ -35,46 +31,37 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %float
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %float
         %int = OpTypeInt 32 1
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
     %float_1 = OpConstant %float 1
 %_ptr_Function_float = OpTypePointer Function %float
        %void = OpTypeVoid
-         %28 = OpTypeFunction %void %uint
+         %26 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
      %uint_0 = OpConstant %uint 0
-         %37 = OpTypeFunction %void
-%subgroupShuffle_030422 = OpFunction %float None %12
-         %13 = OpLabel
+%subgroupShuffle_030422 = OpFunction %float None %10
+         %11 = OpLabel
         %res = OpVariable %_ptr_Function_float Function
-         %14 = OpBitcast %uint %int_1
-         %17 = OpLoad %uint %tint_subgroup_size_mask None
-         %18 = OpBitwiseAnd %uint %14 %17
-         %19 = OpGroupNonUniformShuffle %float %uint_3 %float_1 %18
-               OpStore %res %19
-         %24 = OpLoad %float %res None
-               OpReturnValue %24
+         %12 = OpBitcast %uint %int_1
+         %15 = OpLoad %uint %tint_subgroup_last_id None
+         %16 = OpExtInst %uint %17 UMin %12 %15
+         %18 = OpGroupNonUniformShuffle %float %uint_3 %float_1 %16
+               OpStore %res %18
+         %23 = OpLoad %float %res None
+               OpReturnValue %23
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %28
-%tint_subgroup_size = OpFunctionParameter %uint
-         %29 = OpLabel
-         %30 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %30 None
-         %32 = OpFunctionCall %float %subgroupShuffle_030422
-         %33 = OpAccessChain %_ptr_StorageBuffer_float %1 %uint_0
-               OpStore %33 %32 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %37
-         %38 = OpLabel
-         %39 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %40 = OpFunctionCall %void %fragment_main_inner %39
+%fragment_main = OpFunction %void None %26
+         %27 = OpLabel
+         %28 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %30 = OpISub %uint %28 %uint_1
+               OpStore %tint_subgroup_last_id %30 None
+         %31 = OpFunctionCall %float %subgroupShuffle_030422
+         %32 = OpAccessChain %_ptr_StorageBuffer_float %1 %uint_0
+               OpStore %32 %31 None
                OpReturn
                OpFunctionEnd
 ;
@@ -83,29 +70,26 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 41
+; Bound: 35
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %17 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_030422 "subgroupShuffle_030422"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
       %float = OpTypeFloat 32
 %prevent_dce_block = OpTypeStruct %float
 %_ptr_StorageBuffer_prevent_dce_block = OpTypePointer StorageBuffer %prevent_dce_block
@@ -113,45 +97,36 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %float
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %float
         %int = OpTypeInt 32 1
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
     %float_1 = OpConstant %float 1
 %_ptr_Function_float = OpTypePointer Function %float
        %void = OpTypeVoid
-         %28 = OpTypeFunction %void %uint
+         %26 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
      %uint_0 = OpConstant %uint 0
-         %37 = OpTypeFunction %void
-%subgroupShuffle_030422 = OpFunction %float None %12
-         %13 = OpLabel
+%subgroupShuffle_030422 = OpFunction %float None %10
+         %11 = OpLabel
         %res = OpVariable %_ptr_Function_float Function
-         %14 = OpBitcast %uint %int_1
-         %17 = OpLoad %uint %tint_subgroup_size_mask None
-         %18 = OpBitwiseAnd %uint %14 %17
-         %19 = OpGroupNonUniformShuffle %float %uint_3 %float_1 %18
-               OpStore %res %19
-         %24 = OpLoad %float %res None
-               OpReturnValue %24
+         %12 = OpBitcast %uint %int_1
+         %15 = OpLoad %uint %tint_subgroup_last_id None
+         %16 = OpExtInst %uint %17 UMin %12 %15
+         %18 = OpGroupNonUniformShuffle %float %uint_3 %float_1 %16
+               OpStore %res %18
+         %23 = OpLoad %float %res None
+               OpReturnValue %23
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %28
-%tint_subgroup_size = OpFunctionParameter %uint
-         %29 = OpLabel
-         %30 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %30 None
-         %32 = OpFunctionCall %float %subgroupShuffle_030422
-         %33 = OpAccessChain %_ptr_StorageBuffer_float %1 %uint_0
-               OpStore %33 %32 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %37
-         %38 = OpLabel
-         %39 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %40 = OpFunctionCall %void %compute_main_inner %39
+%compute_main = OpFunction %void None %26
+         %27 = OpLabel
+         %28 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %30 = OpISub %uint %28 %uint_1
+               OpStore %tint_subgroup_last_id %30 None
+         %31 = OpFunctionCall %float %subgroupShuffle_030422
+         %32 = OpAccessChain %_ptr_StorageBuffer_float %1 %uint_0
+               OpStore %32 %31 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/literal/subgroupShuffle/1f664c.wgsl.expected.spvasm b/test/tint/builtins/gen/literal/subgroupShuffle/1f664c.wgsl.expected.spvasm
index f6a92f7..7e9d70c 100644
--- a/test/tint/builtins/gen/literal/subgroupShuffle/1f664c.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/literal/subgroupShuffle/1f664c.wgsl.expected.spvasm
@@ -4,30 +4,26 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 40
+; Bound: 34
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %15 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_1f664c "subgroupShuffle_1f664c"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
       %float = OpTypeFloat 32
     %v3float = OpTypeVector %float 3
 %prevent_dce_block = OpTypeStruct %v3float
@@ -36,44 +32,35 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v3float
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v3float
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
     %float_1 = OpConstant %float 1
-         %20 = OpConstantComposite %v3float %float_1 %float_1 %float_1
+         %19 = OpConstantComposite %v3float %float_1 %float_1 %float_1
 %_ptr_Function_v3float = OpTypePointer Function %v3float
        %void = OpTypeVoid
-         %28 = OpTypeFunction %void %uint
+         %26 = OpTypeFunction %void
 %_ptr_StorageBuffer_v3float = OpTypePointer StorageBuffer %v3float
      %uint_0 = OpConstant %uint 0
-         %36 = OpTypeFunction %void
-%subgroupShuffle_1f664c = OpFunction %v3float None %13
-         %14 = OpLabel
+%subgroupShuffle_1f664c = OpFunction %v3float None %11
+         %12 = OpLabel
         %res = OpVariable %_ptr_Function_v3float Function
-         %15 = OpLoad %uint %tint_subgroup_size_mask None
-         %16 = OpBitwiseAnd %uint %uint_1 %15
-         %18 = OpGroupNonUniformShuffle %v3float %uint_3 %20 %16
-               OpStore %res %18
-         %24 = OpLoad %v3float %res None
-               OpReturnValue %24
+         %13 = OpLoad %uint %tint_subgroup_last_id None
+         %14 = OpExtInst %uint %15 UMin %uint_1 %13
+         %17 = OpGroupNonUniformShuffle %v3float %uint_3 %19 %14
+               OpStore %res %17
+         %23 = OpLoad %v3float %res None
+               OpReturnValue %23
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %28
-%tint_subgroup_size = OpFunctionParameter %uint
-         %29 = OpLabel
-         %30 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %30 None
-         %31 = OpFunctionCall %v3float %subgroupShuffle_1f664c
-         %32 = OpAccessChain %_ptr_StorageBuffer_v3float %1 %uint_0
-               OpStore %32 %31 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %36
-         %37 = OpLabel
-         %38 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %39 = OpFunctionCall %void %fragment_main_inner %38
+%fragment_main = OpFunction %void None %26
+         %27 = OpLabel
+         %28 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %29 = OpISub %uint %28 %uint_1
+               OpStore %tint_subgroup_last_id %29 None
+         %30 = OpFunctionCall %v3float %subgroupShuffle_1f664c
+         %31 = OpAccessChain %_ptr_StorageBuffer_v3float %1 %uint_0
+               OpStore %31 %30 None
                OpReturn
                OpFunctionEnd
 ;
@@ -82,29 +69,26 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 40
+; Bound: 34
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %15 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_1f664c "subgroupShuffle_1f664c"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
       %float = OpTypeFloat 32
     %v3float = OpTypeVector %float 3
 %prevent_dce_block = OpTypeStruct %v3float
@@ -113,43 +97,34 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v3float
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v3float
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
     %float_1 = OpConstant %float 1
-         %20 = OpConstantComposite %v3float %float_1 %float_1 %float_1
+         %19 = OpConstantComposite %v3float %float_1 %float_1 %float_1
 %_ptr_Function_v3float = OpTypePointer Function %v3float
        %void = OpTypeVoid
-         %28 = OpTypeFunction %void %uint
+         %26 = OpTypeFunction %void
 %_ptr_StorageBuffer_v3float = OpTypePointer StorageBuffer %v3float
      %uint_0 = OpConstant %uint 0
-         %36 = OpTypeFunction %void
-%subgroupShuffle_1f664c = OpFunction %v3float None %13
-         %14 = OpLabel
+%subgroupShuffle_1f664c = OpFunction %v3float None %11
+         %12 = OpLabel
         %res = OpVariable %_ptr_Function_v3float Function
-         %15 = OpLoad %uint %tint_subgroup_size_mask None
-         %16 = OpBitwiseAnd %uint %uint_1 %15
-         %18 = OpGroupNonUniformShuffle %v3float %uint_3 %20 %16
-               OpStore %res %18
-         %24 = OpLoad %v3float %res None
-               OpReturnValue %24
+         %13 = OpLoad %uint %tint_subgroup_last_id None
+         %14 = OpExtInst %uint %15 UMin %uint_1 %13
+         %17 = OpGroupNonUniformShuffle %v3float %uint_3 %19 %14
+               OpStore %res %17
+         %23 = OpLoad %v3float %res None
+               OpReturnValue %23
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %28
-%tint_subgroup_size = OpFunctionParameter %uint
-         %29 = OpLabel
-         %30 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %30 None
-         %31 = OpFunctionCall %v3float %subgroupShuffle_1f664c
-         %32 = OpAccessChain %_ptr_StorageBuffer_v3float %1 %uint_0
-               OpStore %32 %31 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %36
-         %37 = OpLabel
-         %38 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %39 = OpFunctionCall %void %compute_main_inner %38
+%compute_main = OpFunction %void None %26
+         %27 = OpLabel
+         %28 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %29 = OpISub %uint %28 %uint_1
+               OpStore %tint_subgroup_last_id %29 None
+         %30 = OpFunctionCall %v3float %subgroupShuffle_1f664c
+         %31 = OpAccessChain %_ptr_StorageBuffer_v3float %1 %uint_0
+               OpStore %31 %30 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/literal/subgroupShuffle/21f083.wgsl.expected.spvasm b/test/tint/builtins/gen/literal/subgroupShuffle/21f083.wgsl.expected.spvasm
index d99a928..813a88a 100644
--- a/test/tint/builtins/gen/literal/subgroupShuffle/21f083.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/literal/subgroupShuffle/21f083.wgsl.expected.spvasm
@@ -4,30 +4,26 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 41
+; Bound: 35
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %17 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_21f083 "subgroupShuffle_21f083"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
        %uint = OpTypeInt 32 0
      %v2uint = OpTypeVector %uint 2
 %prevent_dce_block = OpTypeStruct %v2uint
@@ -35,46 +31,37 @@
           %1 = OpVariable %_ptr_StorageBuffer_prevent_dce_block StorageBuffer
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %v2uint
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %v2uint
         %int = OpTypeInt 32 1
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
      %uint_1 = OpConstant %uint 1
-         %21 = OpConstantComposite %v2uint %uint_1 %uint_1
+         %20 = OpConstantComposite %v2uint %uint_1 %uint_1
 %_ptr_Function_v2uint = OpTypePointer Function %v2uint
        %void = OpTypeVoid
-         %29 = OpTypeFunction %void %uint
+         %27 = OpTypeFunction %void
 %_ptr_StorageBuffer_v2uint = OpTypePointer StorageBuffer %v2uint
      %uint_0 = OpConstant %uint 0
-         %37 = OpTypeFunction %void
-%subgroupShuffle_21f083 = OpFunction %v2uint None %12
-         %13 = OpLabel
+%subgroupShuffle_21f083 = OpFunction %v2uint None %10
+         %11 = OpLabel
         %res = OpVariable %_ptr_Function_v2uint Function
-         %14 = OpBitcast %uint %int_1
-         %17 = OpLoad %uint %tint_subgroup_size_mask None
-         %18 = OpBitwiseAnd %uint %14 %17
-         %19 = OpGroupNonUniformShuffle %v2uint %uint_3 %21 %18
-               OpStore %res %19
-         %25 = OpLoad %v2uint %res None
-               OpReturnValue %25
+         %12 = OpBitcast %uint %int_1
+         %15 = OpLoad %uint %tint_subgroup_last_id None
+         %16 = OpExtInst %uint %17 UMin %12 %15
+         %18 = OpGroupNonUniformShuffle %v2uint %uint_3 %20 %16
+               OpStore %res %18
+         %24 = OpLoad %v2uint %res None
+               OpReturnValue %24
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %29
-%tint_subgroup_size = OpFunctionParameter %uint
-         %30 = OpLabel
-         %31 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %31 None
-         %32 = OpFunctionCall %v2uint %subgroupShuffle_21f083
-         %33 = OpAccessChain %_ptr_StorageBuffer_v2uint %1 %uint_0
-               OpStore %33 %32 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %37
-         %38 = OpLabel
-         %39 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %40 = OpFunctionCall %void %fragment_main_inner %39
+%fragment_main = OpFunction %void None %27
+         %28 = OpLabel
+         %29 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %30 = OpISub %uint %29 %uint_1
+               OpStore %tint_subgroup_last_id %30 None
+         %31 = OpFunctionCall %v2uint %subgroupShuffle_21f083
+         %32 = OpAccessChain %_ptr_StorageBuffer_v2uint %1 %uint_0
+               OpStore %32 %31 None
                OpReturn
                OpFunctionEnd
 ;
@@ -83,29 +70,26 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 41
+; Bound: 35
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %17 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_21f083 "subgroupShuffle_21f083"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
        %uint = OpTypeInt 32 0
      %v2uint = OpTypeVector %uint 2
 %prevent_dce_block = OpTypeStruct %v2uint
@@ -113,45 +97,36 @@
           %1 = OpVariable %_ptr_StorageBuffer_prevent_dce_block StorageBuffer
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %v2uint
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %v2uint
         %int = OpTypeInt 32 1
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
      %uint_1 = OpConstant %uint 1
-         %21 = OpConstantComposite %v2uint %uint_1 %uint_1
+         %20 = OpConstantComposite %v2uint %uint_1 %uint_1
 %_ptr_Function_v2uint = OpTypePointer Function %v2uint
        %void = OpTypeVoid
-         %29 = OpTypeFunction %void %uint
+         %27 = OpTypeFunction %void
 %_ptr_StorageBuffer_v2uint = OpTypePointer StorageBuffer %v2uint
      %uint_0 = OpConstant %uint 0
-         %37 = OpTypeFunction %void
-%subgroupShuffle_21f083 = OpFunction %v2uint None %12
-         %13 = OpLabel
+%subgroupShuffle_21f083 = OpFunction %v2uint None %10
+         %11 = OpLabel
         %res = OpVariable %_ptr_Function_v2uint Function
-         %14 = OpBitcast %uint %int_1
-         %17 = OpLoad %uint %tint_subgroup_size_mask None
-         %18 = OpBitwiseAnd %uint %14 %17
-         %19 = OpGroupNonUniformShuffle %v2uint %uint_3 %21 %18
-               OpStore %res %19
-         %25 = OpLoad %v2uint %res None
-               OpReturnValue %25
+         %12 = OpBitcast %uint %int_1
+         %15 = OpLoad %uint %tint_subgroup_last_id None
+         %16 = OpExtInst %uint %17 UMin %12 %15
+         %18 = OpGroupNonUniformShuffle %v2uint %uint_3 %20 %16
+               OpStore %res %18
+         %24 = OpLoad %v2uint %res None
+               OpReturnValue %24
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %29
-%tint_subgroup_size = OpFunctionParameter %uint
-         %30 = OpLabel
-         %31 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %31 None
-         %32 = OpFunctionCall %v2uint %subgroupShuffle_21f083
-         %33 = OpAccessChain %_ptr_StorageBuffer_v2uint %1 %uint_0
-               OpStore %33 %32 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %37
-         %38 = OpLabel
-         %39 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %40 = OpFunctionCall %void %compute_main_inner %39
+%compute_main = OpFunction %void None %27
+         %28 = OpLabel
+         %29 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %30 = OpISub %uint %29 %uint_1
+               OpStore %tint_subgroup_last_id %30 None
+         %31 = OpFunctionCall %v2uint %subgroupShuffle_21f083
+         %32 = OpAccessChain %_ptr_StorageBuffer_v2uint %1 %uint_0
+               OpStore %32 %31 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/literal/subgroupShuffle/2ee993.wgsl.expected.spvasm b/test/tint/builtins/gen/literal/subgroupShuffle/2ee993.wgsl.expected.spvasm
index bd6bce2..90deac2 100644
--- a/test/tint/builtins/gen/literal/subgroupShuffle/2ee993.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/literal/subgroupShuffle/2ee993.wgsl.expected.spvasm
@@ -4,30 +4,26 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 41
+; Bound: 35
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %17 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_2ee993 "subgroupShuffle_2ee993"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
         %int = OpTypeInt 32 1
       %v4int = OpTypeVector %int 4
 %prevent_dce_block = OpTypeStruct %v4int
@@ -36,45 +32,36 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v4int
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v4int
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
-         %21 = OpConstantComposite %v4int %int_1 %int_1 %int_1 %int_1
+         %20 = OpConstantComposite %v4int %int_1 %int_1 %int_1 %int_1
 %_ptr_Function_v4int = OpTypePointer Function %v4int
        %void = OpTypeVoid
-         %28 = OpTypeFunction %void %uint
+         %26 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_v4int = OpTypePointer StorageBuffer %v4int
      %uint_0 = OpConstant %uint 0
-         %37 = OpTypeFunction %void
-%subgroupShuffle_2ee993 = OpFunction %v4int None %13
-         %14 = OpLabel
+%subgroupShuffle_2ee993 = OpFunction %v4int None %11
+         %12 = OpLabel
         %res = OpVariable %_ptr_Function_v4int Function
-         %15 = OpBitcast %uint %int_1
-         %17 = OpLoad %uint %tint_subgroup_size_mask None
-         %18 = OpBitwiseAnd %uint %15 %17
-         %19 = OpGroupNonUniformShuffle %v4int %uint_3 %21 %18
-               OpStore %res %19
-         %24 = OpLoad %v4int %res None
-               OpReturnValue %24
+         %13 = OpBitcast %uint %int_1
+         %15 = OpLoad %uint %tint_subgroup_last_id None
+         %16 = OpExtInst %uint %17 UMin %13 %15
+         %18 = OpGroupNonUniformShuffle %v4int %uint_3 %20 %16
+               OpStore %res %18
+         %23 = OpLoad %v4int %res None
+               OpReturnValue %23
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %28
-%tint_subgroup_size = OpFunctionParameter %uint
-         %29 = OpLabel
-         %30 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %30 None
-         %32 = OpFunctionCall %v4int %subgroupShuffle_2ee993
-         %33 = OpAccessChain %_ptr_StorageBuffer_v4int %1 %uint_0
-               OpStore %33 %32 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %37
-         %38 = OpLabel
-         %39 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %40 = OpFunctionCall %void %fragment_main_inner %39
+%fragment_main = OpFunction %void None %26
+         %27 = OpLabel
+         %28 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %30 = OpISub %uint %28 %uint_1
+               OpStore %tint_subgroup_last_id %30 None
+         %31 = OpFunctionCall %v4int %subgroupShuffle_2ee993
+         %32 = OpAccessChain %_ptr_StorageBuffer_v4int %1 %uint_0
+               OpStore %32 %31 None
                OpReturn
                OpFunctionEnd
 ;
@@ -83,29 +70,26 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 41
+; Bound: 35
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %17 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_2ee993 "subgroupShuffle_2ee993"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
         %int = OpTypeInt 32 1
       %v4int = OpTypeVector %int 4
 %prevent_dce_block = OpTypeStruct %v4int
@@ -114,44 +98,35 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v4int
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v4int
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
-         %21 = OpConstantComposite %v4int %int_1 %int_1 %int_1 %int_1
+         %20 = OpConstantComposite %v4int %int_1 %int_1 %int_1 %int_1
 %_ptr_Function_v4int = OpTypePointer Function %v4int
        %void = OpTypeVoid
-         %28 = OpTypeFunction %void %uint
+         %26 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_v4int = OpTypePointer StorageBuffer %v4int
      %uint_0 = OpConstant %uint 0
-         %37 = OpTypeFunction %void
-%subgroupShuffle_2ee993 = OpFunction %v4int None %13
-         %14 = OpLabel
+%subgroupShuffle_2ee993 = OpFunction %v4int None %11
+         %12 = OpLabel
         %res = OpVariable %_ptr_Function_v4int Function
-         %15 = OpBitcast %uint %int_1
-         %17 = OpLoad %uint %tint_subgroup_size_mask None
-         %18 = OpBitwiseAnd %uint %15 %17
-         %19 = OpGroupNonUniformShuffle %v4int %uint_3 %21 %18
-               OpStore %res %19
-         %24 = OpLoad %v4int %res None
-               OpReturnValue %24
+         %13 = OpBitcast %uint %int_1
+         %15 = OpLoad %uint %tint_subgroup_last_id None
+         %16 = OpExtInst %uint %17 UMin %13 %15
+         %18 = OpGroupNonUniformShuffle %v4int %uint_3 %20 %16
+               OpStore %res %18
+         %23 = OpLoad %v4int %res None
+               OpReturnValue %23
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %28
-%tint_subgroup_size = OpFunctionParameter %uint
-         %29 = OpLabel
-         %30 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %30 None
-         %32 = OpFunctionCall %v4int %subgroupShuffle_2ee993
-         %33 = OpAccessChain %_ptr_StorageBuffer_v4int %1 %uint_0
-               OpStore %33 %32 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %37
-         %38 = OpLabel
-         %39 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %40 = OpFunctionCall %void %compute_main_inner %39
+%compute_main = OpFunction %void None %26
+         %27 = OpLabel
+         %28 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %30 = OpISub %uint %28 %uint_1
+               OpStore %tint_subgroup_last_id %30 None
+         %31 = OpFunctionCall %v4int %subgroupShuffle_2ee993
+         %32 = OpAccessChain %_ptr_StorageBuffer_v4int %1 %uint_0
+               OpStore %32 %31 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/literal/subgroupShuffle/323416.wgsl.expected.spvasm b/test/tint/builtins/gen/literal/subgroupShuffle/323416.wgsl.expected.spvasm
index 3f17954..0ce4614 100644
--- a/test/tint/builtins/gen/literal/subgroupShuffle/323416.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/literal/subgroupShuffle/323416.wgsl.expected.spvasm
@@ -4,30 +4,26 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 40
+; Bound: 34
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %15 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_323416 "subgroupShuffle_323416"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
         %int = OpTypeInt 32 1
       %v2int = OpTypeVector %int 2
 %prevent_dce_block = OpTypeStruct %v2int
@@ -36,44 +32,35 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v2int
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v2int
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
       %int_1 = OpConstant %int 1
-         %20 = OpConstantComposite %v2int %int_1 %int_1
+         %19 = OpConstantComposite %v2int %int_1 %int_1
 %_ptr_Function_v2int = OpTypePointer Function %v2int
        %void = OpTypeVoid
-         %28 = OpTypeFunction %void %uint
+         %26 = OpTypeFunction %void
 %_ptr_StorageBuffer_v2int = OpTypePointer StorageBuffer %v2int
      %uint_0 = OpConstant %uint 0
-         %36 = OpTypeFunction %void
-%subgroupShuffle_323416 = OpFunction %v2int None %13
-         %14 = OpLabel
+%subgroupShuffle_323416 = OpFunction %v2int None %11
+         %12 = OpLabel
         %res = OpVariable %_ptr_Function_v2int Function
-         %15 = OpLoad %uint %tint_subgroup_size_mask None
-         %16 = OpBitwiseAnd %uint %uint_1 %15
-         %18 = OpGroupNonUniformShuffle %v2int %uint_3 %20 %16
-               OpStore %res %18
-         %24 = OpLoad %v2int %res None
-               OpReturnValue %24
+         %13 = OpLoad %uint %tint_subgroup_last_id None
+         %14 = OpExtInst %uint %15 UMin %uint_1 %13
+         %17 = OpGroupNonUniformShuffle %v2int %uint_3 %19 %14
+               OpStore %res %17
+         %23 = OpLoad %v2int %res None
+               OpReturnValue %23
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %28
-%tint_subgroup_size = OpFunctionParameter %uint
-         %29 = OpLabel
-         %30 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %30 None
-         %31 = OpFunctionCall %v2int %subgroupShuffle_323416
-         %32 = OpAccessChain %_ptr_StorageBuffer_v2int %1 %uint_0
-               OpStore %32 %31 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %36
-         %37 = OpLabel
-         %38 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %39 = OpFunctionCall %void %fragment_main_inner %38
+%fragment_main = OpFunction %void None %26
+         %27 = OpLabel
+         %28 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %29 = OpISub %uint %28 %uint_1
+               OpStore %tint_subgroup_last_id %29 None
+         %30 = OpFunctionCall %v2int %subgroupShuffle_323416
+         %31 = OpAccessChain %_ptr_StorageBuffer_v2int %1 %uint_0
+               OpStore %31 %30 None
                OpReturn
                OpFunctionEnd
 ;
@@ -82,29 +69,26 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 40
+; Bound: 34
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %15 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_323416 "subgroupShuffle_323416"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
         %int = OpTypeInt 32 1
       %v2int = OpTypeVector %int 2
 %prevent_dce_block = OpTypeStruct %v2int
@@ -113,43 +97,34 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v2int
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v2int
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
       %int_1 = OpConstant %int 1
-         %20 = OpConstantComposite %v2int %int_1 %int_1
+         %19 = OpConstantComposite %v2int %int_1 %int_1
 %_ptr_Function_v2int = OpTypePointer Function %v2int
        %void = OpTypeVoid
-         %28 = OpTypeFunction %void %uint
+         %26 = OpTypeFunction %void
 %_ptr_StorageBuffer_v2int = OpTypePointer StorageBuffer %v2int
      %uint_0 = OpConstant %uint 0
-         %36 = OpTypeFunction %void
-%subgroupShuffle_323416 = OpFunction %v2int None %13
-         %14 = OpLabel
+%subgroupShuffle_323416 = OpFunction %v2int None %11
+         %12 = OpLabel
         %res = OpVariable %_ptr_Function_v2int Function
-         %15 = OpLoad %uint %tint_subgroup_size_mask None
-         %16 = OpBitwiseAnd %uint %uint_1 %15
-         %18 = OpGroupNonUniformShuffle %v2int %uint_3 %20 %16
-               OpStore %res %18
-         %24 = OpLoad %v2int %res None
-               OpReturnValue %24
+         %13 = OpLoad %uint %tint_subgroup_last_id None
+         %14 = OpExtInst %uint %15 UMin %uint_1 %13
+         %17 = OpGroupNonUniformShuffle %v2int %uint_3 %19 %14
+               OpStore %res %17
+         %23 = OpLoad %v2int %res None
+               OpReturnValue %23
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %28
-%tint_subgroup_size = OpFunctionParameter %uint
-         %29 = OpLabel
-         %30 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %30 None
-         %31 = OpFunctionCall %v2int %subgroupShuffle_323416
-         %32 = OpAccessChain %_ptr_StorageBuffer_v2int %1 %uint_0
-               OpStore %32 %31 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %36
-         %37 = OpLabel
-         %38 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %39 = OpFunctionCall %void %compute_main_inner %38
+%compute_main = OpFunction %void None %26
+         %27 = OpLabel
+         %28 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %29 = OpISub %uint %28 %uint_1
+               OpStore %tint_subgroup_last_id %29 None
+         %30 = OpFunctionCall %v2int %subgroupShuffle_323416
+         %31 = OpAccessChain %_ptr_StorageBuffer_v2int %1 %uint_0
+               OpStore %31 %30 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/literal/subgroupShuffle/4752bd.wgsl.expected.spvasm b/test/tint/builtins/gen/literal/subgroupShuffle/4752bd.wgsl.expected.spvasm
index a50eaf9..a1ff3fef 100644
--- a/test/tint/builtins/gen/literal/subgroupShuffle/4752bd.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/literal/subgroupShuffle/4752bd.wgsl.expected.spvasm
@@ -4,30 +4,26 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 38
+; Bound: 32
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %14 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_4752bd "subgroupShuffle_4752bd"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
       %float = OpTypeFloat 32
 %prevent_dce_block = OpTypeStruct %float
 %_ptr_StorageBuffer_prevent_dce_block = OpTypePointer StorageBuffer %prevent_dce_block
@@ -35,43 +31,34 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %float
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %float
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
     %float_1 = OpConstant %float 1
 %_ptr_Function_float = OpTypePointer Function %float
        %void = OpTypeVoid
-         %26 = OpTypeFunction %void %uint
+         %24 = OpTypeFunction %void
 %_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
      %uint_0 = OpConstant %uint 0
-         %34 = OpTypeFunction %void
-%subgroupShuffle_4752bd = OpFunction %float None %12
-         %13 = OpLabel
+%subgroupShuffle_4752bd = OpFunction %float None %10
+         %11 = OpLabel
         %res = OpVariable %_ptr_Function_float Function
-         %14 = OpLoad %uint %tint_subgroup_size_mask None
-         %15 = OpBitwiseAnd %uint %uint_1 %14
-         %17 = OpGroupNonUniformShuffle %float %uint_3 %float_1 %15
-               OpStore %res %17
-         %22 = OpLoad %float %res None
-               OpReturnValue %22
+         %12 = OpLoad %uint %tint_subgroup_last_id None
+         %13 = OpExtInst %uint %14 UMin %uint_1 %12
+         %16 = OpGroupNonUniformShuffle %float %uint_3 %float_1 %13
+               OpStore %res %16
+         %21 = OpLoad %float %res None
+               OpReturnValue %21
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %26
-%tint_subgroup_size = OpFunctionParameter %uint
-         %27 = OpLabel
-         %28 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %28 None
-         %29 = OpFunctionCall %float %subgroupShuffle_4752bd
-         %30 = OpAccessChain %_ptr_StorageBuffer_float %1 %uint_0
-               OpStore %30 %29 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %34
-         %35 = OpLabel
-         %36 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %37 = OpFunctionCall %void %fragment_main_inner %36
+%fragment_main = OpFunction %void None %24
+         %25 = OpLabel
+         %26 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %27 = OpISub %uint %26 %uint_1
+               OpStore %tint_subgroup_last_id %27 None
+         %28 = OpFunctionCall %float %subgroupShuffle_4752bd
+         %29 = OpAccessChain %_ptr_StorageBuffer_float %1 %uint_0
+               OpStore %29 %28 None
                OpReturn
                OpFunctionEnd
 ;
@@ -80,29 +67,26 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 38
+; Bound: 32
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %14 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_4752bd "subgroupShuffle_4752bd"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
       %float = OpTypeFloat 32
 %prevent_dce_block = OpTypeStruct %float
 %_ptr_StorageBuffer_prevent_dce_block = OpTypePointer StorageBuffer %prevent_dce_block
@@ -110,42 +94,33 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %float
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %float
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
     %float_1 = OpConstant %float 1
 %_ptr_Function_float = OpTypePointer Function %float
        %void = OpTypeVoid
-         %26 = OpTypeFunction %void %uint
+         %24 = OpTypeFunction %void
 %_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
      %uint_0 = OpConstant %uint 0
-         %34 = OpTypeFunction %void
-%subgroupShuffle_4752bd = OpFunction %float None %12
-         %13 = OpLabel
+%subgroupShuffle_4752bd = OpFunction %float None %10
+         %11 = OpLabel
         %res = OpVariable %_ptr_Function_float Function
-         %14 = OpLoad %uint %tint_subgroup_size_mask None
-         %15 = OpBitwiseAnd %uint %uint_1 %14
-         %17 = OpGroupNonUniformShuffle %float %uint_3 %float_1 %15
-               OpStore %res %17
-         %22 = OpLoad %float %res None
-               OpReturnValue %22
+         %12 = OpLoad %uint %tint_subgroup_last_id None
+         %13 = OpExtInst %uint %14 UMin %uint_1 %12
+         %16 = OpGroupNonUniformShuffle %float %uint_3 %float_1 %13
+               OpStore %res %16
+         %21 = OpLoad %float %res None
+               OpReturnValue %21
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %26
-%tint_subgroup_size = OpFunctionParameter %uint
-         %27 = OpLabel
-         %28 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %28 None
-         %29 = OpFunctionCall %float %subgroupShuffle_4752bd
-         %30 = OpAccessChain %_ptr_StorageBuffer_float %1 %uint_0
-               OpStore %30 %29 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %34
-         %35 = OpLabel
-         %36 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %37 = OpFunctionCall %void %compute_main_inner %36
+%compute_main = OpFunction %void None %24
+         %25 = OpLabel
+         %26 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %27 = OpISub %uint %26 %uint_1
+               OpStore %tint_subgroup_last_id %27 None
+         %28 = OpFunctionCall %float %subgroupShuffle_4752bd
+         %29 = OpAccessChain %_ptr_StorageBuffer_float %1 %uint_0
+               OpStore %29 %28 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/literal/subgroupShuffle/4cbb69.wgsl.expected.spvasm b/test/tint/builtins/gen/literal/subgroupShuffle/4cbb69.wgsl.expected.spvasm
index 7211d42..97935d3 100644
--- a/test/tint/builtins/gen/literal/subgroupShuffle/4cbb69.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/literal/subgroupShuffle/4cbb69.wgsl.expected.spvasm
@@ -4,30 +4,26 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 41
+; Bound: 35
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %17 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_4cbb69 "subgroupShuffle_4cbb69"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
        %uint = OpTypeInt 32 0
      %v3uint = OpTypeVector %uint 3
 %prevent_dce_block = OpTypeStruct %v3uint
@@ -35,46 +31,37 @@
           %1 = OpVariable %_ptr_StorageBuffer_prevent_dce_block StorageBuffer
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %v3uint
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %v3uint
         %int = OpTypeInt 32 1
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
      %uint_1 = OpConstant %uint 1
-         %21 = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
+         %20 = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
 %_ptr_Function_v3uint = OpTypePointer Function %v3uint
        %void = OpTypeVoid
-         %29 = OpTypeFunction %void %uint
+         %27 = OpTypeFunction %void
 %_ptr_StorageBuffer_v3uint = OpTypePointer StorageBuffer %v3uint
      %uint_0 = OpConstant %uint 0
-         %37 = OpTypeFunction %void
-%subgroupShuffle_4cbb69 = OpFunction %v3uint None %12
-         %13 = OpLabel
+%subgroupShuffle_4cbb69 = OpFunction %v3uint None %10
+         %11 = OpLabel
         %res = OpVariable %_ptr_Function_v3uint Function
-         %14 = OpBitcast %uint %int_1
-         %17 = OpLoad %uint %tint_subgroup_size_mask None
-         %18 = OpBitwiseAnd %uint %14 %17
-         %19 = OpGroupNonUniformShuffle %v3uint %uint_3 %21 %18
-               OpStore %res %19
-         %25 = OpLoad %v3uint %res None
-               OpReturnValue %25
+         %12 = OpBitcast %uint %int_1
+         %15 = OpLoad %uint %tint_subgroup_last_id None
+         %16 = OpExtInst %uint %17 UMin %12 %15
+         %18 = OpGroupNonUniformShuffle %v3uint %uint_3 %20 %16
+               OpStore %res %18
+         %24 = OpLoad %v3uint %res None
+               OpReturnValue %24
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %29
-%tint_subgroup_size = OpFunctionParameter %uint
-         %30 = OpLabel
-         %31 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %31 None
-         %32 = OpFunctionCall %v3uint %subgroupShuffle_4cbb69
-         %33 = OpAccessChain %_ptr_StorageBuffer_v3uint %1 %uint_0
-               OpStore %33 %32 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %37
-         %38 = OpLabel
-         %39 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %40 = OpFunctionCall %void %fragment_main_inner %39
+%fragment_main = OpFunction %void None %27
+         %28 = OpLabel
+         %29 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %30 = OpISub %uint %29 %uint_1
+               OpStore %tint_subgroup_last_id %30 None
+         %31 = OpFunctionCall %v3uint %subgroupShuffle_4cbb69
+         %32 = OpAccessChain %_ptr_StorageBuffer_v3uint %1 %uint_0
+               OpStore %32 %31 None
                OpReturn
                OpFunctionEnd
 ;
@@ -83,29 +70,26 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 41
+; Bound: 35
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %17 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_4cbb69 "subgroupShuffle_4cbb69"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
        %uint = OpTypeInt 32 0
      %v3uint = OpTypeVector %uint 3
 %prevent_dce_block = OpTypeStruct %v3uint
@@ -113,45 +97,36 @@
           %1 = OpVariable %_ptr_StorageBuffer_prevent_dce_block StorageBuffer
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %v3uint
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %v3uint
         %int = OpTypeInt 32 1
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
      %uint_1 = OpConstant %uint 1
-         %21 = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
+         %20 = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
 %_ptr_Function_v3uint = OpTypePointer Function %v3uint
        %void = OpTypeVoid
-         %29 = OpTypeFunction %void %uint
+         %27 = OpTypeFunction %void
 %_ptr_StorageBuffer_v3uint = OpTypePointer StorageBuffer %v3uint
      %uint_0 = OpConstant %uint 0
-         %37 = OpTypeFunction %void
-%subgroupShuffle_4cbb69 = OpFunction %v3uint None %12
-         %13 = OpLabel
+%subgroupShuffle_4cbb69 = OpFunction %v3uint None %10
+         %11 = OpLabel
         %res = OpVariable %_ptr_Function_v3uint Function
-         %14 = OpBitcast %uint %int_1
-         %17 = OpLoad %uint %tint_subgroup_size_mask None
-         %18 = OpBitwiseAnd %uint %14 %17
-         %19 = OpGroupNonUniformShuffle %v3uint %uint_3 %21 %18
-               OpStore %res %19
-         %25 = OpLoad %v3uint %res None
-               OpReturnValue %25
+         %12 = OpBitcast %uint %int_1
+         %15 = OpLoad %uint %tint_subgroup_last_id None
+         %16 = OpExtInst %uint %17 UMin %12 %15
+         %18 = OpGroupNonUniformShuffle %v3uint %uint_3 %20 %16
+               OpStore %res %18
+         %24 = OpLoad %v3uint %res None
+               OpReturnValue %24
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %29
-%tint_subgroup_size = OpFunctionParameter %uint
-         %30 = OpLabel
-         %31 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %31 None
-         %32 = OpFunctionCall %v3uint %subgroupShuffle_4cbb69
-         %33 = OpAccessChain %_ptr_StorageBuffer_v3uint %1 %uint_0
-               OpStore %33 %32 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %37
-         %38 = OpLabel
-         %39 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %40 = OpFunctionCall %void %compute_main_inner %39
+%compute_main = OpFunction %void None %27
+         %28 = OpLabel
+         %29 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %30 = OpISub %uint %29 %uint_1
+               OpStore %tint_subgroup_last_id %30 None
+         %31 = OpFunctionCall %v3uint %subgroupShuffle_4cbb69
+         %32 = OpAccessChain %_ptr_StorageBuffer_v3uint %1 %uint_0
+               OpStore %32 %31 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/literal/subgroupShuffle/4f5711.wgsl.expected.spvasm b/test/tint/builtins/gen/literal/subgroupShuffle/4f5711.wgsl.expected.spvasm
index 7284fc0..526b702 100644
--- a/test/tint/builtins/gen/literal/subgroupShuffle/4f5711.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/literal/subgroupShuffle/4f5711.wgsl.expected.spvasm
@@ -4,30 +4,26 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 38
+; Bound: 32
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %14 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_4f5711 "subgroupShuffle_4f5711"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
        %uint = OpTypeInt 32 0
      %v3uint = OpTypeVector %uint 3
 %prevent_dce_block = OpTypeStruct %v3uint
@@ -35,43 +31,34 @@
           %1 = OpVariable %_ptr_StorageBuffer_prevent_dce_block StorageBuffer
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %v3uint
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %v3uint
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
-         %19 = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
+         %18 = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
 %_ptr_Function_v3uint = OpTypePointer Function %v3uint
        %void = OpTypeVoid
-         %26 = OpTypeFunction %void %uint
+         %24 = OpTypeFunction %void
 %_ptr_StorageBuffer_v3uint = OpTypePointer StorageBuffer %v3uint
      %uint_0 = OpConstant %uint 0
-         %34 = OpTypeFunction %void
-%subgroupShuffle_4f5711 = OpFunction %v3uint None %12
-         %13 = OpLabel
+%subgroupShuffle_4f5711 = OpFunction %v3uint None %10
+         %11 = OpLabel
         %res = OpVariable %_ptr_Function_v3uint Function
-         %14 = OpLoad %uint %tint_subgroup_size_mask None
-         %15 = OpBitwiseAnd %uint %uint_1 %14
-         %17 = OpGroupNonUniformShuffle %v3uint %uint_3 %19 %15
-               OpStore %res %17
-         %22 = OpLoad %v3uint %res None
-               OpReturnValue %22
+         %12 = OpLoad %uint %tint_subgroup_last_id None
+         %13 = OpExtInst %uint %14 UMin %uint_1 %12
+         %16 = OpGroupNonUniformShuffle %v3uint %uint_3 %18 %13
+               OpStore %res %16
+         %21 = OpLoad %v3uint %res None
+               OpReturnValue %21
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %26
-%tint_subgroup_size = OpFunctionParameter %uint
-         %27 = OpLabel
-         %28 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %28 None
-         %29 = OpFunctionCall %v3uint %subgroupShuffle_4f5711
-         %30 = OpAccessChain %_ptr_StorageBuffer_v3uint %1 %uint_0
-               OpStore %30 %29 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %34
-         %35 = OpLabel
-         %36 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %37 = OpFunctionCall %void %fragment_main_inner %36
+%fragment_main = OpFunction %void None %24
+         %25 = OpLabel
+         %26 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %27 = OpISub %uint %26 %uint_1
+               OpStore %tint_subgroup_last_id %27 None
+         %28 = OpFunctionCall %v3uint %subgroupShuffle_4f5711
+         %29 = OpAccessChain %_ptr_StorageBuffer_v3uint %1 %uint_0
+               OpStore %29 %28 None
                OpReturn
                OpFunctionEnd
 ;
@@ -80,29 +67,26 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 38
+; Bound: 32
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %14 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_4f5711 "subgroupShuffle_4f5711"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
        %uint = OpTypeInt 32 0
      %v3uint = OpTypeVector %uint 3
 %prevent_dce_block = OpTypeStruct %v3uint
@@ -110,42 +94,33 @@
           %1 = OpVariable %_ptr_StorageBuffer_prevent_dce_block StorageBuffer
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %v3uint
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %v3uint
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
-         %19 = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
+         %18 = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
 %_ptr_Function_v3uint = OpTypePointer Function %v3uint
        %void = OpTypeVoid
-         %26 = OpTypeFunction %void %uint
+         %24 = OpTypeFunction %void
 %_ptr_StorageBuffer_v3uint = OpTypePointer StorageBuffer %v3uint
      %uint_0 = OpConstant %uint 0
-         %34 = OpTypeFunction %void
-%subgroupShuffle_4f5711 = OpFunction %v3uint None %12
-         %13 = OpLabel
+%subgroupShuffle_4f5711 = OpFunction %v3uint None %10
+         %11 = OpLabel
         %res = OpVariable %_ptr_Function_v3uint Function
-         %14 = OpLoad %uint %tint_subgroup_size_mask None
-         %15 = OpBitwiseAnd %uint %uint_1 %14
-         %17 = OpGroupNonUniformShuffle %v3uint %uint_3 %19 %15
-               OpStore %res %17
-         %22 = OpLoad %v3uint %res None
-               OpReturnValue %22
+         %12 = OpLoad %uint %tint_subgroup_last_id None
+         %13 = OpExtInst %uint %14 UMin %uint_1 %12
+         %16 = OpGroupNonUniformShuffle %v3uint %uint_3 %18 %13
+               OpStore %res %16
+         %21 = OpLoad %v3uint %res None
+               OpReturnValue %21
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %26
-%tint_subgroup_size = OpFunctionParameter %uint
-         %27 = OpLabel
-         %28 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %28 None
-         %29 = OpFunctionCall %v3uint %subgroupShuffle_4f5711
-         %30 = OpAccessChain %_ptr_StorageBuffer_v3uint %1 %uint_0
-               OpStore %30 %29 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %34
-         %35 = OpLabel
-         %36 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %37 = OpFunctionCall %void %compute_main_inner %36
+%compute_main = OpFunction %void None %24
+         %25 = OpLabel
+         %26 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %27 = OpISub %uint %26 %uint_1
+               OpStore %tint_subgroup_last_id %27 None
+         %28 = OpFunctionCall %v3uint %subgroupShuffle_4f5711
+         %29 = OpAccessChain %_ptr_StorageBuffer_v3uint %1 %uint_0
+               OpStore %29 %28 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/literal/subgroupShuffle/54f328.wgsl.expected.spvasm b/test/tint/builtins/gen/literal/subgroupShuffle/54f328.wgsl.expected.spvasm
index 7f7b00c..165aa5d 100644
--- a/test/tint/builtins/gen/literal/subgroupShuffle/54f328.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/literal/subgroupShuffle/54f328.wgsl.expected.spvasm
@@ -4,75 +4,62 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 39
+; Bound: 33
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %16 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_54f328 "subgroupShuffle_54f328"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
        %uint = OpTypeInt 32 0
 %prevent_dce_block = OpTypeStruct %uint
 %_ptr_StorageBuffer_prevent_dce_block = OpTypePointer StorageBuffer %prevent_dce_block
           %1 = OpVariable %_ptr_StorageBuffer_prevent_dce_block StorageBuffer
 %_ptr_Private_uint = OpTypePointer Private %uint
           %7 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %7
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %11 = OpTypeFunction %uint
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %7
+          %9 = OpTypeFunction %uint
         %int = OpTypeInt 32 1
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
      %uint_1 = OpConstant %uint 1
 %_ptr_Function_uint = OpTypePointer Function %uint
        %void = OpTypeVoid
-         %27 = OpTypeFunction %void %uint
+         %25 = OpTypeFunction %void
 %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
      %uint_0 = OpConstant %uint 0
-         %35 = OpTypeFunction %void
-%subgroupShuffle_54f328 = OpFunction %uint None %11
-         %12 = OpLabel
+%subgroupShuffle_54f328 = OpFunction %uint None %9
+         %10 = OpLabel
         %res = OpVariable %_ptr_Function_uint Function
-         %13 = OpBitcast %uint %int_1
-         %16 = OpLoad %uint %tint_subgroup_size_mask None
-         %17 = OpBitwiseAnd %uint %13 %16
-         %18 = OpGroupNonUniformShuffle %uint %uint_3 %uint_1 %17
-               OpStore %res %18
-         %23 = OpLoad %uint %res None
-               OpReturnValue %23
+         %11 = OpBitcast %uint %int_1
+         %14 = OpLoad %uint %tint_subgroup_last_id None
+         %15 = OpExtInst %uint %16 UMin %11 %14
+         %17 = OpGroupNonUniformShuffle %uint %uint_3 %uint_1 %15
+               OpStore %res %17
+         %22 = OpLoad %uint %res None
+               OpReturnValue %22
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %27
-%tint_subgroup_size = OpFunctionParameter %uint
-         %28 = OpLabel
-         %29 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %29 None
-         %30 = OpFunctionCall %uint %subgroupShuffle_54f328
-         %31 = OpAccessChain %_ptr_StorageBuffer_uint %1 %uint_0
-               OpStore %31 %30 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %35
-         %36 = OpLabel
-         %37 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %38 = OpFunctionCall %void %fragment_main_inner %37
+%fragment_main = OpFunction %void None %25
+         %26 = OpLabel
+         %27 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %28 = OpISub %uint %27 %uint_1
+               OpStore %tint_subgroup_last_id %28 None
+         %29 = OpFunctionCall %uint %subgroupShuffle_54f328
+         %30 = OpAccessChain %_ptr_StorageBuffer_uint %1 %uint_0
+               OpStore %30 %29 None
                OpReturn
                OpFunctionEnd
 ;
@@ -81,73 +68,61 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 39
+; Bound: 33
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %16 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_54f328 "subgroupShuffle_54f328"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
        %uint = OpTypeInt 32 0
 %prevent_dce_block = OpTypeStruct %uint
 %_ptr_StorageBuffer_prevent_dce_block = OpTypePointer StorageBuffer %prevent_dce_block
           %1 = OpVariable %_ptr_StorageBuffer_prevent_dce_block StorageBuffer
 %_ptr_Private_uint = OpTypePointer Private %uint
           %7 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %7
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %11 = OpTypeFunction %uint
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %7
+          %9 = OpTypeFunction %uint
         %int = OpTypeInt 32 1
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
      %uint_1 = OpConstant %uint 1
 %_ptr_Function_uint = OpTypePointer Function %uint
        %void = OpTypeVoid
-         %27 = OpTypeFunction %void %uint
+         %25 = OpTypeFunction %void
 %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
      %uint_0 = OpConstant %uint 0
-         %35 = OpTypeFunction %void
-%subgroupShuffle_54f328 = OpFunction %uint None %11
-         %12 = OpLabel
+%subgroupShuffle_54f328 = OpFunction %uint None %9
+         %10 = OpLabel
         %res = OpVariable %_ptr_Function_uint Function
-         %13 = OpBitcast %uint %int_1
-         %16 = OpLoad %uint %tint_subgroup_size_mask None
-         %17 = OpBitwiseAnd %uint %13 %16
-         %18 = OpGroupNonUniformShuffle %uint %uint_3 %uint_1 %17
-               OpStore %res %18
-         %23 = OpLoad %uint %res None
-               OpReturnValue %23
+         %11 = OpBitcast %uint %int_1
+         %14 = OpLoad %uint %tint_subgroup_last_id None
+         %15 = OpExtInst %uint %16 UMin %11 %14
+         %17 = OpGroupNonUniformShuffle %uint %uint_3 %uint_1 %15
+               OpStore %res %17
+         %22 = OpLoad %uint %res None
+               OpReturnValue %22
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %27
-%tint_subgroup_size = OpFunctionParameter %uint
-         %28 = OpLabel
-         %29 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %29 None
-         %30 = OpFunctionCall %uint %subgroupShuffle_54f328
-         %31 = OpAccessChain %_ptr_StorageBuffer_uint %1 %uint_0
-               OpStore %31 %30 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %35
-         %36 = OpLabel
-         %37 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %38 = OpFunctionCall %void %compute_main_inner %37
+%compute_main = OpFunction %void None %25
+         %26 = OpLabel
+         %27 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %28 = OpISub %uint %27 %uint_1
+               OpStore %tint_subgroup_last_id %28 None
+         %29 = OpFunctionCall %uint %subgroupShuffle_54f328
+         %30 = OpAccessChain %_ptr_StorageBuffer_uint %1 %uint_0
+               OpStore %30 %29 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/literal/subgroupShuffle/5dfeab.wgsl.expected.spvasm b/test/tint/builtins/gen/literal/subgroupShuffle/5dfeab.wgsl.expected.spvasm
index f6f4aa7..4cece6c 100644
--- a/test/tint/builtins/gen/literal/subgroupShuffle/5dfeab.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/literal/subgroupShuffle/5dfeab.wgsl.expected.spvasm
@@ -4,30 +4,26 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 43
+; Bound: 37
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %18 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_5dfeab "subgroupShuffle_5dfeab"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
       %float = OpTypeFloat 32
     %v4float = OpTypeVector %float 4
 %prevent_dce_block = OpTypeStruct %v4float
@@ -36,47 +32,38 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v4float
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v4float
         %int = OpTypeInt 32 1
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
     %float_1 = OpConstant %float 1
-         %22 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
+         %21 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
 %_ptr_Function_v4float = OpTypePointer Function %v4float
        %void = OpTypeVoid
-         %30 = OpTypeFunction %void %uint
+         %28 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_v4float = OpTypePointer StorageBuffer %v4float
      %uint_0 = OpConstant %uint 0
-         %39 = OpTypeFunction %void
-%subgroupShuffle_5dfeab = OpFunction %v4float None %13
-         %14 = OpLabel
+%subgroupShuffle_5dfeab = OpFunction %v4float None %11
+         %12 = OpLabel
         %res = OpVariable %_ptr_Function_v4float Function
-         %15 = OpBitcast %uint %int_1
-         %18 = OpLoad %uint %tint_subgroup_size_mask None
-         %19 = OpBitwiseAnd %uint %15 %18
-         %20 = OpGroupNonUniformShuffle %v4float %uint_3 %22 %19
-               OpStore %res %20
-         %26 = OpLoad %v4float %res None
-               OpReturnValue %26
+         %13 = OpBitcast %uint %int_1
+         %16 = OpLoad %uint %tint_subgroup_last_id None
+         %17 = OpExtInst %uint %18 UMin %13 %16
+         %19 = OpGroupNonUniformShuffle %v4float %uint_3 %21 %17
+               OpStore %res %19
+         %25 = OpLoad %v4float %res None
+               OpReturnValue %25
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %30
-%tint_subgroup_size = OpFunctionParameter %uint
-         %31 = OpLabel
-         %32 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %32 None
-         %34 = OpFunctionCall %v4float %subgroupShuffle_5dfeab
-         %35 = OpAccessChain %_ptr_StorageBuffer_v4float %1 %uint_0
-               OpStore %35 %34 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %39
-         %40 = OpLabel
-         %41 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %42 = OpFunctionCall %void %fragment_main_inner %41
+%fragment_main = OpFunction %void None %28
+         %29 = OpLabel
+         %30 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %32 = OpISub %uint %30 %uint_1
+               OpStore %tint_subgroup_last_id %32 None
+         %33 = OpFunctionCall %v4float %subgroupShuffle_5dfeab
+         %34 = OpAccessChain %_ptr_StorageBuffer_v4float %1 %uint_0
+               OpStore %34 %33 None
                OpReturn
                OpFunctionEnd
 ;
@@ -85,29 +72,26 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 43
+; Bound: 37
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %18 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_5dfeab "subgroupShuffle_5dfeab"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
       %float = OpTypeFloat 32
     %v4float = OpTypeVector %float 4
 %prevent_dce_block = OpTypeStruct %v4float
@@ -116,46 +100,37 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v4float
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v4float
         %int = OpTypeInt 32 1
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
     %float_1 = OpConstant %float 1
-         %22 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
+         %21 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
 %_ptr_Function_v4float = OpTypePointer Function %v4float
        %void = OpTypeVoid
-         %30 = OpTypeFunction %void %uint
+         %28 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_v4float = OpTypePointer StorageBuffer %v4float
      %uint_0 = OpConstant %uint 0
-         %39 = OpTypeFunction %void
-%subgroupShuffle_5dfeab = OpFunction %v4float None %13
-         %14 = OpLabel
+%subgroupShuffle_5dfeab = OpFunction %v4float None %11
+         %12 = OpLabel
         %res = OpVariable %_ptr_Function_v4float Function
-         %15 = OpBitcast %uint %int_1
-         %18 = OpLoad %uint %tint_subgroup_size_mask None
-         %19 = OpBitwiseAnd %uint %15 %18
-         %20 = OpGroupNonUniformShuffle %v4float %uint_3 %22 %19
-               OpStore %res %20
-         %26 = OpLoad %v4float %res None
-               OpReturnValue %26
+         %13 = OpBitcast %uint %int_1
+         %16 = OpLoad %uint %tint_subgroup_last_id None
+         %17 = OpExtInst %uint %18 UMin %13 %16
+         %19 = OpGroupNonUniformShuffle %v4float %uint_3 %21 %17
+               OpStore %res %19
+         %25 = OpLoad %v4float %res None
+               OpReturnValue %25
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %30
-%tint_subgroup_size = OpFunctionParameter %uint
-         %31 = OpLabel
-         %32 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %32 None
-         %34 = OpFunctionCall %v4float %subgroupShuffle_5dfeab
-         %35 = OpAccessChain %_ptr_StorageBuffer_v4float %1 %uint_0
-               OpStore %35 %34 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %39
-         %40 = OpLabel
-         %41 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %42 = OpFunctionCall %void %compute_main_inner %41
+%compute_main = OpFunction %void None %28
+         %29 = OpLabel
+         %30 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %32 = OpISub %uint %30 %uint_1
+               OpStore %tint_subgroup_last_id %32 None
+         %33 = OpFunctionCall %v4float %subgroupShuffle_5dfeab
+         %34 = OpAccessChain %_ptr_StorageBuffer_v4float %1 %uint_0
+               OpStore %34 %33 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/literal/subgroupShuffle/5ef5a2.wgsl.expected.spvasm b/test/tint/builtins/gen/literal/subgroupShuffle/5ef5a2.wgsl.expected.spvasm
index 951c70e..d082d3d 100644
--- a/test/tint/builtins/gen/literal/subgroupShuffle/5ef5a2.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/literal/subgroupShuffle/5ef5a2.wgsl.expected.spvasm
@@ -4,30 +4,26 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 38
+; Bound: 32
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %14 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_5ef5a2 "subgroupShuffle_5ef5a2"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
        %uint = OpTypeInt 32 0
      %v2uint = OpTypeVector %uint 2
 %prevent_dce_block = OpTypeStruct %v2uint
@@ -35,43 +31,34 @@
           %1 = OpVariable %_ptr_StorageBuffer_prevent_dce_block StorageBuffer
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %v2uint
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %v2uint
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
-         %19 = OpConstantComposite %v2uint %uint_1 %uint_1
+         %18 = OpConstantComposite %v2uint %uint_1 %uint_1
 %_ptr_Function_v2uint = OpTypePointer Function %v2uint
        %void = OpTypeVoid
-         %26 = OpTypeFunction %void %uint
+         %24 = OpTypeFunction %void
 %_ptr_StorageBuffer_v2uint = OpTypePointer StorageBuffer %v2uint
      %uint_0 = OpConstant %uint 0
-         %34 = OpTypeFunction %void
-%subgroupShuffle_5ef5a2 = OpFunction %v2uint None %12
-         %13 = OpLabel
+%subgroupShuffle_5ef5a2 = OpFunction %v2uint None %10
+         %11 = OpLabel
         %res = OpVariable %_ptr_Function_v2uint Function
-         %14 = OpLoad %uint %tint_subgroup_size_mask None
-         %15 = OpBitwiseAnd %uint %uint_1 %14
-         %17 = OpGroupNonUniformShuffle %v2uint %uint_3 %19 %15
-               OpStore %res %17
-         %22 = OpLoad %v2uint %res None
-               OpReturnValue %22
+         %12 = OpLoad %uint %tint_subgroup_last_id None
+         %13 = OpExtInst %uint %14 UMin %uint_1 %12
+         %16 = OpGroupNonUniformShuffle %v2uint %uint_3 %18 %13
+               OpStore %res %16
+         %21 = OpLoad %v2uint %res None
+               OpReturnValue %21
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %26
-%tint_subgroup_size = OpFunctionParameter %uint
-         %27 = OpLabel
-         %28 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %28 None
-         %29 = OpFunctionCall %v2uint %subgroupShuffle_5ef5a2
-         %30 = OpAccessChain %_ptr_StorageBuffer_v2uint %1 %uint_0
-               OpStore %30 %29 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %34
-         %35 = OpLabel
-         %36 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %37 = OpFunctionCall %void %fragment_main_inner %36
+%fragment_main = OpFunction %void None %24
+         %25 = OpLabel
+         %26 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %27 = OpISub %uint %26 %uint_1
+               OpStore %tint_subgroup_last_id %27 None
+         %28 = OpFunctionCall %v2uint %subgroupShuffle_5ef5a2
+         %29 = OpAccessChain %_ptr_StorageBuffer_v2uint %1 %uint_0
+               OpStore %29 %28 None
                OpReturn
                OpFunctionEnd
 ;
@@ -80,29 +67,26 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 38
+; Bound: 32
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %14 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_5ef5a2 "subgroupShuffle_5ef5a2"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
        %uint = OpTypeInt 32 0
      %v2uint = OpTypeVector %uint 2
 %prevent_dce_block = OpTypeStruct %v2uint
@@ -110,42 +94,33 @@
           %1 = OpVariable %_ptr_StorageBuffer_prevent_dce_block StorageBuffer
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %v2uint
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %v2uint
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
-         %19 = OpConstantComposite %v2uint %uint_1 %uint_1
+         %18 = OpConstantComposite %v2uint %uint_1 %uint_1
 %_ptr_Function_v2uint = OpTypePointer Function %v2uint
        %void = OpTypeVoid
-         %26 = OpTypeFunction %void %uint
+         %24 = OpTypeFunction %void
 %_ptr_StorageBuffer_v2uint = OpTypePointer StorageBuffer %v2uint
      %uint_0 = OpConstant %uint 0
-         %34 = OpTypeFunction %void
-%subgroupShuffle_5ef5a2 = OpFunction %v2uint None %12
-         %13 = OpLabel
+%subgroupShuffle_5ef5a2 = OpFunction %v2uint None %10
+         %11 = OpLabel
         %res = OpVariable %_ptr_Function_v2uint Function
-         %14 = OpLoad %uint %tint_subgroup_size_mask None
-         %15 = OpBitwiseAnd %uint %uint_1 %14
-         %17 = OpGroupNonUniformShuffle %v2uint %uint_3 %19 %15
-               OpStore %res %17
-         %22 = OpLoad %v2uint %res None
-               OpReturnValue %22
+         %12 = OpLoad %uint %tint_subgroup_last_id None
+         %13 = OpExtInst %uint %14 UMin %uint_1 %12
+         %16 = OpGroupNonUniformShuffle %v2uint %uint_3 %18 %13
+               OpStore %res %16
+         %21 = OpLoad %v2uint %res None
+               OpReturnValue %21
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %26
-%tint_subgroup_size = OpFunctionParameter %uint
-         %27 = OpLabel
-         %28 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %28 None
-         %29 = OpFunctionCall %v2uint %subgroupShuffle_5ef5a2
-         %30 = OpAccessChain %_ptr_StorageBuffer_v2uint %1 %uint_0
-               OpStore %30 %29 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %34
-         %35 = OpLabel
-         %36 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %37 = OpFunctionCall %void %compute_main_inner %36
+%compute_main = OpFunction %void None %24
+         %25 = OpLabel
+         %26 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %27 = OpISub %uint %26 %uint_1
+               OpStore %tint_subgroup_last_id %27 None
+         %28 = OpFunctionCall %v2uint %subgroupShuffle_5ef5a2
+         %29 = OpAccessChain %_ptr_StorageBuffer_v2uint %1 %uint_0
+               OpStore %29 %28 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/literal/subgroupShuffle/647034.wgsl.expected.spvasm b/test/tint/builtins/gen/literal/subgroupShuffle/647034.wgsl.expected.spvasm
index 0ddc1aa..5f364ad 100644
--- a/test/tint/builtins/gen/literal/subgroupShuffle/647034.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/literal/subgroupShuffle/647034.wgsl.expected.spvasm
@@ -4,32 +4,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 43
+; Bound: 37
 ; Schema: 0
                OpCapability Shader
                OpCapability Float16
                OpCapability StorageBuffer16BitAccess
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %18 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_647034 "subgroupShuffle_647034"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
        %half = OpTypeFloat 16
      %v4half = OpTypeVector %half 4
 %prevent_dce_block = OpTypeStruct %v4half
@@ -38,47 +34,38 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v4half
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v4half
         %int = OpTypeInt 32 1
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
 %half_0x1p_0 = OpConstant %half 0x1p+0
-         %22 = OpConstantComposite %v4half %half_0x1p_0 %half_0x1p_0 %half_0x1p_0 %half_0x1p_0
+         %21 = OpConstantComposite %v4half %half_0x1p_0 %half_0x1p_0 %half_0x1p_0 %half_0x1p_0
 %_ptr_Function_v4half = OpTypePointer Function %v4half
        %void = OpTypeVoid
-         %30 = OpTypeFunction %void %uint
+         %28 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_v4half = OpTypePointer StorageBuffer %v4half
      %uint_0 = OpConstant %uint 0
-         %39 = OpTypeFunction %void
-%subgroupShuffle_647034 = OpFunction %v4half None %13
-         %14 = OpLabel
+%subgroupShuffle_647034 = OpFunction %v4half None %11
+         %12 = OpLabel
         %res = OpVariable %_ptr_Function_v4half Function
-         %15 = OpBitcast %uint %int_1
-         %18 = OpLoad %uint %tint_subgroup_size_mask None
-         %19 = OpBitwiseAnd %uint %15 %18
-         %20 = OpGroupNonUniformShuffle %v4half %uint_3 %22 %19
-               OpStore %res %20
-         %26 = OpLoad %v4half %res None
-               OpReturnValue %26
+         %13 = OpBitcast %uint %int_1
+         %16 = OpLoad %uint %tint_subgroup_last_id None
+         %17 = OpExtInst %uint %18 UMin %13 %16
+         %19 = OpGroupNonUniformShuffle %v4half %uint_3 %21 %17
+               OpStore %res %19
+         %25 = OpLoad %v4half %res None
+               OpReturnValue %25
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %30
-%tint_subgroup_size = OpFunctionParameter %uint
-         %31 = OpLabel
-         %32 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %32 None
-         %34 = OpFunctionCall %v4half %subgroupShuffle_647034
-         %35 = OpAccessChain %_ptr_StorageBuffer_v4half %1 %uint_0
-               OpStore %35 %34 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %39
-         %40 = OpLabel
-         %41 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %42 = OpFunctionCall %void %fragment_main_inner %41
+%fragment_main = OpFunction %void None %28
+         %29 = OpLabel
+         %30 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %32 = OpISub %uint %30 %uint_1
+               OpStore %tint_subgroup_last_id %32 None
+         %33 = OpFunctionCall %v4half %subgroupShuffle_647034
+         %34 = OpAccessChain %_ptr_StorageBuffer_v4half %1 %uint_0
+               OpStore %34 %33 None
                OpReturn
                OpFunctionEnd
 ;
@@ -87,31 +74,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 43
+; Bound: 37
 ; Schema: 0
                OpCapability Shader
                OpCapability Float16
                OpCapability StorageBuffer16BitAccess
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %18 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_647034 "subgroupShuffle_647034"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
        %half = OpTypeFloat 16
      %v4half = OpTypeVector %half 4
 %prevent_dce_block = OpTypeStruct %v4half
@@ -120,46 +104,37 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v4half
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v4half
         %int = OpTypeInt 32 1
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
 %half_0x1p_0 = OpConstant %half 0x1p+0
-         %22 = OpConstantComposite %v4half %half_0x1p_0 %half_0x1p_0 %half_0x1p_0 %half_0x1p_0
+         %21 = OpConstantComposite %v4half %half_0x1p_0 %half_0x1p_0 %half_0x1p_0 %half_0x1p_0
 %_ptr_Function_v4half = OpTypePointer Function %v4half
        %void = OpTypeVoid
-         %30 = OpTypeFunction %void %uint
+         %28 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_v4half = OpTypePointer StorageBuffer %v4half
      %uint_0 = OpConstant %uint 0
-         %39 = OpTypeFunction %void
-%subgroupShuffle_647034 = OpFunction %v4half None %13
-         %14 = OpLabel
+%subgroupShuffle_647034 = OpFunction %v4half None %11
+         %12 = OpLabel
         %res = OpVariable %_ptr_Function_v4half Function
-         %15 = OpBitcast %uint %int_1
-         %18 = OpLoad %uint %tint_subgroup_size_mask None
-         %19 = OpBitwiseAnd %uint %15 %18
-         %20 = OpGroupNonUniformShuffle %v4half %uint_3 %22 %19
-               OpStore %res %20
-         %26 = OpLoad %v4half %res None
-               OpReturnValue %26
+         %13 = OpBitcast %uint %int_1
+         %16 = OpLoad %uint %tint_subgroup_last_id None
+         %17 = OpExtInst %uint %18 UMin %13 %16
+         %19 = OpGroupNonUniformShuffle %v4half %uint_3 %21 %17
+               OpStore %res %19
+         %25 = OpLoad %v4half %res None
+               OpReturnValue %25
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %30
-%tint_subgroup_size = OpFunctionParameter %uint
-         %31 = OpLabel
-         %32 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %32 None
-         %34 = OpFunctionCall %v4half %subgroupShuffle_647034
-         %35 = OpAccessChain %_ptr_StorageBuffer_v4half %1 %uint_0
-               OpStore %35 %34 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %39
-         %40 = OpLabel
-         %41 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %42 = OpFunctionCall %void %compute_main_inner %41
+%compute_main = OpFunction %void None %28
+         %29 = OpLabel
+         %30 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %32 = OpISub %uint %30 %uint_1
+               OpStore %tint_subgroup_last_id %32 None
+         %33 = OpFunctionCall %v4half %subgroupShuffle_647034
+         %34 = OpAccessChain %_ptr_StorageBuffer_v4half %1 %uint_0
+               OpStore %34 %33 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/literal/subgroupShuffle/7ba2d5.wgsl.expected.spvasm b/test/tint/builtins/gen/literal/subgroupShuffle/7ba2d5.wgsl.expected.spvasm
index 5dcf81d..2812625 100644
--- a/test/tint/builtins/gen/literal/subgroupShuffle/7ba2d5.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/literal/subgroupShuffle/7ba2d5.wgsl.expected.spvasm
@@ -4,32 +4,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 40
+; Bound: 34
 ; Schema: 0
                OpCapability Shader
                OpCapability Float16
                OpCapability StorageBuffer16BitAccess
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %15 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_7ba2d5 "subgroupShuffle_7ba2d5"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
        %half = OpTypeFloat 16
      %v4half = OpTypeVector %half 4
 %prevent_dce_block = OpTypeStruct %v4half
@@ -38,44 +34,35 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v4half
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v4half
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
 %half_0x1p_0 = OpConstant %half 0x1p+0
-         %20 = OpConstantComposite %v4half %half_0x1p_0 %half_0x1p_0 %half_0x1p_0 %half_0x1p_0
+         %19 = OpConstantComposite %v4half %half_0x1p_0 %half_0x1p_0 %half_0x1p_0 %half_0x1p_0
 %_ptr_Function_v4half = OpTypePointer Function %v4half
        %void = OpTypeVoid
-         %28 = OpTypeFunction %void %uint
+         %26 = OpTypeFunction %void
 %_ptr_StorageBuffer_v4half = OpTypePointer StorageBuffer %v4half
      %uint_0 = OpConstant %uint 0
-         %36 = OpTypeFunction %void
-%subgroupShuffle_7ba2d5 = OpFunction %v4half None %13
-         %14 = OpLabel
+%subgroupShuffle_7ba2d5 = OpFunction %v4half None %11
+         %12 = OpLabel
         %res = OpVariable %_ptr_Function_v4half Function
-         %15 = OpLoad %uint %tint_subgroup_size_mask None
-         %16 = OpBitwiseAnd %uint %uint_1 %15
-         %18 = OpGroupNonUniformShuffle %v4half %uint_3 %20 %16
-               OpStore %res %18
-         %24 = OpLoad %v4half %res None
-               OpReturnValue %24
+         %13 = OpLoad %uint %tint_subgroup_last_id None
+         %14 = OpExtInst %uint %15 UMin %uint_1 %13
+         %17 = OpGroupNonUniformShuffle %v4half %uint_3 %19 %14
+               OpStore %res %17
+         %23 = OpLoad %v4half %res None
+               OpReturnValue %23
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %28
-%tint_subgroup_size = OpFunctionParameter %uint
-         %29 = OpLabel
-         %30 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %30 None
-         %31 = OpFunctionCall %v4half %subgroupShuffle_7ba2d5
-         %32 = OpAccessChain %_ptr_StorageBuffer_v4half %1 %uint_0
-               OpStore %32 %31 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %36
-         %37 = OpLabel
-         %38 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %39 = OpFunctionCall %void %fragment_main_inner %38
+%fragment_main = OpFunction %void None %26
+         %27 = OpLabel
+         %28 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %29 = OpISub %uint %28 %uint_1
+               OpStore %tint_subgroup_last_id %29 None
+         %30 = OpFunctionCall %v4half %subgroupShuffle_7ba2d5
+         %31 = OpAccessChain %_ptr_StorageBuffer_v4half %1 %uint_0
+               OpStore %31 %30 None
                OpReturn
                OpFunctionEnd
 ;
@@ -84,31 +71,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 40
+; Bound: 34
 ; Schema: 0
                OpCapability Shader
                OpCapability Float16
                OpCapability StorageBuffer16BitAccess
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %15 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_7ba2d5 "subgroupShuffle_7ba2d5"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
        %half = OpTypeFloat 16
      %v4half = OpTypeVector %half 4
 %prevent_dce_block = OpTypeStruct %v4half
@@ -117,43 +101,34 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v4half
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v4half
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
 %half_0x1p_0 = OpConstant %half 0x1p+0
-         %20 = OpConstantComposite %v4half %half_0x1p_0 %half_0x1p_0 %half_0x1p_0 %half_0x1p_0
+         %19 = OpConstantComposite %v4half %half_0x1p_0 %half_0x1p_0 %half_0x1p_0 %half_0x1p_0
 %_ptr_Function_v4half = OpTypePointer Function %v4half
        %void = OpTypeVoid
-         %28 = OpTypeFunction %void %uint
+         %26 = OpTypeFunction %void
 %_ptr_StorageBuffer_v4half = OpTypePointer StorageBuffer %v4half
      %uint_0 = OpConstant %uint 0
-         %36 = OpTypeFunction %void
-%subgroupShuffle_7ba2d5 = OpFunction %v4half None %13
-         %14 = OpLabel
+%subgroupShuffle_7ba2d5 = OpFunction %v4half None %11
+         %12 = OpLabel
         %res = OpVariable %_ptr_Function_v4half Function
-         %15 = OpLoad %uint %tint_subgroup_size_mask None
-         %16 = OpBitwiseAnd %uint %uint_1 %15
-         %18 = OpGroupNonUniformShuffle %v4half %uint_3 %20 %16
-               OpStore %res %18
-         %24 = OpLoad %v4half %res None
-               OpReturnValue %24
+         %13 = OpLoad %uint %tint_subgroup_last_id None
+         %14 = OpExtInst %uint %15 UMin %uint_1 %13
+         %17 = OpGroupNonUniformShuffle %v4half %uint_3 %19 %14
+               OpStore %res %17
+         %23 = OpLoad %v4half %res None
+               OpReturnValue %23
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %28
-%tint_subgroup_size = OpFunctionParameter %uint
-         %29 = OpLabel
-         %30 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %30 None
-         %31 = OpFunctionCall %v4half %subgroupShuffle_7ba2d5
-         %32 = OpAccessChain %_ptr_StorageBuffer_v4half %1 %uint_0
-               OpStore %32 %31 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %36
-         %37 = OpLabel
-         %38 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %39 = OpFunctionCall %void %compute_main_inner %38
+%compute_main = OpFunction %void None %26
+         %27 = OpLabel
+         %28 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %29 = OpISub %uint %28 %uint_1
+               OpStore %tint_subgroup_last_id %29 None
+         %30 = OpFunctionCall %v4half %subgroupShuffle_7ba2d5
+         %31 = OpAccessChain %_ptr_StorageBuffer_v4half %1 %uint_0
+               OpStore %31 %30 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/literal/subgroupShuffle/7c5d64.wgsl.expected.spvasm b/test/tint/builtins/gen/literal/subgroupShuffle/7c5d64.wgsl.expected.spvasm
index 2df9e3d..ade62e0 100644
--- a/test/tint/builtins/gen/literal/subgroupShuffle/7c5d64.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/literal/subgroupShuffle/7c5d64.wgsl.expected.spvasm
@@ -4,30 +4,26 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 43
+; Bound: 37
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %18 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_7c5d64 "subgroupShuffle_7c5d64"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
       %float = OpTypeFloat 32
     %v3float = OpTypeVector %float 3
 %prevent_dce_block = OpTypeStruct %v3float
@@ -36,47 +32,38 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v3float
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v3float
         %int = OpTypeInt 32 1
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
     %float_1 = OpConstant %float 1
-         %22 = OpConstantComposite %v3float %float_1 %float_1 %float_1
+         %21 = OpConstantComposite %v3float %float_1 %float_1 %float_1
 %_ptr_Function_v3float = OpTypePointer Function %v3float
        %void = OpTypeVoid
-         %30 = OpTypeFunction %void %uint
+         %28 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_v3float = OpTypePointer StorageBuffer %v3float
      %uint_0 = OpConstant %uint 0
-         %39 = OpTypeFunction %void
-%subgroupShuffle_7c5d64 = OpFunction %v3float None %13
-         %14 = OpLabel
+%subgroupShuffle_7c5d64 = OpFunction %v3float None %11
+         %12 = OpLabel
         %res = OpVariable %_ptr_Function_v3float Function
-         %15 = OpBitcast %uint %int_1
-         %18 = OpLoad %uint %tint_subgroup_size_mask None
-         %19 = OpBitwiseAnd %uint %15 %18
-         %20 = OpGroupNonUniformShuffle %v3float %uint_3 %22 %19
-               OpStore %res %20
-         %26 = OpLoad %v3float %res None
-               OpReturnValue %26
+         %13 = OpBitcast %uint %int_1
+         %16 = OpLoad %uint %tint_subgroup_last_id None
+         %17 = OpExtInst %uint %18 UMin %13 %16
+         %19 = OpGroupNonUniformShuffle %v3float %uint_3 %21 %17
+               OpStore %res %19
+         %25 = OpLoad %v3float %res None
+               OpReturnValue %25
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %30
-%tint_subgroup_size = OpFunctionParameter %uint
-         %31 = OpLabel
-         %32 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %32 None
-         %34 = OpFunctionCall %v3float %subgroupShuffle_7c5d64
-         %35 = OpAccessChain %_ptr_StorageBuffer_v3float %1 %uint_0
-               OpStore %35 %34 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %39
-         %40 = OpLabel
-         %41 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %42 = OpFunctionCall %void %fragment_main_inner %41
+%fragment_main = OpFunction %void None %28
+         %29 = OpLabel
+         %30 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %32 = OpISub %uint %30 %uint_1
+               OpStore %tint_subgroup_last_id %32 None
+         %33 = OpFunctionCall %v3float %subgroupShuffle_7c5d64
+         %34 = OpAccessChain %_ptr_StorageBuffer_v3float %1 %uint_0
+               OpStore %34 %33 None
                OpReturn
                OpFunctionEnd
 ;
@@ -85,29 +72,26 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 43
+; Bound: 37
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %18 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_7c5d64 "subgroupShuffle_7c5d64"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
       %float = OpTypeFloat 32
     %v3float = OpTypeVector %float 3
 %prevent_dce_block = OpTypeStruct %v3float
@@ -116,46 +100,37 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v3float
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v3float
         %int = OpTypeInt 32 1
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
     %float_1 = OpConstant %float 1
-         %22 = OpConstantComposite %v3float %float_1 %float_1 %float_1
+         %21 = OpConstantComposite %v3float %float_1 %float_1 %float_1
 %_ptr_Function_v3float = OpTypePointer Function %v3float
        %void = OpTypeVoid
-         %30 = OpTypeFunction %void %uint
+         %28 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_v3float = OpTypePointer StorageBuffer %v3float
      %uint_0 = OpConstant %uint 0
-         %39 = OpTypeFunction %void
-%subgroupShuffle_7c5d64 = OpFunction %v3float None %13
-         %14 = OpLabel
+%subgroupShuffle_7c5d64 = OpFunction %v3float None %11
+         %12 = OpLabel
         %res = OpVariable %_ptr_Function_v3float Function
-         %15 = OpBitcast %uint %int_1
-         %18 = OpLoad %uint %tint_subgroup_size_mask None
-         %19 = OpBitwiseAnd %uint %15 %18
-         %20 = OpGroupNonUniformShuffle %v3float %uint_3 %22 %19
-               OpStore %res %20
-         %26 = OpLoad %v3float %res None
-               OpReturnValue %26
+         %13 = OpBitcast %uint %int_1
+         %16 = OpLoad %uint %tint_subgroup_last_id None
+         %17 = OpExtInst %uint %18 UMin %13 %16
+         %19 = OpGroupNonUniformShuffle %v3float %uint_3 %21 %17
+               OpStore %res %19
+         %25 = OpLoad %v3float %res None
+               OpReturnValue %25
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %30
-%tint_subgroup_size = OpFunctionParameter %uint
-         %31 = OpLabel
-         %32 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %32 None
-         %34 = OpFunctionCall %v3float %subgroupShuffle_7c5d64
-         %35 = OpAccessChain %_ptr_StorageBuffer_v3float %1 %uint_0
-               OpStore %35 %34 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %39
-         %40 = OpLabel
-         %41 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %42 = OpFunctionCall %void %compute_main_inner %41
+%compute_main = OpFunction %void None %28
+         %29 = OpLabel
+         %30 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %32 = OpISub %uint %30 %uint_1
+               OpStore %tint_subgroup_last_id %32 None
+         %33 = OpFunctionCall %v3float %subgroupShuffle_7c5d64
+         %34 = OpAccessChain %_ptr_StorageBuffer_v3float %1 %uint_0
+               OpStore %34 %33 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/literal/subgroupShuffle/7d7b1e.wgsl.expected.spvasm b/test/tint/builtins/gen/literal/subgroupShuffle/7d7b1e.wgsl.expected.spvasm
index 37a0faf..0c0891d 100644
--- a/test/tint/builtins/gen/literal/subgroupShuffle/7d7b1e.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/literal/subgroupShuffle/7d7b1e.wgsl.expected.spvasm
@@ -4,32 +4,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 38
+; Bound: 32
 ; Schema: 0
                OpCapability Shader
                OpCapability Float16
                OpCapability StorageBuffer16BitAccess
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %14 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_7d7b1e "subgroupShuffle_7d7b1e"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
        %half = OpTypeFloat 16
 %prevent_dce_block = OpTypeStruct %half
 %_ptr_StorageBuffer_prevent_dce_block = OpTypePointer StorageBuffer %prevent_dce_block
@@ -37,43 +33,34 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %half
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %half
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
 %half_0x1p_0 = OpConstant %half 0x1p+0
 %_ptr_Function_half = OpTypePointer Function %half
        %void = OpTypeVoid
-         %26 = OpTypeFunction %void %uint
+         %24 = OpTypeFunction %void
 %_ptr_StorageBuffer_half = OpTypePointer StorageBuffer %half
      %uint_0 = OpConstant %uint 0
-         %34 = OpTypeFunction %void
-%subgroupShuffle_7d7b1e = OpFunction %half None %12
-         %13 = OpLabel
+%subgroupShuffle_7d7b1e = OpFunction %half None %10
+         %11 = OpLabel
         %res = OpVariable %_ptr_Function_half Function
-         %14 = OpLoad %uint %tint_subgroup_size_mask None
-         %15 = OpBitwiseAnd %uint %uint_1 %14
-         %17 = OpGroupNonUniformShuffle %half %uint_3 %half_0x1p_0 %15
-               OpStore %res %17
-         %22 = OpLoad %half %res None
-               OpReturnValue %22
+         %12 = OpLoad %uint %tint_subgroup_last_id None
+         %13 = OpExtInst %uint %14 UMin %uint_1 %12
+         %16 = OpGroupNonUniformShuffle %half %uint_3 %half_0x1p_0 %13
+               OpStore %res %16
+         %21 = OpLoad %half %res None
+               OpReturnValue %21
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %26
-%tint_subgroup_size = OpFunctionParameter %uint
-         %27 = OpLabel
-         %28 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %28 None
-         %29 = OpFunctionCall %half %subgroupShuffle_7d7b1e
-         %30 = OpAccessChain %_ptr_StorageBuffer_half %1 %uint_0
-               OpStore %30 %29 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %34
-         %35 = OpLabel
-         %36 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %37 = OpFunctionCall %void %fragment_main_inner %36
+%fragment_main = OpFunction %void None %24
+         %25 = OpLabel
+         %26 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %27 = OpISub %uint %26 %uint_1
+               OpStore %tint_subgroup_last_id %27 None
+         %28 = OpFunctionCall %half %subgroupShuffle_7d7b1e
+         %29 = OpAccessChain %_ptr_StorageBuffer_half %1 %uint_0
+               OpStore %29 %28 None
                OpReturn
                OpFunctionEnd
 ;
@@ -82,31 +69,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 38
+; Bound: 32
 ; Schema: 0
                OpCapability Shader
                OpCapability Float16
                OpCapability StorageBuffer16BitAccess
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %14 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_7d7b1e "subgroupShuffle_7d7b1e"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
        %half = OpTypeFloat 16
 %prevent_dce_block = OpTypeStruct %half
 %_ptr_StorageBuffer_prevent_dce_block = OpTypePointer StorageBuffer %prevent_dce_block
@@ -114,42 +98,33 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %half
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %half
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
 %half_0x1p_0 = OpConstant %half 0x1p+0
 %_ptr_Function_half = OpTypePointer Function %half
        %void = OpTypeVoid
-         %26 = OpTypeFunction %void %uint
+         %24 = OpTypeFunction %void
 %_ptr_StorageBuffer_half = OpTypePointer StorageBuffer %half
      %uint_0 = OpConstant %uint 0
-         %34 = OpTypeFunction %void
-%subgroupShuffle_7d7b1e = OpFunction %half None %12
-         %13 = OpLabel
+%subgroupShuffle_7d7b1e = OpFunction %half None %10
+         %11 = OpLabel
         %res = OpVariable %_ptr_Function_half Function
-         %14 = OpLoad %uint %tint_subgroup_size_mask None
-         %15 = OpBitwiseAnd %uint %uint_1 %14
-         %17 = OpGroupNonUniformShuffle %half %uint_3 %half_0x1p_0 %15
-               OpStore %res %17
-         %22 = OpLoad %half %res None
-               OpReturnValue %22
+         %12 = OpLoad %uint %tint_subgroup_last_id None
+         %13 = OpExtInst %uint %14 UMin %uint_1 %12
+         %16 = OpGroupNonUniformShuffle %half %uint_3 %half_0x1p_0 %13
+               OpStore %res %16
+         %21 = OpLoad %half %res None
+               OpReturnValue %21
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %26
-%tint_subgroup_size = OpFunctionParameter %uint
-         %27 = OpLabel
-         %28 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %28 None
-         %29 = OpFunctionCall %half %subgroupShuffle_7d7b1e
-         %30 = OpAccessChain %_ptr_StorageBuffer_half %1 %uint_0
-               OpStore %30 %29 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %34
-         %35 = OpLabel
-         %36 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %37 = OpFunctionCall %void %compute_main_inner %36
+%compute_main = OpFunction %void None %24
+         %25 = OpLabel
+         %26 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %27 = OpISub %uint %26 %uint_1
+               OpStore %tint_subgroup_last_id %27 None
+         %28 = OpFunctionCall %half %subgroupShuffle_7d7b1e
+         %29 = OpAccessChain %_ptr_StorageBuffer_half %1 %uint_0
+               OpStore %29 %28 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/literal/subgroupShuffle/821df9.wgsl.expected.spvasm b/test/tint/builtins/gen/literal/subgroupShuffle/821df9.wgsl.expected.spvasm
index ff65063..d6e7e20 100644
--- a/test/tint/builtins/gen/literal/subgroupShuffle/821df9.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/literal/subgroupShuffle/821df9.wgsl.expected.spvasm
@@ -4,32 +4,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 43
+; Bound: 37
 ; Schema: 0
                OpCapability Shader
                OpCapability Float16
                OpCapability StorageBuffer16BitAccess
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %18 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_821df9 "subgroupShuffle_821df9"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
        %half = OpTypeFloat 16
      %v3half = OpTypeVector %half 3
 %prevent_dce_block = OpTypeStruct %v3half
@@ -38,47 +34,38 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v3half
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v3half
         %int = OpTypeInt 32 1
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
 %half_0x1p_0 = OpConstant %half 0x1p+0
-         %22 = OpConstantComposite %v3half %half_0x1p_0 %half_0x1p_0 %half_0x1p_0
+         %21 = OpConstantComposite %v3half %half_0x1p_0 %half_0x1p_0 %half_0x1p_0
 %_ptr_Function_v3half = OpTypePointer Function %v3half
        %void = OpTypeVoid
-         %30 = OpTypeFunction %void %uint
+         %28 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_v3half = OpTypePointer StorageBuffer %v3half
      %uint_0 = OpConstant %uint 0
-         %39 = OpTypeFunction %void
-%subgroupShuffle_821df9 = OpFunction %v3half None %13
-         %14 = OpLabel
+%subgroupShuffle_821df9 = OpFunction %v3half None %11
+         %12 = OpLabel
         %res = OpVariable %_ptr_Function_v3half Function
-         %15 = OpBitcast %uint %int_1
-         %18 = OpLoad %uint %tint_subgroup_size_mask None
-         %19 = OpBitwiseAnd %uint %15 %18
-         %20 = OpGroupNonUniformShuffle %v3half %uint_3 %22 %19
-               OpStore %res %20
-         %26 = OpLoad %v3half %res None
-               OpReturnValue %26
+         %13 = OpBitcast %uint %int_1
+         %16 = OpLoad %uint %tint_subgroup_last_id None
+         %17 = OpExtInst %uint %18 UMin %13 %16
+         %19 = OpGroupNonUniformShuffle %v3half %uint_3 %21 %17
+               OpStore %res %19
+         %25 = OpLoad %v3half %res None
+               OpReturnValue %25
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %30
-%tint_subgroup_size = OpFunctionParameter %uint
-         %31 = OpLabel
-         %32 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %32 None
-         %34 = OpFunctionCall %v3half %subgroupShuffle_821df9
-         %35 = OpAccessChain %_ptr_StorageBuffer_v3half %1 %uint_0
-               OpStore %35 %34 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %39
-         %40 = OpLabel
-         %41 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %42 = OpFunctionCall %void %fragment_main_inner %41
+%fragment_main = OpFunction %void None %28
+         %29 = OpLabel
+         %30 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %32 = OpISub %uint %30 %uint_1
+               OpStore %tint_subgroup_last_id %32 None
+         %33 = OpFunctionCall %v3half %subgroupShuffle_821df9
+         %34 = OpAccessChain %_ptr_StorageBuffer_v3half %1 %uint_0
+               OpStore %34 %33 None
                OpReturn
                OpFunctionEnd
 ;
@@ -87,31 +74,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 43
+; Bound: 37
 ; Schema: 0
                OpCapability Shader
                OpCapability Float16
                OpCapability StorageBuffer16BitAccess
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %18 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_821df9 "subgroupShuffle_821df9"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
        %half = OpTypeFloat 16
      %v3half = OpTypeVector %half 3
 %prevent_dce_block = OpTypeStruct %v3half
@@ -120,46 +104,37 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v3half
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v3half
         %int = OpTypeInt 32 1
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
 %half_0x1p_0 = OpConstant %half 0x1p+0
-         %22 = OpConstantComposite %v3half %half_0x1p_0 %half_0x1p_0 %half_0x1p_0
+         %21 = OpConstantComposite %v3half %half_0x1p_0 %half_0x1p_0 %half_0x1p_0
 %_ptr_Function_v3half = OpTypePointer Function %v3half
        %void = OpTypeVoid
-         %30 = OpTypeFunction %void %uint
+         %28 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_v3half = OpTypePointer StorageBuffer %v3half
      %uint_0 = OpConstant %uint 0
-         %39 = OpTypeFunction %void
-%subgroupShuffle_821df9 = OpFunction %v3half None %13
-         %14 = OpLabel
+%subgroupShuffle_821df9 = OpFunction %v3half None %11
+         %12 = OpLabel
         %res = OpVariable %_ptr_Function_v3half Function
-         %15 = OpBitcast %uint %int_1
-         %18 = OpLoad %uint %tint_subgroup_size_mask None
-         %19 = OpBitwiseAnd %uint %15 %18
-         %20 = OpGroupNonUniformShuffle %v3half %uint_3 %22 %19
-               OpStore %res %20
-         %26 = OpLoad %v3half %res None
-               OpReturnValue %26
+         %13 = OpBitcast %uint %int_1
+         %16 = OpLoad %uint %tint_subgroup_last_id None
+         %17 = OpExtInst %uint %18 UMin %13 %16
+         %19 = OpGroupNonUniformShuffle %v3half %uint_3 %21 %17
+               OpStore %res %19
+         %25 = OpLoad %v3half %res None
+               OpReturnValue %25
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %30
-%tint_subgroup_size = OpFunctionParameter %uint
-         %31 = OpLabel
-         %32 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %32 None
-         %34 = OpFunctionCall %v3half %subgroupShuffle_821df9
-         %35 = OpAccessChain %_ptr_StorageBuffer_v3half %1 %uint_0
-               OpStore %35 %34 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %39
-         %40 = OpLabel
-         %41 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %42 = OpFunctionCall %void %compute_main_inner %41
+%compute_main = OpFunction %void None %28
+         %29 = OpLabel
+         %30 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %32 = OpISub %uint %30 %uint_1
+               OpStore %tint_subgroup_last_id %32 None
+         %33 = OpFunctionCall %v3half %subgroupShuffle_821df9
+         %34 = OpAccessChain %_ptr_StorageBuffer_v3half %1 %uint_0
+               OpStore %34 %33 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/literal/subgroupShuffle/824702.wgsl.expected.spvasm b/test/tint/builtins/gen/literal/subgroupShuffle/824702.wgsl.expected.spvasm
index 3b60243..ad6dc58 100644
--- a/test/tint/builtins/gen/literal/subgroupShuffle/824702.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/literal/subgroupShuffle/824702.wgsl.expected.spvasm
@@ -4,30 +4,26 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 41
+; Bound: 35
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %17 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_824702 "subgroupShuffle_824702"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
         %int = OpTypeInt 32 1
       %v3int = OpTypeVector %int 3
 %prevent_dce_block = OpTypeStruct %v3int
@@ -36,45 +32,36 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v3int
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v3int
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
-         %21 = OpConstantComposite %v3int %int_1 %int_1 %int_1
+         %20 = OpConstantComposite %v3int %int_1 %int_1 %int_1
 %_ptr_Function_v3int = OpTypePointer Function %v3int
        %void = OpTypeVoid
-         %28 = OpTypeFunction %void %uint
+         %26 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_v3int = OpTypePointer StorageBuffer %v3int
      %uint_0 = OpConstant %uint 0
-         %37 = OpTypeFunction %void
-%subgroupShuffle_824702 = OpFunction %v3int None %13
-         %14 = OpLabel
+%subgroupShuffle_824702 = OpFunction %v3int None %11
+         %12 = OpLabel
         %res = OpVariable %_ptr_Function_v3int Function
-         %15 = OpBitcast %uint %int_1
-         %17 = OpLoad %uint %tint_subgroup_size_mask None
-         %18 = OpBitwiseAnd %uint %15 %17
-         %19 = OpGroupNonUniformShuffle %v3int %uint_3 %21 %18
-               OpStore %res %19
-         %24 = OpLoad %v3int %res None
-               OpReturnValue %24
+         %13 = OpBitcast %uint %int_1
+         %15 = OpLoad %uint %tint_subgroup_last_id None
+         %16 = OpExtInst %uint %17 UMin %13 %15
+         %18 = OpGroupNonUniformShuffle %v3int %uint_3 %20 %16
+               OpStore %res %18
+         %23 = OpLoad %v3int %res None
+               OpReturnValue %23
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %28
-%tint_subgroup_size = OpFunctionParameter %uint
-         %29 = OpLabel
-         %30 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %30 None
-         %32 = OpFunctionCall %v3int %subgroupShuffle_824702
-         %33 = OpAccessChain %_ptr_StorageBuffer_v3int %1 %uint_0
-               OpStore %33 %32 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %37
-         %38 = OpLabel
-         %39 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %40 = OpFunctionCall %void %fragment_main_inner %39
+%fragment_main = OpFunction %void None %26
+         %27 = OpLabel
+         %28 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %30 = OpISub %uint %28 %uint_1
+               OpStore %tint_subgroup_last_id %30 None
+         %31 = OpFunctionCall %v3int %subgroupShuffle_824702
+         %32 = OpAccessChain %_ptr_StorageBuffer_v3int %1 %uint_0
+               OpStore %32 %31 None
                OpReturn
                OpFunctionEnd
 ;
@@ -83,29 +70,26 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 41
+; Bound: 35
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %17 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_824702 "subgroupShuffle_824702"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
         %int = OpTypeInt 32 1
       %v3int = OpTypeVector %int 3
 %prevent_dce_block = OpTypeStruct %v3int
@@ -114,44 +98,35 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v3int
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v3int
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
-         %21 = OpConstantComposite %v3int %int_1 %int_1 %int_1
+         %20 = OpConstantComposite %v3int %int_1 %int_1 %int_1
 %_ptr_Function_v3int = OpTypePointer Function %v3int
        %void = OpTypeVoid
-         %28 = OpTypeFunction %void %uint
+         %26 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_v3int = OpTypePointer StorageBuffer %v3int
      %uint_0 = OpConstant %uint 0
-         %37 = OpTypeFunction %void
-%subgroupShuffle_824702 = OpFunction %v3int None %13
-         %14 = OpLabel
+%subgroupShuffle_824702 = OpFunction %v3int None %11
+         %12 = OpLabel
         %res = OpVariable %_ptr_Function_v3int Function
-         %15 = OpBitcast %uint %int_1
-         %17 = OpLoad %uint %tint_subgroup_size_mask None
-         %18 = OpBitwiseAnd %uint %15 %17
-         %19 = OpGroupNonUniformShuffle %v3int %uint_3 %21 %18
-               OpStore %res %19
-         %24 = OpLoad %v3int %res None
-               OpReturnValue %24
+         %13 = OpBitcast %uint %int_1
+         %15 = OpLoad %uint %tint_subgroup_last_id None
+         %16 = OpExtInst %uint %17 UMin %13 %15
+         %18 = OpGroupNonUniformShuffle %v3int %uint_3 %20 %16
+               OpStore %res %18
+         %23 = OpLoad %v3int %res None
+               OpReturnValue %23
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %28
-%tint_subgroup_size = OpFunctionParameter %uint
-         %29 = OpLabel
-         %30 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %30 None
-         %32 = OpFunctionCall %v3int %subgroupShuffle_824702
-         %33 = OpAccessChain %_ptr_StorageBuffer_v3int %1 %uint_0
-               OpStore %33 %32 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %37
-         %38 = OpLabel
-         %39 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %40 = OpFunctionCall %void %compute_main_inner %39
+%compute_main = OpFunction %void None %26
+         %27 = OpLabel
+         %28 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %30 = OpISub %uint %28 %uint_1
+               OpStore %tint_subgroup_last_id %30 None
+         %31 = OpFunctionCall %v3int %subgroupShuffle_824702
+         %32 = OpAccessChain %_ptr_StorageBuffer_v3int %1 %uint_0
+               OpStore %32 %31 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/literal/subgroupShuffle/84f261.wgsl.expected.spvasm b/test/tint/builtins/gen/literal/subgroupShuffle/84f261.wgsl.expected.spvasm
index 2e4bfd7..9e554db 100644
--- a/test/tint/builtins/gen/literal/subgroupShuffle/84f261.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/literal/subgroupShuffle/84f261.wgsl.expected.spvasm
@@ -4,30 +4,26 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 38
+; Bound: 32
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %14 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_84f261 "subgroupShuffle_84f261"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
        %uint = OpTypeInt 32 0
      %v4uint = OpTypeVector %uint 4
 %prevent_dce_block = OpTypeStruct %v4uint
@@ -35,43 +31,34 @@
           %1 = OpVariable %_ptr_StorageBuffer_prevent_dce_block StorageBuffer
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %v4uint
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %v4uint
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
-         %19 = OpConstantComposite %v4uint %uint_1 %uint_1 %uint_1 %uint_1
+         %18 = OpConstantComposite %v4uint %uint_1 %uint_1 %uint_1 %uint_1
 %_ptr_Function_v4uint = OpTypePointer Function %v4uint
        %void = OpTypeVoid
-         %26 = OpTypeFunction %void %uint
+         %24 = OpTypeFunction %void
 %_ptr_StorageBuffer_v4uint = OpTypePointer StorageBuffer %v4uint
      %uint_0 = OpConstant %uint 0
-         %34 = OpTypeFunction %void
-%subgroupShuffle_84f261 = OpFunction %v4uint None %12
-         %13 = OpLabel
+%subgroupShuffle_84f261 = OpFunction %v4uint None %10
+         %11 = OpLabel
         %res = OpVariable %_ptr_Function_v4uint Function
-         %14 = OpLoad %uint %tint_subgroup_size_mask None
-         %15 = OpBitwiseAnd %uint %uint_1 %14
-         %17 = OpGroupNonUniformShuffle %v4uint %uint_3 %19 %15
-               OpStore %res %17
-         %22 = OpLoad %v4uint %res None
-               OpReturnValue %22
+         %12 = OpLoad %uint %tint_subgroup_last_id None
+         %13 = OpExtInst %uint %14 UMin %uint_1 %12
+         %16 = OpGroupNonUniformShuffle %v4uint %uint_3 %18 %13
+               OpStore %res %16
+         %21 = OpLoad %v4uint %res None
+               OpReturnValue %21
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %26
-%tint_subgroup_size = OpFunctionParameter %uint
-         %27 = OpLabel
-         %28 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %28 None
-         %29 = OpFunctionCall %v4uint %subgroupShuffle_84f261
-         %30 = OpAccessChain %_ptr_StorageBuffer_v4uint %1 %uint_0
-               OpStore %30 %29 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %34
-         %35 = OpLabel
-         %36 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %37 = OpFunctionCall %void %fragment_main_inner %36
+%fragment_main = OpFunction %void None %24
+         %25 = OpLabel
+         %26 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %27 = OpISub %uint %26 %uint_1
+               OpStore %tint_subgroup_last_id %27 None
+         %28 = OpFunctionCall %v4uint %subgroupShuffle_84f261
+         %29 = OpAccessChain %_ptr_StorageBuffer_v4uint %1 %uint_0
+               OpStore %29 %28 None
                OpReturn
                OpFunctionEnd
 ;
@@ -80,29 +67,26 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 38
+; Bound: 32
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %14 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_84f261 "subgroupShuffle_84f261"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
        %uint = OpTypeInt 32 0
      %v4uint = OpTypeVector %uint 4
 %prevent_dce_block = OpTypeStruct %v4uint
@@ -110,42 +94,33 @@
           %1 = OpVariable %_ptr_StorageBuffer_prevent_dce_block StorageBuffer
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %v4uint
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %v4uint
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
-         %19 = OpConstantComposite %v4uint %uint_1 %uint_1 %uint_1 %uint_1
+         %18 = OpConstantComposite %v4uint %uint_1 %uint_1 %uint_1 %uint_1
 %_ptr_Function_v4uint = OpTypePointer Function %v4uint
        %void = OpTypeVoid
-         %26 = OpTypeFunction %void %uint
+         %24 = OpTypeFunction %void
 %_ptr_StorageBuffer_v4uint = OpTypePointer StorageBuffer %v4uint
      %uint_0 = OpConstant %uint 0
-         %34 = OpTypeFunction %void
-%subgroupShuffle_84f261 = OpFunction %v4uint None %12
-         %13 = OpLabel
+%subgroupShuffle_84f261 = OpFunction %v4uint None %10
+         %11 = OpLabel
         %res = OpVariable %_ptr_Function_v4uint Function
-         %14 = OpLoad %uint %tint_subgroup_size_mask None
-         %15 = OpBitwiseAnd %uint %uint_1 %14
-         %17 = OpGroupNonUniformShuffle %v4uint %uint_3 %19 %15
-               OpStore %res %17
-         %22 = OpLoad %v4uint %res None
-               OpReturnValue %22
+         %12 = OpLoad %uint %tint_subgroup_last_id None
+         %13 = OpExtInst %uint %14 UMin %uint_1 %12
+         %16 = OpGroupNonUniformShuffle %v4uint %uint_3 %18 %13
+               OpStore %res %16
+         %21 = OpLoad %v4uint %res None
+               OpReturnValue %21
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %26
-%tint_subgroup_size = OpFunctionParameter %uint
-         %27 = OpLabel
-         %28 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %28 None
-         %29 = OpFunctionCall %v4uint %subgroupShuffle_84f261
-         %30 = OpAccessChain %_ptr_StorageBuffer_v4uint %1 %uint_0
-               OpStore %30 %29 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %34
-         %35 = OpLabel
-         %36 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %37 = OpFunctionCall %void %compute_main_inner %36
+%compute_main = OpFunction %void None %24
+         %25 = OpLabel
+         %26 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %27 = OpISub %uint %26 %uint_1
+               OpStore %tint_subgroup_last_id %27 None
+         %28 = OpFunctionCall %v4uint %subgroupShuffle_84f261
+         %29 = OpAccessChain %_ptr_StorageBuffer_v4uint %1 %uint_0
+               OpStore %29 %28 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/literal/subgroupShuffle/85587b.wgsl.expected.spvasm b/test/tint/builtins/gen/literal/subgroupShuffle/85587b.wgsl.expected.spvasm
index cba671b..203f09a 100644
--- a/test/tint/builtins/gen/literal/subgroupShuffle/85587b.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/literal/subgroupShuffle/85587b.wgsl.expected.spvasm
@@ -4,30 +4,26 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 40
+; Bound: 34
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %15 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_85587b "subgroupShuffle_85587b"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
       %float = OpTypeFloat 32
     %v4float = OpTypeVector %float 4
 %prevent_dce_block = OpTypeStruct %v4float
@@ -36,44 +32,35 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v4float
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v4float
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
     %float_1 = OpConstant %float 1
-         %20 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
+         %19 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
 %_ptr_Function_v4float = OpTypePointer Function %v4float
        %void = OpTypeVoid
-         %28 = OpTypeFunction %void %uint
+         %26 = OpTypeFunction %void
 %_ptr_StorageBuffer_v4float = OpTypePointer StorageBuffer %v4float
      %uint_0 = OpConstant %uint 0
-         %36 = OpTypeFunction %void
-%subgroupShuffle_85587b = OpFunction %v4float None %13
-         %14 = OpLabel
+%subgroupShuffle_85587b = OpFunction %v4float None %11
+         %12 = OpLabel
         %res = OpVariable %_ptr_Function_v4float Function
-         %15 = OpLoad %uint %tint_subgroup_size_mask None
-         %16 = OpBitwiseAnd %uint %uint_1 %15
-         %18 = OpGroupNonUniformShuffle %v4float %uint_3 %20 %16
-               OpStore %res %18
-         %24 = OpLoad %v4float %res None
-               OpReturnValue %24
+         %13 = OpLoad %uint %tint_subgroup_last_id None
+         %14 = OpExtInst %uint %15 UMin %uint_1 %13
+         %17 = OpGroupNonUniformShuffle %v4float %uint_3 %19 %14
+               OpStore %res %17
+         %23 = OpLoad %v4float %res None
+               OpReturnValue %23
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %28
-%tint_subgroup_size = OpFunctionParameter %uint
-         %29 = OpLabel
-         %30 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %30 None
-         %31 = OpFunctionCall %v4float %subgroupShuffle_85587b
-         %32 = OpAccessChain %_ptr_StorageBuffer_v4float %1 %uint_0
-               OpStore %32 %31 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %36
-         %37 = OpLabel
-         %38 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %39 = OpFunctionCall %void %fragment_main_inner %38
+%fragment_main = OpFunction %void None %26
+         %27 = OpLabel
+         %28 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %29 = OpISub %uint %28 %uint_1
+               OpStore %tint_subgroup_last_id %29 None
+         %30 = OpFunctionCall %v4float %subgroupShuffle_85587b
+         %31 = OpAccessChain %_ptr_StorageBuffer_v4float %1 %uint_0
+               OpStore %31 %30 None
                OpReturn
                OpFunctionEnd
 ;
@@ -82,29 +69,26 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 40
+; Bound: 34
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %15 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_85587b "subgroupShuffle_85587b"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
       %float = OpTypeFloat 32
     %v4float = OpTypeVector %float 4
 %prevent_dce_block = OpTypeStruct %v4float
@@ -113,43 +97,34 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v4float
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v4float
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
     %float_1 = OpConstant %float 1
-         %20 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
+         %19 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
 %_ptr_Function_v4float = OpTypePointer Function %v4float
        %void = OpTypeVoid
-         %28 = OpTypeFunction %void %uint
+         %26 = OpTypeFunction %void
 %_ptr_StorageBuffer_v4float = OpTypePointer StorageBuffer %v4float
      %uint_0 = OpConstant %uint 0
-         %36 = OpTypeFunction %void
-%subgroupShuffle_85587b = OpFunction %v4float None %13
-         %14 = OpLabel
+%subgroupShuffle_85587b = OpFunction %v4float None %11
+         %12 = OpLabel
         %res = OpVariable %_ptr_Function_v4float Function
-         %15 = OpLoad %uint %tint_subgroup_size_mask None
-         %16 = OpBitwiseAnd %uint %uint_1 %15
-         %18 = OpGroupNonUniformShuffle %v4float %uint_3 %20 %16
-               OpStore %res %18
-         %24 = OpLoad %v4float %res None
-               OpReturnValue %24
+         %13 = OpLoad %uint %tint_subgroup_last_id None
+         %14 = OpExtInst %uint %15 UMin %uint_1 %13
+         %17 = OpGroupNonUniformShuffle %v4float %uint_3 %19 %14
+               OpStore %res %17
+         %23 = OpLoad %v4float %res None
+               OpReturnValue %23
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %28
-%tint_subgroup_size = OpFunctionParameter %uint
-         %29 = OpLabel
-         %30 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %30 None
-         %31 = OpFunctionCall %v4float %subgroupShuffle_85587b
-         %32 = OpAccessChain %_ptr_StorageBuffer_v4float %1 %uint_0
-               OpStore %32 %31 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %36
-         %37 = OpLabel
-         %38 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %39 = OpFunctionCall %void %compute_main_inner %38
+%compute_main = OpFunction %void None %26
+         %27 = OpLabel
+         %28 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %29 = OpISub %uint %28 %uint_1
+               OpStore %tint_subgroup_last_id %29 None
+         %30 = OpFunctionCall %v4float %subgroupShuffle_85587b
+         %31 = OpAccessChain %_ptr_StorageBuffer_v4float %1 %uint_0
+               OpStore %31 %30 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/literal/subgroupShuffle/8890a5.wgsl.expected.spvasm b/test/tint/builtins/gen/literal/subgroupShuffle/8890a5.wgsl.expected.spvasm
index e5b490c..e507bde 100644
--- a/test/tint/builtins/gen/literal/subgroupShuffle/8890a5.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/literal/subgroupShuffle/8890a5.wgsl.expected.spvasm
@@ -4,30 +4,26 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 40
+; Bound: 34
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %15 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_8890a5 "subgroupShuffle_8890a5"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
       %float = OpTypeFloat 32
     %v2float = OpTypeVector %float 2
 %prevent_dce_block = OpTypeStruct %v2float
@@ -36,44 +32,35 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v2float
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v2float
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
     %float_1 = OpConstant %float 1
-         %20 = OpConstantComposite %v2float %float_1 %float_1
+         %19 = OpConstantComposite %v2float %float_1 %float_1
 %_ptr_Function_v2float = OpTypePointer Function %v2float
        %void = OpTypeVoid
-         %28 = OpTypeFunction %void %uint
+         %26 = OpTypeFunction %void
 %_ptr_StorageBuffer_v2float = OpTypePointer StorageBuffer %v2float
      %uint_0 = OpConstant %uint 0
-         %36 = OpTypeFunction %void
-%subgroupShuffle_8890a5 = OpFunction %v2float None %13
-         %14 = OpLabel
+%subgroupShuffle_8890a5 = OpFunction %v2float None %11
+         %12 = OpLabel
         %res = OpVariable %_ptr_Function_v2float Function
-         %15 = OpLoad %uint %tint_subgroup_size_mask None
-         %16 = OpBitwiseAnd %uint %uint_1 %15
-         %18 = OpGroupNonUniformShuffle %v2float %uint_3 %20 %16
-               OpStore %res %18
-         %24 = OpLoad %v2float %res None
-               OpReturnValue %24
+         %13 = OpLoad %uint %tint_subgroup_last_id None
+         %14 = OpExtInst %uint %15 UMin %uint_1 %13
+         %17 = OpGroupNonUniformShuffle %v2float %uint_3 %19 %14
+               OpStore %res %17
+         %23 = OpLoad %v2float %res None
+               OpReturnValue %23
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %28
-%tint_subgroup_size = OpFunctionParameter %uint
-         %29 = OpLabel
-         %30 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %30 None
-         %31 = OpFunctionCall %v2float %subgroupShuffle_8890a5
-         %32 = OpAccessChain %_ptr_StorageBuffer_v2float %1 %uint_0
-               OpStore %32 %31 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %36
-         %37 = OpLabel
-         %38 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %39 = OpFunctionCall %void %fragment_main_inner %38
+%fragment_main = OpFunction %void None %26
+         %27 = OpLabel
+         %28 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %29 = OpISub %uint %28 %uint_1
+               OpStore %tint_subgroup_last_id %29 None
+         %30 = OpFunctionCall %v2float %subgroupShuffle_8890a5
+         %31 = OpAccessChain %_ptr_StorageBuffer_v2float %1 %uint_0
+               OpStore %31 %30 None
                OpReturn
                OpFunctionEnd
 ;
@@ -82,29 +69,26 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 40
+; Bound: 34
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %15 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_8890a5 "subgroupShuffle_8890a5"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
       %float = OpTypeFloat 32
     %v2float = OpTypeVector %float 2
 %prevent_dce_block = OpTypeStruct %v2float
@@ -113,43 +97,34 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v2float
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v2float
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
     %float_1 = OpConstant %float 1
-         %20 = OpConstantComposite %v2float %float_1 %float_1
+         %19 = OpConstantComposite %v2float %float_1 %float_1
 %_ptr_Function_v2float = OpTypePointer Function %v2float
        %void = OpTypeVoid
-         %28 = OpTypeFunction %void %uint
+         %26 = OpTypeFunction %void
 %_ptr_StorageBuffer_v2float = OpTypePointer StorageBuffer %v2float
      %uint_0 = OpConstant %uint 0
-         %36 = OpTypeFunction %void
-%subgroupShuffle_8890a5 = OpFunction %v2float None %13
-         %14 = OpLabel
+%subgroupShuffle_8890a5 = OpFunction %v2float None %11
+         %12 = OpLabel
         %res = OpVariable %_ptr_Function_v2float Function
-         %15 = OpLoad %uint %tint_subgroup_size_mask None
-         %16 = OpBitwiseAnd %uint %uint_1 %15
-         %18 = OpGroupNonUniformShuffle %v2float %uint_3 %20 %16
-               OpStore %res %18
-         %24 = OpLoad %v2float %res None
-               OpReturnValue %24
+         %13 = OpLoad %uint %tint_subgroup_last_id None
+         %14 = OpExtInst %uint %15 UMin %uint_1 %13
+         %17 = OpGroupNonUniformShuffle %v2float %uint_3 %19 %14
+               OpStore %res %17
+         %23 = OpLoad %v2float %res None
+               OpReturnValue %23
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %28
-%tint_subgroup_size = OpFunctionParameter %uint
-         %29 = OpLabel
-         %30 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %30 None
-         %31 = OpFunctionCall %v2float %subgroupShuffle_8890a5
-         %32 = OpAccessChain %_ptr_StorageBuffer_v2float %1 %uint_0
-               OpStore %32 %31 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %36
-         %37 = OpLabel
-         %38 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %39 = OpFunctionCall %void %compute_main_inner %38
+%compute_main = OpFunction %void None %26
+         %27 = OpLabel
+         %28 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %29 = OpISub %uint %28 %uint_1
+               OpStore %tint_subgroup_last_id %29 None
+         %30 = OpFunctionCall %v2float %subgroupShuffle_8890a5
+         %31 = OpAccessChain %_ptr_StorageBuffer_v2float %1 %uint_0
+               OpStore %31 %30 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/literal/subgroupShuffle/8bfbcd.wgsl.expected.spvasm b/test/tint/builtins/gen/literal/subgroupShuffle/8bfbcd.wgsl.expected.spvasm
index 6ba22c1..97ba604 100644
--- a/test/tint/builtins/gen/literal/subgroupShuffle/8bfbcd.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/literal/subgroupShuffle/8bfbcd.wgsl.expected.spvasm
@@ -4,30 +4,26 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 39
+; Bound: 33
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %16 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_8bfbcd "subgroupShuffle_8bfbcd"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
         %int = OpTypeInt 32 1
 %prevent_dce_block = OpTypeStruct %int
 %_ptr_StorageBuffer_prevent_dce_block = OpTypePointer StorageBuffer %prevent_dce_block
@@ -35,44 +31,35 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %int
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %int
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
 %_ptr_Function_int = OpTypePointer Function %int
        %void = OpTypeVoid
-         %26 = OpTypeFunction %void %uint
+         %24 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_int = OpTypePointer StorageBuffer %int
      %uint_0 = OpConstant %uint 0
-         %35 = OpTypeFunction %void
-%subgroupShuffle_8bfbcd = OpFunction %int None %12
-         %13 = OpLabel
+%subgroupShuffle_8bfbcd = OpFunction %int None %10
+         %11 = OpLabel
         %res = OpVariable %_ptr_Function_int Function
-         %14 = OpBitcast %uint %int_1
-         %16 = OpLoad %uint %tint_subgroup_size_mask None
-         %17 = OpBitwiseAnd %uint %14 %16
-         %18 = OpGroupNonUniformShuffle %int %uint_3 %int_1 %17
-               OpStore %res %18
-         %22 = OpLoad %int %res None
-               OpReturnValue %22
+         %12 = OpBitcast %uint %int_1
+         %14 = OpLoad %uint %tint_subgroup_last_id None
+         %15 = OpExtInst %uint %16 UMin %12 %14
+         %17 = OpGroupNonUniformShuffle %int %uint_3 %int_1 %15
+               OpStore %res %17
+         %21 = OpLoad %int %res None
+               OpReturnValue %21
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %26
-%tint_subgroup_size = OpFunctionParameter %uint
-         %27 = OpLabel
-         %28 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %28 None
-         %30 = OpFunctionCall %int %subgroupShuffle_8bfbcd
-         %31 = OpAccessChain %_ptr_StorageBuffer_int %1 %uint_0
-               OpStore %31 %30 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %35
-         %36 = OpLabel
-         %37 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %38 = OpFunctionCall %void %fragment_main_inner %37
+%fragment_main = OpFunction %void None %24
+         %25 = OpLabel
+         %26 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %28 = OpISub %uint %26 %uint_1
+               OpStore %tint_subgroup_last_id %28 None
+         %29 = OpFunctionCall %int %subgroupShuffle_8bfbcd
+         %30 = OpAccessChain %_ptr_StorageBuffer_int %1 %uint_0
+               OpStore %30 %29 None
                OpReturn
                OpFunctionEnd
 ;
@@ -81,29 +68,26 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 39
+; Bound: 33
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %16 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_8bfbcd "subgroupShuffle_8bfbcd"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
         %int = OpTypeInt 32 1
 %prevent_dce_block = OpTypeStruct %int
 %_ptr_StorageBuffer_prevent_dce_block = OpTypePointer StorageBuffer %prevent_dce_block
@@ -111,43 +95,34 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %int
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %int
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
 %_ptr_Function_int = OpTypePointer Function %int
        %void = OpTypeVoid
-         %26 = OpTypeFunction %void %uint
+         %24 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_int = OpTypePointer StorageBuffer %int
      %uint_0 = OpConstant %uint 0
-         %35 = OpTypeFunction %void
-%subgroupShuffle_8bfbcd = OpFunction %int None %12
-         %13 = OpLabel
+%subgroupShuffle_8bfbcd = OpFunction %int None %10
+         %11 = OpLabel
         %res = OpVariable %_ptr_Function_int Function
-         %14 = OpBitcast %uint %int_1
-         %16 = OpLoad %uint %tint_subgroup_size_mask None
-         %17 = OpBitwiseAnd %uint %14 %16
-         %18 = OpGroupNonUniformShuffle %int %uint_3 %int_1 %17
-               OpStore %res %18
-         %22 = OpLoad %int %res None
-               OpReturnValue %22
+         %12 = OpBitcast %uint %int_1
+         %14 = OpLoad %uint %tint_subgroup_last_id None
+         %15 = OpExtInst %uint %16 UMin %12 %14
+         %17 = OpGroupNonUniformShuffle %int %uint_3 %int_1 %15
+               OpStore %res %17
+         %21 = OpLoad %int %res None
+               OpReturnValue %21
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %26
-%tint_subgroup_size = OpFunctionParameter %uint
-         %27 = OpLabel
-         %28 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %28 None
-         %30 = OpFunctionCall %int %subgroupShuffle_8bfbcd
-         %31 = OpAccessChain %_ptr_StorageBuffer_int %1 %uint_0
-               OpStore %31 %30 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %35
-         %36 = OpLabel
-         %37 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %38 = OpFunctionCall %void %compute_main_inner %37
+%compute_main = OpFunction %void None %24
+         %25 = OpLabel
+         %26 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %28 = OpISub %uint %26 %uint_1
+               OpStore %tint_subgroup_last_id %28 None
+         %29 = OpFunctionCall %int %subgroupShuffle_8bfbcd
+         %30 = OpAccessChain %_ptr_StorageBuffer_int %1 %uint_0
+               OpStore %30 %29 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/literal/subgroupShuffle/8c3fd2.wgsl.expected.spvasm b/test/tint/builtins/gen/literal/subgroupShuffle/8c3fd2.wgsl.expected.spvasm
index cd32fa0..e307d02 100644
--- a/test/tint/builtins/gen/literal/subgroupShuffle/8c3fd2.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/literal/subgroupShuffle/8c3fd2.wgsl.expected.spvasm
@@ -4,32 +4,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 43
+; Bound: 37
 ; Schema: 0
                OpCapability Shader
                OpCapability Float16
                OpCapability StorageBuffer16BitAccess
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %18 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_8c3fd2 "subgroupShuffle_8c3fd2"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
        %half = OpTypeFloat 16
      %v2half = OpTypeVector %half 2
 %prevent_dce_block = OpTypeStruct %v2half
@@ -38,47 +34,38 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v2half
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v2half
         %int = OpTypeInt 32 1
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
 %half_0x1p_0 = OpConstant %half 0x1p+0
-         %22 = OpConstantComposite %v2half %half_0x1p_0 %half_0x1p_0
+         %21 = OpConstantComposite %v2half %half_0x1p_0 %half_0x1p_0
 %_ptr_Function_v2half = OpTypePointer Function %v2half
        %void = OpTypeVoid
-         %30 = OpTypeFunction %void %uint
+         %28 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_v2half = OpTypePointer StorageBuffer %v2half
      %uint_0 = OpConstant %uint 0
-         %39 = OpTypeFunction %void
-%subgroupShuffle_8c3fd2 = OpFunction %v2half None %13
-         %14 = OpLabel
+%subgroupShuffle_8c3fd2 = OpFunction %v2half None %11
+         %12 = OpLabel
         %res = OpVariable %_ptr_Function_v2half Function
-         %15 = OpBitcast %uint %int_1
-         %18 = OpLoad %uint %tint_subgroup_size_mask None
-         %19 = OpBitwiseAnd %uint %15 %18
-         %20 = OpGroupNonUniformShuffle %v2half %uint_3 %22 %19
-               OpStore %res %20
-         %26 = OpLoad %v2half %res None
-               OpReturnValue %26
+         %13 = OpBitcast %uint %int_1
+         %16 = OpLoad %uint %tint_subgroup_last_id None
+         %17 = OpExtInst %uint %18 UMin %13 %16
+         %19 = OpGroupNonUniformShuffle %v2half %uint_3 %21 %17
+               OpStore %res %19
+         %25 = OpLoad %v2half %res None
+               OpReturnValue %25
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %30
-%tint_subgroup_size = OpFunctionParameter %uint
-         %31 = OpLabel
-         %32 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %32 None
-         %34 = OpFunctionCall %v2half %subgroupShuffle_8c3fd2
-         %35 = OpAccessChain %_ptr_StorageBuffer_v2half %1 %uint_0
-               OpStore %35 %34 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %39
-         %40 = OpLabel
-         %41 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %42 = OpFunctionCall %void %fragment_main_inner %41
+%fragment_main = OpFunction %void None %28
+         %29 = OpLabel
+         %30 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %32 = OpISub %uint %30 %uint_1
+               OpStore %tint_subgroup_last_id %32 None
+         %33 = OpFunctionCall %v2half %subgroupShuffle_8c3fd2
+         %34 = OpAccessChain %_ptr_StorageBuffer_v2half %1 %uint_0
+               OpStore %34 %33 None
                OpReturn
                OpFunctionEnd
 ;
@@ -87,31 +74,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 43
+; Bound: 37
 ; Schema: 0
                OpCapability Shader
                OpCapability Float16
                OpCapability StorageBuffer16BitAccess
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %18 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_8c3fd2 "subgroupShuffle_8c3fd2"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
        %half = OpTypeFloat 16
      %v2half = OpTypeVector %half 2
 %prevent_dce_block = OpTypeStruct %v2half
@@ -120,46 +104,37 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v2half
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v2half
         %int = OpTypeInt 32 1
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
 %half_0x1p_0 = OpConstant %half 0x1p+0
-         %22 = OpConstantComposite %v2half %half_0x1p_0 %half_0x1p_0
+         %21 = OpConstantComposite %v2half %half_0x1p_0 %half_0x1p_0
 %_ptr_Function_v2half = OpTypePointer Function %v2half
        %void = OpTypeVoid
-         %30 = OpTypeFunction %void %uint
+         %28 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_v2half = OpTypePointer StorageBuffer %v2half
      %uint_0 = OpConstant %uint 0
-         %39 = OpTypeFunction %void
-%subgroupShuffle_8c3fd2 = OpFunction %v2half None %13
-         %14 = OpLabel
+%subgroupShuffle_8c3fd2 = OpFunction %v2half None %11
+         %12 = OpLabel
         %res = OpVariable %_ptr_Function_v2half Function
-         %15 = OpBitcast %uint %int_1
-         %18 = OpLoad %uint %tint_subgroup_size_mask None
-         %19 = OpBitwiseAnd %uint %15 %18
-         %20 = OpGroupNonUniformShuffle %v2half %uint_3 %22 %19
-               OpStore %res %20
-         %26 = OpLoad %v2half %res None
-               OpReturnValue %26
+         %13 = OpBitcast %uint %int_1
+         %16 = OpLoad %uint %tint_subgroup_last_id None
+         %17 = OpExtInst %uint %18 UMin %13 %16
+         %19 = OpGroupNonUniformShuffle %v2half %uint_3 %21 %17
+               OpStore %res %19
+         %25 = OpLoad %v2half %res None
+               OpReturnValue %25
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %30
-%tint_subgroup_size = OpFunctionParameter %uint
-         %31 = OpLabel
-         %32 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %32 None
-         %34 = OpFunctionCall %v2half %subgroupShuffle_8c3fd2
-         %35 = OpAccessChain %_ptr_StorageBuffer_v2half %1 %uint_0
-               OpStore %35 %34 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %39
-         %40 = OpLabel
-         %41 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %42 = OpFunctionCall %void %compute_main_inner %41
+%compute_main = OpFunction %void None %28
+         %29 = OpLabel
+         %30 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %32 = OpISub %uint %30 %uint_1
+               OpStore %tint_subgroup_last_id %32 None
+         %33 = OpFunctionCall %v2half %subgroupShuffle_8c3fd2
+         %34 = OpAccessChain %_ptr_StorageBuffer_v2half %1 %uint_0
+               OpStore %34 %33 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/literal/subgroupShuffle/aa1d5c.wgsl.expected.spvasm b/test/tint/builtins/gen/literal/subgroupShuffle/aa1d5c.wgsl.expected.spvasm
index 7522cb3..1a07be9 100644
--- a/test/tint/builtins/gen/literal/subgroupShuffle/aa1d5c.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/literal/subgroupShuffle/aa1d5c.wgsl.expected.spvasm
@@ -4,32 +4,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 40
+; Bound: 34
 ; Schema: 0
                OpCapability Shader
                OpCapability Float16
                OpCapability StorageBuffer16BitAccess
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %15 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_aa1d5c "subgroupShuffle_aa1d5c"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
        %half = OpTypeFloat 16
      %v2half = OpTypeVector %half 2
 %prevent_dce_block = OpTypeStruct %v2half
@@ -38,44 +34,35 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v2half
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v2half
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
 %half_0x1p_0 = OpConstant %half 0x1p+0
-         %20 = OpConstantComposite %v2half %half_0x1p_0 %half_0x1p_0
+         %19 = OpConstantComposite %v2half %half_0x1p_0 %half_0x1p_0
 %_ptr_Function_v2half = OpTypePointer Function %v2half
        %void = OpTypeVoid
-         %28 = OpTypeFunction %void %uint
+         %26 = OpTypeFunction %void
 %_ptr_StorageBuffer_v2half = OpTypePointer StorageBuffer %v2half
      %uint_0 = OpConstant %uint 0
-         %36 = OpTypeFunction %void
-%subgroupShuffle_aa1d5c = OpFunction %v2half None %13
-         %14 = OpLabel
+%subgroupShuffle_aa1d5c = OpFunction %v2half None %11
+         %12 = OpLabel
         %res = OpVariable %_ptr_Function_v2half Function
-         %15 = OpLoad %uint %tint_subgroup_size_mask None
-         %16 = OpBitwiseAnd %uint %uint_1 %15
-         %18 = OpGroupNonUniformShuffle %v2half %uint_3 %20 %16
-               OpStore %res %18
-         %24 = OpLoad %v2half %res None
-               OpReturnValue %24
+         %13 = OpLoad %uint %tint_subgroup_last_id None
+         %14 = OpExtInst %uint %15 UMin %uint_1 %13
+         %17 = OpGroupNonUniformShuffle %v2half %uint_3 %19 %14
+               OpStore %res %17
+         %23 = OpLoad %v2half %res None
+               OpReturnValue %23
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %28
-%tint_subgroup_size = OpFunctionParameter %uint
-         %29 = OpLabel
-         %30 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %30 None
-         %31 = OpFunctionCall %v2half %subgroupShuffle_aa1d5c
-         %32 = OpAccessChain %_ptr_StorageBuffer_v2half %1 %uint_0
-               OpStore %32 %31 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %36
-         %37 = OpLabel
-         %38 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %39 = OpFunctionCall %void %fragment_main_inner %38
+%fragment_main = OpFunction %void None %26
+         %27 = OpLabel
+         %28 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %29 = OpISub %uint %28 %uint_1
+               OpStore %tint_subgroup_last_id %29 None
+         %30 = OpFunctionCall %v2half %subgroupShuffle_aa1d5c
+         %31 = OpAccessChain %_ptr_StorageBuffer_v2half %1 %uint_0
+               OpStore %31 %30 None
                OpReturn
                OpFunctionEnd
 ;
@@ -84,31 +71,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 40
+; Bound: 34
 ; Schema: 0
                OpCapability Shader
                OpCapability Float16
                OpCapability StorageBuffer16BitAccess
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %15 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_aa1d5c "subgroupShuffle_aa1d5c"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
        %half = OpTypeFloat 16
      %v2half = OpTypeVector %half 2
 %prevent_dce_block = OpTypeStruct %v2half
@@ -117,43 +101,34 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v2half
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v2half
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
 %half_0x1p_0 = OpConstant %half 0x1p+0
-         %20 = OpConstantComposite %v2half %half_0x1p_0 %half_0x1p_0
+         %19 = OpConstantComposite %v2half %half_0x1p_0 %half_0x1p_0
 %_ptr_Function_v2half = OpTypePointer Function %v2half
        %void = OpTypeVoid
-         %28 = OpTypeFunction %void %uint
+         %26 = OpTypeFunction %void
 %_ptr_StorageBuffer_v2half = OpTypePointer StorageBuffer %v2half
      %uint_0 = OpConstant %uint 0
-         %36 = OpTypeFunction %void
-%subgroupShuffle_aa1d5c = OpFunction %v2half None %13
-         %14 = OpLabel
+%subgroupShuffle_aa1d5c = OpFunction %v2half None %11
+         %12 = OpLabel
         %res = OpVariable %_ptr_Function_v2half Function
-         %15 = OpLoad %uint %tint_subgroup_size_mask None
-         %16 = OpBitwiseAnd %uint %uint_1 %15
-         %18 = OpGroupNonUniformShuffle %v2half %uint_3 %20 %16
-               OpStore %res %18
-         %24 = OpLoad %v2half %res None
-               OpReturnValue %24
+         %13 = OpLoad %uint %tint_subgroup_last_id None
+         %14 = OpExtInst %uint %15 UMin %uint_1 %13
+         %17 = OpGroupNonUniformShuffle %v2half %uint_3 %19 %14
+               OpStore %res %17
+         %23 = OpLoad %v2half %res None
+               OpReturnValue %23
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %28
-%tint_subgroup_size = OpFunctionParameter %uint
-         %29 = OpLabel
-         %30 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %30 None
-         %31 = OpFunctionCall %v2half %subgroupShuffle_aa1d5c
-         %32 = OpAccessChain %_ptr_StorageBuffer_v2half %1 %uint_0
-               OpStore %32 %31 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %36
-         %37 = OpLabel
-         %38 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %39 = OpFunctionCall %void %compute_main_inner %38
+%compute_main = OpFunction %void None %26
+         %27 = OpLabel
+         %28 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %29 = OpISub %uint %28 %uint_1
+               OpStore %tint_subgroup_last_id %29 None
+         %30 = OpFunctionCall %v2half %subgroupShuffle_aa1d5c
+         %31 = OpAccessChain %_ptr_StorageBuffer_v2half %1 %uint_0
+               OpStore %31 %30 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/literal/subgroupShuffle/b0f28d.wgsl.expected.spvasm b/test/tint/builtins/gen/literal/subgroupShuffle/b0f28d.wgsl.expected.spvasm
index 493b199..53ae831 100644
--- a/test/tint/builtins/gen/literal/subgroupShuffle/b0f28d.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/literal/subgroupShuffle/b0f28d.wgsl.expected.spvasm
@@ -4,32 +4,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 41
+; Bound: 35
 ; Schema: 0
                OpCapability Shader
                OpCapability Float16
                OpCapability StorageBuffer16BitAccess
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %17 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_b0f28d "subgroupShuffle_b0f28d"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
        %half = OpTypeFloat 16
 %prevent_dce_block = OpTypeStruct %half
 %_ptr_StorageBuffer_prevent_dce_block = OpTypePointer StorageBuffer %prevent_dce_block
@@ -37,46 +33,37 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %half
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %half
         %int = OpTypeInt 32 1
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
 %half_0x1p_0 = OpConstant %half 0x1p+0
 %_ptr_Function_half = OpTypePointer Function %half
        %void = OpTypeVoid
-         %28 = OpTypeFunction %void %uint
+         %26 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_half = OpTypePointer StorageBuffer %half
      %uint_0 = OpConstant %uint 0
-         %37 = OpTypeFunction %void
-%subgroupShuffle_b0f28d = OpFunction %half None %12
-         %13 = OpLabel
+%subgroupShuffle_b0f28d = OpFunction %half None %10
+         %11 = OpLabel
         %res = OpVariable %_ptr_Function_half Function
-         %14 = OpBitcast %uint %int_1
-         %17 = OpLoad %uint %tint_subgroup_size_mask None
-         %18 = OpBitwiseAnd %uint %14 %17
-         %19 = OpGroupNonUniformShuffle %half %uint_3 %half_0x1p_0 %18
-               OpStore %res %19
-         %24 = OpLoad %half %res None
-               OpReturnValue %24
+         %12 = OpBitcast %uint %int_1
+         %15 = OpLoad %uint %tint_subgroup_last_id None
+         %16 = OpExtInst %uint %17 UMin %12 %15
+         %18 = OpGroupNonUniformShuffle %half %uint_3 %half_0x1p_0 %16
+               OpStore %res %18
+         %23 = OpLoad %half %res None
+               OpReturnValue %23
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %28
-%tint_subgroup_size = OpFunctionParameter %uint
-         %29 = OpLabel
-         %30 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %30 None
-         %32 = OpFunctionCall %half %subgroupShuffle_b0f28d
-         %33 = OpAccessChain %_ptr_StorageBuffer_half %1 %uint_0
-               OpStore %33 %32 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %37
-         %38 = OpLabel
-         %39 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %40 = OpFunctionCall %void %fragment_main_inner %39
+%fragment_main = OpFunction %void None %26
+         %27 = OpLabel
+         %28 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %30 = OpISub %uint %28 %uint_1
+               OpStore %tint_subgroup_last_id %30 None
+         %31 = OpFunctionCall %half %subgroupShuffle_b0f28d
+         %32 = OpAccessChain %_ptr_StorageBuffer_half %1 %uint_0
+               OpStore %32 %31 None
                OpReturn
                OpFunctionEnd
 ;
@@ -85,31 +72,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 41
+; Bound: 35
 ; Schema: 0
                OpCapability Shader
                OpCapability Float16
                OpCapability StorageBuffer16BitAccess
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %17 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_b0f28d "subgroupShuffle_b0f28d"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
        %half = OpTypeFloat 16
 %prevent_dce_block = OpTypeStruct %half
 %_ptr_StorageBuffer_prevent_dce_block = OpTypePointer StorageBuffer %prevent_dce_block
@@ -117,45 +101,36 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %half
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %half
         %int = OpTypeInt 32 1
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
 %half_0x1p_0 = OpConstant %half 0x1p+0
 %_ptr_Function_half = OpTypePointer Function %half
        %void = OpTypeVoid
-         %28 = OpTypeFunction %void %uint
+         %26 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_half = OpTypePointer StorageBuffer %half
      %uint_0 = OpConstant %uint 0
-         %37 = OpTypeFunction %void
-%subgroupShuffle_b0f28d = OpFunction %half None %12
-         %13 = OpLabel
+%subgroupShuffle_b0f28d = OpFunction %half None %10
+         %11 = OpLabel
         %res = OpVariable %_ptr_Function_half Function
-         %14 = OpBitcast %uint %int_1
-         %17 = OpLoad %uint %tint_subgroup_size_mask None
-         %18 = OpBitwiseAnd %uint %14 %17
-         %19 = OpGroupNonUniformShuffle %half %uint_3 %half_0x1p_0 %18
-               OpStore %res %19
-         %24 = OpLoad %half %res None
-               OpReturnValue %24
+         %12 = OpBitcast %uint %int_1
+         %15 = OpLoad %uint %tint_subgroup_last_id None
+         %16 = OpExtInst %uint %17 UMin %12 %15
+         %18 = OpGroupNonUniformShuffle %half %uint_3 %half_0x1p_0 %16
+               OpStore %res %18
+         %23 = OpLoad %half %res None
+               OpReturnValue %23
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %28
-%tint_subgroup_size = OpFunctionParameter %uint
-         %29 = OpLabel
-         %30 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %30 None
-         %32 = OpFunctionCall %half %subgroupShuffle_b0f28d
-         %33 = OpAccessChain %_ptr_StorageBuffer_half %1 %uint_0
-               OpStore %33 %32 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %37
-         %38 = OpLabel
-         %39 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %40 = OpFunctionCall %void %compute_main_inner %39
+%compute_main = OpFunction %void None %26
+         %27 = OpLabel
+         %28 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %30 = OpISub %uint %28 %uint_1
+               OpStore %tint_subgroup_last_id %30 None
+         %31 = OpFunctionCall %half %subgroupShuffle_b0f28d
+         %32 = OpAccessChain %_ptr_StorageBuffer_half %1 %uint_0
+               OpStore %32 %31 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/literal/subgroupShuffle/b4bbb7.wgsl.expected.spvasm b/test/tint/builtins/gen/literal/subgroupShuffle/b4bbb7.wgsl.expected.spvasm
index a10016b..39790c1 100644
--- a/test/tint/builtins/gen/literal/subgroupShuffle/b4bbb7.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/literal/subgroupShuffle/b4bbb7.wgsl.expected.spvasm
@@ -4,30 +4,26 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 40
+; Bound: 34
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %15 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_b4bbb7 "subgroupShuffle_b4bbb7"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
         %int = OpTypeInt 32 1
       %v3int = OpTypeVector %int 3
 %prevent_dce_block = OpTypeStruct %v3int
@@ -36,44 +32,35 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v3int
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v3int
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
       %int_1 = OpConstant %int 1
-         %20 = OpConstantComposite %v3int %int_1 %int_1 %int_1
+         %19 = OpConstantComposite %v3int %int_1 %int_1 %int_1
 %_ptr_Function_v3int = OpTypePointer Function %v3int
        %void = OpTypeVoid
-         %28 = OpTypeFunction %void %uint
+         %26 = OpTypeFunction %void
 %_ptr_StorageBuffer_v3int = OpTypePointer StorageBuffer %v3int
      %uint_0 = OpConstant %uint 0
-         %36 = OpTypeFunction %void
-%subgroupShuffle_b4bbb7 = OpFunction %v3int None %13
-         %14 = OpLabel
+%subgroupShuffle_b4bbb7 = OpFunction %v3int None %11
+         %12 = OpLabel
         %res = OpVariable %_ptr_Function_v3int Function
-         %15 = OpLoad %uint %tint_subgroup_size_mask None
-         %16 = OpBitwiseAnd %uint %uint_1 %15
-         %18 = OpGroupNonUniformShuffle %v3int %uint_3 %20 %16
-               OpStore %res %18
-         %24 = OpLoad %v3int %res None
-               OpReturnValue %24
+         %13 = OpLoad %uint %tint_subgroup_last_id None
+         %14 = OpExtInst %uint %15 UMin %uint_1 %13
+         %17 = OpGroupNonUniformShuffle %v3int %uint_3 %19 %14
+               OpStore %res %17
+         %23 = OpLoad %v3int %res None
+               OpReturnValue %23
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %28
-%tint_subgroup_size = OpFunctionParameter %uint
-         %29 = OpLabel
-         %30 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %30 None
-         %31 = OpFunctionCall %v3int %subgroupShuffle_b4bbb7
-         %32 = OpAccessChain %_ptr_StorageBuffer_v3int %1 %uint_0
-               OpStore %32 %31 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %36
-         %37 = OpLabel
-         %38 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %39 = OpFunctionCall %void %fragment_main_inner %38
+%fragment_main = OpFunction %void None %26
+         %27 = OpLabel
+         %28 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %29 = OpISub %uint %28 %uint_1
+               OpStore %tint_subgroup_last_id %29 None
+         %30 = OpFunctionCall %v3int %subgroupShuffle_b4bbb7
+         %31 = OpAccessChain %_ptr_StorageBuffer_v3int %1 %uint_0
+               OpStore %31 %30 None
                OpReturn
                OpFunctionEnd
 ;
@@ -82,29 +69,26 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 40
+; Bound: 34
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %15 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_b4bbb7 "subgroupShuffle_b4bbb7"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
         %int = OpTypeInt 32 1
       %v3int = OpTypeVector %int 3
 %prevent_dce_block = OpTypeStruct %v3int
@@ -113,43 +97,34 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v3int
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v3int
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
       %int_1 = OpConstant %int 1
-         %20 = OpConstantComposite %v3int %int_1 %int_1 %int_1
+         %19 = OpConstantComposite %v3int %int_1 %int_1 %int_1
 %_ptr_Function_v3int = OpTypePointer Function %v3int
        %void = OpTypeVoid
-         %28 = OpTypeFunction %void %uint
+         %26 = OpTypeFunction %void
 %_ptr_StorageBuffer_v3int = OpTypePointer StorageBuffer %v3int
      %uint_0 = OpConstant %uint 0
-         %36 = OpTypeFunction %void
-%subgroupShuffle_b4bbb7 = OpFunction %v3int None %13
-         %14 = OpLabel
+%subgroupShuffle_b4bbb7 = OpFunction %v3int None %11
+         %12 = OpLabel
         %res = OpVariable %_ptr_Function_v3int Function
-         %15 = OpLoad %uint %tint_subgroup_size_mask None
-         %16 = OpBitwiseAnd %uint %uint_1 %15
-         %18 = OpGroupNonUniformShuffle %v3int %uint_3 %20 %16
-               OpStore %res %18
-         %24 = OpLoad %v3int %res None
-               OpReturnValue %24
+         %13 = OpLoad %uint %tint_subgroup_last_id None
+         %14 = OpExtInst %uint %15 UMin %uint_1 %13
+         %17 = OpGroupNonUniformShuffle %v3int %uint_3 %19 %14
+               OpStore %res %17
+         %23 = OpLoad %v3int %res None
+               OpReturnValue %23
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %28
-%tint_subgroup_size = OpFunctionParameter %uint
-         %29 = OpLabel
-         %30 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %30 None
-         %31 = OpFunctionCall %v3int %subgroupShuffle_b4bbb7
-         %32 = OpAccessChain %_ptr_StorageBuffer_v3int %1 %uint_0
-               OpStore %32 %31 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %36
-         %37 = OpLabel
-         %38 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %39 = OpFunctionCall %void %compute_main_inner %38
+%compute_main = OpFunction %void None %26
+         %27 = OpLabel
+         %28 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %29 = OpISub %uint %28 %uint_1
+               OpStore %tint_subgroup_last_id %29 None
+         %30 = OpFunctionCall %v3int %subgroupShuffle_b4bbb7
+         %31 = OpAccessChain %_ptr_StorageBuffer_v3int %1 %uint_0
+               OpStore %31 %30 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/literal/subgroupShuffle/bbb06c.wgsl.expected.spvasm b/test/tint/builtins/gen/literal/subgroupShuffle/bbb06c.wgsl.expected.spvasm
index 307c575..a5eca95 100644
--- a/test/tint/builtins/gen/literal/subgroupShuffle/bbb06c.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/literal/subgroupShuffle/bbb06c.wgsl.expected.spvasm
@@ -4,30 +4,26 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 41
+; Bound: 35
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %17 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_bbb06c "subgroupShuffle_bbb06c"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
         %int = OpTypeInt 32 1
       %v2int = OpTypeVector %int 2
 %prevent_dce_block = OpTypeStruct %v2int
@@ -36,45 +32,36 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v2int
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v2int
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
-         %21 = OpConstantComposite %v2int %int_1 %int_1
+         %20 = OpConstantComposite %v2int %int_1 %int_1
 %_ptr_Function_v2int = OpTypePointer Function %v2int
        %void = OpTypeVoid
-         %28 = OpTypeFunction %void %uint
+         %26 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_v2int = OpTypePointer StorageBuffer %v2int
      %uint_0 = OpConstant %uint 0
-         %37 = OpTypeFunction %void
-%subgroupShuffle_bbb06c = OpFunction %v2int None %13
-         %14 = OpLabel
+%subgroupShuffle_bbb06c = OpFunction %v2int None %11
+         %12 = OpLabel
         %res = OpVariable %_ptr_Function_v2int Function
-         %15 = OpBitcast %uint %int_1
-         %17 = OpLoad %uint %tint_subgroup_size_mask None
-         %18 = OpBitwiseAnd %uint %15 %17
-         %19 = OpGroupNonUniformShuffle %v2int %uint_3 %21 %18
-               OpStore %res %19
-         %24 = OpLoad %v2int %res None
-               OpReturnValue %24
+         %13 = OpBitcast %uint %int_1
+         %15 = OpLoad %uint %tint_subgroup_last_id None
+         %16 = OpExtInst %uint %17 UMin %13 %15
+         %18 = OpGroupNonUniformShuffle %v2int %uint_3 %20 %16
+               OpStore %res %18
+         %23 = OpLoad %v2int %res None
+               OpReturnValue %23
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %28
-%tint_subgroup_size = OpFunctionParameter %uint
-         %29 = OpLabel
-         %30 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %30 None
-         %32 = OpFunctionCall %v2int %subgroupShuffle_bbb06c
-         %33 = OpAccessChain %_ptr_StorageBuffer_v2int %1 %uint_0
-               OpStore %33 %32 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %37
-         %38 = OpLabel
-         %39 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %40 = OpFunctionCall %void %fragment_main_inner %39
+%fragment_main = OpFunction %void None %26
+         %27 = OpLabel
+         %28 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %30 = OpISub %uint %28 %uint_1
+               OpStore %tint_subgroup_last_id %30 None
+         %31 = OpFunctionCall %v2int %subgroupShuffle_bbb06c
+         %32 = OpAccessChain %_ptr_StorageBuffer_v2int %1 %uint_0
+               OpStore %32 %31 None
                OpReturn
                OpFunctionEnd
 ;
@@ -83,29 +70,26 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 41
+; Bound: 35
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %17 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_bbb06c "subgroupShuffle_bbb06c"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
         %int = OpTypeInt 32 1
       %v2int = OpTypeVector %int 2
 %prevent_dce_block = OpTypeStruct %v2int
@@ -114,44 +98,35 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v2int
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v2int
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
-         %21 = OpConstantComposite %v2int %int_1 %int_1
+         %20 = OpConstantComposite %v2int %int_1 %int_1
 %_ptr_Function_v2int = OpTypePointer Function %v2int
        %void = OpTypeVoid
-         %28 = OpTypeFunction %void %uint
+         %26 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_v2int = OpTypePointer StorageBuffer %v2int
      %uint_0 = OpConstant %uint 0
-         %37 = OpTypeFunction %void
-%subgroupShuffle_bbb06c = OpFunction %v2int None %13
-         %14 = OpLabel
+%subgroupShuffle_bbb06c = OpFunction %v2int None %11
+         %12 = OpLabel
         %res = OpVariable %_ptr_Function_v2int Function
-         %15 = OpBitcast %uint %int_1
-         %17 = OpLoad %uint %tint_subgroup_size_mask None
-         %18 = OpBitwiseAnd %uint %15 %17
-         %19 = OpGroupNonUniformShuffle %v2int %uint_3 %21 %18
-               OpStore %res %19
-         %24 = OpLoad %v2int %res None
-               OpReturnValue %24
+         %13 = OpBitcast %uint %int_1
+         %15 = OpLoad %uint %tint_subgroup_last_id None
+         %16 = OpExtInst %uint %17 UMin %13 %15
+         %18 = OpGroupNonUniformShuffle %v2int %uint_3 %20 %16
+               OpStore %res %18
+         %23 = OpLoad %v2int %res None
+               OpReturnValue %23
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %28
-%tint_subgroup_size = OpFunctionParameter %uint
-         %29 = OpLabel
-         %30 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %30 None
-         %32 = OpFunctionCall %v2int %subgroupShuffle_bbb06c
-         %33 = OpAccessChain %_ptr_StorageBuffer_v2int %1 %uint_0
-               OpStore %33 %32 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %37
-         %38 = OpLabel
-         %39 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %40 = OpFunctionCall %void %compute_main_inner %39
+%compute_main = OpFunction %void None %26
+         %27 = OpLabel
+         %28 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %30 = OpISub %uint %28 %uint_1
+               OpStore %tint_subgroup_last_id %30 None
+         %31 = OpFunctionCall %v2int %subgroupShuffle_bbb06c
+         %32 = OpAccessChain %_ptr_StorageBuffer_v2int %1 %uint_0
+               OpStore %32 %31 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/literal/subgroupShuffle/d4a772.wgsl.expected.spvasm b/test/tint/builtins/gen/literal/subgroupShuffle/d4a772.wgsl.expected.spvasm
index a44a14b..7228861 100644
--- a/test/tint/builtins/gen/literal/subgroupShuffle/d4a772.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/literal/subgroupShuffle/d4a772.wgsl.expected.spvasm
@@ -4,30 +4,26 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 38
+; Bound: 32
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %14 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_d4a772 "subgroupShuffle_d4a772"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
         %int = OpTypeInt 32 1
 %prevent_dce_block = OpTypeStruct %int
 %_ptr_StorageBuffer_prevent_dce_block = OpTypePointer StorageBuffer %prevent_dce_block
@@ -35,43 +31,34 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %int
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %int
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
       %int_1 = OpConstant %int 1
 %_ptr_Function_int = OpTypePointer Function %int
        %void = OpTypeVoid
-         %26 = OpTypeFunction %void %uint
+         %24 = OpTypeFunction %void
 %_ptr_StorageBuffer_int = OpTypePointer StorageBuffer %int
      %uint_0 = OpConstant %uint 0
-         %34 = OpTypeFunction %void
-%subgroupShuffle_d4a772 = OpFunction %int None %12
-         %13 = OpLabel
+%subgroupShuffle_d4a772 = OpFunction %int None %10
+         %11 = OpLabel
         %res = OpVariable %_ptr_Function_int Function
-         %14 = OpLoad %uint %tint_subgroup_size_mask None
-         %15 = OpBitwiseAnd %uint %uint_1 %14
-         %17 = OpGroupNonUniformShuffle %int %uint_3 %int_1 %15
-               OpStore %res %17
-         %22 = OpLoad %int %res None
-               OpReturnValue %22
+         %12 = OpLoad %uint %tint_subgroup_last_id None
+         %13 = OpExtInst %uint %14 UMin %uint_1 %12
+         %16 = OpGroupNonUniformShuffle %int %uint_3 %int_1 %13
+               OpStore %res %16
+         %21 = OpLoad %int %res None
+               OpReturnValue %21
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %26
-%tint_subgroup_size = OpFunctionParameter %uint
-         %27 = OpLabel
-         %28 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %28 None
-         %29 = OpFunctionCall %int %subgroupShuffle_d4a772
-         %30 = OpAccessChain %_ptr_StorageBuffer_int %1 %uint_0
-               OpStore %30 %29 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %34
-         %35 = OpLabel
-         %36 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %37 = OpFunctionCall %void %fragment_main_inner %36
+%fragment_main = OpFunction %void None %24
+         %25 = OpLabel
+         %26 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %27 = OpISub %uint %26 %uint_1
+               OpStore %tint_subgroup_last_id %27 None
+         %28 = OpFunctionCall %int %subgroupShuffle_d4a772
+         %29 = OpAccessChain %_ptr_StorageBuffer_int %1 %uint_0
+               OpStore %29 %28 None
                OpReturn
                OpFunctionEnd
 ;
@@ -80,29 +67,26 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 38
+; Bound: 32
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %14 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_d4a772 "subgroupShuffle_d4a772"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
         %int = OpTypeInt 32 1
 %prevent_dce_block = OpTypeStruct %int
 %_ptr_StorageBuffer_prevent_dce_block = OpTypePointer StorageBuffer %prevent_dce_block
@@ -110,42 +94,33 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %int
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %int
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
       %int_1 = OpConstant %int 1
 %_ptr_Function_int = OpTypePointer Function %int
        %void = OpTypeVoid
-         %26 = OpTypeFunction %void %uint
+         %24 = OpTypeFunction %void
 %_ptr_StorageBuffer_int = OpTypePointer StorageBuffer %int
      %uint_0 = OpConstant %uint 0
-         %34 = OpTypeFunction %void
-%subgroupShuffle_d4a772 = OpFunction %int None %12
-         %13 = OpLabel
+%subgroupShuffle_d4a772 = OpFunction %int None %10
+         %11 = OpLabel
         %res = OpVariable %_ptr_Function_int Function
-         %14 = OpLoad %uint %tint_subgroup_size_mask None
-         %15 = OpBitwiseAnd %uint %uint_1 %14
-         %17 = OpGroupNonUniformShuffle %int %uint_3 %int_1 %15
-               OpStore %res %17
-         %22 = OpLoad %int %res None
-               OpReturnValue %22
+         %12 = OpLoad %uint %tint_subgroup_last_id None
+         %13 = OpExtInst %uint %14 UMin %uint_1 %12
+         %16 = OpGroupNonUniformShuffle %int %uint_3 %int_1 %13
+               OpStore %res %16
+         %21 = OpLoad %int %res None
+               OpReturnValue %21
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %26
-%tint_subgroup_size = OpFunctionParameter %uint
-         %27 = OpLabel
-         %28 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %28 None
-         %29 = OpFunctionCall %int %subgroupShuffle_d4a772
-         %30 = OpAccessChain %_ptr_StorageBuffer_int %1 %uint_0
-               OpStore %30 %29 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %34
-         %35 = OpLabel
-         %36 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %37 = OpFunctionCall %void %compute_main_inner %36
+%compute_main = OpFunction %void None %24
+         %25 = OpLabel
+         %26 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %27 = OpISub %uint %26 %uint_1
+               OpStore %tint_subgroup_last_id %27 None
+         %28 = OpFunctionCall %int %subgroupShuffle_d4a772
+         %29 = OpAccessChain %_ptr_StorageBuffer_int %1 %uint_0
+               OpStore %29 %28 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/literal/subgroupShuffle/d9ff67.wgsl.expected.spvasm b/test/tint/builtins/gen/literal/subgroupShuffle/d9ff67.wgsl.expected.spvasm
index 5238261..96ded93 100644
--- a/test/tint/builtins/gen/literal/subgroupShuffle/d9ff67.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/literal/subgroupShuffle/d9ff67.wgsl.expected.spvasm
@@ -4,30 +4,26 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 43
+; Bound: 37
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %18 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_d9ff67 "subgroupShuffle_d9ff67"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
       %float = OpTypeFloat 32
     %v2float = OpTypeVector %float 2
 %prevent_dce_block = OpTypeStruct %v2float
@@ -36,47 +32,38 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v2float
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v2float
         %int = OpTypeInt 32 1
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
     %float_1 = OpConstant %float 1
-         %22 = OpConstantComposite %v2float %float_1 %float_1
+         %21 = OpConstantComposite %v2float %float_1 %float_1
 %_ptr_Function_v2float = OpTypePointer Function %v2float
        %void = OpTypeVoid
-         %30 = OpTypeFunction %void %uint
+         %28 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_v2float = OpTypePointer StorageBuffer %v2float
      %uint_0 = OpConstant %uint 0
-         %39 = OpTypeFunction %void
-%subgroupShuffle_d9ff67 = OpFunction %v2float None %13
-         %14 = OpLabel
+%subgroupShuffle_d9ff67 = OpFunction %v2float None %11
+         %12 = OpLabel
         %res = OpVariable %_ptr_Function_v2float Function
-         %15 = OpBitcast %uint %int_1
-         %18 = OpLoad %uint %tint_subgroup_size_mask None
-         %19 = OpBitwiseAnd %uint %15 %18
-         %20 = OpGroupNonUniformShuffle %v2float %uint_3 %22 %19
-               OpStore %res %20
-         %26 = OpLoad %v2float %res None
-               OpReturnValue %26
+         %13 = OpBitcast %uint %int_1
+         %16 = OpLoad %uint %tint_subgroup_last_id None
+         %17 = OpExtInst %uint %18 UMin %13 %16
+         %19 = OpGroupNonUniformShuffle %v2float %uint_3 %21 %17
+               OpStore %res %19
+         %25 = OpLoad %v2float %res None
+               OpReturnValue %25
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %30
-%tint_subgroup_size = OpFunctionParameter %uint
-         %31 = OpLabel
-         %32 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %32 None
-         %34 = OpFunctionCall %v2float %subgroupShuffle_d9ff67
-         %35 = OpAccessChain %_ptr_StorageBuffer_v2float %1 %uint_0
-               OpStore %35 %34 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %39
-         %40 = OpLabel
-         %41 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %42 = OpFunctionCall %void %fragment_main_inner %41
+%fragment_main = OpFunction %void None %28
+         %29 = OpLabel
+         %30 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %32 = OpISub %uint %30 %uint_1
+               OpStore %tint_subgroup_last_id %32 None
+         %33 = OpFunctionCall %v2float %subgroupShuffle_d9ff67
+         %34 = OpAccessChain %_ptr_StorageBuffer_v2float %1 %uint_0
+               OpStore %34 %33 None
                OpReturn
                OpFunctionEnd
 ;
@@ -85,29 +72,26 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 43
+; Bound: 37
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %18 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_d9ff67 "subgroupShuffle_d9ff67"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
       %float = OpTypeFloat 32
     %v2float = OpTypeVector %float 2
 %prevent_dce_block = OpTypeStruct %v2float
@@ -116,46 +100,37 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v2float
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v2float
         %int = OpTypeInt 32 1
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
     %float_1 = OpConstant %float 1
-         %22 = OpConstantComposite %v2float %float_1 %float_1
+         %21 = OpConstantComposite %v2float %float_1 %float_1
 %_ptr_Function_v2float = OpTypePointer Function %v2float
        %void = OpTypeVoid
-         %30 = OpTypeFunction %void %uint
+         %28 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_v2float = OpTypePointer StorageBuffer %v2float
      %uint_0 = OpConstant %uint 0
-         %39 = OpTypeFunction %void
-%subgroupShuffle_d9ff67 = OpFunction %v2float None %13
-         %14 = OpLabel
+%subgroupShuffle_d9ff67 = OpFunction %v2float None %11
+         %12 = OpLabel
         %res = OpVariable %_ptr_Function_v2float Function
-         %15 = OpBitcast %uint %int_1
-         %18 = OpLoad %uint %tint_subgroup_size_mask None
-         %19 = OpBitwiseAnd %uint %15 %18
-         %20 = OpGroupNonUniformShuffle %v2float %uint_3 %22 %19
-               OpStore %res %20
-         %26 = OpLoad %v2float %res None
-               OpReturnValue %26
+         %13 = OpBitcast %uint %int_1
+         %16 = OpLoad %uint %tint_subgroup_last_id None
+         %17 = OpExtInst %uint %18 UMin %13 %16
+         %19 = OpGroupNonUniformShuffle %v2float %uint_3 %21 %17
+               OpStore %res %19
+         %25 = OpLoad %v2float %res None
+               OpReturnValue %25
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %30
-%tint_subgroup_size = OpFunctionParameter %uint
-         %31 = OpLabel
-         %32 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %32 None
-         %34 = OpFunctionCall %v2float %subgroupShuffle_d9ff67
-         %35 = OpAccessChain %_ptr_StorageBuffer_v2float %1 %uint_0
-               OpStore %35 %34 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %39
-         %40 = OpLabel
-         %41 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %42 = OpFunctionCall %void %compute_main_inner %41
+%compute_main = OpFunction %void None %28
+         %29 = OpLabel
+         %30 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %32 = OpISub %uint %30 %uint_1
+               OpStore %tint_subgroup_last_id %32 None
+         %33 = OpFunctionCall %v2float %subgroupShuffle_d9ff67
+         %34 = OpAccessChain %_ptr_StorageBuffer_v2float %1 %uint_0
+               OpStore %34 %33 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/literal/subgroupShuffle/e13c81.wgsl.expected.spvasm b/test/tint/builtins/gen/literal/subgroupShuffle/e13c81.wgsl.expected.spvasm
index f633012..8579e2e 100644
--- a/test/tint/builtins/gen/literal/subgroupShuffle/e13c81.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/literal/subgroupShuffle/e13c81.wgsl.expected.spvasm
@@ -4,30 +4,26 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 41
+; Bound: 35
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %17 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_e13c81 "subgroupShuffle_e13c81"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
        %uint = OpTypeInt 32 0
      %v4uint = OpTypeVector %uint 4
 %prevent_dce_block = OpTypeStruct %v4uint
@@ -35,46 +31,37 @@
           %1 = OpVariable %_ptr_StorageBuffer_prevent_dce_block StorageBuffer
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %v4uint
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %v4uint
         %int = OpTypeInt 32 1
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
      %uint_1 = OpConstant %uint 1
-         %21 = OpConstantComposite %v4uint %uint_1 %uint_1 %uint_1 %uint_1
+         %20 = OpConstantComposite %v4uint %uint_1 %uint_1 %uint_1 %uint_1
 %_ptr_Function_v4uint = OpTypePointer Function %v4uint
        %void = OpTypeVoid
-         %29 = OpTypeFunction %void %uint
+         %27 = OpTypeFunction %void
 %_ptr_StorageBuffer_v4uint = OpTypePointer StorageBuffer %v4uint
      %uint_0 = OpConstant %uint 0
-         %37 = OpTypeFunction %void
-%subgroupShuffle_e13c81 = OpFunction %v4uint None %12
-         %13 = OpLabel
+%subgroupShuffle_e13c81 = OpFunction %v4uint None %10
+         %11 = OpLabel
         %res = OpVariable %_ptr_Function_v4uint Function
-         %14 = OpBitcast %uint %int_1
-         %17 = OpLoad %uint %tint_subgroup_size_mask None
-         %18 = OpBitwiseAnd %uint %14 %17
-         %19 = OpGroupNonUniformShuffle %v4uint %uint_3 %21 %18
-               OpStore %res %19
-         %25 = OpLoad %v4uint %res None
-               OpReturnValue %25
+         %12 = OpBitcast %uint %int_1
+         %15 = OpLoad %uint %tint_subgroup_last_id None
+         %16 = OpExtInst %uint %17 UMin %12 %15
+         %18 = OpGroupNonUniformShuffle %v4uint %uint_3 %20 %16
+               OpStore %res %18
+         %24 = OpLoad %v4uint %res None
+               OpReturnValue %24
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %29
-%tint_subgroup_size = OpFunctionParameter %uint
-         %30 = OpLabel
-         %31 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %31 None
-         %32 = OpFunctionCall %v4uint %subgroupShuffle_e13c81
-         %33 = OpAccessChain %_ptr_StorageBuffer_v4uint %1 %uint_0
-               OpStore %33 %32 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %37
-         %38 = OpLabel
-         %39 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %40 = OpFunctionCall %void %fragment_main_inner %39
+%fragment_main = OpFunction %void None %27
+         %28 = OpLabel
+         %29 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %30 = OpISub %uint %29 %uint_1
+               OpStore %tint_subgroup_last_id %30 None
+         %31 = OpFunctionCall %v4uint %subgroupShuffle_e13c81
+         %32 = OpAccessChain %_ptr_StorageBuffer_v4uint %1 %uint_0
+               OpStore %32 %31 None
                OpReturn
                OpFunctionEnd
 ;
@@ -83,29 +70,26 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 41
+; Bound: 35
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %17 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_e13c81 "subgroupShuffle_e13c81"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
        %uint = OpTypeInt 32 0
      %v4uint = OpTypeVector %uint 4
 %prevent_dce_block = OpTypeStruct %v4uint
@@ -113,45 +97,36 @@
           %1 = OpVariable %_ptr_StorageBuffer_prevent_dce_block StorageBuffer
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %v4uint
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %v4uint
         %int = OpTypeInt 32 1
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
      %uint_1 = OpConstant %uint 1
-         %21 = OpConstantComposite %v4uint %uint_1 %uint_1 %uint_1 %uint_1
+         %20 = OpConstantComposite %v4uint %uint_1 %uint_1 %uint_1 %uint_1
 %_ptr_Function_v4uint = OpTypePointer Function %v4uint
        %void = OpTypeVoid
-         %29 = OpTypeFunction %void %uint
+         %27 = OpTypeFunction %void
 %_ptr_StorageBuffer_v4uint = OpTypePointer StorageBuffer %v4uint
      %uint_0 = OpConstant %uint 0
-         %37 = OpTypeFunction %void
-%subgroupShuffle_e13c81 = OpFunction %v4uint None %12
-         %13 = OpLabel
+%subgroupShuffle_e13c81 = OpFunction %v4uint None %10
+         %11 = OpLabel
         %res = OpVariable %_ptr_Function_v4uint Function
-         %14 = OpBitcast %uint %int_1
-         %17 = OpLoad %uint %tint_subgroup_size_mask None
-         %18 = OpBitwiseAnd %uint %14 %17
-         %19 = OpGroupNonUniformShuffle %v4uint %uint_3 %21 %18
-               OpStore %res %19
-         %25 = OpLoad %v4uint %res None
-               OpReturnValue %25
+         %12 = OpBitcast %uint %int_1
+         %15 = OpLoad %uint %tint_subgroup_last_id None
+         %16 = OpExtInst %uint %17 UMin %12 %15
+         %18 = OpGroupNonUniformShuffle %v4uint %uint_3 %20 %16
+               OpStore %res %18
+         %24 = OpLoad %v4uint %res None
+               OpReturnValue %24
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %29
-%tint_subgroup_size = OpFunctionParameter %uint
-         %30 = OpLabel
-         %31 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %31 None
-         %32 = OpFunctionCall %v4uint %subgroupShuffle_e13c81
-         %33 = OpAccessChain %_ptr_StorageBuffer_v4uint %1 %uint_0
-               OpStore %33 %32 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %37
-         %38 = OpLabel
-         %39 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %40 = OpFunctionCall %void %compute_main_inner %39
+%compute_main = OpFunction %void None %27
+         %28 = OpLabel
+         %29 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %30 = OpISub %uint %29 %uint_1
+               OpStore %tint_subgroup_last_id %30 None
+         %31 = OpFunctionCall %v4uint %subgroupShuffle_e13c81
+         %32 = OpAccessChain %_ptr_StorageBuffer_v4uint %1 %uint_0
+               OpStore %32 %31 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/literal/subgroupShuffle/e854d5.wgsl.expected.spvasm b/test/tint/builtins/gen/literal/subgroupShuffle/e854d5.wgsl.expected.spvasm
index e907e02..10b071f 100644
--- a/test/tint/builtins/gen/literal/subgroupShuffle/e854d5.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/literal/subgroupShuffle/e854d5.wgsl.expected.spvasm
@@ -4,30 +4,26 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 40
+; Bound: 34
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %15 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_e854d5 "subgroupShuffle_e854d5"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
         %int = OpTypeInt 32 1
       %v4int = OpTypeVector %int 4
 %prevent_dce_block = OpTypeStruct %v4int
@@ -36,44 +32,35 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v4int
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v4int
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
       %int_1 = OpConstant %int 1
-         %20 = OpConstantComposite %v4int %int_1 %int_1 %int_1 %int_1
+         %19 = OpConstantComposite %v4int %int_1 %int_1 %int_1 %int_1
 %_ptr_Function_v4int = OpTypePointer Function %v4int
        %void = OpTypeVoid
-         %28 = OpTypeFunction %void %uint
+         %26 = OpTypeFunction %void
 %_ptr_StorageBuffer_v4int = OpTypePointer StorageBuffer %v4int
      %uint_0 = OpConstant %uint 0
-         %36 = OpTypeFunction %void
-%subgroupShuffle_e854d5 = OpFunction %v4int None %13
-         %14 = OpLabel
+%subgroupShuffle_e854d5 = OpFunction %v4int None %11
+         %12 = OpLabel
         %res = OpVariable %_ptr_Function_v4int Function
-         %15 = OpLoad %uint %tint_subgroup_size_mask None
-         %16 = OpBitwiseAnd %uint %uint_1 %15
-         %18 = OpGroupNonUniformShuffle %v4int %uint_3 %20 %16
-               OpStore %res %18
-         %24 = OpLoad %v4int %res None
-               OpReturnValue %24
+         %13 = OpLoad %uint %tint_subgroup_last_id None
+         %14 = OpExtInst %uint %15 UMin %uint_1 %13
+         %17 = OpGroupNonUniformShuffle %v4int %uint_3 %19 %14
+               OpStore %res %17
+         %23 = OpLoad %v4int %res None
+               OpReturnValue %23
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %28
-%tint_subgroup_size = OpFunctionParameter %uint
-         %29 = OpLabel
-         %30 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %30 None
-         %31 = OpFunctionCall %v4int %subgroupShuffle_e854d5
-         %32 = OpAccessChain %_ptr_StorageBuffer_v4int %1 %uint_0
-               OpStore %32 %31 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %36
-         %37 = OpLabel
-         %38 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %39 = OpFunctionCall %void %fragment_main_inner %38
+%fragment_main = OpFunction %void None %26
+         %27 = OpLabel
+         %28 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %29 = OpISub %uint %28 %uint_1
+               OpStore %tint_subgroup_last_id %29 None
+         %30 = OpFunctionCall %v4int %subgroupShuffle_e854d5
+         %31 = OpAccessChain %_ptr_StorageBuffer_v4int %1 %uint_0
+               OpStore %31 %30 None
                OpReturn
                OpFunctionEnd
 ;
@@ -82,29 +69,26 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 40
+; Bound: 34
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %15 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_e854d5 "subgroupShuffle_e854d5"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
         %int = OpTypeInt 32 1
       %v4int = OpTypeVector %int 4
 %prevent_dce_block = OpTypeStruct %v4int
@@ -113,43 +97,34 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v4int
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v4int
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
       %int_1 = OpConstant %int 1
-         %20 = OpConstantComposite %v4int %int_1 %int_1 %int_1 %int_1
+         %19 = OpConstantComposite %v4int %int_1 %int_1 %int_1 %int_1
 %_ptr_Function_v4int = OpTypePointer Function %v4int
        %void = OpTypeVoid
-         %28 = OpTypeFunction %void %uint
+         %26 = OpTypeFunction %void
 %_ptr_StorageBuffer_v4int = OpTypePointer StorageBuffer %v4int
      %uint_0 = OpConstant %uint 0
-         %36 = OpTypeFunction %void
-%subgroupShuffle_e854d5 = OpFunction %v4int None %13
-         %14 = OpLabel
+%subgroupShuffle_e854d5 = OpFunction %v4int None %11
+         %12 = OpLabel
         %res = OpVariable %_ptr_Function_v4int Function
-         %15 = OpLoad %uint %tint_subgroup_size_mask None
-         %16 = OpBitwiseAnd %uint %uint_1 %15
-         %18 = OpGroupNonUniformShuffle %v4int %uint_3 %20 %16
-               OpStore %res %18
-         %24 = OpLoad %v4int %res None
-               OpReturnValue %24
+         %13 = OpLoad %uint %tint_subgroup_last_id None
+         %14 = OpExtInst %uint %15 UMin %uint_1 %13
+         %17 = OpGroupNonUniformShuffle %v4int %uint_3 %19 %14
+               OpStore %res %17
+         %23 = OpLoad %v4int %res None
+               OpReturnValue %23
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %28
-%tint_subgroup_size = OpFunctionParameter %uint
-         %29 = OpLabel
-         %30 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %30 None
-         %31 = OpFunctionCall %v4int %subgroupShuffle_e854d5
-         %32 = OpAccessChain %_ptr_StorageBuffer_v4int %1 %uint_0
-               OpStore %32 %31 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %36
-         %37 = OpLabel
-         %38 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %39 = OpFunctionCall %void %compute_main_inner %38
+%compute_main = OpFunction %void None %26
+         %27 = OpLabel
+         %28 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %29 = OpISub %uint %28 %uint_1
+               OpStore %tint_subgroup_last_id %29 None
+         %30 = OpFunctionCall %v4int %subgroupShuffle_e854d5
+         %31 = OpAccessChain %_ptr_StorageBuffer_v4int %1 %uint_0
+               OpStore %31 %30 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/literal/subgroupShuffle/f194f5.wgsl.expected.spvasm b/test/tint/builtins/gen/literal/subgroupShuffle/f194f5.wgsl.expected.spvasm
index 41c9062..96422cc 100644
--- a/test/tint/builtins/gen/literal/subgroupShuffle/f194f5.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/literal/subgroupShuffle/f194f5.wgsl.expected.spvasm
@@ -4,72 +4,59 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 36
+; Bound: 30
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %13 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_f194f5 "subgroupShuffle_f194f5"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
        %uint = OpTypeInt 32 0
 %prevent_dce_block = OpTypeStruct %uint
 %_ptr_StorageBuffer_prevent_dce_block = OpTypePointer StorageBuffer %prevent_dce_block
           %1 = OpVariable %_ptr_StorageBuffer_prevent_dce_block StorageBuffer
 %_ptr_Private_uint = OpTypePointer Private %uint
           %7 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %7
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %11 = OpTypeFunction %uint
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %7
+          %9 = OpTypeFunction %uint
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
 %_ptr_Function_uint = OpTypePointer Function %uint
        %void = OpTypeVoid
-         %24 = OpTypeFunction %void %uint
+         %22 = OpTypeFunction %void
 %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
      %uint_0 = OpConstant %uint 0
-         %32 = OpTypeFunction %void
-%subgroupShuffle_f194f5 = OpFunction %uint None %11
-         %12 = OpLabel
+%subgroupShuffle_f194f5 = OpFunction %uint None %9
+         %10 = OpLabel
         %res = OpVariable %_ptr_Function_uint Function
-         %13 = OpLoad %uint %tint_subgroup_size_mask None
-         %14 = OpBitwiseAnd %uint %uint_1 %13
-         %16 = OpGroupNonUniformShuffle %uint %uint_3 %uint_1 %14
-               OpStore %res %16
-         %20 = OpLoad %uint %res None
-               OpReturnValue %20
+         %11 = OpLoad %uint %tint_subgroup_last_id None
+         %12 = OpExtInst %uint %13 UMin %uint_1 %11
+         %15 = OpGroupNonUniformShuffle %uint %uint_3 %uint_1 %12
+               OpStore %res %15
+         %19 = OpLoad %uint %res None
+               OpReturnValue %19
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %24
-%tint_subgroup_size = OpFunctionParameter %uint
-         %25 = OpLabel
-         %26 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %26 None
-         %27 = OpFunctionCall %uint %subgroupShuffle_f194f5
-         %28 = OpAccessChain %_ptr_StorageBuffer_uint %1 %uint_0
-               OpStore %28 %27 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %32
-         %33 = OpLabel
-         %34 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %35 = OpFunctionCall %void %fragment_main_inner %34
+%fragment_main = OpFunction %void None %22
+         %23 = OpLabel
+         %24 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %25 = OpISub %uint %24 %uint_1
+               OpStore %tint_subgroup_last_id %25 None
+         %26 = OpFunctionCall %uint %subgroupShuffle_f194f5
+         %27 = OpAccessChain %_ptr_StorageBuffer_uint %1 %uint_0
+               OpStore %27 %26 None
                OpReturn
                OpFunctionEnd
 ;
@@ -78,70 +65,58 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 36
+; Bound: 30
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %13 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_f194f5 "subgroupShuffle_f194f5"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
        %uint = OpTypeInt 32 0
 %prevent_dce_block = OpTypeStruct %uint
 %_ptr_StorageBuffer_prevent_dce_block = OpTypePointer StorageBuffer %prevent_dce_block
           %1 = OpVariable %_ptr_StorageBuffer_prevent_dce_block StorageBuffer
 %_ptr_Private_uint = OpTypePointer Private %uint
           %7 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %7
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %11 = OpTypeFunction %uint
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %7
+          %9 = OpTypeFunction %uint
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
 %_ptr_Function_uint = OpTypePointer Function %uint
        %void = OpTypeVoid
-         %24 = OpTypeFunction %void %uint
+         %22 = OpTypeFunction %void
 %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
      %uint_0 = OpConstant %uint 0
-         %32 = OpTypeFunction %void
-%subgroupShuffle_f194f5 = OpFunction %uint None %11
-         %12 = OpLabel
+%subgroupShuffle_f194f5 = OpFunction %uint None %9
+         %10 = OpLabel
         %res = OpVariable %_ptr_Function_uint Function
-         %13 = OpLoad %uint %tint_subgroup_size_mask None
-         %14 = OpBitwiseAnd %uint %uint_1 %13
-         %16 = OpGroupNonUniformShuffle %uint %uint_3 %uint_1 %14
-               OpStore %res %16
-         %20 = OpLoad %uint %res None
-               OpReturnValue %20
+         %11 = OpLoad %uint %tint_subgroup_last_id None
+         %12 = OpExtInst %uint %13 UMin %uint_1 %11
+         %15 = OpGroupNonUniformShuffle %uint %uint_3 %uint_1 %12
+               OpStore %res %15
+         %19 = OpLoad %uint %res None
+               OpReturnValue %19
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %24
-%tint_subgroup_size = OpFunctionParameter %uint
-         %25 = OpLabel
-         %26 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %26 None
-         %27 = OpFunctionCall %uint %subgroupShuffle_f194f5
-         %28 = OpAccessChain %_ptr_StorageBuffer_uint %1 %uint_0
-               OpStore %28 %27 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %32
-         %33 = OpLabel
-         %34 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %35 = OpFunctionCall %void %compute_main_inner %34
+%compute_main = OpFunction %void None %22
+         %23 = OpLabel
+         %24 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %25 = OpISub %uint %24 %uint_1
+               OpStore %tint_subgroup_last_id %25 None
+         %26 = OpFunctionCall %uint %subgroupShuffle_f194f5
+         %27 = OpAccessChain %_ptr_StorageBuffer_uint %1 %uint_0
+               OpStore %27 %26 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/literal/subgroupShuffle/fb4ab9.wgsl.expected.spvasm b/test/tint/builtins/gen/literal/subgroupShuffle/fb4ab9.wgsl.expected.spvasm
index 741993a..cec4f54 100644
--- a/test/tint/builtins/gen/literal/subgroupShuffle/fb4ab9.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/literal/subgroupShuffle/fb4ab9.wgsl.expected.spvasm
@@ -4,32 +4,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 40
+; Bound: 34
 ; Schema: 0
                OpCapability Shader
                OpCapability Float16
                OpCapability StorageBuffer16BitAccess
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %15 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_fb4ab9 "subgroupShuffle_fb4ab9"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
        %half = OpTypeFloat 16
      %v3half = OpTypeVector %half 3
 %prevent_dce_block = OpTypeStruct %v3half
@@ -38,44 +34,35 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v3half
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v3half
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
 %half_0x1p_0 = OpConstant %half 0x1p+0
-         %20 = OpConstantComposite %v3half %half_0x1p_0 %half_0x1p_0 %half_0x1p_0
+         %19 = OpConstantComposite %v3half %half_0x1p_0 %half_0x1p_0 %half_0x1p_0
 %_ptr_Function_v3half = OpTypePointer Function %v3half
        %void = OpTypeVoid
-         %28 = OpTypeFunction %void %uint
+         %26 = OpTypeFunction %void
 %_ptr_StorageBuffer_v3half = OpTypePointer StorageBuffer %v3half
      %uint_0 = OpConstant %uint 0
-         %36 = OpTypeFunction %void
-%subgroupShuffle_fb4ab9 = OpFunction %v3half None %13
-         %14 = OpLabel
+%subgroupShuffle_fb4ab9 = OpFunction %v3half None %11
+         %12 = OpLabel
         %res = OpVariable %_ptr_Function_v3half Function
-         %15 = OpLoad %uint %tint_subgroup_size_mask None
-         %16 = OpBitwiseAnd %uint %uint_1 %15
-         %18 = OpGroupNonUniformShuffle %v3half %uint_3 %20 %16
-               OpStore %res %18
-         %24 = OpLoad %v3half %res None
-               OpReturnValue %24
+         %13 = OpLoad %uint %tint_subgroup_last_id None
+         %14 = OpExtInst %uint %15 UMin %uint_1 %13
+         %17 = OpGroupNonUniformShuffle %v3half %uint_3 %19 %14
+               OpStore %res %17
+         %23 = OpLoad %v3half %res None
+               OpReturnValue %23
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %28
-%tint_subgroup_size = OpFunctionParameter %uint
-         %29 = OpLabel
-         %30 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %30 None
-         %31 = OpFunctionCall %v3half %subgroupShuffle_fb4ab9
-         %32 = OpAccessChain %_ptr_StorageBuffer_v3half %1 %uint_0
-               OpStore %32 %31 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %36
-         %37 = OpLabel
-         %38 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %39 = OpFunctionCall %void %fragment_main_inner %38
+%fragment_main = OpFunction %void None %26
+         %27 = OpLabel
+         %28 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %29 = OpISub %uint %28 %uint_1
+               OpStore %tint_subgroup_last_id %29 None
+         %30 = OpFunctionCall %v3half %subgroupShuffle_fb4ab9
+         %31 = OpAccessChain %_ptr_StorageBuffer_v3half %1 %uint_0
+               OpStore %31 %30 None
                OpReturn
                OpFunctionEnd
 ;
@@ -84,31 +71,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 40
+; Bound: 34
 ; Schema: 0
                OpCapability Shader
                OpCapability Float16
                OpCapability StorageBuffer16BitAccess
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %15 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_fb4ab9 "subgroupShuffle_fb4ab9"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
        %half = OpTypeFloat 16
      %v3half = OpTypeVector %half 3
 %prevent_dce_block = OpTypeStruct %v3half
@@ -117,43 +101,34 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v3half
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v3half
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
 %half_0x1p_0 = OpConstant %half 0x1p+0
-         %20 = OpConstantComposite %v3half %half_0x1p_0 %half_0x1p_0 %half_0x1p_0
+         %19 = OpConstantComposite %v3half %half_0x1p_0 %half_0x1p_0 %half_0x1p_0
 %_ptr_Function_v3half = OpTypePointer Function %v3half
        %void = OpTypeVoid
-         %28 = OpTypeFunction %void %uint
+         %26 = OpTypeFunction %void
 %_ptr_StorageBuffer_v3half = OpTypePointer StorageBuffer %v3half
      %uint_0 = OpConstant %uint 0
-         %36 = OpTypeFunction %void
-%subgroupShuffle_fb4ab9 = OpFunction %v3half None %13
-         %14 = OpLabel
+%subgroupShuffle_fb4ab9 = OpFunction %v3half None %11
+         %12 = OpLabel
         %res = OpVariable %_ptr_Function_v3half Function
-         %15 = OpLoad %uint %tint_subgroup_size_mask None
-         %16 = OpBitwiseAnd %uint %uint_1 %15
-         %18 = OpGroupNonUniformShuffle %v3half %uint_3 %20 %16
-               OpStore %res %18
-         %24 = OpLoad %v3half %res None
-               OpReturnValue %24
+         %13 = OpLoad %uint %tint_subgroup_last_id None
+         %14 = OpExtInst %uint %15 UMin %uint_1 %13
+         %17 = OpGroupNonUniformShuffle %v3half %uint_3 %19 %14
+               OpStore %res %17
+         %23 = OpLoad %v3half %res None
+               OpReturnValue %23
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %28
-%tint_subgroup_size = OpFunctionParameter %uint
-         %29 = OpLabel
-         %30 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %30 None
-         %31 = OpFunctionCall %v3half %subgroupShuffle_fb4ab9
-         %32 = OpAccessChain %_ptr_StorageBuffer_v3half %1 %uint_0
-               OpStore %32 %31 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %36
-         %37 = OpLabel
-         %38 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %39 = OpFunctionCall %void %compute_main_inner %38
+%compute_main = OpFunction %void None %26
+         %27 = OpLabel
+         %28 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %29 = OpISub %uint %28 %uint_1
+               OpStore %tint_subgroup_last_id %29 None
+         %30 = OpFunctionCall %v3half %subgroupShuffle_fb4ab9
+         %31 = OpAccessChain %_ptr_StorageBuffer_v3half %1 %uint_0
+               OpStore %31 %30 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/literal/textureSampleCompareLevel/4cf3a2.wgsl.expected.glsl b/test/tint/builtins/gen/literal/textureSampleCompareLevel/4cf3a2.wgsl.expected.glsl
index 4c147e1..a52da78 100644
--- a/test/tint/builtins/gen/literal/textureSampleCompareLevel/4cf3a2.wgsl.expected.glsl
+++ b/test/tint/builtins/gen/literal/textureSampleCompareLevel/4cf3a2.wgsl.expected.glsl
@@ -1,4 +1,3 @@
-SKIP: INVALID   no textureSampleCompareLevel in compat
 //
 // fragment_main
 //
diff --git a/test/tint/builtins/gen/literal/textureSampleCompareLevel/7f2b9a.wgsl.expected.glsl b/test/tint/builtins/gen/literal/textureSampleCompareLevel/7f2b9a.wgsl.expected.glsl
index 68440c1..393569d 100644
--- a/test/tint/builtins/gen/literal/textureSampleCompareLevel/7f2b9a.wgsl.expected.glsl
+++ b/test/tint/builtins/gen/literal/textureSampleCompareLevel/7f2b9a.wgsl.expected.glsl
@@ -1,4 +1,3 @@
-SKIP: INVALID   no textureSampleCompareLevel in compat
 //
 // fragment_main
 //
diff --git a/test/tint/builtins/gen/literal/textureSampleCompareLevel/958c87.wgsl.expected.glsl b/test/tint/builtins/gen/literal/textureSampleCompareLevel/958c87.wgsl.expected.glsl
index 2e74dcd..26dec42 100644
--- a/test/tint/builtins/gen/literal/textureSampleCompareLevel/958c87.wgsl.expected.glsl
+++ b/test/tint/builtins/gen/literal/textureSampleCompareLevel/958c87.wgsl.expected.glsl
@@ -1,4 +1,3 @@
-SKIP: INVALID   no textureSampleCompareLevel in compat
 //
 // fragment_main
 //
diff --git a/test/tint/builtins/gen/var/subgroupShuffle/030422.wgsl.expected.spvasm b/test/tint/builtins/gen/var/subgroupShuffle/030422.wgsl.expected.spvasm
index 324fc9d..b71903b 100644
--- a/test/tint/builtins/gen/var/subgroupShuffle/030422.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/var/subgroupShuffle/030422.wgsl.expected.spvasm
@@ -4,32 +4,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 46
+; Bound: 40
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %24 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_030422 "subgroupShuffle_030422"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
       %float = OpTypeFloat 32
 %prevent_dce_block = OpTypeStruct %float
 %_ptr_StorageBuffer_prevent_dce_block = OpTypePointer StorageBuffer %prevent_dce_block
@@ -37,10 +33,8 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %float
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %float
 %_ptr_Function_float = OpTypePointer Function %float
     %float_1 = OpConstant %float 1
         %int = OpTypeInt 32 1
@@ -48,42 +42,35 @@
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %33 = OpTypeFunction %void %uint
+         %31 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
      %uint_0 = OpConstant %uint 0
-         %42 = OpTypeFunction %void
-%subgroupShuffle_030422 = OpFunction %float None %12
-         %13 = OpLabel
+%subgroupShuffle_030422 = OpFunction %float None %10
+         %11 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_float Function
       %arg_1 = OpVariable %_ptr_Function_int Function
         %res = OpVariable %_ptr_Function_float Function
                OpStore %arg_0 %float_1
                OpStore %arg_1 %int_1
-         %21 = OpLoad %float %arg_0 None
-         %22 = OpLoad %int %arg_1 None
-         %23 = OpBitcast %uint %22
-         %24 = OpLoad %uint %tint_subgroup_size_mask None
-         %25 = OpBitwiseAnd %uint %23 %24
-         %26 = OpGroupNonUniformShuffle %float %uint_3 %21 %25
-               OpStore %res %26
-         %29 = OpLoad %float %res None
-               OpReturnValue %29
+         %19 = OpLoad %float %arg_0 None
+         %20 = OpLoad %int %arg_1 None
+         %21 = OpBitcast %uint %20
+         %22 = OpLoad %uint %tint_subgroup_last_id None
+         %23 = OpExtInst %uint %24 UMin %21 %22
+         %25 = OpGroupNonUniformShuffle %float %uint_3 %19 %23
+               OpStore %res %25
+         %28 = OpLoad %float %res None
+               OpReturnValue %28
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %33
-%tint_subgroup_size = OpFunctionParameter %uint
-         %34 = OpLabel
-         %35 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %35 None
-         %37 = OpFunctionCall %float %subgroupShuffle_030422
-         %38 = OpAccessChain %_ptr_StorageBuffer_float %1 %uint_0
-               OpStore %38 %37 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %42
-         %43 = OpLabel
-         %44 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %45 = OpFunctionCall %void %fragment_main_inner %44
+%fragment_main = OpFunction %void None %31
+         %32 = OpLabel
+         %33 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %35 = OpISub %uint %33 %uint_1
+               OpStore %tint_subgroup_last_id %35 None
+         %36 = OpFunctionCall %float %subgroupShuffle_030422
+         %37 = OpAccessChain %_ptr_StorageBuffer_float %1 %uint_0
+               OpStore %37 %36 None
                OpReturn
                OpFunctionEnd
 ;
@@ -92,31 +79,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 46
+; Bound: 40
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %24 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_030422 "subgroupShuffle_030422"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
       %float = OpTypeFloat 32
 %prevent_dce_block = OpTypeStruct %float
 %_ptr_StorageBuffer_prevent_dce_block = OpTypePointer StorageBuffer %prevent_dce_block
@@ -124,10 +108,8 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %float
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %float
 %_ptr_Function_float = OpTypePointer Function %float
     %float_1 = OpConstant %float 1
         %int = OpTypeInt 32 1
@@ -135,41 +117,34 @@
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %33 = OpTypeFunction %void %uint
+         %31 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
      %uint_0 = OpConstant %uint 0
-         %42 = OpTypeFunction %void
-%subgroupShuffle_030422 = OpFunction %float None %12
-         %13 = OpLabel
+%subgroupShuffle_030422 = OpFunction %float None %10
+         %11 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_float Function
       %arg_1 = OpVariable %_ptr_Function_int Function
         %res = OpVariable %_ptr_Function_float Function
                OpStore %arg_0 %float_1
                OpStore %arg_1 %int_1
-         %21 = OpLoad %float %arg_0 None
-         %22 = OpLoad %int %arg_1 None
-         %23 = OpBitcast %uint %22
-         %24 = OpLoad %uint %tint_subgroup_size_mask None
-         %25 = OpBitwiseAnd %uint %23 %24
-         %26 = OpGroupNonUniformShuffle %float %uint_3 %21 %25
-               OpStore %res %26
-         %29 = OpLoad %float %res None
-               OpReturnValue %29
+         %19 = OpLoad %float %arg_0 None
+         %20 = OpLoad %int %arg_1 None
+         %21 = OpBitcast %uint %20
+         %22 = OpLoad %uint %tint_subgroup_last_id None
+         %23 = OpExtInst %uint %24 UMin %21 %22
+         %25 = OpGroupNonUniformShuffle %float %uint_3 %19 %23
+               OpStore %res %25
+         %28 = OpLoad %float %res None
+               OpReturnValue %28
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %33
-%tint_subgroup_size = OpFunctionParameter %uint
-         %34 = OpLabel
-         %35 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %35 None
-         %37 = OpFunctionCall %float %subgroupShuffle_030422
-         %38 = OpAccessChain %_ptr_StorageBuffer_float %1 %uint_0
-               OpStore %38 %37 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %42
-         %43 = OpLabel
-         %44 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %45 = OpFunctionCall %void %compute_main_inner %44
+%compute_main = OpFunction %void None %31
+         %32 = OpLabel
+         %33 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %35 = OpISub %uint %33 %uint_1
+               OpStore %tint_subgroup_last_id %35 None
+         %36 = OpFunctionCall %float %subgroupShuffle_030422
+         %37 = OpAccessChain %_ptr_StorageBuffer_float %1 %uint_0
+               OpStore %37 %36 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/var/subgroupShuffle/1f664c.wgsl.expected.spvasm b/test/tint/builtins/gen/var/subgroupShuffle/1f664c.wgsl.expected.spvasm
index 8ed201d..d8e6bc0 100644
--- a/test/tint/builtins/gen/var/subgroupShuffle/1f664c.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/var/subgroupShuffle/1f664c.wgsl.expected.spvasm
@@ -4,32 +4,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 45
+; Bound: 39
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %24 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_1f664c "subgroupShuffle_1f664c"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
       %float = OpTypeFloat 32
     %v3float = OpTypeVector %float 3
 %prevent_dce_block = OpTypeStruct %v3float
@@ -38,51 +34,42 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v3float
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v3float
 %_ptr_Function_v3float = OpTypePointer Function %v3float
     %float_1 = OpConstant %float 1
-         %17 = OpConstantComposite %v3float %float_1 %float_1 %float_1
+         %15 = OpConstantComposite %v3float %float_1 %float_1 %float_1
 %_ptr_Function_uint = OpTypePointer Function %uint
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %33 = OpTypeFunction %void %uint
+         %31 = OpTypeFunction %void
 %_ptr_StorageBuffer_v3float = OpTypePointer StorageBuffer %v3float
      %uint_0 = OpConstant %uint 0
-         %41 = OpTypeFunction %void
-%subgroupShuffle_1f664c = OpFunction %v3float None %13
-         %14 = OpLabel
+%subgroupShuffle_1f664c = OpFunction %v3float None %11
+         %12 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v3float Function
       %arg_1 = OpVariable %_ptr_Function_uint Function
         %res = OpVariable %_ptr_Function_v3float Function
-               OpStore %arg_0 %17
+               OpStore %arg_0 %15
                OpStore %arg_1 %uint_1
-         %22 = OpLoad %v3float %arg_0 None
-         %23 = OpLoad %uint %arg_1 None
-         %24 = OpLoad %uint %tint_subgroup_size_mask None
-         %25 = OpBitwiseAnd %uint %23 %24
-         %26 = OpGroupNonUniformShuffle %v3float %uint_3 %22 %25
-               OpStore %res %26
-         %29 = OpLoad %v3float %res None
-               OpReturnValue %29
+         %20 = OpLoad %v3float %arg_0 None
+         %21 = OpLoad %uint %arg_1 None
+         %22 = OpLoad %uint %tint_subgroup_last_id None
+         %23 = OpExtInst %uint %24 UMin %21 %22
+         %25 = OpGroupNonUniformShuffle %v3float %uint_3 %20 %23
+               OpStore %res %25
+         %28 = OpLoad %v3float %res None
+               OpReturnValue %28
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %33
-%tint_subgroup_size = OpFunctionParameter %uint
-         %34 = OpLabel
-         %35 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %35 None
-         %36 = OpFunctionCall %v3float %subgroupShuffle_1f664c
-         %37 = OpAccessChain %_ptr_StorageBuffer_v3float %1 %uint_0
-               OpStore %37 %36 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %41
-         %42 = OpLabel
-         %43 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %44 = OpFunctionCall %void %fragment_main_inner %43
+%fragment_main = OpFunction %void None %31
+         %32 = OpLabel
+         %33 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %34 = OpISub %uint %33 %uint_1
+               OpStore %tint_subgroup_last_id %34 None
+         %35 = OpFunctionCall %v3float %subgroupShuffle_1f664c
+         %36 = OpAccessChain %_ptr_StorageBuffer_v3float %1 %uint_0
+               OpStore %36 %35 None
                OpReturn
                OpFunctionEnd
 ;
@@ -91,31 +78,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 45
+; Bound: 39
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %24 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_1f664c "subgroupShuffle_1f664c"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
       %float = OpTypeFloat 32
     %v3float = OpTypeVector %float 3
 %prevent_dce_block = OpTypeStruct %v3float
@@ -124,50 +108,41 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v3float
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v3float
 %_ptr_Function_v3float = OpTypePointer Function %v3float
     %float_1 = OpConstant %float 1
-         %17 = OpConstantComposite %v3float %float_1 %float_1 %float_1
+         %15 = OpConstantComposite %v3float %float_1 %float_1 %float_1
 %_ptr_Function_uint = OpTypePointer Function %uint
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %33 = OpTypeFunction %void %uint
+         %31 = OpTypeFunction %void
 %_ptr_StorageBuffer_v3float = OpTypePointer StorageBuffer %v3float
      %uint_0 = OpConstant %uint 0
-         %41 = OpTypeFunction %void
-%subgroupShuffle_1f664c = OpFunction %v3float None %13
-         %14 = OpLabel
+%subgroupShuffle_1f664c = OpFunction %v3float None %11
+         %12 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v3float Function
       %arg_1 = OpVariable %_ptr_Function_uint Function
         %res = OpVariable %_ptr_Function_v3float Function
-               OpStore %arg_0 %17
+               OpStore %arg_0 %15
                OpStore %arg_1 %uint_1
-         %22 = OpLoad %v3float %arg_0 None
-         %23 = OpLoad %uint %arg_1 None
-         %24 = OpLoad %uint %tint_subgroup_size_mask None
-         %25 = OpBitwiseAnd %uint %23 %24
-         %26 = OpGroupNonUniformShuffle %v3float %uint_3 %22 %25
-               OpStore %res %26
-         %29 = OpLoad %v3float %res None
-               OpReturnValue %29
+         %20 = OpLoad %v3float %arg_0 None
+         %21 = OpLoad %uint %arg_1 None
+         %22 = OpLoad %uint %tint_subgroup_last_id None
+         %23 = OpExtInst %uint %24 UMin %21 %22
+         %25 = OpGroupNonUniformShuffle %v3float %uint_3 %20 %23
+               OpStore %res %25
+         %28 = OpLoad %v3float %res None
+               OpReturnValue %28
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %33
-%tint_subgroup_size = OpFunctionParameter %uint
-         %34 = OpLabel
-         %35 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %35 None
-         %36 = OpFunctionCall %v3float %subgroupShuffle_1f664c
-         %37 = OpAccessChain %_ptr_StorageBuffer_v3float %1 %uint_0
-               OpStore %37 %36 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %41
-         %42 = OpLabel
-         %43 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %44 = OpFunctionCall %void %compute_main_inner %43
+%compute_main = OpFunction %void None %31
+         %32 = OpLabel
+         %33 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %34 = OpISub %uint %33 %uint_1
+               OpStore %tint_subgroup_last_id %34 None
+         %35 = OpFunctionCall %v3float %subgroupShuffle_1f664c
+         %36 = OpAccessChain %_ptr_StorageBuffer_v3float %1 %uint_0
+               OpStore %36 %35 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/var/subgroupShuffle/21f083.wgsl.expected.spvasm b/test/tint/builtins/gen/var/subgroupShuffle/21f083.wgsl.expected.spvasm
index bbe691c..c16d2a3 100644
--- a/test/tint/builtins/gen/var/subgroupShuffle/21f083.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/var/subgroupShuffle/21f083.wgsl.expected.spvasm
@@ -4,32 +4,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 46
+; Bound: 40
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %25 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_21f083 "subgroupShuffle_21f083"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
        %uint = OpTypeInt 32 0
      %v2uint = OpTypeVector %uint 2
 %prevent_dce_block = OpTypeStruct %v2uint
@@ -37,53 +33,44 @@
           %1 = OpVariable %_ptr_StorageBuffer_prevent_dce_block StorageBuffer
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %v2uint
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %v2uint
 %_ptr_Function_v2uint = OpTypePointer Function %v2uint
      %uint_1 = OpConstant %uint 1
-         %16 = OpConstantComposite %v2uint %uint_1 %uint_1
+         %14 = OpConstantComposite %v2uint %uint_1 %uint_1
         %int = OpTypeInt 32 1
 %_ptr_Function_int = OpTypePointer Function %int
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %34 = OpTypeFunction %void %uint
+         %32 = OpTypeFunction %void
 %_ptr_StorageBuffer_v2uint = OpTypePointer StorageBuffer %v2uint
      %uint_0 = OpConstant %uint 0
-         %42 = OpTypeFunction %void
-%subgroupShuffle_21f083 = OpFunction %v2uint None %12
-         %13 = OpLabel
+%subgroupShuffle_21f083 = OpFunction %v2uint None %10
+         %11 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v2uint Function
       %arg_1 = OpVariable %_ptr_Function_int Function
         %res = OpVariable %_ptr_Function_v2uint Function
-               OpStore %arg_0 %16
+               OpStore %arg_0 %14
                OpStore %arg_1 %int_1
-         %22 = OpLoad %v2uint %arg_0 None
-         %23 = OpLoad %int %arg_1 None
-         %24 = OpBitcast %uint %23
-         %25 = OpLoad %uint %tint_subgroup_size_mask None
-         %26 = OpBitwiseAnd %uint %24 %25
-         %27 = OpGroupNonUniformShuffle %v2uint %uint_3 %22 %26
-               OpStore %res %27
-         %30 = OpLoad %v2uint %res None
-               OpReturnValue %30
+         %20 = OpLoad %v2uint %arg_0 None
+         %21 = OpLoad %int %arg_1 None
+         %22 = OpBitcast %uint %21
+         %23 = OpLoad %uint %tint_subgroup_last_id None
+         %24 = OpExtInst %uint %25 UMin %22 %23
+         %26 = OpGroupNonUniformShuffle %v2uint %uint_3 %20 %24
+               OpStore %res %26
+         %29 = OpLoad %v2uint %res None
+               OpReturnValue %29
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %34
-%tint_subgroup_size = OpFunctionParameter %uint
-         %35 = OpLabel
-         %36 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %36 None
-         %37 = OpFunctionCall %v2uint %subgroupShuffle_21f083
-         %38 = OpAccessChain %_ptr_StorageBuffer_v2uint %1 %uint_0
-               OpStore %38 %37 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %42
-         %43 = OpLabel
-         %44 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %45 = OpFunctionCall %void %fragment_main_inner %44
+%fragment_main = OpFunction %void None %32
+         %33 = OpLabel
+         %34 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %35 = OpISub %uint %34 %uint_1
+               OpStore %tint_subgroup_last_id %35 None
+         %36 = OpFunctionCall %v2uint %subgroupShuffle_21f083
+         %37 = OpAccessChain %_ptr_StorageBuffer_v2uint %1 %uint_0
+               OpStore %37 %36 None
                OpReturn
                OpFunctionEnd
 ;
@@ -92,31 +79,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 46
+; Bound: 40
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %25 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_21f083 "subgroupShuffle_21f083"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
        %uint = OpTypeInt 32 0
      %v2uint = OpTypeVector %uint 2
 %prevent_dce_block = OpTypeStruct %v2uint
@@ -124,52 +108,43 @@
           %1 = OpVariable %_ptr_StorageBuffer_prevent_dce_block StorageBuffer
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %v2uint
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %v2uint
 %_ptr_Function_v2uint = OpTypePointer Function %v2uint
      %uint_1 = OpConstant %uint 1
-         %16 = OpConstantComposite %v2uint %uint_1 %uint_1
+         %14 = OpConstantComposite %v2uint %uint_1 %uint_1
         %int = OpTypeInt 32 1
 %_ptr_Function_int = OpTypePointer Function %int
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %34 = OpTypeFunction %void %uint
+         %32 = OpTypeFunction %void
 %_ptr_StorageBuffer_v2uint = OpTypePointer StorageBuffer %v2uint
      %uint_0 = OpConstant %uint 0
-         %42 = OpTypeFunction %void
-%subgroupShuffle_21f083 = OpFunction %v2uint None %12
-         %13 = OpLabel
+%subgroupShuffle_21f083 = OpFunction %v2uint None %10
+         %11 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v2uint Function
       %arg_1 = OpVariable %_ptr_Function_int Function
         %res = OpVariable %_ptr_Function_v2uint Function
-               OpStore %arg_0 %16
+               OpStore %arg_0 %14
                OpStore %arg_1 %int_1
-         %22 = OpLoad %v2uint %arg_0 None
-         %23 = OpLoad %int %arg_1 None
-         %24 = OpBitcast %uint %23
-         %25 = OpLoad %uint %tint_subgroup_size_mask None
-         %26 = OpBitwiseAnd %uint %24 %25
-         %27 = OpGroupNonUniformShuffle %v2uint %uint_3 %22 %26
-               OpStore %res %27
-         %30 = OpLoad %v2uint %res None
-               OpReturnValue %30
+         %20 = OpLoad %v2uint %arg_0 None
+         %21 = OpLoad %int %arg_1 None
+         %22 = OpBitcast %uint %21
+         %23 = OpLoad %uint %tint_subgroup_last_id None
+         %24 = OpExtInst %uint %25 UMin %22 %23
+         %26 = OpGroupNonUniformShuffle %v2uint %uint_3 %20 %24
+               OpStore %res %26
+         %29 = OpLoad %v2uint %res None
+               OpReturnValue %29
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %34
-%tint_subgroup_size = OpFunctionParameter %uint
-         %35 = OpLabel
-         %36 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %36 None
-         %37 = OpFunctionCall %v2uint %subgroupShuffle_21f083
-         %38 = OpAccessChain %_ptr_StorageBuffer_v2uint %1 %uint_0
-               OpStore %38 %37 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %42
-         %43 = OpLabel
-         %44 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %45 = OpFunctionCall %void %compute_main_inner %44
+%compute_main = OpFunction %void None %32
+         %33 = OpLabel
+         %34 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %35 = OpISub %uint %34 %uint_1
+               OpStore %tint_subgroup_last_id %35 None
+         %36 = OpFunctionCall %v2uint %subgroupShuffle_21f083
+         %37 = OpAccessChain %_ptr_StorageBuffer_v2uint %1 %uint_0
+               OpStore %37 %36 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/var/subgroupShuffle/2ee993.wgsl.expected.spvasm b/test/tint/builtins/gen/var/subgroupShuffle/2ee993.wgsl.expected.spvasm
index 8df3366..0c2f763 100644
--- a/test/tint/builtins/gen/var/subgroupShuffle/2ee993.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/var/subgroupShuffle/2ee993.wgsl.expected.spvasm
@@ -4,32 +4,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 46
+; Bound: 40
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %24 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_2ee993 "subgroupShuffle_2ee993"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
         %int = OpTypeInt 32 1
       %v4int = OpTypeVector %int 4
 %prevent_dce_block = OpTypeStruct %v4int
@@ -38,52 +34,43 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v4int
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v4int
 %_ptr_Function_v4int = OpTypePointer Function %v4int
       %int_1 = OpConstant %int 1
-         %17 = OpConstantComposite %v4int %int_1 %int_1 %int_1 %int_1
+         %15 = OpConstantComposite %v4int %int_1 %int_1 %int_1 %int_1
 %_ptr_Function_int = OpTypePointer Function %int
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %33 = OpTypeFunction %void %uint
+         %31 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_v4int = OpTypePointer StorageBuffer %v4int
      %uint_0 = OpConstant %uint 0
-         %42 = OpTypeFunction %void
-%subgroupShuffle_2ee993 = OpFunction %v4int None %13
-         %14 = OpLabel
+%subgroupShuffle_2ee993 = OpFunction %v4int None %11
+         %12 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v4int Function
       %arg_1 = OpVariable %_ptr_Function_int Function
         %res = OpVariable %_ptr_Function_v4int Function
-               OpStore %arg_0 %17
+               OpStore %arg_0 %15
                OpStore %arg_1 %int_1
-         %21 = OpLoad %v4int %arg_0 None
-         %22 = OpLoad %int %arg_1 None
-         %23 = OpBitcast %uint %22
-         %24 = OpLoad %uint %tint_subgroup_size_mask None
-         %25 = OpBitwiseAnd %uint %23 %24
-         %26 = OpGroupNonUniformShuffle %v4int %uint_3 %21 %25
-               OpStore %res %26
-         %29 = OpLoad %v4int %res None
-               OpReturnValue %29
+         %19 = OpLoad %v4int %arg_0 None
+         %20 = OpLoad %int %arg_1 None
+         %21 = OpBitcast %uint %20
+         %22 = OpLoad %uint %tint_subgroup_last_id None
+         %23 = OpExtInst %uint %24 UMin %21 %22
+         %25 = OpGroupNonUniformShuffle %v4int %uint_3 %19 %23
+               OpStore %res %25
+         %28 = OpLoad %v4int %res None
+               OpReturnValue %28
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %33
-%tint_subgroup_size = OpFunctionParameter %uint
-         %34 = OpLabel
-         %35 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %35 None
-         %37 = OpFunctionCall %v4int %subgroupShuffle_2ee993
-         %38 = OpAccessChain %_ptr_StorageBuffer_v4int %1 %uint_0
-               OpStore %38 %37 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %42
-         %43 = OpLabel
-         %44 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %45 = OpFunctionCall %void %fragment_main_inner %44
+%fragment_main = OpFunction %void None %31
+         %32 = OpLabel
+         %33 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %35 = OpISub %uint %33 %uint_1
+               OpStore %tint_subgroup_last_id %35 None
+         %36 = OpFunctionCall %v4int %subgroupShuffle_2ee993
+         %37 = OpAccessChain %_ptr_StorageBuffer_v4int %1 %uint_0
+               OpStore %37 %36 None
                OpReturn
                OpFunctionEnd
 ;
@@ -92,31 +79,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 46
+; Bound: 40
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %24 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_2ee993 "subgroupShuffle_2ee993"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
         %int = OpTypeInt 32 1
       %v4int = OpTypeVector %int 4
 %prevent_dce_block = OpTypeStruct %v4int
@@ -125,51 +109,42 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v4int
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v4int
 %_ptr_Function_v4int = OpTypePointer Function %v4int
       %int_1 = OpConstant %int 1
-         %17 = OpConstantComposite %v4int %int_1 %int_1 %int_1 %int_1
+         %15 = OpConstantComposite %v4int %int_1 %int_1 %int_1 %int_1
 %_ptr_Function_int = OpTypePointer Function %int
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %33 = OpTypeFunction %void %uint
+         %31 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_v4int = OpTypePointer StorageBuffer %v4int
      %uint_0 = OpConstant %uint 0
-         %42 = OpTypeFunction %void
-%subgroupShuffle_2ee993 = OpFunction %v4int None %13
-         %14 = OpLabel
+%subgroupShuffle_2ee993 = OpFunction %v4int None %11
+         %12 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v4int Function
       %arg_1 = OpVariable %_ptr_Function_int Function
         %res = OpVariable %_ptr_Function_v4int Function
-               OpStore %arg_0 %17
+               OpStore %arg_0 %15
                OpStore %arg_1 %int_1
-         %21 = OpLoad %v4int %arg_0 None
-         %22 = OpLoad %int %arg_1 None
-         %23 = OpBitcast %uint %22
-         %24 = OpLoad %uint %tint_subgroup_size_mask None
-         %25 = OpBitwiseAnd %uint %23 %24
-         %26 = OpGroupNonUniformShuffle %v4int %uint_3 %21 %25
-               OpStore %res %26
-         %29 = OpLoad %v4int %res None
-               OpReturnValue %29
+         %19 = OpLoad %v4int %arg_0 None
+         %20 = OpLoad %int %arg_1 None
+         %21 = OpBitcast %uint %20
+         %22 = OpLoad %uint %tint_subgroup_last_id None
+         %23 = OpExtInst %uint %24 UMin %21 %22
+         %25 = OpGroupNonUniformShuffle %v4int %uint_3 %19 %23
+               OpStore %res %25
+         %28 = OpLoad %v4int %res None
+               OpReturnValue %28
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %33
-%tint_subgroup_size = OpFunctionParameter %uint
-         %34 = OpLabel
-         %35 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %35 None
-         %37 = OpFunctionCall %v4int %subgroupShuffle_2ee993
-         %38 = OpAccessChain %_ptr_StorageBuffer_v4int %1 %uint_0
-               OpStore %38 %37 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %42
-         %43 = OpLabel
-         %44 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %45 = OpFunctionCall %void %compute_main_inner %44
+%compute_main = OpFunction %void None %31
+         %32 = OpLabel
+         %33 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %35 = OpISub %uint %33 %uint_1
+               OpStore %tint_subgroup_last_id %35 None
+         %36 = OpFunctionCall %v4int %subgroupShuffle_2ee993
+         %37 = OpAccessChain %_ptr_StorageBuffer_v4int %1 %uint_0
+               OpStore %37 %36 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/var/subgroupShuffle/323416.wgsl.expected.spvasm b/test/tint/builtins/gen/var/subgroupShuffle/323416.wgsl.expected.spvasm
index 33674a3..df17ab8 100644
--- a/test/tint/builtins/gen/var/subgroupShuffle/323416.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/var/subgroupShuffle/323416.wgsl.expected.spvasm
@@ -4,32 +4,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 45
+; Bound: 39
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %24 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_323416 "subgroupShuffle_323416"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
         %int = OpTypeInt 32 1
       %v2int = OpTypeVector %int 2
 %prevent_dce_block = OpTypeStruct %v2int
@@ -38,51 +34,42 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v2int
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v2int
 %_ptr_Function_v2int = OpTypePointer Function %v2int
       %int_1 = OpConstant %int 1
-         %17 = OpConstantComposite %v2int %int_1 %int_1
+         %15 = OpConstantComposite %v2int %int_1 %int_1
 %_ptr_Function_uint = OpTypePointer Function %uint
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %33 = OpTypeFunction %void %uint
+         %31 = OpTypeFunction %void
 %_ptr_StorageBuffer_v2int = OpTypePointer StorageBuffer %v2int
      %uint_0 = OpConstant %uint 0
-         %41 = OpTypeFunction %void
-%subgroupShuffle_323416 = OpFunction %v2int None %13
-         %14 = OpLabel
+%subgroupShuffle_323416 = OpFunction %v2int None %11
+         %12 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v2int Function
       %arg_1 = OpVariable %_ptr_Function_uint Function
         %res = OpVariable %_ptr_Function_v2int Function
-               OpStore %arg_0 %17
+               OpStore %arg_0 %15
                OpStore %arg_1 %uint_1
-         %22 = OpLoad %v2int %arg_0 None
-         %23 = OpLoad %uint %arg_1 None
-         %24 = OpLoad %uint %tint_subgroup_size_mask None
-         %25 = OpBitwiseAnd %uint %23 %24
-         %26 = OpGroupNonUniformShuffle %v2int %uint_3 %22 %25
-               OpStore %res %26
-         %29 = OpLoad %v2int %res None
-               OpReturnValue %29
+         %20 = OpLoad %v2int %arg_0 None
+         %21 = OpLoad %uint %arg_1 None
+         %22 = OpLoad %uint %tint_subgroup_last_id None
+         %23 = OpExtInst %uint %24 UMin %21 %22
+         %25 = OpGroupNonUniformShuffle %v2int %uint_3 %20 %23
+               OpStore %res %25
+         %28 = OpLoad %v2int %res None
+               OpReturnValue %28
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %33
-%tint_subgroup_size = OpFunctionParameter %uint
-         %34 = OpLabel
-         %35 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %35 None
-         %36 = OpFunctionCall %v2int %subgroupShuffle_323416
-         %37 = OpAccessChain %_ptr_StorageBuffer_v2int %1 %uint_0
-               OpStore %37 %36 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %41
-         %42 = OpLabel
-         %43 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %44 = OpFunctionCall %void %fragment_main_inner %43
+%fragment_main = OpFunction %void None %31
+         %32 = OpLabel
+         %33 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %34 = OpISub %uint %33 %uint_1
+               OpStore %tint_subgroup_last_id %34 None
+         %35 = OpFunctionCall %v2int %subgroupShuffle_323416
+         %36 = OpAccessChain %_ptr_StorageBuffer_v2int %1 %uint_0
+               OpStore %36 %35 None
                OpReturn
                OpFunctionEnd
 ;
@@ -91,31 +78,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 45
+; Bound: 39
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %24 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_323416 "subgroupShuffle_323416"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
         %int = OpTypeInt 32 1
       %v2int = OpTypeVector %int 2
 %prevent_dce_block = OpTypeStruct %v2int
@@ -124,50 +108,41 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v2int
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v2int
 %_ptr_Function_v2int = OpTypePointer Function %v2int
       %int_1 = OpConstant %int 1
-         %17 = OpConstantComposite %v2int %int_1 %int_1
+         %15 = OpConstantComposite %v2int %int_1 %int_1
 %_ptr_Function_uint = OpTypePointer Function %uint
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %33 = OpTypeFunction %void %uint
+         %31 = OpTypeFunction %void
 %_ptr_StorageBuffer_v2int = OpTypePointer StorageBuffer %v2int
      %uint_0 = OpConstant %uint 0
-         %41 = OpTypeFunction %void
-%subgroupShuffle_323416 = OpFunction %v2int None %13
-         %14 = OpLabel
+%subgroupShuffle_323416 = OpFunction %v2int None %11
+         %12 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v2int Function
       %arg_1 = OpVariable %_ptr_Function_uint Function
         %res = OpVariable %_ptr_Function_v2int Function
-               OpStore %arg_0 %17
+               OpStore %arg_0 %15
                OpStore %arg_1 %uint_1
-         %22 = OpLoad %v2int %arg_0 None
-         %23 = OpLoad %uint %arg_1 None
-         %24 = OpLoad %uint %tint_subgroup_size_mask None
-         %25 = OpBitwiseAnd %uint %23 %24
-         %26 = OpGroupNonUniformShuffle %v2int %uint_3 %22 %25
-               OpStore %res %26
-         %29 = OpLoad %v2int %res None
-               OpReturnValue %29
+         %20 = OpLoad %v2int %arg_0 None
+         %21 = OpLoad %uint %arg_1 None
+         %22 = OpLoad %uint %tint_subgroup_last_id None
+         %23 = OpExtInst %uint %24 UMin %21 %22
+         %25 = OpGroupNonUniformShuffle %v2int %uint_3 %20 %23
+               OpStore %res %25
+         %28 = OpLoad %v2int %res None
+               OpReturnValue %28
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %33
-%tint_subgroup_size = OpFunctionParameter %uint
-         %34 = OpLabel
-         %35 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %35 None
-         %36 = OpFunctionCall %v2int %subgroupShuffle_323416
-         %37 = OpAccessChain %_ptr_StorageBuffer_v2int %1 %uint_0
-               OpStore %37 %36 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %41
-         %42 = OpLabel
-         %43 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %44 = OpFunctionCall %void %compute_main_inner %43
+%compute_main = OpFunction %void None %31
+         %32 = OpLabel
+         %33 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %34 = OpISub %uint %33 %uint_1
+               OpStore %tint_subgroup_last_id %34 None
+         %35 = OpFunctionCall %v2int %subgroupShuffle_323416
+         %36 = OpAccessChain %_ptr_StorageBuffer_v2int %1 %uint_0
+               OpStore %36 %35 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/var/subgroupShuffle/4752bd.wgsl.expected.spvasm b/test/tint/builtins/gen/var/subgroupShuffle/4752bd.wgsl.expected.spvasm
index 690c206..e049989 100644
--- a/test/tint/builtins/gen/var/subgroupShuffle/4752bd.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/var/subgroupShuffle/4752bd.wgsl.expected.spvasm
@@ -4,32 +4,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 43
+; Bound: 37
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %22 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_4752bd "subgroupShuffle_4752bd"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
       %float = OpTypeFloat 32
 %prevent_dce_block = OpTypeStruct %float
 %_ptr_StorageBuffer_prevent_dce_block = OpTypePointer StorageBuffer %prevent_dce_block
@@ -37,50 +33,41 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %float
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %float
 %_ptr_Function_float = OpTypePointer Function %float
     %float_1 = OpConstant %float 1
 %_ptr_Function_uint = OpTypePointer Function %uint
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %31 = OpTypeFunction %void %uint
+         %29 = OpTypeFunction %void
 %_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
      %uint_0 = OpConstant %uint 0
-         %39 = OpTypeFunction %void
-%subgroupShuffle_4752bd = OpFunction %float None %12
-         %13 = OpLabel
+%subgroupShuffle_4752bd = OpFunction %float None %10
+         %11 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_float Function
       %arg_1 = OpVariable %_ptr_Function_uint Function
         %res = OpVariable %_ptr_Function_float Function
                OpStore %arg_0 %float_1
                OpStore %arg_1 %uint_1
-         %20 = OpLoad %float %arg_0 None
-         %21 = OpLoad %uint %arg_1 None
-         %22 = OpLoad %uint %tint_subgroup_size_mask None
-         %23 = OpBitwiseAnd %uint %21 %22
-         %24 = OpGroupNonUniformShuffle %float %uint_3 %20 %23
-               OpStore %res %24
-         %27 = OpLoad %float %res None
-               OpReturnValue %27
+         %18 = OpLoad %float %arg_0 None
+         %19 = OpLoad %uint %arg_1 None
+         %20 = OpLoad %uint %tint_subgroup_last_id None
+         %21 = OpExtInst %uint %22 UMin %19 %20
+         %23 = OpGroupNonUniformShuffle %float %uint_3 %18 %21
+               OpStore %res %23
+         %26 = OpLoad %float %res None
+               OpReturnValue %26
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %31
-%tint_subgroup_size = OpFunctionParameter %uint
-         %32 = OpLabel
-         %33 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %33 None
-         %34 = OpFunctionCall %float %subgroupShuffle_4752bd
-         %35 = OpAccessChain %_ptr_StorageBuffer_float %1 %uint_0
-               OpStore %35 %34 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %39
-         %40 = OpLabel
-         %41 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %42 = OpFunctionCall %void %fragment_main_inner %41
+%fragment_main = OpFunction %void None %29
+         %30 = OpLabel
+         %31 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %32 = OpISub %uint %31 %uint_1
+               OpStore %tint_subgroup_last_id %32 None
+         %33 = OpFunctionCall %float %subgroupShuffle_4752bd
+         %34 = OpAccessChain %_ptr_StorageBuffer_float %1 %uint_0
+               OpStore %34 %33 None
                OpReturn
                OpFunctionEnd
 ;
@@ -89,31 +76,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 43
+; Bound: 37
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %22 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_4752bd "subgroupShuffle_4752bd"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
       %float = OpTypeFloat 32
 %prevent_dce_block = OpTypeStruct %float
 %_ptr_StorageBuffer_prevent_dce_block = OpTypePointer StorageBuffer %prevent_dce_block
@@ -121,49 +105,40 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %float
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %float
 %_ptr_Function_float = OpTypePointer Function %float
     %float_1 = OpConstant %float 1
 %_ptr_Function_uint = OpTypePointer Function %uint
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %31 = OpTypeFunction %void %uint
+         %29 = OpTypeFunction %void
 %_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
      %uint_0 = OpConstant %uint 0
-         %39 = OpTypeFunction %void
-%subgroupShuffle_4752bd = OpFunction %float None %12
-         %13 = OpLabel
+%subgroupShuffle_4752bd = OpFunction %float None %10
+         %11 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_float Function
       %arg_1 = OpVariable %_ptr_Function_uint Function
         %res = OpVariable %_ptr_Function_float Function
                OpStore %arg_0 %float_1
                OpStore %arg_1 %uint_1
-         %20 = OpLoad %float %arg_0 None
-         %21 = OpLoad %uint %arg_1 None
-         %22 = OpLoad %uint %tint_subgroup_size_mask None
-         %23 = OpBitwiseAnd %uint %21 %22
-         %24 = OpGroupNonUniformShuffle %float %uint_3 %20 %23
-               OpStore %res %24
-         %27 = OpLoad %float %res None
-               OpReturnValue %27
+         %18 = OpLoad %float %arg_0 None
+         %19 = OpLoad %uint %arg_1 None
+         %20 = OpLoad %uint %tint_subgroup_last_id None
+         %21 = OpExtInst %uint %22 UMin %19 %20
+         %23 = OpGroupNonUniformShuffle %float %uint_3 %18 %21
+               OpStore %res %23
+         %26 = OpLoad %float %res None
+               OpReturnValue %26
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %31
-%tint_subgroup_size = OpFunctionParameter %uint
-         %32 = OpLabel
-         %33 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %33 None
-         %34 = OpFunctionCall %float %subgroupShuffle_4752bd
-         %35 = OpAccessChain %_ptr_StorageBuffer_float %1 %uint_0
-               OpStore %35 %34 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %39
-         %40 = OpLabel
-         %41 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %42 = OpFunctionCall %void %compute_main_inner %41
+%compute_main = OpFunction %void None %29
+         %30 = OpLabel
+         %31 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %32 = OpISub %uint %31 %uint_1
+               OpStore %tint_subgroup_last_id %32 None
+         %33 = OpFunctionCall %float %subgroupShuffle_4752bd
+         %34 = OpAccessChain %_ptr_StorageBuffer_float %1 %uint_0
+               OpStore %34 %33 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/var/subgroupShuffle/4cbb69.wgsl.expected.spvasm b/test/tint/builtins/gen/var/subgroupShuffle/4cbb69.wgsl.expected.spvasm
index e9ce041..449b6d8 100644
--- a/test/tint/builtins/gen/var/subgroupShuffle/4cbb69.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/var/subgroupShuffle/4cbb69.wgsl.expected.spvasm
@@ -4,32 +4,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 46
+; Bound: 40
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %25 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_4cbb69 "subgroupShuffle_4cbb69"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
        %uint = OpTypeInt 32 0
      %v3uint = OpTypeVector %uint 3
 %prevent_dce_block = OpTypeStruct %v3uint
@@ -37,53 +33,44 @@
           %1 = OpVariable %_ptr_StorageBuffer_prevent_dce_block StorageBuffer
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %v3uint
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %v3uint
 %_ptr_Function_v3uint = OpTypePointer Function %v3uint
      %uint_1 = OpConstant %uint 1
-         %16 = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
+         %14 = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
         %int = OpTypeInt 32 1
 %_ptr_Function_int = OpTypePointer Function %int
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %34 = OpTypeFunction %void %uint
+         %32 = OpTypeFunction %void
 %_ptr_StorageBuffer_v3uint = OpTypePointer StorageBuffer %v3uint
      %uint_0 = OpConstant %uint 0
-         %42 = OpTypeFunction %void
-%subgroupShuffle_4cbb69 = OpFunction %v3uint None %12
-         %13 = OpLabel
+%subgroupShuffle_4cbb69 = OpFunction %v3uint None %10
+         %11 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v3uint Function
       %arg_1 = OpVariable %_ptr_Function_int Function
         %res = OpVariable %_ptr_Function_v3uint Function
-               OpStore %arg_0 %16
+               OpStore %arg_0 %14
                OpStore %arg_1 %int_1
-         %22 = OpLoad %v3uint %arg_0 None
-         %23 = OpLoad %int %arg_1 None
-         %24 = OpBitcast %uint %23
-         %25 = OpLoad %uint %tint_subgroup_size_mask None
-         %26 = OpBitwiseAnd %uint %24 %25
-         %27 = OpGroupNonUniformShuffle %v3uint %uint_3 %22 %26
-               OpStore %res %27
-         %30 = OpLoad %v3uint %res None
-               OpReturnValue %30
+         %20 = OpLoad %v3uint %arg_0 None
+         %21 = OpLoad %int %arg_1 None
+         %22 = OpBitcast %uint %21
+         %23 = OpLoad %uint %tint_subgroup_last_id None
+         %24 = OpExtInst %uint %25 UMin %22 %23
+         %26 = OpGroupNonUniformShuffle %v3uint %uint_3 %20 %24
+               OpStore %res %26
+         %29 = OpLoad %v3uint %res None
+               OpReturnValue %29
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %34
-%tint_subgroup_size = OpFunctionParameter %uint
-         %35 = OpLabel
-         %36 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %36 None
-         %37 = OpFunctionCall %v3uint %subgroupShuffle_4cbb69
-         %38 = OpAccessChain %_ptr_StorageBuffer_v3uint %1 %uint_0
-               OpStore %38 %37 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %42
-         %43 = OpLabel
-         %44 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %45 = OpFunctionCall %void %fragment_main_inner %44
+%fragment_main = OpFunction %void None %32
+         %33 = OpLabel
+         %34 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %35 = OpISub %uint %34 %uint_1
+               OpStore %tint_subgroup_last_id %35 None
+         %36 = OpFunctionCall %v3uint %subgroupShuffle_4cbb69
+         %37 = OpAccessChain %_ptr_StorageBuffer_v3uint %1 %uint_0
+               OpStore %37 %36 None
                OpReturn
                OpFunctionEnd
 ;
@@ -92,31 +79,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 46
+; Bound: 40
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %25 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_4cbb69 "subgroupShuffle_4cbb69"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
        %uint = OpTypeInt 32 0
      %v3uint = OpTypeVector %uint 3
 %prevent_dce_block = OpTypeStruct %v3uint
@@ -124,52 +108,43 @@
           %1 = OpVariable %_ptr_StorageBuffer_prevent_dce_block StorageBuffer
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %v3uint
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %v3uint
 %_ptr_Function_v3uint = OpTypePointer Function %v3uint
      %uint_1 = OpConstant %uint 1
-         %16 = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
+         %14 = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
         %int = OpTypeInt 32 1
 %_ptr_Function_int = OpTypePointer Function %int
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %34 = OpTypeFunction %void %uint
+         %32 = OpTypeFunction %void
 %_ptr_StorageBuffer_v3uint = OpTypePointer StorageBuffer %v3uint
      %uint_0 = OpConstant %uint 0
-         %42 = OpTypeFunction %void
-%subgroupShuffle_4cbb69 = OpFunction %v3uint None %12
-         %13 = OpLabel
+%subgroupShuffle_4cbb69 = OpFunction %v3uint None %10
+         %11 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v3uint Function
       %arg_1 = OpVariable %_ptr_Function_int Function
         %res = OpVariable %_ptr_Function_v3uint Function
-               OpStore %arg_0 %16
+               OpStore %arg_0 %14
                OpStore %arg_1 %int_1
-         %22 = OpLoad %v3uint %arg_0 None
-         %23 = OpLoad %int %arg_1 None
-         %24 = OpBitcast %uint %23
-         %25 = OpLoad %uint %tint_subgroup_size_mask None
-         %26 = OpBitwiseAnd %uint %24 %25
-         %27 = OpGroupNonUniformShuffle %v3uint %uint_3 %22 %26
-               OpStore %res %27
-         %30 = OpLoad %v3uint %res None
-               OpReturnValue %30
+         %20 = OpLoad %v3uint %arg_0 None
+         %21 = OpLoad %int %arg_1 None
+         %22 = OpBitcast %uint %21
+         %23 = OpLoad %uint %tint_subgroup_last_id None
+         %24 = OpExtInst %uint %25 UMin %22 %23
+         %26 = OpGroupNonUniformShuffle %v3uint %uint_3 %20 %24
+               OpStore %res %26
+         %29 = OpLoad %v3uint %res None
+               OpReturnValue %29
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %34
-%tint_subgroup_size = OpFunctionParameter %uint
-         %35 = OpLabel
-         %36 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %36 None
-         %37 = OpFunctionCall %v3uint %subgroupShuffle_4cbb69
-         %38 = OpAccessChain %_ptr_StorageBuffer_v3uint %1 %uint_0
-               OpStore %38 %37 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %42
-         %43 = OpLabel
-         %44 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %45 = OpFunctionCall %void %compute_main_inner %44
+%compute_main = OpFunction %void None %32
+         %33 = OpLabel
+         %34 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %35 = OpISub %uint %34 %uint_1
+               OpStore %tint_subgroup_last_id %35 None
+         %36 = OpFunctionCall %v3uint %subgroupShuffle_4cbb69
+         %37 = OpAccessChain %_ptr_StorageBuffer_v3uint %1 %uint_0
+               OpStore %37 %36 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/var/subgroupShuffle/4f5711.wgsl.expected.spvasm b/test/tint/builtins/gen/var/subgroupShuffle/4f5711.wgsl.expected.spvasm
index 704fcd6..76c2bab 100644
--- a/test/tint/builtins/gen/var/subgroupShuffle/4f5711.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/var/subgroupShuffle/4f5711.wgsl.expected.spvasm
@@ -4,32 +4,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 43
+; Bound: 37
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %22 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_4f5711 "subgroupShuffle_4f5711"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
        %uint = OpTypeInt 32 0
      %v3uint = OpTypeVector %uint 3
 %prevent_dce_block = OpTypeStruct %v3uint
@@ -37,50 +33,41 @@
           %1 = OpVariable %_ptr_StorageBuffer_prevent_dce_block StorageBuffer
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %v3uint
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %v3uint
 %_ptr_Function_v3uint = OpTypePointer Function %v3uint
      %uint_1 = OpConstant %uint 1
-         %16 = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
+         %14 = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
 %_ptr_Function_uint = OpTypePointer Function %uint
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %31 = OpTypeFunction %void %uint
+         %29 = OpTypeFunction %void
 %_ptr_StorageBuffer_v3uint = OpTypePointer StorageBuffer %v3uint
      %uint_0 = OpConstant %uint 0
-         %39 = OpTypeFunction %void
-%subgroupShuffle_4f5711 = OpFunction %v3uint None %12
-         %13 = OpLabel
+%subgroupShuffle_4f5711 = OpFunction %v3uint None %10
+         %11 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v3uint Function
       %arg_1 = OpVariable %_ptr_Function_uint Function
         %res = OpVariable %_ptr_Function_v3uint Function
-               OpStore %arg_0 %16
+               OpStore %arg_0 %14
                OpStore %arg_1 %uint_1
-         %20 = OpLoad %v3uint %arg_0 None
-         %21 = OpLoad %uint %arg_1 None
-         %22 = OpLoad %uint %tint_subgroup_size_mask None
-         %23 = OpBitwiseAnd %uint %21 %22
-         %24 = OpGroupNonUniformShuffle %v3uint %uint_3 %20 %23
-               OpStore %res %24
-         %27 = OpLoad %v3uint %res None
-               OpReturnValue %27
+         %18 = OpLoad %v3uint %arg_0 None
+         %19 = OpLoad %uint %arg_1 None
+         %20 = OpLoad %uint %tint_subgroup_last_id None
+         %21 = OpExtInst %uint %22 UMin %19 %20
+         %23 = OpGroupNonUniformShuffle %v3uint %uint_3 %18 %21
+               OpStore %res %23
+         %26 = OpLoad %v3uint %res None
+               OpReturnValue %26
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %31
-%tint_subgroup_size = OpFunctionParameter %uint
-         %32 = OpLabel
-         %33 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %33 None
-         %34 = OpFunctionCall %v3uint %subgroupShuffle_4f5711
-         %35 = OpAccessChain %_ptr_StorageBuffer_v3uint %1 %uint_0
-               OpStore %35 %34 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %39
-         %40 = OpLabel
-         %41 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %42 = OpFunctionCall %void %fragment_main_inner %41
+%fragment_main = OpFunction %void None %29
+         %30 = OpLabel
+         %31 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %32 = OpISub %uint %31 %uint_1
+               OpStore %tint_subgroup_last_id %32 None
+         %33 = OpFunctionCall %v3uint %subgroupShuffle_4f5711
+         %34 = OpAccessChain %_ptr_StorageBuffer_v3uint %1 %uint_0
+               OpStore %34 %33 None
                OpReturn
                OpFunctionEnd
 ;
@@ -89,31 +76,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 43
+; Bound: 37
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %22 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_4f5711 "subgroupShuffle_4f5711"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
        %uint = OpTypeInt 32 0
      %v3uint = OpTypeVector %uint 3
 %prevent_dce_block = OpTypeStruct %v3uint
@@ -121,49 +105,40 @@
           %1 = OpVariable %_ptr_StorageBuffer_prevent_dce_block StorageBuffer
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %v3uint
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %v3uint
 %_ptr_Function_v3uint = OpTypePointer Function %v3uint
      %uint_1 = OpConstant %uint 1
-         %16 = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
+         %14 = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
 %_ptr_Function_uint = OpTypePointer Function %uint
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %31 = OpTypeFunction %void %uint
+         %29 = OpTypeFunction %void
 %_ptr_StorageBuffer_v3uint = OpTypePointer StorageBuffer %v3uint
      %uint_0 = OpConstant %uint 0
-         %39 = OpTypeFunction %void
-%subgroupShuffle_4f5711 = OpFunction %v3uint None %12
-         %13 = OpLabel
+%subgroupShuffle_4f5711 = OpFunction %v3uint None %10
+         %11 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v3uint Function
       %arg_1 = OpVariable %_ptr_Function_uint Function
         %res = OpVariable %_ptr_Function_v3uint Function
-               OpStore %arg_0 %16
+               OpStore %arg_0 %14
                OpStore %arg_1 %uint_1
-         %20 = OpLoad %v3uint %arg_0 None
-         %21 = OpLoad %uint %arg_1 None
-         %22 = OpLoad %uint %tint_subgroup_size_mask None
-         %23 = OpBitwiseAnd %uint %21 %22
-         %24 = OpGroupNonUniformShuffle %v3uint %uint_3 %20 %23
-               OpStore %res %24
-         %27 = OpLoad %v3uint %res None
-               OpReturnValue %27
+         %18 = OpLoad %v3uint %arg_0 None
+         %19 = OpLoad %uint %arg_1 None
+         %20 = OpLoad %uint %tint_subgroup_last_id None
+         %21 = OpExtInst %uint %22 UMin %19 %20
+         %23 = OpGroupNonUniformShuffle %v3uint %uint_3 %18 %21
+               OpStore %res %23
+         %26 = OpLoad %v3uint %res None
+               OpReturnValue %26
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %31
-%tint_subgroup_size = OpFunctionParameter %uint
-         %32 = OpLabel
-         %33 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %33 None
-         %34 = OpFunctionCall %v3uint %subgroupShuffle_4f5711
-         %35 = OpAccessChain %_ptr_StorageBuffer_v3uint %1 %uint_0
-               OpStore %35 %34 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %39
-         %40 = OpLabel
-         %41 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %42 = OpFunctionCall %void %compute_main_inner %41
+%compute_main = OpFunction %void None %29
+         %30 = OpLabel
+         %31 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %32 = OpISub %uint %31 %uint_1
+               OpStore %tint_subgroup_last_id %32 None
+         %33 = OpFunctionCall %v3uint %subgroupShuffle_4f5711
+         %34 = OpAccessChain %_ptr_StorageBuffer_v3uint %1 %uint_0
+               OpStore %34 %33 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/var/subgroupShuffle/54f328.wgsl.expected.spvasm b/test/tint/builtins/gen/var/subgroupShuffle/54f328.wgsl.expected.spvasm
index 294d554..7a6df59 100644
--- a/test/tint/builtins/gen/var/subgroupShuffle/54f328.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/var/subgroupShuffle/54f328.wgsl.expected.spvasm
@@ -4,42 +4,36 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 44
+; Bound: 38
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %23 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_54f328 "subgroupShuffle_54f328"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
        %uint = OpTypeInt 32 0
 %prevent_dce_block = OpTypeStruct %uint
 %_ptr_StorageBuffer_prevent_dce_block = OpTypePointer StorageBuffer %prevent_dce_block
           %1 = OpVariable %_ptr_StorageBuffer_prevent_dce_block StorageBuffer
 %_ptr_Private_uint = OpTypePointer Private %uint
           %7 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %7
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %11 = OpTypeFunction %uint
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %7
+          %9 = OpTypeFunction %uint
 %_ptr_Function_uint = OpTypePointer Function %uint
      %uint_1 = OpConstant %uint 1
         %int = OpTypeInt 32 1
@@ -47,41 +41,34 @@
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %32 = OpTypeFunction %void %uint
+         %30 = OpTypeFunction %void
 %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
      %uint_0 = OpConstant %uint 0
-         %40 = OpTypeFunction %void
-%subgroupShuffle_54f328 = OpFunction %uint None %11
-         %12 = OpLabel
+%subgroupShuffle_54f328 = OpFunction %uint None %9
+         %10 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_uint Function
       %arg_1 = OpVariable %_ptr_Function_int Function
         %res = OpVariable %_ptr_Function_uint Function
                OpStore %arg_0 %uint_1
                OpStore %arg_1 %int_1
-         %20 = OpLoad %uint %arg_0 None
-         %21 = OpLoad %int %arg_1 None
-         %22 = OpBitcast %uint %21
-         %23 = OpLoad %uint %tint_subgroup_size_mask None
-         %24 = OpBitwiseAnd %uint %22 %23
-         %25 = OpGroupNonUniformShuffle %uint %uint_3 %20 %24
-               OpStore %res %25
-         %28 = OpLoad %uint %res None
-               OpReturnValue %28
+         %18 = OpLoad %uint %arg_0 None
+         %19 = OpLoad %int %arg_1 None
+         %20 = OpBitcast %uint %19
+         %21 = OpLoad %uint %tint_subgroup_last_id None
+         %22 = OpExtInst %uint %23 UMin %20 %21
+         %24 = OpGroupNonUniformShuffle %uint %uint_3 %18 %22
+               OpStore %res %24
+         %27 = OpLoad %uint %res None
+               OpReturnValue %27
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %32
-%tint_subgroup_size = OpFunctionParameter %uint
-         %33 = OpLabel
-         %34 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %34 None
-         %35 = OpFunctionCall %uint %subgroupShuffle_54f328
-         %36 = OpAccessChain %_ptr_StorageBuffer_uint %1 %uint_0
-               OpStore %36 %35 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %40
-         %41 = OpLabel
-         %42 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %43 = OpFunctionCall %void %fragment_main_inner %42
+%fragment_main = OpFunction %void None %30
+         %31 = OpLabel
+         %32 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %33 = OpISub %uint %32 %uint_1
+               OpStore %tint_subgroup_last_id %33 None
+         %34 = OpFunctionCall %uint %subgroupShuffle_54f328
+         %35 = OpAccessChain %_ptr_StorageBuffer_uint %1 %uint_0
+               OpStore %35 %34 None
                OpReturn
                OpFunctionEnd
 ;
@@ -90,41 +77,36 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 44
+; Bound: 38
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %23 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_54f328 "subgroupShuffle_54f328"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
        %uint = OpTypeInt 32 0
 %prevent_dce_block = OpTypeStruct %uint
 %_ptr_StorageBuffer_prevent_dce_block = OpTypePointer StorageBuffer %prevent_dce_block
           %1 = OpVariable %_ptr_StorageBuffer_prevent_dce_block StorageBuffer
 %_ptr_Private_uint = OpTypePointer Private %uint
           %7 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %7
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %11 = OpTypeFunction %uint
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %7
+          %9 = OpTypeFunction %uint
 %_ptr_Function_uint = OpTypePointer Function %uint
      %uint_1 = OpConstant %uint 1
         %int = OpTypeInt 32 1
@@ -132,40 +114,33 @@
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %32 = OpTypeFunction %void %uint
+         %30 = OpTypeFunction %void
 %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
      %uint_0 = OpConstant %uint 0
-         %40 = OpTypeFunction %void
-%subgroupShuffle_54f328 = OpFunction %uint None %11
-         %12 = OpLabel
+%subgroupShuffle_54f328 = OpFunction %uint None %9
+         %10 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_uint Function
       %arg_1 = OpVariable %_ptr_Function_int Function
         %res = OpVariable %_ptr_Function_uint Function
                OpStore %arg_0 %uint_1
                OpStore %arg_1 %int_1
-         %20 = OpLoad %uint %arg_0 None
-         %21 = OpLoad %int %arg_1 None
-         %22 = OpBitcast %uint %21
-         %23 = OpLoad %uint %tint_subgroup_size_mask None
-         %24 = OpBitwiseAnd %uint %22 %23
-         %25 = OpGroupNonUniformShuffle %uint %uint_3 %20 %24
-               OpStore %res %25
-         %28 = OpLoad %uint %res None
-               OpReturnValue %28
+         %18 = OpLoad %uint %arg_0 None
+         %19 = OpLoad %int %arg_1 None
+         %20 = OpBitcast %uint %19
+         %21 = OpLoad %uint %tint_subgroup_last_id None
+         %22 = OpExtInst %uint %23 UMin %20 %21
+         %24 = OpGroupNonUniformShuffle %uint %uint_3 %18 %22
+               OpStore %res %24
+         %27 = OpLoad %uint %res None
+               OpReturnValue %27
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %32
-%tint_subgroup_size = OpFunctionParameter %uint
-         %33 = OpLabel
-         %34 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %34 None
-         %35 = OpFunctionCall %uint %subgroupShuffle_54f328
-         %36 = OpAccessChain %_ptr_StorageBuffer_uint %1 %uint_0
-               OpStore %36 %35 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %40
-         %41 = OpLabel
-         %42 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %43 = OpFunctionCall %void %compute_main_inner %42
+%compute_main = OpFunction %void None %30
+         %31 = OpLabel
+         %32 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %33 = OpISub %uint %32 %uint_1
+               OpStore %tint_subgroup_last_id %33 None
+         %34 = OpFunctionCall %uint %subgroupShuffle_54f328
+         %35 = OpAccessChain %_ptr_StorageBuffer_uint %1 %uint_0
+               OpStore %35 %34 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/var/subgroupShuffle/5dfeab.wgsl.expected.spvasm b/test/tint/builtins/gen/var/subgroupShuffle/5dfeab.wgsl.expected.spvasm
index 9e737f1..ea97342 100644
--- a/test/tint/builtins/gen/var/subgroupShuffle/5dfeab.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/var/subgroupShuffle/5dfeab.wgsl.expected.spvasm
@@ -4,32 +4,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 48
+; Bound: 42
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %26 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_5dfeab "subgroupShuffle_5dfeab"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
       %float = OpTypeFloat 32
     %v4float = OpTypeVector %float 4
 %prevent_dce_block = OpTypeStruct %v4float
@@ -38,54 +34,45 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v4float
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v4float
 %_ptr_Function_v4float = OpTypePointer Function %v4float
     %float_1 = OpConstant %float 1
-         %17 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
+         %15 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
         %int = OpTypeInt 32 1
 %_ptr_Function_int = OpTypePointer Function %int
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %35 = OpTypeFunction %void %uint
+         %33 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_v4float = OpTypePointer StorageBuffer %v4float
      %uint_0 = OpConstant %uint 0
-         %44 = OpTypeFunction %void
-%subgroupShuffle_5dfeab = OpFunction %v4float None %13
-         %14 = OpLabel
+%subgroupShuffle_5dfeab = OpFunction %v4float None %11
+         %12 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v4float Function
       %arg_1 = OpVariable %_ptr_Function_int Function
         %res = OpVariable %_ptr_Function_v4float Function
-               OpStore %arg_0 %17
+               OpStore %arg_0 %15
                OpStore %arg_1 %int_1
-         %23 = OpLoad %v4float %arg_0 None
-         %24 = OpLoad %int %arg_1 None
-         %25 = OpBitcast %uint %24
-         %26 = OpLoad %uint %tint_subgroup_size_mask None
-         %27 = OpBitwiseAnd %uint %25 %26
-         %28 = OpGroupNonUniformShuffle %v4float %uint_3 %23 %27
-               OpStore %res %28
-         %31 = OpLoad %v4float %res None
-               OpReturnValue %31
+         %21 = OpLoad %v4float %arg_0 None
+         %22 = OpLoad %int %arg_1 None
+         %23 = OpBitcast %uint %22
+         %24 = OpLoad %uint %tint_subgroup_last_id None
+         %25 = OpExtInst %uint %26 UMin %23 %24
+         %27 = OpGroupNonUniformShuffle %v4float %uint_3 %21 %25
+               OpStore %res %27
+         %30 = OpLoad %v4float %res None
+               OpReturnValue %30
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %35
-%tint_subgroup_size = OpFunctionParameter %uint
-         %36 = OpLabel
-         %37 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %37 None
-         %39 = OpFunctionCall %v4float %subgroupShuffle_5dfeab
-         %40 = OpAccessChain %_ptr_StorageBuffer_v4float %1 %uint_0
-               OpStore %40 %39 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %44
-         %45 = OpLabel
-         %46 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %47 = OpFunctionCall %void %fragment_main_inner %46
+%fragment_main = OpFunction %void None %33
+         %34 = OpLabel
+         %35 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %37 = OpISub %uint %35 %uint_1
+               OpStore %tint_subgroup_last_id %37 None
+         %38 = OpFunctionCall %v4float %subgroupShuffle_5dfeab
+         %39 = OpAccessChain %_ptr_StorageBuffer_v4float %1 %uint_0
+               OpStore %39 %38 None
                OpReturn
                OpFunctionEnd
 ;
@@ -94,31 +81,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 48
+; Bound: 42
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %26 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_5dfeab "subgroupShuffle_5dfeab"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
       %float = OpTypeFloat 32
     %v4float = OpTypeVector %float 4
 %prevent_dce_block = OpTypeStruct %v4float
@@ -127,53 +111,44 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v4float
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v4float
 %_ptr_Function_v4float = OpTypePointer Function %v4float
     %float_1 = OpConstant %float 1
-         %17 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
+         %15 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
         %int = OpTypeInt 32 1
 %_ptr_Function_int = OpTypePointer Function %int
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %35 = OpTypeFunction %void %uint
+         %33 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_v4float = OpTypePointer StorageBuffer %v4float
      %uint_0 = OpConstant %uint 0
-         %44 = OpTypeFunction %void
-%subgroupShuffle_5dfeab = OpFunction %v4float None %13
-         %14 = OpLabel
+%subgroupShuffle_5dfeab = OpFunction %v4float None %11
+         %12 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v4float Function
       %arg_1 = OpVariable %_ptr_Function_int Function
         %res = OpVariable %_ptr_Function_v4float Function
-               OpStore %arg_0 %17
+               OpStore %arg_0 %15
                OpStore %arg_1 %int_1
-         %23 = OpLoad %v4float %arg_0 None
-         %24 = OpLoad %int %arg_1 None
-         %25 = OpBitcast %uint %24
-         %26 = OpLoad %uint %tint_subgroup_size_mask None
-         %27 = OpBitwiseAnd %uint %25 %26
-         %28 = OpGroupNonUniformShuffle %v4float %uint_3 %23 %27
-               OpStore %res %28
-         %31 = OpLoad %v4float %res None
-               OpReturnValue %31
+         %21 = OpLoad %v4float %arg_0 None
+         %22 = OpLoad %int %arg_1 None
+         %23 = OpBitcast %uint %22
+         %24 = OpLoad %uint %tint_subgroup_last_id None
+         %25 = OpExtInst %uint %26 UMin %23 %24
+         %27 = OpGroupNonUniformShuffle %v4float %uint_3 %21 %25
+               OpStore %res %27
+         %30 = OpLoad %v4float %res None
+               OpReturnValue %30
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %35
-%tint_subgroup_size = OpFunctionParameter %uint
-         %36 = OpLabel
-         %37 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %37 None
-         %39 = OpFunctionCall %v4float %subgroupShuffle_5dfeab
-         %40 = OpAccessChain %_ptr_StorageBuffer_v4float %1 %uint_0
-               OpStore %40 %39 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %44
-         %45 = OpLabel
-         %46 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %47 = OpFunctionCall %void %compute_main_inner %46
+%compute_main = OpFunction %void None %33
+         %34 = OpLabel
+         %35 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %37 = OpISub %uint %35 %uint_1
+               OpStore %tint_subgroup_last_id %37 None
+         %38 = OpFunctionCall %v4float %subgroupShuffle_5dfeab
+         %39 = OpAccessChain %_ptr_StorageBuffer_v4float %1 %uint_0
+               OpStore %39 %38 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/var/subgroupShuffle/5ef5a2.wgsl.expected.spvasm b/test/tint/builtins/gen/var/subgroupShuffle/5ef5a2.wgsl.expected.spvasm
index 92f25f8..2e00e32 100644
--- a/test/tint/builtins/gen/var/subgroupShuffle/5ef5a2.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/var/subgroupShuffle/5ef5a2.wgsl.expected.spvasm
@@ -4,32 +4,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 43
+; Bound: 37
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %22 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_5ef5a2 "subgroupShuffle_5ef5a2"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
        %uint = OpTypeInt 32 0
      %v2uint = OpTypeVector %uint 2
 %prevent_dce_block = OpTypeStruct %v2uint
@@ -37,50 +33,41 @@
           %1 = OpVariable %_ptr_StorageBuffer_prevent_dce_block StorageBuffer
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %v2uint
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %v2uint
 %_ptr_Function_v2uint = OpTypePointer Function %v2uint
      %uint_1 = OpConstant %uint 1
-         %16 = OpConstantComposite %v2uint %uint_1 %uint_1
+         %14 = OpConstantComposite %v2uint %uint_1 %uint_1
 %_ptr_Function_uint = OpTypePointer Function %uint
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %31 = OpTypeFunction %void %uint
+         %29 = OpTypeFunction %void
 %_ptr_StorageBuffer_v2uint = OpTypePointer StorageBuffer %v2uint
      %uint_0 = OpConstant %uint 0
-         %39 = OpTypeFunction %void
-%subgroupShuffle_5ef5a2 = OpFunction %v2uint None %12
-         %13 = OpLabel
+%subgroupShuffle_5ef5a2 = OpFunction %v2uint None %10
+         %11 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v2uint Function
       %arg_1 = OpVariable %_ptr_Function_uint Function
         %res = OpVariable %_ptr_Function_v2uint Function
-               OpStore %arg_0 %16
+               OpStore %arg_0 %14
                OpStore %arg_1 %uint_1
-         %20 = OpLoad %v2uint %arg_0 None
-         %21 = OpLoad %uint %arg_1 None
-         %22 = OpLoad %uint %tint_subgroup_size_mask None
-         %23 = OpBitwiseAnd %uint %21 %22
-         %24 = OpGroupNonUniformShuffle %v2uint %uint_3 %20 %23
-               OpStore %res %24
-         %27 = OpLoad %v2uint %res None
-               OpReturnValue %27
+         %18 = OpLoad %v2uint %arg_0 None
+         %19 = OpLoad %uint %arg_1 None
+         %20 = OpLoad %uint %tint_subgroup_last_id None
+         %21 = OpExtInst %uint %22 UMin %19 %20
+         %23 = OpGroupNonUniformShuffle %v2uint %uint_3 %18 %21
+               OpStore %res %23
+         %26 = OpLoad %v2uint %res None
+               OpReturnValue %26
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %31
-%tint_subgroup_size = OpFunctionParameter %uint
-         %32 = OpLabel
-         %33 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %33 None
-         %34 = OpFunctionCall %v2uint %subgroupShuffle_5ef5a2
-         %35 = OpAccessChain %_ptr_StorageBuffer_v2uint %1 %uint_0
-               OpStore %35 %34 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %39
-         %40 = OpLabel
-         %41 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %42 = OpFunctionCall %void %fragment_main_inner %41
+%fragment_main = OpFunction %void None %29
+         %30 = OpLabel
+         %31 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %32 = OpISub %uint %31 %uint_1
+               OpStore %tint_subgroup_last_id %32 None
+         %33 = OpFunctionCall %v2uint %subgroupShuffle_5ef5a2
+         %34 = OpAccessChain %_ptr_StorageBuffer_v2uint %1 %uint_0
+               OpStore %34 %33 None
                OpReturn
                OpFunctionEnd
 ;
@@ -89,31 +76,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 43
+; Bound: 37
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %22 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_5ef5a2 "subgroupShuffle_5ef5a2"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
        %uint = OpTypeInt 32 0
      %v2uint = OpTypeVector %uint 2
 %prevent_dce_block = OpTypeStruct %v2uint
@@ -121,49 +105,40 @@
           %1 = OpVariable %_ptr_StorageBuffer_prevent_dce_block StorageBuffer
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %v2uint
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %v2uint
 %_ptr_Function_v2uint = OpTypePointer Function %v2uint
      %uint_1 = OpConstant %uint 1
-         %16 = OpConstantComposite %v2uint %uint_1 %uint_1
+         %14 = OpConstantComposite %v2uint %uint_1 %uint_1
 %_ptr_Function_uint = OpTypePointer Function %uint
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %31 = OpTypeFunction %void %uint
+         %29 = OpTypeFunction %void
 %_ptr_StorageBuffer_v2uint = OpTypePointer StorageBuffer %v2uint
      %uint_0 = OpConstant %uint 0
-         %39 = OpTypeFunction %void
-%subgroupShuffle_5ef5a2 = OpFunction %v2uint None %12
-         %13 = OpLabel
+%subgroupShuffle_5ef5a2 = OpFunction %v2uint None %10
+         %11 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v2uint Function
       %arg_1 = OpVariable %_ptr_Function_uint Function
         %res = OpVariable %_ptr_Function_v2uint Function
-               OpStore %arg_0 %16
+               OpStore %arg_0 %14
                OpStore %arg_1 %uint_1
-         %20 = OpLoad %v2uint %arg_0 None
-         %21 = OpLoad %uint %arg_1 None
-         %22 = OpLoad %uint %tint_subgroup_size_mask None
-         %23 = OpBitwiseAnd %uint %21 %22
-         %24 = OpGroupNonUniformShuffle %v2uint %uint_3 %20 %23
-               OpStore %res %24
-         %27 = OpLoad %v2uint %res None
-               OpReturnValue %27
+         %18 = OpLoad %v2uint %arg_0 None
+         %19 = OpLoad %uint %arg_1 None
+         %20 = OpLoad %uint %tint_subgroup_last_id None
+         %21 = OpExtInst %uint %22 UMin %19 %20
+         %23 = OpGroupNonUniformShuffle %v2uint %uint_3 %18 %21
+               OpStore %res %23
+         %26 = OpLoad %v2uint %res None
+               OpReturnValue %26
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %31
-%tint_subgroup_size = OpFunctionParameter %uint
-         %32 = OpLabel
-         %33 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %33 None
-         %34 = OpFunctionCall %v2uint %subgroupShuffle_5ef5a2
-         %35 = OpAccessChain %_ptr_StorageBuffer_v2uint %1 %uint_0
-               OpStore %35 %34 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %39
-         %40 = OpLabel
-         %41 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %42 = OpFunctionCall %void %compute_main_inner %41
+%compute_main = OpFunction %void None %29
+         %30 = OpLabel
+         %31 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %32 = OpISub %uint %31 %uint_1
+               OpStore %tint_subgroup_last_id %32 None
+         %33 = OpFunctionCall %v2uint %subgroupShuffle_5ef5a2
+         %34 = OpAccessChain %_ptr_StorageBuffer_v2uint %1 %uint_0
+               OpStore %34 %33 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/var/subgroupShuffle/647034.wgsl.expected.spvasm b/test/tint/builtins/gen/var/subgroupShuffle/647034.wgsl.expected.spvasm
index 1f862c7..d01d644 100644
--- a/test/tint/builtins/gen/var/subgroupShuffle/647034.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/var/subgroupShuffle/647034.wgsl.expected.spvasm
@@ -4,34 +4,30 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 48
+; Bound: 42
 ; Schema: 0
                OpCapability Shader
                OpCapability Float16
                OpCapability StorageBuffer16BitAccess
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %26 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_647034 "subgroupShuffle_647034"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
        %half = OpTypeFloat 16
      %v4half = OpTypeVector %half 4
 %prevent_dce_block = OpTypeStruct %v4half
@@ -40,54 +36,45 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v4half
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v4half
 %_ptr_Function_v4half = OpTypePointer Function %v4half
 %half_0x1p_0 = OpConstant %half 0x1p+0
-         %17 = OpConstantComposite %v4half %half_0x1p_0 %half_0x1p_0 %half_0x1p_0 %half_0x1p_0
+         %15 = OpConstantComposite %v4half %half_0x1p_0 %half_0x1p_0 %half_0x1p_0 %half_0x1p_0
         %int = OpTypeInt 32 1
 %_ptr_Function_int = OpTypePointer Function %int
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %35 = OpTypeFunction %void %uint
+         %33 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_v4half = OpTypePointer StorageBuffer %v4half
      %uint_0 = OpConstant %uint 0
-         %44 = OpTypeFunction %void
-%subgroupShuffle_647034 = OpFunction %v4half None %13
-         %14 = OpLabel
+%subgroupShuffle_647034 = OpFunction %v4half None %11
+         %12 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v4half Function
       %arg_1 = OpVariable %_ptr_Function_int Function
         %res = OpVariable %_ptr_Function_v4half Function
-               OpStore %arg_0 %17
+               OpStore %arg_0 %15
                OpStore %arg_1 %int_1
-         %23 = OpLoad %v4half %arg_0 None
-         %24 = OpLoad %int %arg_1 None
-         %25 = OpBitcast %uint %24
-         %26 = OpLoad %uint %tint_subgroup_size_mask None
-         %27 = OpBitwiseAnd %uint %25 %26
-         %28 = OpGroupNonUniformShuffle %v4half %uint_3 %23 %27
-               OpStore %res %28
-         %31 = OpLoad %v4half %res None
-               OpReturnValue %31
+         %21 = OpLoad %v4half %arg_0 None
+         %22 = OpLoad %int %arg_1 None
+         %23 = OpBitcast %uint %22
+         %24 = OpLoad %uint %tint_subgroup_last_id None
+         %25 = OpExtInst %uint %26 UMin %23 %24
+         %27 = OpGroupNonUniformShuffle %v4half %uint_3 %21 %25
+               OpStore %res %27
+         %30 = OpLoad %v4half %res None
+               OpReturnValue %30
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %35
-%tint_subgroup_size = OpFunctionParameter %uint
-         %36 = OpLabel
-         %37 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %37 None
-         %39 = OpFunctionCall %v4half %subgroupShuffle_647034
-         %40 = OpAccessChain %_ptr_StorageBuffer_v4half %1 %uint_0
-               OpStore %40 %39 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %44
-         %45 = OpLabel
-         %46 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %47 = OpFunctionCall %void %fragment_main_inner %46
+%fragment_main = OpFunction %void None %33
+         %34 = OpLabel
+         %35 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %37 = OpISub %uint %35 %uint_1
+               OpStore %tint_subgroup_last_id %37 None
+         %38 = OpFunctionCall %v4half %subgroupShuffle_647034
+         %39 = OpAccessChain %_ptr_StorageBuffer_v4half %1 %uint_0
+               OpStore %39 %38 None
                OpReturn
                OpFunctionEnd
 ;
@@ -96,33 +83,30 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 48
+; Bound: 42
 ; Schema: 0
                OpCapability Shader
                OpCapability Float16
                OpCapability StorageBuffer16BitAccess
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %26 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_647034 "subgroupShuffle_647034"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
        %half = OpTypeFloat 16
      %v4half = OpTypeVector %half 4
 %prevent_dce_block = OpTypeStruct %v4half
@@ -131,53 +115,44 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v4half
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v4half
 %_ptr_Function_v4half = OpTypePointer Function %v4half
 %half_0x1p_0 = OpConstant %half 0x1p+0
-         %17 = OpConstantComposite %v4half %half_0x1p_0 %half_0x1p_0 %half_0x1p_0 %half_0x1p_0
+         %15 = OpConstantComposite %v4half %half_0x1p_0 %half_0x1p_0 %half_0x1p_0 %half_0x1p_0
         %int = OpTypeInt 32 1
 %_ptr_Function_int = OpTypePointer Function %int
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %35 = OpTypeFunction %void %uint
+         %33 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_v4half = OpTypePointer StorageBuffer %v4half
      %uint_0 = OpConstant %uint 0
-         %44 = OpTypeFunction %void
-%subgroupShuffle_647034 = OpFunction %v4half None %13
-         %14 = OpLabel
+%subgroupShuffle_647034 = OpFunction %v4half None %11
+         %12 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v4half Function
       %arg_1 = OpVariable %_ptr_Function_int Function
         %res = OpVariable %_ptr_Function_v4half Function
-               OpStore %arg_0 %17
+               OpStore %arg_0 %15
                OpStore %arg_1 %int_1
-         %23 = OpLoad %v4half %arg_0 None
-         %24 = OpLoad %int %arg_1 None
-         %25 = OpBitcast %uint %24
-         %26 = OpLoad %uint %tint_subgroup_size_mask None
-         %27 = OpBitwiseAnd %uint %25 %26
-         %28 = OpGroupNonUniformShuffle %v4half %uint_3 %23 %27
-               OpStore %res %28
-         %31 = OpLoad %v4half %res None
-               OpReturnValue %31
+         %21 = OpLoad %v4half %arg_0 None
+         %22 = OpLoad %int %arg_1 None
+         %23 = OpBitcast %uint %22
+         %24 = OpLoad %uint %tint_subgroup_last_id None
+         %25 = OpExtInst %uint %26 UMin %23 %24
+         %27 = OpGroupNonUniformShuffle %v4half %uint_3 %21 %25
+               OpStore %res %27
+         %30 = OpLoad %v4half %res None
+               OpReturnValue %30
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %35
-%tint_subgroup_size = OpFunctionParameter %uint
-         %36 = OpLabel
-         %37 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %37 None
-         %39 = OpFunctionCall %v4half %subgroupShuffle_647034
-         %40 = OpAccessChain %_ptr_StorageBuffer_v4half %1 %uint_0
-               OpStore %40 %39 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %44
-         %45 = OpLabel
-         %46 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %47 = OpFunctionCall %void %compute_main_inner %46
+%compute_main = OpFunction %void None %33
+         %34 = OpLabel
+         %35 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %37 = OpISub %uint %35 %uint_1
+               OpStore %tint_subgroup_last_id %37 None
+         %38 = OpFunctionCall %v4half %subgroupShuffle_647034
+         %39 = OpAccessChain %_ptr_StorageBuffer_v4half %1 %uint_0
+               OpStore %39 %38 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/var/subgroupShuffle/7ba2d5.wgsl.expected.spvasm b/test/tint/builtins/gen/var/subgroupShuffle/7ba2d5.wgsl.expected.spvasm
index 306eb35..24cb54e 100644
--- a/test/tint/builtins/gen/var/subgroupShuffle/7ba2d5.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/var/subgroupShuffle/7ba2d5.wgsl.expected.spvasm
@@ -4,34 +4,30 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 45
+; Bound: 39
 ; Schema: 0
                OpCapability Shader
                OpCapability Float16
                OpCapability StorageBuffer16BitAccess
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %24 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_7ba2d5 "subgroupShuffle_7ba2d5"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
        %half = OpTypeFloat 16
      %v4half = OpTypeVector %half 4
 %prevent_dce_block = OpTypeStruct %v4half
@@ -40,51 +36,42 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v4half
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v4half
 %_ptr_Function_v4half = OpTypePointer Function %v4half
 %half_0x1p_0 = OpConstant %half 0x1p+0
-         %17 = OpConstantComposite %v4half %half_0x1p_0 %half_0x1p_0 %half_0x1p_0 %half_0x1p_0
+         %15 = OpConstantComposite %v4half %half_0x1p_0 %half_0x1p_0 %half_0x1p_0 %half_0x1p_0
 %_ptr_Function_uint = OpTypePointer Function %uint
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %33 = OpTypeFunction %void %uint
+         %31 = OpTypeFunction %void
 %_ptr_StorageBuffer_v4half = OpTypePointer StorageBuffer %v4half
      %uint_0 = OpConstant %uint 0
-         %41 = OpTypeFunction %void
-%subgroupShuffle_7ba2d5 = OpFunction %v4half None %13
-         %14 = OpLabel
+%subgroupShuffle_7ba2d5 = OpFunction %v4half None %11
+         %12 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v4half Function
       %arg_1 = OpVariable %_ptr_Function_uint Function
         %res = OpVariable %_ptr_Function_v4half Function
-               OpStore %arg_0 %17
+               OpStore %arg_0 %15
                OpStore %arg_1 %uint_1
-         %22 = OpLoad %v4half %arg_0 None
-         %23 = OpLoad %uint %arg_1 None
-         %24 = OpLoad %uint %tint_subgroup_size_mask None
-         %25 = OpBitwiseAnd %uint %23 %24
-         %26 = OpGroupNonUniformShuffle %v4half %uint_3 %22 %25
-               OpStore %res %26
-         %29 = OpLoad %v4half %res None
-               OpReturnValue %29
+         %20 = OpLoad %v4half %arg_0 None
+         %21 = OpLoad %uint %arg_1 None
+         %22 = OpLoad %uint %tint_subgroup_last_id None
+         %23 = OpExtInst %uint %24 UMin %21 %22
+         %25 = OpGroupNonUniformShuffle %v4half %uint_3 %20 %23
+               OpStore %res %25
+         %28 = OpLoad %v4half %res None
+               OpReturnValue %28
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %33
-%tint_subgroup_size = OpFunctionParameter %uint
-         %34 = OpLabel
-         %35 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %35 None
-         %36 = OpFunctionCall %v4half %subgroupShuffle_7ba2d5
-         %37 = OpAccessChain %_ptr_StorageBuffer_v4half %1 %uint_0
-               OpStore %37 %36 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %41
-         %42 = OpLabel
-         %43 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %44 = OpFunctionCall %void %fragment_main_inner %43
+%fragment_main = OpFunction %void None %31
+         %32 = OpLabel
+         %33 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %34 = OpISub %uint %33 %uint_1
+               OpStore %tint_subgroup_last_id %34 None
+         %35 = OpFunctionCall %v4half %subgroupShuffle_7ba2d5
+         %36 = OpAccessChain %_ptr_StorageBuffer_v4half %1 %uint_0
+               OpStore %36 %35 None
                OpReturn
                OpFunctionEnd
 ;
@@ -93,33 +80,30 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 45
+; Bound: 39
 ; Schema: 0
                OpCapability Shader
                OpCapability Float16
                OpCapability StorageBuffer16BitAccess
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %24 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_7ba2d5 "subgroupShuffle_7ba2d5"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
        %half = OpTypeFloat 16
      %v4half = OpTypeVector %half 4
 %prevent_dce_block = OpTypeStruct %v4half
@@ -128,50 +112,41 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v4half
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v4half
 %_ptr_Function_v4half = OpTypePointer Function %v4half
 %half_0x1p_0 = OpConstant %half 0x1p+0
-         %17 = OpConstantComposite %v4half %half_0x1p_0 %half_0x1p_0 %half_0x1p_0 %half_0x1p_0
+         %15 = OpConstantComposite %v4half %half_0x1p_0 %half_0x1p_0 %half_0x1p_0 %half_0x1p_0
 %_ptr_Function_uint = OpTypePointer Function %uint
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %33 = OpTypeFunction %void %uint
+         %31 = OpTypeFunction %void
 %_ptr_StorageBuffer_v4half = OpTypePointer StorageBuffer %v4half
      %uint_0 = OpConstant %uint 0
-         %41 = OpTypeFunction %void
-%subgroupShuffle_7ba2d5 = OpFunction %v4half None %13
-         %14 = OpLabel
+%subgroupShuffle_7ba2d5 = OpFunction %v4half None %11
+         %12 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v4half Function
       %arg_1 = OpVariable %_ptr_Function_uint Function
         %res = OpVariable %_ptr_Function_v4half Function
-               OpStore %arg_0 %17
+               OpStore %arg_0 %15
                OpStore %arg_1 %uint_1
-         %22 = OpLoad %v4half %arg_0 None
-         %23 = OpLoad %uint %arg_1 None
-         %24 = OpLoad %uint %tint_subgroup_size_mask None
-         %25 = OpBitwiseAnd %uint %23 %24
-         %26 = OpGroupNonUniformShuffle %v4half %uint_3 %22 %25
-               OpStore %res %26
-         %29 = OpLoad %v4half %res None
-               OpReturnValue %29
+         %20 = OpLoad %v4half %arg_0 None
+         %21 = OpLoad %uint %arg_1 None
+         %22 = OpLoad %uint %tint_subgroup_last_id None
+         %23 = OpExtInst %uint %24 UMin %21 %22
+         %25 = OpGroupNonUniformShuffle %v4half %uint_3 %20 %23
+               OpStore %res %25
+         %28 = OpLoad %v4half %res None
+               OpReturnValue %28
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %33
-%tint_subgroup_size = OpFunctionParameter %uint
-         %34 = OpLabel
-         %35 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %35 None
-         %36 = OpFunctionCall %v4half %subgroupShuffle_7ba2d5
-         %37 = OpAccessChain %_ptr_StorageBuffer_v4half %1 %uint_0
-               OpStore %37 %36 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %41
-         %42 = OpLabel
-         %43 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %44 = OpFunctionCall %void %compute_main_inner %43
+%compute_main = OpFunction %void None %31
+         %32 = OpLabel
+         %33 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %34 = OpISub %uint %33 %uint_1
+               OpStore %tint_subgroup_last_id %34 None
+         %35 = OpFunctionCall %v4half %subgroupShuffle_7ba2d5
+         %36 = OpAccessChain %_ptr_StorageBuffer_v4half %1 %uint_0
+               OpStore %36 %35 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/var/subgroupShuffle/7c5d64.wgsl.expected.spvasm b/test/tint/builtins/gen/var/subgroupShuffle/7c5d64.wgsl.expected.spvasm
index eae3589..20c04f2 100644
--- a/test/tint/builtins/gen/var/subgroupShuffle/7c5d64.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/var/subgroupShuffle/7c5d64.wgsl.expected.spvasm
@@ -4,32 +4,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 48
+; Bound: 42
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %26 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_7c5d64 "subgroupShuffle_7c5d64"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
       %float = OpTypeFloat 32
     %v3float = OpTypeVector %float 3
 %prevent_dce_block = OpTypeStruct %v3float
@@ -38,54 +34,45 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v3float
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v3float
 %_ptr_Function_v3float = OpTypePointer Function %v3float
     %float_1 = OpConstant %float 1
-         %17 = OpConstantComposite %v3float %float_1 %float_1 %float_1
+         %15 = OpConstantComposite %v3float %float_1 %float_1 %float_1
         %int = OpTypeInt 32 1
 %_ptr_Function_int = OpTypePointer Function %int
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %35 = OpTypeFunction %void %uint
+         %33 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_v3float = OpTypePointer StorageBuffer %v3float
      %uint_0 = OpConstant %uint 0
-         %44 = OpTypeFunction %void
-%subgroupShuffle_7c5d64 = OpFunction %v3float None %13
-         %14 = OpLabel
+%subgroupShuffle_7c5d64 = OpFunction %v3float None %11
+         %12 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v3float Function
       %arg_1 = OpVariable %_ptr_Function_int Function
         %res = OpVariable %_ptr_Function_v3float Function
-               OpStore %arg_0 %17
+               OpStore %arg_0 %15
                OpStore %arg_1 %int_1
-         %23 = OpLoad %v3float %arg_0 None
-         %24 = OpLoad %int %arg_1 None
-         %25 = OpBitcast %uint %24
-         %26 = OpLoad %uint %tint_subgroup_size_mask None
-         %27 = OpBitwiseAnd %uint %25 %26
-         %28 = OpGroupNonUniformShuffle %v3float %uint_3 %23 %27
-               OpStore %res %28
-         %31 = OpLoad %v3float %res None
-               OpReturnValue %31
+         %21 = OpLoad %v3float %arg_0 None
+         %22 = OpLoad %int %arg_1 None
+         %23 = OpBitcast %uint %22
+         %24 = OpLoad %uint %tint_subgroup_last_id None
+         %25 = OpExtInst %uint %26 UMin %23 %24
+         %27 = OpGroupNonUniformShuffle %v3float %uint_3 %21 %25
+               OpStore %res %27
+         %30 = OpLoad %v3float %res None
+               OpReturnValue %30
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %35
-%tint_subgroup_size = OpFunctionParameter %uint
-         %36 = OpLabel
-         %37 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %37 None
-         %39 = OpFunctionCall %v3float %subgroupShuffle_7c5d64
-         %40 = OpAccessChain %_ptr_StorageBuffer_v3float %1 %uint_0
-               OpStore %40 %39 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %44
-         %45 = OpLabel
-         %46 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %47 = OpFunctionCall %void %fragment_main_inner %46
+%fragment_main = OpFunction %void None %33
+         %34 = OpLabel
+         %35 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %37 = OpISub %uint %35 %uint_1
+               OpStore %tint_subgroup_last_id %37 None
+         %38 = OpFunctionCall %v3float %subgroupShuffle_7c5d64
+         %39 = OpAccessChain %_ptr_StorageBuffer_v3float %1 %uint_0
+               OpStore %39 %38 None
                OpReturn
                OpFunctionEnd
 ;
@@ -94,31 +81,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 48
+; Bound: 42
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %26 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_7c5d64 "subgroupShuffle_7c5d64"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
       %float = OpTypeFloat 32
     %v3float = OpTypeVector %float 3
 %prevent_dce_block = OpTypeStruct %v3float
@@ -127,53 +111,44 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v3float
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v3float
 %_ptr_Function_v3float = OpTypePointer Function %v3float
     %float_1 = OpConstant %float 1
-         %17 = OpConstantComposite %v3float %float_1 %float_1 %float_1
+         %15 = OpConstantComposite %v3float %float_1 %float_1 %float_1
         %int = OpTypeInt 32 1
 %_ptr_Function_int = OpTypePointer Function %int
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %35 = OpTypeFunction %void %uint
+         %33 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_v3float = OpTypePointer StorageBuffer %v3float
      %uint_0 = OpConstant %uint 0
-         %44 = OpTypeFunction %void
-%subgroupShuffle_7c5d64 = OpFunction %v3float None %13
-         %14 = OpLabel
+%subgroupShuffle_7c5d64 = OpFunction %v3float None %11
+         %12 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v3float Function
       %arg_1 = OpVariable %_ptr_Function_int Function
         %res = OpVariable %_ptr_Function_v3float Function
-               OpStore %arg_0 %17
+               OpStore %arg_0 %15
                OpStore %arg_1 %int_1
-         %23 = OpLoad %v3float %arg_0 None
-         %24 = OpLoad %int %arg_1 None
-         %25 = OpBitcast %uint %24
-         %26 = OpLoad %uint %tint_subgroup_size_mask None
-         %27 = OpBitwiseAnd %uint %25 %26
-         %28 = OpGroupNonUniformShuffle %v3float %uint_3 %23 %27
-               OpStore %res %28
-         %31 = OpLoad %v3float %res None
-               OpReturnValue %31
+         %21 = OpLoad %v3float %arg_0 None
+         %22 = OpLoad %int %arg_1 None
+         %23 = OpBitcast %uint %22
+         %24 = OpLoad %uint %tint_subgroup_last_id None
+         %25 = OpExtInst %uint %26 UMin %23 %24
+         %27 = OpGroupNonUniformShuffle %v3float %uint_3 %21 %25
+               OpStore %res %27
+         %30 = OpLoad %v3float %res None
+               OpReturnValue %30
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %35
-%tint_subgroup_size = OpFunctionParameter %uint
-         %36 = OpLabel
-         %37 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %37 None
-         %39 = OpFunctionCall %v3float %subgroupShuffle_7c5d64
-         %40 = OpAccessChain %_ptr_StorageBuffer_v3float %1 %uint_0
-               OpStore %40 %39 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %44
-         %45 = OpLabel
-         %46 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %47 = OpFunctionCall %void %compute_main_inner %46
+%compute_main = OpFunction %void None %33
+         %34 = OpLabel
+         %35 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %37 = OpISub %uint %35 %uint_1
+               OpStore %tint_subgroup_last_id %37 None
+         %38 = OpFunctionCall %v3float %subgroupShuffle_7c5d64
+         %39 = OpAccessChain %_ptr_StorageBuffer_v3float %1 %uint_0
+               OpStore %39 %38 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/var/subgroupShuffle/7d7b1e.wgsl.expected.spvasm b/test/tint/builtins/gen/var/subgroupShuffle/7d7b1e.wgsl.expected.spvasm
index 646ddf3..505a446 100644
--- a/test/tint/builtins/gen/var/subgroupShuffle/7d7b1e.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/var/subgroupShuffle/7d7b1e.wgsl.expected.spvasm
@@ -4,34 +4,30 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 43
+; Bound: 37
 ; Schema: 0
                OpCapability Shader
                OpCapability Float16
                OpCapability StorageBuffer16BitAccess
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %22 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_7d7b1e "subgroupShuffle_7d7b1e"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
        %half = OpTypeFloat 16
 %prevent_dce_block = OpTypeStruct %half
 %_ptr_StorageBuffer_prevent_dce_block = OpTypePointer StorageBuffer %prevent_dce_block
@@ -39,50 +35,41 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %half
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %half
 %_ptr_Function_half = OpTypePointer Function %half
 %half_0x1p_0 = OpConstant %half 0x1p+0
 %_ptr_Function_uint = OpTypePointer Function %uint
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %31 = OpTypeFunction %void %uint
+         %29 = OpTypeFunction %void
 %_ptr_StorageBuffer_half = OpTypePointer StorageBuffer %half
      %uint_0 = OpConstant %uint 0
-         %39 = OpTypeFunction %void
-%subgroupShuffle_7d7b1e = OpFunction %half None %12
-         %13 = OpLabel
+%subgroupShuffle_7d7b1e = OpFunction %half None %10
+         %11 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_half Function
       %arg_1 = OpVariable %_ptr_Function_uint Function
         %res = OpVariable %_ptr_Function_half Function
                OpStore %arg_0 %half_0x1p_0
                OpStore %arg_1 %uint_1
-         %20 = OpLoad %half %arg_0 None
-         %21 = OpLoad %uint %arg_1 None
-         %22 = OpLoad %uint %tint_subgroup_size_mask None
-         %23 = OpBitwiseAnd %uint %21 %22
-         %24 = OpGroupNonUniformShuffle %half %uint_3 %20 %23
-               OpStore %res %24
-         %27 = OpLoad %half %res None
-               OpReturnValue %27
+         %18 = OpLoad %half %arg_0 None
+         %19 = OpLoad %uint %arg_1 None
+         %20 = OpLoad %uint %tint_subgroup_last_id None
+         %21 = OpExtInst %uint %22 UMin %19 %20
+         %23 = OpGroupNonUniformShuffle %half %uint_3 %18 %21
+               OpStore %res %23
+         %26 = OpLoad %half %res None
+               OpReturnValue %26
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %31
-%tint_subgroup_size = OpFunctionParameter %uint
-         %32 = OpLabel
-         %33 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %33 None
-         %34 = OpFunctionCall %half %subgroupShuffle_7d7b1e
-         %35 = OpAccessChain %_ptr_StorageBuffer_half %1 %uint_0
-               OpStore %35 %34 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %39
-         %40 = OpLabel
-         %41 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %42 = OpFunctionCall %void %fragment_main_inner %41
+%fragment_main = OpFunction %void None %29
+         %30 = OpLabel
+         %31 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %32 = OpISub %uint %31 %uint_1
+               OpStore %tint_subgroup_last_id %32 None
+         %33 = OpFunctionCall %half %subgroupShuffle_7d7b1e
+         %34 = OpAccessChain %_ptr_StorageBuffer_half %1 %uint_0
+               OpStore %34 %33 None
                OpReturn
                OpFunctionEnd
 ;
@@ -91,33 +78,30 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 43
+; Bound: 37
 ; Schema: 0
                OpCapability Shader
                OpCapability Float16
                OpCapability StorageBuffer16BitAccess
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %22 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_7d7b1e "subgroupShuffle_7d7b1e"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
        %half = OpTypeFloat 16
 %prevent_dce_block = OpTypeStruct %half
 %_ptr_StorageBuffer_prevent_dce_block = OpTypePointer StorageBuffer %prevent_dce_block
@@ -125,49 +109,40 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %half
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %half
 %_ptr_Function_half = OpTypePointer Function %half
 %half_0x1p_0 = OpConstant %half 0x1p+0
 %_ptr_Function_uint = OpTypePointer Function %uint
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %31 = OpTypeFunction %void %uint
+         %29 = OpTypeFunction %void
 %_ptr_StorageBuffer_half = OpTypePointer StorageBuffer %half
      %uint_0 = OpConstant %uint 0
-         %39 = OpTypeFunction %void
-%subgroupShuffle_7d7b1e = OpFunction %half None %12
-         %13 = OpLabel
+%subgroupShuffle_7d7b1e = OpFunction %half None %10
+         %11 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_half Function
       %arg_1 = OpVariable %_ptr_Function_uint Function
         %res = OpVariable %_ptr_Function_half Function
                OpStore %arg_0 %half_0x1p_0
                OpStore %arg_1 %uint_1
-         %20 = OpLoad %half %arg_0 None
-         %21 = OpLoad %uint %arg_1 None
-         %22 = OpLoad %uint %tint_subgroup_size_mask None
-         %23 = OpBitwiseAnd %uint %21 %22
-         %24 = OpGroupNonUniformShuffle %half %uint_3 %20 %23
-               OpStore %res %24
-         %27 = OpLoad %half %res None
-               OpReturnValue %27
+         %18 = OpLoad %half %arg_0 None
+         %19 = OpLoad %uint %arg_1 None
+         %20 = OpLoad %uint %tint_subgroup_last_id None
+         %21 = OpExtInst %uint %22 UMin %19 %20
+         %23 = OpGroupNonUniformShuffle %half %uint_3 %18 %21
+               OpStore %res %23
+         %26 = OpLoad %half %res None
+               OpReturnValue %26
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %31
-%tint_subgroup_size = OpFunctionParameter %uint
-         %32 = OpLabel
-         %33 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %33 None
-         %34 = OpFunctionCall %half %subgroupShuffle_7d7b1e
-         %35 = OpAccessChain %_ptr_StorageBuffer_half %1 %uint_0
-               OpStore %35 %34 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %39
-         %40 = OpLabel
-         %41 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %42 = OpFunctionCall %void %compute_main_inner %41
+%compute_main = OpFunction %void None %29
+         %30 = OpLabel
+         %31 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %32 = OpISub %uint %31 %uint_1
+               OpStore %tint_subgroup_last_id %32 None
+         %33 = OpFunctionCall %half %subgroupShuffle_7d7b1e
+         %34 = OpAccessChain %_ptr_StorageBuffer_half %1 %uint_0
+               OpStore %34 %33 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/var/subgroupShuffle/821df9.wgsl.expected.spvasm b/test/tint/builtins/gen/var/subgroupShuffle/821df9.wgsl.expected.spvasm
index 418fbf2..edda6a0 100644
--- a/test/tint/builtins/gen/var/subgroupShuffle/821df9.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/var/subgroupShuffle/821df9.wgsl.expected.spvasm
@@ -4,34 +4,30 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 48
+; Bound: 42
 ; Schema: 0
                OpCapability Shader
                OpCapability Float16
                OpCapability StorageBuffer16BitAccess
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %26 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_821df9 "subgroupShuffle_821df9"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
        %half = OpTypeFloat 16
      %v3half = OpTypeVector %half 3
 %prevent_dce_block = OpTypeStruct %v3half
@@ -40,54 +36,45 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v3half
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v3half
 %_ptr_Function_v3half = OpTypePointer Function %v3half
 %half_0x1p_0 = OpConstant %half 0x1p+0
-         %17 = OpConstantComposite %v3half %half_0x1p_0 %half_0x1p_0 %half_0x1p_0
+         %15 = OpConstantComposite %v3half %half_0x1p_0 %half_0x1p_0 %half_0x1p_0
         %int = OpTypeInt 32 1
 %_ptr_Function_int = OpTypePointer Function %int
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %35 = OpTypeFunction %void %uint
+         %33 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_v3half = OpTypePointer StorageBuffer %v3half
      %uint_0 = OpConstant %uint 0
-         %44 = OpTypeFunction %void
-%subgroupShuffle_821df9 = OpFunction %v3half None %13
-         %14 = OpLabel
+%subgroupShuffle_821df9 = OpFunction %v3half None %11
+         %12 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v3half Function
       %arg_1 = OpVariable %_ptr_Function_int Function
         %res = OpVariable %_ptr_Function_v3half Function
-               OpStore %arg_0 %17
+               OpStore %arg_0 %15
                OpStore %arg_1 %int_1
-         %23 = OpLoad %v3half %arg_0 None
-         %24 = OpLoad %int %arg_1 None
-         %25 = OpBitcast %uint %24
-         %26 = OpLoad %uint %tint_subgroup_size_mask None
-         %27 = OpBitwiseAnd %uint %25 %26
-         %28 = OpGroupNonUniformShuffle %v3half %uint_3 %23 %27
-               OpStore %res %28
-         %31 = OpLoad %v3half %res None
-               OpReturnValue %31
+         %21 = OpLoad %v3half %arg_0 None
+         %22 = OpLoad %int %arg_1 None
+         %23 = OpBitcast %uint %22
+         %24 = OpLoad %uint %tint_subgroup_last_id None
+         %25 = OpExtInst %uint %26 UMin %23 %24
+         %27 = OpGroupNonUniformShuffle %v3half %uint_3 %21 %25
+               OpStore %res %27
+         %30 = OpLoad %v3half %res None
+               OpReturnValue %30
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %35
-%tint_subgroup_size = OpFunctionParameter %uint
-         %36 = OpLabel
-         %37 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %37 None
-         %39 = OpFunctionCall %v3half %subgroupShuffle_821df9
-         %40 = OpAccessChain %_ptr_StorageBuffer_v3half %1 %uint_0
-               OpStore %40 %39 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %44
-         %45 = OpLabel
-         %46 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %47 = OpFunctionCall %void %fragment_main_inner %46
+%fragment_main = OpFunction %void None %33
+         %34 = OpLabel
+         %35 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %37 = OpISub %uint %35 %uint_1
+               OpStore %tint_subgroup_last_id %37 None
+         %38 = OpFunctionCall %v3half %subgroupShuffle_821df9
+         %39 = OpAccessChain %_ptr_StorageBuffer_v3half %1 %uint_0
+               OpStore %39 %38 None
                OpReturn
                OpFunctionEnd
 ;
@@ -96,33 +83,30 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 48
+; Bound: 42
 ; Schema: 0
                OpCapability Shader
                OpCapability Float16
                OpCapability StorageBuffer16BitAccess
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %26 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_821df9 "subgroupShuffle_821df9"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
        %half = OpTypeFloat 16
      %v3half = OpTypeVector %half 3
 %prevent_dce_block = OpTypeStruct %v3half
@@ -131,53 +115,44 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v3half
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v3half
 %_ptr_Function_v3half = OpTypePointer Function %v3half
 %half_0x1p_0 = OpConstant %half 0x1p+0
-         %17 = OpConstantComposite %v3half %half_0x1p_0 %half_0x1p_0 %half_0x1p_0
+         %15 = OpConstantComposite %v3half %half_0x1p_0 %half_0x1p_0 %half_0x1p_0
         %int = OpTypeInt 32 1
 %_ptr_Function_int = OpTypePointer Function %int
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %35 = OpTypeFunction %void %uint
+         %33 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_v3half = OpTypePointer StorageBuffer %v3half
      %uint_0 = OpConstant %uint 0
-         %44 = OpTypeFunction %void
-%subgroupShuffle_821df9 = OpFunction %v3half None %13
-         %14 = OpLabel
+%subgroupShuffle_821df9 = OpFunction %v3half None %11
+         %12 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v3half Function
       %arg_1 = OpVariable %_ptr_Function_int Function
         %res = OpVariable %_ptr_Function_v3half Function
-               OpStore %arg_0 %17
+               OpStore %arg_0 %15
                OpStore %arg_1 %int_1
-         %23 = OpLoad %v3half %arg_0 None
-         %24 = OpLoad %int %arg_1 None
-         %25 = OpBitcast %uint %24
-         %26 = OpLoad %uint %tint_subgroup_size_mask None
-         %27 = OpBitwiseAnd %uint %25 %26
-         %28 = OpGroupNonUniformShuffle %v3half %uint_3 %23 %27
-               OpStore %res %28
-         %31 = OpLoad %v3half %res None
-               OpReturnValue %31
+         %21 = OpLoad %v3half %arg_0 None
+         %22 = OpLoad %int %arg_1 None
+         %23 = OpBitcast %uint %22
+         %24 = OpLoad %uint %tint_subgroup_last_id None
+         %25 = OpExtInst %uint %26 UMin %23 %24
+         %27 = OpGroupNonUniformShuffle %v3half %uint_3 %21 %25
+               OpStore %res %27
+         %30 = OpLoad %v3half %res None
+               OpReturnValue %30
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %35
-%tint_subgroup_size = OpFunctionParameter %uint
-         %36 = OpLabel
-         %37 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %37 None
-         %39 = OpFunctionCall %v3half %subgroupShuffle_821df9
-         %40 = OpAccessChain %_ptr_StorageBuffer_v3half %1 %uint_0
-               OpStore %40 %39 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %44
-         %45 = OpLabel
-         %46 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %47 = OpFunctionCall %void %compute_main_inner %46
+%compute_main = OpFunction %void None %33
+         %34 = OpLabel
+         %35 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %37 = OpISub %uint %35 %uint_1
+               OpStore %tint_subgroup_last_id %37 None
+         %38 = OpFunctionCall %v3half %subgroupShuffle_821df9
+         %39 = OpAccessChain %_ptr_StorageBuffer_v3half %1 %uint_0
+               OpStore %39 %38 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/var/subgroupShuffle/824702.wgsl.expected.spvasm b/test/tint/builtins/gen/var/subgroupShuffle/824702.wgsl.expected.spvasm
index 00320ea..1298380 100644
--- a/test/tint/builtins/gen/var/subgroupShuffle/824702.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/var/subgroupShuffle/824702.wgsl.expected.spvasm
@@ -4,32 +4,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 46
+; Bound: 40
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %24 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_824702 "subgroupShuffle_824702"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
         %int = OpTypeInt 32 1
       %v3int = OpTypeVector %int 3
 %prevent_dce_block = OpTypeStruct %v3int
@@ -38,52 +34,43 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v3int
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v3int
 %_ptr_Function_v3int = OpTypePointer Function %v3int
       %int_1 = OpConstant %int 1
-         %17 = OpConstantComposite %v3int %int_1 %int_1 %int_1
+         %15 = OpConstantComposite %v3int %int_1 %int_1 %int_1
 %_ptr_Function_int = OpTypePointer Function %int
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %33 = OpTypeFunction %void %uint
+         %31 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_v3int = OpTypePointer StorageBuffer %v3int
      %uint_0 = OpConstant %uint 0
-         %42 = OpTypeFunction %void
-%subgroupShuffle_824702 = OpFunction %v3int None %13
-         %14 = OpLabel
+%subgroupShuffle_824702 = OpFunction %v3int None %11
+         %12 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v3int Function
       %arg_1 = OpVariable %_ptr_Function_int Function
         %res = OpVariable %_ptr_Function_v3int Function
-               OpStore %arg_0 %17
+               OpStore %arg_0 %15
                OpStore %arg_1 %int_1
-         %21 = OpLoad %v3int %arg_0 None
-         %22 = OpLoad %int %arg_1 None
-         %23 = OpBitcast %uint %22
-         %24 = OpLoad %uint %tint_subgroup_size_mask None
-         %25 = OpBitwiseAnd %uint %23 %24
-         %26 = OpGroupNonUniformShuffle %v3int %uint_3 %21 %25
-               OpStore %res %26
-         %29 = OpLoad %v3int %res None
-               OpReturnValue %29
+         %19 = OpLoad %v3int %arg_0 None
+         %20 = OpLoad %int %arg_1 None
+         %21 = OpBitcast %uint %20
+         %22 = OpLoad %uint %tint_subgroup_last_id None
+         %23 = OpExtInst %uint %24 UMin %21 %22
+         %25 = OpGroupNonUniformShuffle %v3int %uint_3 %19 %23
+               OpStore %res %25
+         %28 = OpLoad %v3int %res None
+               OpReturnValue %28
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %33
-%tint_subgroup_size = OpFunctionParameter %uint
-         %34 = OpLabel
-         %35 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %35 None
-         %37 = OpFunctionCall %v3int %subgroupShuffle_824702
-         %38 = OpAccessChain %_ptr_StorageBuffer_v3int %1 %uint_0
-               OpStore %38 %37 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %42
-         %43 = OpLabel
-         %44 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %45 = OpFunctionCall %void %fragment_main_inner %44
+%fragment_main = OpFunction %void None %31
+         %32 = OpLabel
+         %33 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %35 = OpISub %uint %33 %uint_1
+               OpStore %tint_subgroup_last_id %35 None
+         %36 = OpFunctionCall %v3int %subgroupShuffle_824702
+         %37 = OpAccessChain %_ptr_StorageBuffer_v3int %1 %uint_0
+               OpStore %37 %36 None
                OpReturn
                OpFunctionEnd
 ;
@@ -92,31 +79,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 46
+; Bound: 40
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %24 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_824702 "subgroupShuffle_824702"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
         %int = OpTypeInt 32 1
       %v3int = OpTypeVector %int 3
 %prevent_dce_block = OpTypeStruct %v3int
@@ -125,51 +109,42 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v3int
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v3int
 %_ptr_Function_v3int = OpTypePointer Function %v3int
       %int_1 = OpConstant %int 1
-         %17 = OpConstantComposite %v3int %int_1 %int_1 %int_1
+         %15 = OpConstantComposite %v3int %int_1 %int_1 %int_1
 %_ptr_Function_int = OpTypePointer Function %int
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %33 = OpTypeFunction %void %uint
+         %31 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_v3int = OpTypePointer StorageBuffer %v3int
      %uint_0 = OpConstant %uint 0
-         %42 = OpTypeFunction %void
-%subgroupShuffle_824702 = OpFunction %v3int None %13
-         %14 = OpLabel
+%subgroupShuffle_824702 = OpFunction %v3int None %11
+         %12 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v3int Function
       %arg_1 = OpVariable %_ptr_Function_int Function
         %res = OpVariable %_ptr_Function_v3int Function
-               OpStore %arg_0 %17
+               OpStore %arg_0 %15
                OpStore %arg_1 %int_1
-         %21 = OpLoad %v3int %arg_0 None
-         %22 = OpLoad %int %arg_1 None
-         %23 = OpBitcast %uint %22
-         %24 = OpLoad %uint %tint_subgroup_size_mask None
-         %25 = OpBitwiseAnd %uint %23 %24
-         %26 = OpGroupNonUniformShuffle %v3int %uint_3 %21 %25
-               OpStore %res %26
-         %29 = OpLoad %v3int %res None
-               OpReturnValue %29
+         %19 = OpLoad %v3int %arg_0 None
+         %20 = OpLoad %int %arg_1 None
+         %21 = OpBitcast %uint %20
+         %22 = OpLoad %uint %tint_subgroup_last_id None
+         %23 = OpExtInst %uint %24 UMin %21 %22
+         %25 = OpGroupNonUniformShuffle %v3int %uint_3 %19 %23
+               OpStore %res %25
+         %28 = OpLoad %v3int %res None
+               OpReturnValue %28
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %33
-%tint_subgroup_size = OpFunctionParameter %uint
-         %34 = OpLabel
-         %35 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %35 None
-         %37 = OpFunctionCall %v3int %subgroupShuffle_824702
-         %38 = OpAccessChain %_ptr_StorageBuffer_v3int %1 %uint_0
-               OpStore %38 %37 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %42
-         %43 = OpLabel
-         %44 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %45 = OpFunctionCall %void %compute_main_inner %44
+%compute_main = OpFunction %void None %31
+         %32 = OpLabel
+         %33 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %35 = OpISub %uint %33 %uint_1
+               OpStore %tint_subgroup_last_id %35 None
+         %36 = OpFunctionCall %v3int %subgroupShuffle_824702
+         %37 = OpAccessChain %_ptr_StorageBuffer_v3int %1 %uint_0
+               OpStore %37 %36 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/var/subgroupShuffle/84f261.wgsl.expected.spvasm b/test/tint/builtins/gen/var/subgroupShuffle/84f261.wgsl.expected.spvasm
index 5a211aad..e03082e 100644
--- a/test/tint/builtins/gen/var/subgroupShuffle/84f261.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/var/subgroupShuffle/84f261.wgsl.expected.spvasm
@@ -4,32 +4,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 43
+; Bound: 37
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %22 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_84f261 "subgroupShuffle_84f261"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
        %uint = OpTypeInt 32 0
      %v4uint = OpTypeVector %uint 4
 %prevent_dce_block = OpTypeStruct %v4uint
@@ -37,50 +33,41 @@
           %1 = OpVariable %_ptr_StorageBuffer_prevent_dce_block StorageBuffer
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %v4uint
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %v4uint
 %_ptr_Function_v4uint = OpTypePointer Function %v4uint
      %uint_1 = OpConstant %uint 1
-         %16 = OpConstantComposite %v4uint %uint_1 %uint_1 %uint_1 %uint_1
+         %14 = OpConstantComposite %v4uint %uint_1 %uint_1 %uint_1 %uint_1
 %_ptr_Function_uint = OpTypePointer Function %uint
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %31 = OpTypeFunction %void %uint
+         %29 = OpTypeFunction %void
 %_ptr_StorageBuffer_v4uint = OpTypePointer StorageBuffer %v4uint
      %uint_0 = OpConstant %uint 0
-         %39 = OpTypeFunction %void
-%subgroupShuffle_84f261 = OpFunction %v4uint None %12
-         %13 = OpLabel
+%subgroupShuffle_84f261 = OpFunction %v4uint None %10
+         %11 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v4uint Function
       %arg_1 = OpVariable %_ptr_Function_uint Function
         %res = OpVariable %_ptr_Function_v4uint Function
-               OpStore %arg_0 %16
+               OpStore %arg_0 %14
                OpStore %arg_1 %uint_1
-         %20 = OpLoad %v4uint %arg_0 None
-         %21 = OpLoad %uint %arg_1 None
-         %22 = OpLoad %uint %tint_subgroup_size_mask None
-         %23 = OpBitwiseAnd %uint %21 %22
-         %24 = OpGroupNonUniformShuffle %v4uint %uint_3 %20 %23
-               OpStore %res %24
-         %27 = OpLoad %v4uint %res None
-               OpReturnValue %27
+         %18 = OpLoad %v4uint %arg_0 None
+         %19 = OpLoad %uint %arg_1 None
+         %20 = OpLoad %uint %tint_subgroup_last_id None
+         %21 = OpExtInst %uint %22 UMin %19 %20
+         %23 = OpGroupNonUniformShuffle %v4uint %uint_3 %18 %21
+               OpStore %res %23
+         %26 = OpLoad %v4uint %res None
+               OpReturnValue %26
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %31
-%tint_subgroup_size = OpFunctionParameter %uint
-         %32 = OpLabel
-         %33 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %33 None
-         %34 = OpFunctionCall %v4uint %subgroupShuffle_84f261
-         %35 = OpAccessChain %_ptr_StorageBuffer_v4uint %1 %uint_0
-               OpStore %35 %34 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %39
-         %40 = OpLabel
-         %41 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %42 = OpFunctionCall %void %fragment_main_inner %41
+%fragment_main = OpFunction %void None %29
+         %30 = OpLabel
+         %31 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %32 = OpISub %uint %31 %uint_1
+               OpStore %tint_subgroup_last_id %32 None
+         %33 = OpFunctionCall %v4uint %subgroupShuffle_84f261
+         %34 = OpAccessChain %_ptr_StorageBuffer_v4uint %1 %uint_0
+               OpStore %34 %33 None
                OpReturn
                OpFunctionEnd
 ;
@@ -89,31 +76,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 43
+; Bound: 37
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %22 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_84f261 "subgroupShuffle_84f261"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
        %uint = OpTypeInt 32 0
      %v4uint = OpTypeVector %uint 4
 %prevent_dce_block = OpTypeStruct %v4uint
@@ -121,49 +105,40 @@
           %1 = OpVariable %_ptr_StorageBuffer_prevent_dce_block StorageBuffer
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %v4uint
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %v4uint
 %_ptr_Function_v4uint = OpTypePointer Function %v4uint
      %uint_1 = OpConstant %uint 1
-         %16 = OpConstantComposite %v4uint %uint_1 %uint_1 %uint_1 %uint_1
+         %14 = OpConstantComposite %v4uint %uint_1 %uint_1 %uint_1 %uint_1
 %_ptr_Function_uint = OpTypePointer Function %uint
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %31 = OpTypeFunction %void %uint
+         %29 = OpTypeFunction %void
 %_ptr_StorageBuffer_v4uint = OpTypePointer StorageBuffer %v4uint
      %uint_0 = OpConstant %uint 0
-         %39 = OpTypeFunction %void
-%subgroupShuffle_84f261 = OpFunction %v4uint None %12
-         %13 = OpLabel
+%subgroupShuffle_84f261 = OpFunction %v4uint None %10
+         %11 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v4uint Function
       %arg_1 = OpVariable %_ptr_Function_uint Function
         %res = OpVariable %_ptr_Function_v4uint Function
-               OpStore %arg_0 %16
+               OpStore %arg_0 %14
                OpStore %arg_1 %uint_1
-         %20 = OpLoad %v4uint %arg_0 None
-         %21 = OpLoad %uint %arg_1 None
-         %22 = OpLoad %uint %tint_subgroup_size_mask None
-         %23 = OpBitwiseAnd %uint %21 %22
-         %24 = OpGroupNonUniformShuffle %v4uint %uint_3 %20 %23
-               OpStore %res %24
-         %27 = OpLoad %v4uint %res None
-               OpReturnValue %27
+         %18 = OpLoad %v4uint %arg_0 None
+         %19 = OpLoad %uint %arg_1 None
+         %20 = OpLoad %uint %tint_subgroup_last_id None
+         %21 = OpExtInst %uint %22 UMin %19 %20
+         %23 = OpGroupNonUniformShuffle %v4uint %uint_3 %18 %21
+               OpStore %res %23
+         %26 = OpLoad %v4uint %res None
+               OpReturnValue %26
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %31
-%tint_subgroup_size = OpFunctionParameter %uint
-         %32 = OpLabel
-         %33 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %33 None
-         %34 = OpFunctionCall %v4uint %subgroupShuffle_84f261
-         %35 = OpAccessChain %_ptr_StorageBuffer_v4uint %1 %uint_0
-               OpStore %35 %34 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %39
-         %40 = OpLabel
-         %41 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %42 = OpFunctionCall %void %compute_main_inner %41
+%compute_main = OpFunction %void None %29
+         %30 = OpLabel
+         %31 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %32 = OpISub %uint %31 %uint_1
+               OpStore %tint_subgroup_last_id %32 None
+         %33 = OpFunctionCall %v4uint %subgroupShuffle_84f261
+         %34 = OpAccessChain %_ptr_StorageBuffer_v4uint %1 %uint_0
+               OpStore %34 %33 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/var/subgroupShuffle/85587b.wgsl.expected.spvasm b/test/tint/builtins/gen/var/subgroupShuffle/85587b.wgsl.expected.spvasm
index 213f962..f6da309 100644
--- a/test/tint/builtins/gen/var/subgroupShuffle/85587b.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/var/subgroupShuffle/85587b.wgsl.expected.spvasm
@@ -4,32 +4,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 45
+; Bound: 39
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %24 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_85587b "subgroupShuffle_85587b"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
       %float = OpTypeFloat 32
     %v4float = OpTypeVector %float 4
 %prevent_dce_block = OpTypeStruct %v4float
@@ -38,51 +34,42 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v4float
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v4float
 %_ptr_Function_v4float = OpTypePointer Function %v4float
     %float_1 = OpConstant %float 1
-         %17 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
+         %15 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
 %_ptr_Function_uint = OpTypePointer Function %uint
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %33 = OpTypeFunction %void %uint
+         %31 = OpTypeFunction %void
 %_ptr_StorageBuffer_v4float = OpTypePointer StorageBuffer %v4float
      %uint_0 = OpConstant %uint 0
-         %41 = OpTypeFunction %void
-%subgroupShuffle_85587b = OpFunction %v4float None %13
-         %14 = OpLabel
+%subgroupShuffle_85587b = OpFunction %v4float None %11
+         %12 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v4float Function
       %arg_1 = OpVariable %_ptr_Function_uint Function
         %res = OpVariable %_ptr_Function_v4float Function
-               OpStore %arg_0 %17
+               OpStore %arg_0 %15
                OpStore %arg_1 %uint_1
-         %22 = OpLoad %v4float %arg_0 None
-         %23 = OpLoad %uint %arg_1 None
-         %24 = OpLoad %uint %tint_subgroup_size_mask None
-         %25 = OpBitwiseAnd %uint %23 %24
-         %26 = OpGroupNonUniformShuffle %v4float %uint_3 %22 %25
-               OpStore %res %26
-         %29 = OpLoad %v4float %res None
-               OpReturnValue %29
+         %20 = OpLoad %v4float %arg_0 None
+         %21 = OpLoad %uint %arg_1 None
+         %22 = OpLoad %uint %tint_subgroup_last_id None
+         %23 = OpExtInst %uint %24 UMin %21 %22
+         %25 = OpGroupNonUniformShuffle %v4float %uint_3 %20 %23
+               OpStore %res %25
+         %28 = OpLoad %v4float %res None
+               OpReturnValue %28
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %33
-%tint_subgroup_size = OpFunctionParameter %uint
-         %34 = OpLabel
-         %35 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %35 None
-         %36 = OpFunctionCall %v4float %subgroupShuffle_85587b
-         %37 = OpAccessChain %_ptr_StorageBuffer_v4float %1 %uint_0
-               OpStore %37 %36 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %41
-         %42 = OpLabel
-         %43 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %44 = OpFunctionCall %void %fragment_main_inner %43
+%fragment_main = OpFunction %void None %31
+         %32 = OpLabel
+         %33 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %34 = OpISub %uint %33 %uint_1
+               OpStore %tint_subgroup_last_id %34 None
+         %35 = OpFunctionCall %v4float %subgroupShuffle_85587b
+         %36 = OpAccessChain %_ptr_StorageBuffer_v4float %1 %uint_0
+               OpStore %36 %35 None
                OpReturn
                OpFunctionEnd
 ;
@@ -91,31 +78,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 45
+; Bound: 39
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %24 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_85587b "subgroupShuffle_85587b"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
       %float = OpTypeFloat 32
     %v4float = OpTypeVector %float 4
 %prevent_dce_block = OpTypeStruct %v4float
@@ -124,50 +108,41 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v4float
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v4float
 %_ptr_Function_v4float = OpTypePointer Function %v4float
     %float_1 = OpConstant %float 1
-         %17 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
+         %15 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
 %_ptr_Function_uint = OpTypePointer Function %uint
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %33 = OpTypeFunction %void %uint
+         %31 = OpTypeFunction %void
 %_ptr_StorageBuffer_v4float = OpTypePointer StorageBuffer %v4float
      %uint_0 = OpConstant %uint 0
-         %41 = OpTypeFunction %void
-%subgroupShuffle_85587b = OpFunction %v4float None %13
-         %14 = OpLabel
+%subgroupShuffle_85587b = OpFunction %v4float None %11
+         %12 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v4float Function
       %arg_1 = OpVariable %_ptr_Function_uint Function
         %res = OpVariable %_ptr_Function_v4float Function
-               OpStore %arg_0 %17
+               OpStore %arg_0 %15
                OpStore %arg_1 %uint_1
-         %22 = OpLoad %v4float %arg_0 None
-         %23 = OpLoad %uint %arg_1 None
-         %24 = OpLoad %uint %tint_subgroup_size_mask None
-         %25 = OpBitwiseAnd %uint %23 %24
-         %26 = OpGroupNonUniformShuffle %v4float %uint_3 %22 %25
-               OpStore %res %26
-         %29 = OpLoad %v4float %res None
-               OpReturnValue %29
+         %20 = OpLoad %v4float %arg_0 None
+         %21 = OpLoad %uint %arg_1 None
+         %22 = OpLoad %uint %tint_subgroup_last_id None
+         %23 = OpExtInst %uint %24 UMin %21 %22
+         %25 = OpGroupNonUniformShuffle %v4float %uint_3 %20 %23
+               OpStore %res %25
+         %28 = OpLoad %v4float %res None
+               OpReturnValue %28
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %33
-%tint_subgroup_size = OpFunctionParameter %uint
-         %34 = OpLabel
-         %35 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %35 None
-         %36 = OpFunctionCall %v4float %subgroupShuffle_85587b
-         %37 = OpAccessChain %_ptr_StorageBuffer_v4float %1 %uint_0
-               OpStore %37 %36 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %41
-         %42 = OpLabel
-         %43 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %44 = OpFunctionCall %void %compute_main_inner %43
+%compute_main = OpFunction %void None %31
+         %32 = OpLabel
+         %33 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %34 = OpISub %uint %33 %uint_1
+               OpStore %tint_subgroup_last_id %34 None
+         %35 = OpFunctionCall %v4float %subgroupShuffle_85587b
+         %36 = OpAccessChain %_ptr_StorageBuffer_v4float %1 %uint_0
+               OpStore %36 %35 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/var/subgroupShuffle/8890a5.wgsl.expected.spvasm b/test/tint/builtins/gen/var/subgroupShuffle/8890a5.wgsl.expected.spvasm
index 98641a0..4ba6cce 100644
--- a/test/tint/builtins/gen/var/subgroupShuffle/8890a5.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/var/subgroupShuffle/8890a5.wgsl.expected.spvasm
@@ -4,32 +4,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 45
+; Bound: 39
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %24 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_8890a5 "subgroupShuffle_8890a5"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
       %float = OpTypeFloat 32
     %v2float = OpTypeVector %float 2
 %prevent_dce_block = OpTypeStruct %v2float
@@ -38,51 +34,42 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v2float
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v2float
 %_ptr_Function_v2float = OpTypePointer Function %v2float
     %float_1 = OpConstant %float 1
-         %17 = OpConstantComposite %v2float %float_1 %float_1
+         %15 = OpConstantComposite %v2float %float_1 %float_1
 %_ptr_Function_uint = OpTypePointer Function %uint
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %33 = OpTypeFunction %void %uint
+         %31 = OpTypeFunction %void
 %_ptr_StorageBuffer_v2float = OpTypePointer StorageBuffer %v2float
      %uint_0 = OpConstant %uint 0
-         %41 = OpTypeFunction %void
-%subgroupShuffle_8890a5 = OpFunction %v2float None %13
-         %14 = OpLabel
+%subgroupShuffle_8890a5 = OpFunction %v2float None %11
+         %12 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v2float Function
       %arg_1 = OpVariable %_ptr_Function_uint Function
         %res = OpVariable %_ptr_Function_v2float Function
-               OpStore %arg_0 %17
+               OpStore %arg_0 %15
                OpStore %arg_1 %uint_1
-         %22 = OpLoad %v2float %arg_0 None
-         %23 = OpLoad %uint %arg_1 None
-         %24 = OpLoad %uint %tint_subgroup_size_mask None
-         %25 = OpBitwiseAnd %uint %23 %24
-         %26 = OpGroupNonUniformShuffle %v2float %uint_3 %22 %25
-               OpStore %res %26
-         %29 = OpLoad %v2float %res None
-               OpReturnValue %29
+         %20 = OpLoad %v2float %arg_0 None
+         %21 = OpLoad %uint %arg_1 None
+         %22 = OpLoad %uint %tint_subgroup_last_id None
+         %23 = OpExtInst %uint %24 UMin %21 %22
+         %25 = OpGroupNonUniformShuffle %v2float %uint_3 %20 %23
+               OpStore %res %25
+         %28 = OpLoad %v2float %res None
+               OpReturnValue %28
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %33
-%tint_subgroup_size = OpFunctionParameter %uint
-         %34 = OpLabel
-         %35 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %35 None
-         %36 = OpFunctionCall %v2float %subgroupShuffle_8890a5
-         %37 = OpAccessChain %_ptr_StorageBuffer_v2float %1 %uint_0
-               OpStore %37 %36 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %41
-         %42 = OpLabel
-         %43 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %44 = OpFunctionCall %void %fragment_main_inner %43
+%fragment_main = OpFunction %void None %31
+         %32 = OpLabel
+         %33 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %34 = OpISub %uint %33 %uint_1
+               OpStore %tint_subgroup_last_id %34 None
+         %35 = OpFunctionCall %v2float %subgroupShuffle_8890a5
+         %36 = OpAccessChain %_ptr_StorageBuffer_v2float %1 %uint_0
+               OpStore %36 %35 None
                OpReturn
                OpFunctionEnd
 ;
@@ -91,31 +78,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 45
+; Bound: 39
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %24 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_8890a5 "subgroupShuffle_8890a5"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
       %float = OpTypeFloat 32
     %v2float = OpTypeVector %float 2
 %prevent_dce_block = OpTypeStruct %v2float
@@ -124,50 +108,41 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v2float
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v2float
 %_ptr_Function_v2float = OpTypePointer Function %v2float
     %float_1 = OpConstant %float 1
-         %17 = OpConstantComposite %v2float %float_1 %float_1
+         %15 = OpConstantComposite %v2float %float_1 %float_1
 %_ptr_Function_uint = OpTypePointer Function %uint
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %33 = OpTypeFunction %void %uint
+         %31 = OpTypeFunction %void
 %_ptr_StorageBuffer_v2float = OpTypePointer StorageBuffer %v2float
      %uint_0 = OpConstant %uint 0
-         %41 = OpTypeFunction %void
-%subgroupShuffle_8890a5 = OpFunction %v2float None %13
-         %14 = OpLabel
+%subgroupShuffle_8890a5 = OpFunction %v2float None %11
+         %12 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v2float Function
       %arg_1 = OpVariable %_ptr_Function_uint Function
         %res = OpVariable %_ptr_Function_v2float Function
-               OpStore %arg_0 %17
+               OpStore %arg_0 %15
                OpStore %arg_1 %uint_1
-         %22 = OpLoad %v2float %arg_0 None
-         %23 = OpLoad %uint %arg_1 None
-         %24 = OpLoad %uint %tint_subgroup_size_mask None
-         %25 = OpBitwiseAnd %uint %23 %24
-         %26 = OpGroupNonUniformShuffle %v2float %uint_3 %22 %25
-               OpStore %res %26
-         %29 = OpLoad %v2float %res None
-               OpReturnValue %29
+         %20 = OpLoad %v2float %arg_0 None
+         %21 = OpLoad %uint %arg_1 None
+         %22 = OpLoad %uint %tint_subgroup_last_id None
+         %23 = OpExtInst %uint %24 UMin %21 %22
+         %25 = OpGroupNonUniformShuffle %v2float %uint_3 %20 %23
+               OpStore %res %25
+         %28 = OpLoad %v2float %res None
+               OpReturnValue %28
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %33
-%tint_subgroup_size = OpFunctionParameter %uint
-         %34 = OpLabel
-         %35 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %35 None
-         %36 = OpFunctionCall %v2float %subgroupShuffle_8890a5
-         %37 = OpAccessChain %_ptr_StorageBuffer_v2float %1 %uint_0
-               OpStore %37 %36 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %41
-         %42 = OpLabel
-         %43 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %44 = OpFunctionCall %void %compute_main_inner %43
+%compute_main = OpFunction %void None %31
+         %32 = OpLabel
+         %33 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %34 = OpISub %uint %33 %uint_1
+               OpStore %tint_subgroup_last_id %34 None
+         %35 = OpFunctionCall %v2float %subgroupShuffle_8890a5
+         %36 = OpAccessChain %_ptr_StorageBuffer_v2float %1 %uint_0
+               OpStore %36 %35 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/var/subgroupShuffle/8bfbcd.wgsl.expected.spvasm b/test/tint/builtins/gen/var/subgroupShuffle/8bfbcd.wgsl.expected.spvasm
index bb4d3c7..ae10d0e 100644
--- a/test/tint/builtins/gen/var/subgroupShuffle/8bfbcd.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/var/subgroupShuffle/8bfbcd.wgsl.expected.spvasm
@@ -4,32 +4,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 43
+; Bound: 37
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %21 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_8bfbcd "subgroupShuffle_8bfbcd"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
         %int = OpTypeInt 32 1
 %prevent_dce_block = OpTypeStruct %int
 %_ptr_StorageBuffer_prevent_dce_block = OpTypePointer StorageBuffer %prevent_dce_block
@@ -37,50 +33,41 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %int
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %int
 %_ptr_Function_int = OpTypePointer Function %int
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %30 = OpTypeFunction %void %uint
+         %28 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_int = OpTypePointer StorageBuffer %int
      %uint_0 = OpConstant %uint 0
-         %39 = OpTypeFunction %void
-%subgroupShuffle_8bfbcd = OpFunction %int None %12
-         %13 = OpLabel
+%subgroupShuffle_8bfbcd = OpFunction %int None %10
+         %11 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_int Function
       %arg_1 = OpVariable %_ptr_Function_int Function
         %res = OpVariable %_ptr_Function_int Function
                OpStore %arg_0 %int_1
                OpStore %arg_1 %int_1
-         %18 = OpLoad %int %arg_0 None
-         %19 = OpLoad %int %arg_1 None
-         %20 = OpBitcast %uint %19
-         %21 = OpLoad %uint %tint_subgroup_size_mask None
-         %22 = OpBitwiseAnd %uint %20 %21
-         %23 = OpGroupNonUniformShuffle %int %uint_3 %18 %22
-               OpStore %res %23
-         %26 = OpLoad %int %res None
-               OpReturnValue %26
+         %16 = OpLoad %int %arg_0 None
+         %17 = OpLoad %int %arg_1 None
+         %18 = OpBitcast %uint %17
+         %19 = OpLoad %uint %tint_subgroup_last_id None
+         %20 = OpExtInst %uint %21 UMin %18 %19
+         %22 = OpGroupNonUniformShuffle %int %uint_3 %16 %20
+               OpStore %res %22
+         %25 = OpLoad %int %res None
+               OpReturnValue %25
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %30
-%tint_subgroup_size = OpFunctionParameter %uint
-         %31 = OpLabel
-         %32 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %32 None
-         %34 = OpFunctionCall %int %subgroupShuffle_8bfbcd
-         %35 = OpAccessChain %_ptr_StorageBuffer_int %1 %uint_0
-               OpStore %35 %34 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %39
-         %40 = OpLabel
-         %41 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %42 = OpFunctionCall %void %fragment_main_inner %41
+%fragment_main = OpFunction %void None %28
+         %29 = OpLabel
+         %30 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %32 = OpISub %uint %30 %uint_1
+               OpStore %tint_subgroup_last_id %32 None
+         %33 = OpFunctionCall %int %subgroupShuffle_8bfbcd
+         %34 = OpAccessChain %_ptr_StorageBuffer_int %1 %uint_0
+               OpStore %34 %33 None
                OpReturn
                OpFunctionEnd
 ;
@@ -89,31 +76,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 43
+; Bound: 37
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %21 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_8bfbcd "subgroupShuffle_8bfbcd"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
         %int = OpTypeInt 32 1
 %prevent_dce_block = OpTypeStruct %int
 %_ptr_StorageBuffer_prevent_dce_block = OpTypePointer StorageBuffer %prevent_dce_block
@@ -121,49 +105,40 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %int
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %int
 %_ptr_Function_int = OpTypePointer Function %int
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %30 = OpTypeFunction %void %uint
+         %28 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_int = OpTypePointer StorageBuffer %int
      %uint_0 = OpConstant %uint 0
-         %39 = OpTypeFunction %void
-%subgroupShuffle_8bfbcd = OpFunction %int None %12
-         %13 = OpLabel
+%subgroupShuffle_8bfbcd = OpFunction %int None %10
+         %11 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_int Function
       %arg_1 = OpVariable %_ptr_Function_int Function
         %res = OpVariable %_ptr_Function_int Function
                OpStore %arg_0 %int_1
                OpStore %arg_1 %int_1
-         %18 = OpLoad %int %arg_0 None
-         %19 = OpLoad %int %arg_1 None
-         %20 = OpBitcast %uint %19
-         %21 = OpLoad %uint %tint_subgroup_size_mask None
-         %22 = OpBitwiseAnd %uint %20 %21
-         %23 = OpGroupNonUniformShuffle %int %uint_3 %18 %22
-               OpStore %res %23
-         %26 = OpLoad %int %res None
-               OpReturnValue %26
+         %16 = OpLoad %int %arg_0 None
+         %17 = OpLoad %int %arg_1 None
+         %18 = OpBitcast %uint %17
+         %19 = OpLoad %uint %tint_subgroup_last_id None
+         %20 = OpExtInst %uint %21 UMin %18 %19
+         %22 = OpGroupNonUniformShuffle %int %uint_3 %16 %20
+               OpStore %res %22
+         %25 = OpLoad %int %res None
+               OpReturnValue %25
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %30
-%tint_subgroup_size = OpFunctionParameter %uint
-         %31 = OpLabel
-         %32 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %32 None
-         %34 = OpFunctionCall %int %subgroupShuffle_8bfbcd
-         %35 = OpAccessChain %_ptr_StorageBuffer_int %1 %uint_0
-               OpStore %35 %34 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %39
-         %40 = OpLabel
-         %41 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %42 = OpFunctionCall %void %compute_main_inner %41
+%compute_main = OpFunction %void None %28
+         %29 = OpLabel
+         %30 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %32 = OpISub %uint %30 %uint_1
+               OpStore %tint_subgroup_last_id %32 None
+         %33 = OpFunctionCall %int %subgroupShuffle_8bfbcd
+         %34 = OpAccessChain %_ptr_StorageBuffer_int %1 %uint_0
+               OpStore %34 %33 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/var/subgroupShuffle/8c3fd2.wgsl.expected.spvasm b/test/tint/builtins/gen/var/subgroupShuffle/8c3fd2.wgsl.expected.spvasm
index 46384dc..4d065c6 100644
--- a/test/tint/builtins/gen/var/subgroupShuffle/8c3fd2.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/var/subgroupShuffle/8c3fd2.wgsl.expected.spvasm
@@ -4,34 +4,30 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 48
+; Bound: 42
 ; Schema: 0
                OpCapability Shader
                OpCapability Float16
                OpCapability StorageBuffer16BitAccess
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %26 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_8c3fd2 "subgroupShuffle_8c3fd2"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
        %half = OpTypeFloat 16
      %v2half = OpTypeVector %half 2
 %prevent_dce_block = OpTypeStruct %v2half
@@ -40,54 +36,45 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v2half
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v2half
 %_ptr_Function_v2half = OpTypePointer Function %v2half
 %half_0x1p_0 = OpConstant %half 0x1p+0
-         %17 = OpConstantComposite %v2half %half_0x1p_0 %half_0x1p_0
+         %15 = OpConstantComposite %v2half %half_0x1p_0 %half_0x1p_0
         %int = OpTypeInt 32 1
 %_ptr_Function_int = OpTypePointer Function %int
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %35 = OpTypeFunction %void %uint
+         %33 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_v2half = OpTypePointer StorageBuffer %v2half
      %uint_0 = OpConstant %uint 0
-         %44 = OpTypeFunction %void
-%subgroupShuffle_8c3fd2 = OpFunction %v2half None %13
-         %14 = OpLabel
+%subgroupShuffle_8c3fd2 = OpFunction %v2half None %11
+         %12 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v2half Function
       %arg_1 = OpVariable %_ptr_Function_int Function
         %res = OpVariable %_ptr_Function_v2half Function
-               OpStore %arg_0 %17
+               OpStore %arg_0 %15
                OpStore %arg_1 %int_1
-         %23 = OpLoad %v2half %arg_0 None
-         %24 = OpLoad %int %arg_1 None
-         %25 = OpBitcast %uint %24
-         %26 = OpLoad %uint %tint_subgroup_size_mask None
-         %27 = OpBitwiseAnd %uint %25 %26
-         %28 = OpGroupNonUniformShuffle %v2half %uint_3 %23 %27
-               OpStore %res %28
-         %31 = OpLoad %v2half %res None
-               OpReturnValue %31
+         %21 = OpLoad %v2half %arg_0 None
+         %22 = OpLoad %int %arg_1 None
+         %23 = OpBitcast %uint %22
+         %24 = OpLoad %uint %tint_subgroup_last_id None
+         %25 = OpExtInst %uint %26 UMin %23 %24
+         %27 = OpGroupNonUniformShuffle %v2half %uint_3 %21 %25
+               OpStore %res %27
+         %30 = OpLoad %v2half %res None
+               OpReturnValue %30
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %35
-%tint_subgroup_size = OpFunctionParameter %uint
-         %36 = OpLabel
-         %37 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %37 None
-         %39 = OpFunctionCall %v2half %subgroupShuffle_8c3fd2
-         %40 = OpAccessChain %_ptr_StorageBuffer_v2half %1 %uint_0
-               OpStore %40 %39 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %44
-         %45 = OpLabel
-         %46 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %47 = OpFunctionCall %void %fragment_main_inner %46
+%fragment_main = OpFunction %void None %33
+         %34 = OpLabel
+         %35 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %37 = OpISub %uint %35 %uint_1
+               OpStore %tint_subgroup_last_id %37 None
+         %38 = OpFunctionCall %v2half %subgroupShuffle_8c3fd2
+         %39 = OpAccessChain %_ptr_StorageBuffer_v2half %1 %uint_0
+               OpStore %39 %38 None
                OpReturn
                OpFunctionEnd
 ;
@@ -96,33 +83,30 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 48
+; Bound: 42
 ; Schema: 0
                OpCapability Shader
                OpCapability Float16
                OpCapability StorageBuffer16BitAccess
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %26 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_8c3fd2 "subgroupShuffle_8c3fd2"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
        %half = OpTypeFloat 16
      %v2half = OpTypeVector %half 2
 %prevent_dce_block = OpTypeStruct %v2half
@@ -131,53 +115,44 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v2half
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v2half
 %_ptr_Function_v2half = OpTypePointer Function %v2half
 %half_0x1p_0 = OpConstant %half 0x1p+0
-         %17 = OpConstantComposite %v2half %half_0x1p_0 %half_0x1p_0
+         %15 = OpConstantComposite %v2half %half_0x1p_0 %half_0x1p_0
         %int = OpTypeInt 32 1
 %_ptr_Function_int = OpTypePointer Function %int
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %35 = OpTypeFunction %void %uint
+         %33 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_v2half = OpTypePointer StorageBuffer %v2half
      %uint_0 = OpConstant %uint 0
-         %44 = OpTypeFunction %void
-%subgroupShuffle_8c3fd2 = OpFunction %v2half None %13
-         %14 = OpLabel
+%subgroupShuffle_8c3fd2 = OpFunction %v2half None %11
+         %12 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v2half Function
       %arg_1 = OpVariable %_ptr_Function_int Function
         %res = OpVariable %_ptr_Function_v2half Function
-               OpStore %arg_0 %17
+               OpStore %arg_0 %15
                OpStore %arg_1 %int_1
-         %23 = OpLoad %v2half %arg_0 None
-         %24 = OpLoad %int %arg_1 None
-         %25 = OpBitcast %uint %24
-         %26 = OpLoad %uint %tint_subgroup_size_mask None
-         %27 = OpBitwiseAnd %uint %25 %26
-         %28 = OpGroupNonUniformShuffle %v2half %uint_3 %23 %27
-               OpStore %res %28
-         %31 = OpLoad %v2half %res None
-               OpReturnValue %31
+         %21 = OpLoad %v2half %arg_0 None
+         %22 = OpLoad %int %arg_1 None
+         %23 = OpBitcast %uint %22
+         %24 = OpLoad %uint %tint_subgroup_last_id None
+         %25 = OpExtInst %uint %26 UMin %23 %24
+         %27 = OpGroupNonUniformShuffle %v2half %uint_3 %21 %25
+               OpStore %res %27
+         %30 = OpLoad %v2half %res None
+               OpReturnValue %30
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %35
-%tint_subgroup_size = OpFunctionParameter %uint
-         %36 = OpLabel
-         %37 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %37 None
-         %39 = OpFunctionCall %v2half %subgroupShuffle_8c3fd2
-         %40 = OpAccessChain %_ptr_StorageBuffer_v2half %1 %uint_0
-               OpStore %40 %39 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %44
-         %45 = OpLabel
-         %46 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %47 = OpFunctionCall %void %compute_main_inner %46
+%compute_main = OpFunction %void None %33
+         %34 = OpLabel
+         %35 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %37 = OpISub %uint %35 %uint_1
+               OpStore %tint_subgroup_last_id %37 None
+         %38 = OpFunctionCall %v2half %subgroupShuffle_8c3fd2
+         %39 = OpAccessChain %_ptr_StorageBuffer_v2half %1 %uint_0
+               OpStore %39 %38 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/var/subgroupShuffle/aa1d5c.wgsl.expected.spvasm b/test/tint/builtins/gen/var/subgroupShuffle/aa1d5c.wgsl.expected.spvasm
index da88188..9aef734 100644
--- a/test/tint/builtins/gen/var/subgroupShuffle/aa1d5c.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/var/subgroupShuffle/aa1d5c.wgsl.expected.spvasm
@@ -4,34 +4,30 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 45
+; Bound: 39
 ; Schema: 0
                OpCapability Shader
                OpCapability Float16
                OpCapability StorageBuffer16BitAccess
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %24 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_aa1d5c "subgroupShuffle_aa1d5c"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
        %half = OpTypeFloat 16
      %v2half = OpTypeVector %half 2
 %prevent_dce_block = OpTypeStruct %v2half
@@ -40,51 +36,42 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v2half
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v2half
 %_ptr_Function_v2half = OpTypePointer Function %v2half
 %half_0x1p_0 = OpConstant %half 0x1p+0
-         %17 = OpConstantComposite %v2half %half_0x1p_0 %half_0x1p_0
+         %15 = OpConstantComposite %v2half %half_0x1p_0 %half_0x1p_0
 %_ptr_Function_uint = OpTypePointer Function %uint
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %33 = OpTypeFunction %void %uint
+         %31 = OpTypeFunction %void
 %_ptr_StorageBuffer_v2half = OpTypePointer StorageBuffer %v2half
      %uint_0 = OpConstant %uint 0
-         %41 = OpTypeFunction %void
-%subgroupShuffle_aa1d5c = OpFunction %v2half None %13
-         %14 = OpLabel
+%subgroupShuffle_aa1d5c = OpFunction %v2half None %11
+         %12 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v2half Function
       %arg_1 = OpVariable %_ptr_Function_uint Function
         %res = OpVariable %_ptr_Function_v2half Function
-               OpStore %arg_0 %17
+               OpStore %arg_0 %15
                OpStore %arg_1 %uint_1
-         %22 = OpLoad %v2half %arg_0 None
-         %23 = OpLoad %uint %arg_1 None
-         %24 = OpLoad %uint %tint_subgroup_size_mask None
-         %25 = OpBitwiseAnd %uint %23 %24
-         %26 = OpGroupNonUniformShuffle %v2half %uint_3 %22 %25
-               OpStore %res %26
-         %29 = OpLoad %v2half %res None
-               OpReturnValue %29
+         %20 = OpLoad %v2half %arg_0 None
+         %21 = OpLoad %uint %arg_1 None
+         %22 = OpLoad %uint %tint_subgroup_last_id None
+         %23 = OpExtInst %uint %24 UMin %21 %22
+         %25 = OpGroupNonUniformShuffle %v2half %uint_3 %20 %23
+               OpStore %res %25
+         %28 = OpLoad %v2half %res None
+               OpReturnValue %28
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %33
-%tint_subgroup_size = OpFunctionParameter %uint
-         %34 = OpLabel
-         %35 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %35 None
-         %36 = OpFunctionCall %v2half %subgroupShuffle_aa1d5c
-         %37 = OpAccessChain %_ptr_StorageBuffer_v2half %1 %uint_0
-               OpStore %37 %36 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %41
-         %42 = OpLabel
-         %43 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %44 = OpFunctionCall %void %fragment_main_inner %43
+%fragment_main = OpFunction %void None %31
+         %32 = OpLabel
+         %33 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %34 = OpISub %uint %33 %uint_1
+               OpStore %tint_subgroup_last_id %34 None
+         %35 = OpFunctionCall %v2half %subgroupShuffle_aa1d5c
+         %36 = OpAccessChain %_ptr_StorageBuffer_v2half %1 %uint_0
+               OpStore %36 %35 None
                OpReturn
                OpFunctionEnd
 ;
@@ -93,33 +80,30 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 45
+; Bound: 39
 ; Schema: 0
                OpCapability Shader
                OpCapability Float16
                OpCapability StorageBuffer16BitAccess
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %24 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_aa1d5c "subgroupShuffle_aa1d5c"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
        %half = OpTypeFloat 16
      %v2half = OpTypeVector %half 2
 %prevent_dce_block = OpTypeStruct %v2half
@@ -128,50 +112,41 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v2half
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v2half
 %_ptr_Function_v2half = OpTypePointer Function %v2half
 %half_0x1p_0 = OpConstant %half 0x1p+0
-         %17 = OpConstantComposite %v2half %half_0x1p_0 %half_0x1p_0
+         %15 = OpConstantComposite %v2half %half_0x1p_0 %half_0x1p_0
 %_ptr_Function_uint = OpTypePointer Function %uint
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %33 = OpTypeFunction %void %uint
+         %31 = OpTypeFunction %void
 %_ptr_StorageBuffer_v2half = OpTypePointer StorageBuffer %v2half
      %uint_0 = OpConstant %uint 0
-         %41 = OpTypeFunction %void
-%subgroupShuffle_aa1d5c = OpFunction %v2half None %13
-         %14 = OpLabel
+%subgroupShuffle_aa1d5c = OpFunction %v2half None %11
+         %12 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v2half Function
       %arg_1 = OpVariable %_ptr_Function_uint Function
         %res = OpVariable %_ptr_Function_v2half Function
-               OpStore %arg_0 %17
+               OpStore %arg_0 %15
                OpStore %arg_1 %uint_1
-         %22 = OpLoad %v2half %arg_0 None
-         %23 = OpLoad %uint %arg_1 None
-         %24 = OpLoad %uint %tint_subgroup_size_mask None
-         %25 = OpBitwiseAnd %uint %23 %24
-         %26 = OpGroupNonUniformShuffle %v2half %uint_3 %22 %25
-               OpStore %res %26
-         %29 = OpLoad %v2half %res None
-               OpReturnValue %29
+         %20 = OpLoad %v2half %arg_0 None
+         %21 = OpLoad %uint %arg_1 None
+         %22 = OpLoad %uint %tint_subgroup_last_id None
+         %23 = OpExtInst %uint %24 UMin %21 %22
+         %25 = OpGroupNonUniformShuffle %v2half %uint_3 %20 %23
+               OpStore %res %25
+         %28 = OpLoad %v2half %res None
+               OpReturnValue %28
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %33
-%tint_subgroup_size = OpFunctionParameter %uint
-         %34 = OpLabel
-         %35 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %35 None
-         %36 = OpFunctionCall %v2half %subgroupShuffle_aa1d5c
-         %37 = OpAccessChain %_ptr_StorageBuffer_v2half %1 %uint_0
-               OpStore %37 %36 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %41
-         %42 = OpLabel
-         %43 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %44 = OpFunctionCall %void %compute_main_inner %43
+%compute_main = OpFunction %void None %31
+         %32 = OpLabel
+         %33 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %34 = OpISub %uint %33 %uint_1
+               OpStore %tint_subgroup_last_id %34 None
+         %35 = OpFunctionCall %v2half %subgroupShuffle_aa1d5c
+         %36 = OpAccessChain %_ptr_StorageBuffer_v2half %1 %uint_0
+               OpStore %36 %35 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/var/subgroupShuffle/b0f28d.wgsl.expected.spvasm b/test/tint/builtins/gen/var/subgroupShuffle/b0f28d.wgsl.expected.spvasm
index 6574d3e..20b668f 100644
--- a/test/tint/builtins/gen/var/subgroupShuffle/b0f28d.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/var/subgroupShuffle/b0f28d.wgsl.expected.spvasm
@@ -4,34 +4,30 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 46
+; Bound: 40
 ; Schema: 0
                OpCapability Shader
                OpCapability Float16
                OpCapability StorageBuffer16BitAccess
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %24 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_b0f28d "subgroupShuffle_b0f28d"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
        %half = OpTypeFloat 16
 %prevent_dce_block = OpTypeStruct %half
 %_ptr_StorageBuffer_prevent_dce_block = OpTypePointer StorageBuffer %prevent_dce_block
@@ -39,10 +35,8 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %half
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %half
 %_ptr_Function_half = OpTypePointer Function %half
 %half_0x1p_0 = OpConstant %half 0x1p+0
         %int = OpTypeInt 32 1
@@ -50,42 +44,35 @@
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %33 = OpTypeFunction %void %uint
+         %31 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_half = OpTypePointer StorageBuffer %half
      %uint_0 = OpConstant %uint 0
-         %42 = OpTypeFunction %void
-%subgroupShuffle_b0f28d = OpFunction %half None %12
-         %13 = OpLabel
+%subgroupShuffle_b0f28d = OpFunction %half None %10
+         %11 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_half Function
       %arg_1 = OpVariable %_ptr_Function_int Function
         %res = OpVariable %_ptr_Function_half Function
                OpStore %arg_0 %half_0x1p_0
                OpStore %arg_1 %int_1
-         %21 = OpLoad %half %arg_0 None
-         %22 = OpLoad %int %arg_1 None
-         %23 = OpBitcast %uint %22
-         %24 = OpLoad %uint %tint_subgroup_size_mask None
-         %25 = OpBitwiseAnd %uint %23 %24
-         %26 = OpGroupNonUniformShuffle %half %uint_3 %21 %25
-               OpStore %res %26
-         %29 = OpLoad %half %res None
-               OpReturnValue %29
+         %19 = OpLoad %half %arg_0 None
+         %20 = OpLoad %int %arg_1 None
+         %21 = OpBitcast %uint %20
+         %22 = OpLoad %uint %tint_subgroup_last_id None
+         %23 = OpExtInst %uint %24 UMin %21 %22
+         %25 = OpGroupNonUniformShuffle %half %uint_3 %19 %23
+               OpStore %res %25
+         %28 = OpLoad %half %res None
+               OpReturnValue %28
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %33
-%tint_subgroup_size = OpFunctionParameter %uint
-         %34 = OpLabel
-         %35 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %35 None
-         %37 = OpFunctionCall %half %subgroupShuffle_b0f28d
-         %38 = OpAccessChain %_ptr_StorageBuffer_half %1 %uint_0
-               OpStore %38 %37 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %42
-         %43 = OpLabel
-         %44 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %45 = OpFunctionCall %void %fragment_main_inner %44
+%fragment_main = OpFunction %void None %31
+         %32 = OpLabel
+         %33 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %35 = OpISub %uint %33 %uint_1
+               OpStore %tint_subgroup_last_id %35 None
+         %36 = OpFunctionCall %half %subgroupShuffle_b0f28d
+         %37 = OpAccessChain %_ptr_StorageBuffer_half %1 %uint_0
+               OpStore %37 %36 None
                OpReturn
                OpFunctionEnd
 ;
@@ -94,33 +81,30 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 46
+; Bound: 40
 ; Schema: 0
                OpCapability Shader
                OpCapability Float16
                OpCapability StorageBuffer16BitAccess
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %24 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_b0f28d "subgroupShuffle_b0f28d"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
        %half = OpTypeFloat 16
 %prevent_dce_block = OpTypeStruct %half
 %_ptr_StorageBuffer_prevent_dce_block = OpTypePointer StorageBuffer %prevent_dce_block
@@ -128,10 +112,8 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %half
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %half
 %_ptr_Function_half = OpTypePointer Function %half
 %half_0x1p_0 = OpConstant %half 0x1p+0
         %int = OpTypeInt 32 1
@@ -139,41 +121,34 @@
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %33 = OpTypeFunction %void %uint
+         %31 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_half = OpTypePointer StorageBuffer %half
      %uint_0 = OpConstant %uint 0
-         %42 = OpTypeFunction %void
-%subgroupShuffle_b0f28d = OpFunction %half None %12
-         %13 = OpLabel
+%subgroupShuffle_b0f28d = OpFunction %half None %10
+         %11 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_half Function
       %arg_1 = OpVariable %_ptr_Function_int Function
         %res = OpVariable %_ptr_Function_half Function
                OpStore %arg_0 %half_0x1p_0
                OpStore %arg_1 %int_1
-         %21 = OpLoad %half %arg_0 None
-         %22 = OpLoad %int %arg_1 None
-         %23 = OpBitcast %uint %22
-         %24 = OpLoad %uint %tint_subgroup_size_mask None
-         %25 = OpBitwiseAnd %uint %23 %24
-         %26 = OpGroupNonUniformShuffle %half %uint_3 %21 %25
-               OpStore %res %26
-         %29 = OpLoad %half %res None
-               OpReturnValue %29
+         %19 = OpLoad %half %arg_0 None
+         %20 = OpLoad %int %arg_1 None
+         %21 = OpBitcast %uint %20
+         %22 = OpLoad %uint %tint_subgroup_last_id None
+         %23 = OpExtInst %uint %24 UMin %21 %22
+         %25 = OpGroupNonUniformShuffle %half %uint_3 %19 %23
+               OpStore %res %25
+         %28 = OpLoad %half %res None
+               OpReturnValue %28
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %33
-%tint_subgroup_size = OpFunctionParameter %uint
-         %34 = OpLabel
-         %35 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %35 None
-         %37 = OpFunctionCall %half %subgroupShuffle_b0f28d
-         %38 = OpAccessChain %_ptr_StorageBuffer_half %1 %uint_0
-               OpStore %38 %37 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %42
-         %43 = OpLabel
-         %44 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %45 = OpFunctionCall %void %compute_main_inner %44
+%compute_main = OpFunction %void None %31
+         %32 = OpLabel
+         %33 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %35 = OpISub %uint %33 %uint_1
+               OpStore %tint_subgroup_last_id %35 None
+         %36 = OpFunctionCall %half %subgroupShuffle_b0f28d
+         %37 = OpAccessChain %_ptr_StorageBuffer_half %1 %uint_0
+               OpStore %37 %36 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/var/subgroupShuffle/b4bbb7.wgsl.expected.spvasm b/test/tint/builtins/gen/var/subgroupShuffle/b4bbb7.wgsl.expected.spvasm
index c0d8772..578a579 100644
--- a/test/tint/builtins/gen/var/subgroupShuffle/b4bbb7.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/var/subgroupShuffle/b4bbb7.wgsl.expected.spvasm
@@ -4,32 +4,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 45
+; Bound: 39
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %24 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_b4bbb7 "subgroupShuffle_b4bbb7"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
         %int = OpTypeInt 32 1
       %v3int = OpTypeVector %int 3
 %prevent_dce_block = OpTypeStruct %v3int
@@ -38,51 +34,42 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v3int
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v3int
 %_ptr_Function_v3int = OpTypePointer Function %v3int
       %int_1 = OpConstant %int 1
-         %17 = OpConstantComposite %v3int %int_1 %int_1 %int_1
+         %15 = OpConstantComposite %v3int %int_1 %int_1 %int_1
 %_ptr_Function_uint = OpTypePointer Function %uint
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %33 = OpTypeFunction %void %uint
+         %31 = OpTypeFunction %void
 %_ptr_StorageBuffer_v3int = OpTypePointer StorageBuffer %v3int
      %uint_0 = OpConstant %uint 0
-         %41 = OpTypeFunction %void
-%subgroupShuffle_b4bbb7 = OpFunction %v3int None %13
-         %14 = OpLabel
+%subgroupShuffle_b4bbb7 = OpFunction %v3int None %11
+         %12 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v3int Function
       %arg_1 = OpVariable %_ptr_Function_uint Function
         %res = OpVariable %_ptr_Function_v3int Function
-               OpStore %arg_0 %17
+               OpStore %arg_0 %15
                OpStore %arg_1 %uint_1
-         %22 = OpLoad %v3int %arg_0 None
-         %23 = OpLoad %uint %arg_1 None
-         %24 = OpLoad %uint %tint_subgroup_size_mask None
-         %25 = OpBitwiseAnd %uint %23 %24
-         %26 = OpGroupNonUniformShuffle %v3int %uint_3 %22 %25
-               OpStore %res %26
-         %29 = OpLoad %v3int %res None
-               OpReturnValue %29
+         %20 = OpLoad %v3int %arg_0 None
+         %21 = OpLoad %uint %arg_1 None
+         %22 = OpLoad %uint %tint_subgroup_last_id None
+         %23 = OpExtInst %uint %24 UMin %21 %22
+         %25 = OpGroupNonUniformShuffle %v3int %uint_3 %20 %23
+               OpStore %res %25
+         %28 = OpLoad %v3int %res None
+               OpReturnValue %28
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %33
-%tint_subgroup_size = OpFunctionParameter %uint
-         %34 = OpLabel
-         %35 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %35 None
-         %36 = OpFunctionCall %v3int %subgroupShuffle_b4bbb7
-         %37 = OpAccessChain %_ptr_StorageBuffer_v3int %1 %uint_0
-               OpStore %37 %36 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %41
-         %42 = OpLabel
-         %43 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %44 = OpFunctionCall %void %fragment_main_inner %43
+%fragment_main = OpFunction %void None %31
+         %32 = OpLabel
+         %33 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %34 = OpISub %uint %33 %uint_1
+               OpStore %tint_subgroup_last_id %34 None
+         %35 = OpFunctionCall %v3int %subgroupShuffle_b4bbb7
+         %36 = OpAccessChain %_ptr_StorageBuffer_v3int %1 %uint_0
+               OpStore %36 %35 None
                OpReturn
                OpFunctionEnd
 ;
@@ -91,31 +78,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 45
+; Bound: 39
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %24 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_b4bbb7 "subgroupShuffle_b4bbb7"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
         %int = OpTypeInt 32 1
       %v3int = OpTypeVector %int 3
 %prevent_dce_block = OpTypeStruct %v3int
@@ -124,50 +108,41 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v3int
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v3int
 %_ptr_Function_v3int = OpTypePointer Function %v3int
       %int_1 = OpConstant %int 1
-         %17 = OpConstantComposite %v3int %int_1 %int_1 %int_1
+         %15 = OpConstantComposite %v3int %int_1 %int_1 %int_1
 %_ptr_Function_uint = OpTypePointer Function %uint
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %33 = OpTypeFunction %void %uint
+         %31 = OpTypeFunction %void
 %_ptr_StorageBuffer_v3int = OpTypePointer StorageBuffer %v3int
      %uint_0 = OpConstant %uint 0
-         %41 = OpTypeFunction %void
-%subgroupShuffle_b4bbb7 = OpFunction %v3int None %13
-         %14 = OpLabel
+%subgroupShuffle_b4bbb7 = OpFunction %v3int None %11
+         %12 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v3int Function
       %arg_1 = OpVariable %_ptr_Function_uint Function
         %res = OpVariable %_ptr_Function_v3int Function
-               OpStore %arg_0 %17
+               OpStore %arg_0 %15
                OpStore %arg_1 %uint_1
-         %22 = OpLoad %v3int %arg_0 None
-         %23 = OpLoad %uint %arg_1 None
-         %24 = OpLoad %uint %tint_subgroup_size_mask None
-         %25 = OpBitwiseAnd %uint %23 %24
-         %26 = OpGroupNonUniformShuffle %v3int %uint_3 %22 %25
-               OpStore %res %26
-         %29 = OpLoad %v3int %res None
-               OpReturnValue %29
+         %20 = OpLoad %v3int %arg_0 None
+         %21 = OpLoad %uint %arg_1 None
+         %22 = OpLoad %uint %tint_subgroup_last_id None
+         %23 = OpExtInst %uint %24 UMin %21 %22
+         %25 = OpGroupNonUniformShuffle %v3int %uint_3 %20 %23
+               OpStore %res %25
+         %28 = OpLoad %v3int %res None
+               OpReturnValue %28
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %33
-%tint_subgroup_size = OpFunctionParameter %uint
-         %34 = OpLabel
-         %35 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %35 None
-         %36 = OpFunctionCall %v3int %subgroupShuffle_b4bbb7
-         %37 = OpAccessChain %_ptr_StorageBuffer_v3int %1 %uint_0
-               OpStore %37 %36 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %41
-         %42 = OpLabel
-         %43 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %44 = OpFunctionCall %void %compute_main_inner %43
+%compute_main = OpFunction %void None %31
+         %32 = OpLabel
+         %33 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %34 = OpISub %uint %33 %uint_1
+               OpStore %tint_subgroup_last_id %34 None
+         %35 = OpFunctionCall %v3int %subgroupShuffle_b4bbb7
+         %36 = OpAccessChain %_ptr_StorageBuffer_v3int %1 %uint_0
+               OpStore %36 %35 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/var/subgroupShuffle/bbb06c.wgsl.expected.spvasm b/test/tint/builtins/gen/var/subgroupShuffle/bbb06c.wgsl.expected.spvasm
index c661567..ef21aef 100644
--- a/test/tint/builtins/gen/var/subgroupShuffle/bbb06c.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/var/subgroupShuffle/bbb06c.wgsl.expected.spvasm
@@ -4,32 +4,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 46
+; Bound: 40
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %24 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_bbb06c "subgroupShuffle_bbb06c"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
         %int = OpTypeInt 32 1
       %v2int = OpTypeVector %int 2
 %prevent_dce_block = OpTypeStruct %v2int
@@ -38,52 +34,43 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v2int
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v2int
 %_ptr_Function_v2int = OpTypePointer Function %v2int
       %int_1 = OpConstant %int 1
-         %17 = OpConstantComposite %v2int %int_1 %int_1
+         %15 = OpConstantComposite %v2int %int_1 %int_1
 %_ptr_Function_int = OpTypePointer Function %int
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %33 = OpTypeFunction %void %uint
+         %31 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_v2int = OpTypePointer StorageBuffer %v2int
      %uint_0 = OpConstant %uint 0
-         %42 = OpTypeFunction %void
-%subgroupShuffle_bbb06c = OpFunction %v2int None %13
-         %14 = OpLabel
+%subgroupShuffle_bbb06c = OpFunction %v2int None %11
+         %12 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v2int Function
       %arg_1 = OpVariable %_ptr_Function_int Function
         %res = OpVariable %_ptr_Function_v2int Function
-               OpStore %arg_0 %17
+               OpStore %arg_0 %15
                OpStore %arg_1 %int_1
-         %21 = OpLoad %v2int %arg_0 None
-         %22 = OpLoad %int %arg_1 None
-         %23 = OpBitcast %uint %22
-         %24 = OpLoad %uint %tint_subgroup_size_mask None
-         %25 = OpBitwiseAnd %uint %23 %24
-         %26 = OpGroupNonUniformShuffle %v2int %uint_3 %21 %25
-               OpStore %res %26
-         %29 = OpLoad %v2int %res None
-               OpReturnValue %29
+         %19 = OpLoad %v2int %arg_0 None
+         %20 = OpLoad %int %arg_1 None
+         %21 = OpBitcast %uint %20
+         %22 = OpLoad %uint %tint_subgroup_last_id None
+         %23 = OpExtInst %uint %24 UMin %21 %22
+         %25 = OpGroupNonUniformShuffle %v2int %uint_3 %19 %23
+               OpStore %res %25
+         %28 = OpLoad %v2int %res None
+               OpReturnValue %28
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %33
-%tint_subgroup_size = OpFunctionParameter %uint
-         %34 = OpLabel
-         %35 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %35 None
-         %37 = OpFunctionCall %v2int %subgroupShuffle_bbb06c
-         %38 = OpAccessChain %_ptr_StorageBuffer_v2int %1 %uint_0
-               OpStore %38 %37 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %42
-         %43 = OpLabel
-         %44 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %45 = OpFunctionCall %void %fragment_main_inner %44
+%fragment_main = OpFunction %void None %31
+         %32 = OpLabel
+         %33 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %35 = OpISub %uint %33 %uint_1
+               OpStore %tint_subgroup_last_id %35 None
+         %36 = OpFunctionCall %v2int %subgroupShuffle_bbb06c
+         %37 = OpAccessChain %_ptr_StorageBuffer_v2int %1 %uint_0
+               OpStore %37 %36 None
                OpReturn
                OpFunctionEnd
 ;
@@ -92,31 +79,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 46
+; Bound: 40
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %24 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_bbb06c "subgroupShuffle_bbb06c"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
         %int = OpTypeInt 32 1
       %v2int = OpTypeVector %int 2
 %prevent_dce_block = OpTypeStruct %v2int
@@ -125,51 +109,42 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v2int
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v2int
 %_ptr_Function_v2int = OpTypePointer Function %v2int
       %int_1 = OpConstant %int 1
-         %17 = OpConstantComposite %v2int %int_1 %int_1
+         %15 = OpConstantComposite %v2int %int_1 %int_1
 %_ptr_Function_int = OpTypePointer Function %int
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %33 = OpTypeFunction %void %uint
+         %31 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_v2int = OpTypePointer StorageBuffer %v2int
      %uint_0 = OpConstant %uint 0
-         %42 = OpTypeFunction %void
-%subgroupShuffle_bbb06c = OpFunction %v2int None %13
-         %14 = OpLabel
+%subgroupShuffle_bbb06c = OpFunction %v2int None %11
+         %12 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v2int Function
       %arg_1 = OpVariable %_ptr_Function_int Function
         %res = OpVariable %_ptr_Function_v2int Function
-               OpStore %arg_0 %17
+               OpStore %arg_0 %15
                OpStore %arg_1 %int_1
-         %21 = OpLoad %v2int %arg_0 None
-         %22 = OpLoad %int %arg_1 None
-         %23 = OpBitcast %uint %22
-         %24 = OpLoad %uint %tint_subgroup_size_mask None
-         %25 = OpBitwiseAnd %uint %23 %24
-         %26 = OpGroupNonUniformShuffle %v2int %uint_3 %21 %25
-               OpStore %res %26
-         %29 = OpLoad %v2int %res None
-               OpReturnValue %29
+         %19 = OpLoad %v2int %arg_0 None
+         %20 = OpLoad %int %arg_1 None
+         %21 = OpBitcast %uint %20
+         %22 = OpLoad %uint %tint_subgroup_last_id None
+         %23 = OpExtInst %uint %24 UMin %21 %22
+         %25 = OpGroupNonUniformShuffle %v2int %uint_3 %19 %23
+               OpStore %res %25
+         %28 = OpLoad %v2int %res None
+               OpReturnValue %28
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %33
-%tint_subgroup_size = OpFunctionParameter %uint
-         %34 = OpLabel
-         %35 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %35 None
-         %37 = OpFunctionCall %v2int %subgroupShuffle_bbb06c
-         %38 = OpAccessChain %_ptr_StorageBuffer_v2int %1 %uint_0
-               OpStore %38 %37 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %42
-         %43 = OpLabel
-         %44 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %45 = OpFunctionCall %void %compute_main_inner %44
+%compute_main = OpFunction %void None %31
+         %32 = OpLabel
+         %33 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %35 = OpISub %uint %33 %uint_1
+               OpStore %tint_subgroup_last_id %35 None
+         %36 = OpFunctionCall %v2int %subgroupShuffle_bbb06c
+         %37 = OpAccessChain %_ptr_StorageBuffer_v2int %1 %uint_0
+               OpStore %37 %36 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/var/subgroupShuffle/d4a772.wgsl.expected.spvasm b/test/tint/builtins/gen/var/subgroupShuffle/d4a772.wgsl.expected.spvasm
index cd4b459..61d5fa4 100644
--- a/test/tint/builtins/gen/var/subgroupShuffle/d4a772.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/var/subgroupShuffle/d4a772.wgsl.expected.spvasm
@@ -4,32 +4,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 43
+; Bound: 37
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %22 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_d4a772 "subgroupShuffle_d4a772"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
         %int = OpTypeInt 32 1
 %prevent_dce_block = OpTypeStruct %int
 %_ptr_StorageBuffer_prevent_dce_block = OpTypePointer StorageBuffer %prevent_dce_block
@@ -37,50 +33,41 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %int
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %int
 %_ptr_Function_int = OpTypePointer Function %int
       %int_1 = OpConstant %int 1
 %_ptr_Function_uint = OpTypePointer Function %uint
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %31 = OpTypeFunction %void %uint
+         %29 = OpTypeFunction %void
 %_ptr_StorageBuffer_int = OpTypePointer StorageBuffer %int
      %uint_0 = OpConstant %uint 0
-         %39 = OpTypeFunction %void
-%subgroupShuffle_d4a772 = OpFunction %int None %12
-         %13 = OpLabel
+%subgroupShuffle_d4a772 = OpFunction %int None %10
+         %11 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_int Function
       %arg_1 = OpVariable %_ptr_Function_uint Function
         %res = OpVariable %_ptr_Function_int Function
                OpStore %arg_0 %int_1
                OpStore %arg_1 %uint_1
-         %20 = OpLoad %int %arg_0 None
-         %21 = OpLoad %uint %arg_1 None
-         %22 = OpLoad %uint %tint_subgroup_size_mask None
-         %23 = OpBitwiseAnd %uint %21 %22
-         %24 = OpGroupNonUniformShuffle %int %uint_3 %20 %23
-               OpStore %res %24
-         %27 = OpLoad %int %res None
-               OpReturnValue %27
+         %18 = OpLoad %int %arg_0 None
+         %19 = OpLoad %uint %arg_1 None
+         %20 = OpLoad %uint %tint_subgroup_last_id None
+         %21 = OpExtInst %uint %22 UMin %19 %20
+         %23 = OpGroupNonUniformShuffle %int %uint_3 %18 %21
+               OpStore %res %23
+         %26 = OpLoad %int %res None
+               OpReturnValue %26
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %31
-%tint_subgroup_size = OpFunctionParameter %uint
-         %32 = OpLabel
-         %33 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %33 None
-         %34 = OpFunctionCall %int %subgroupShuffle_d4a772
-         %35 = OpAccessChain %_ptr_StorageBuffer_int %1 %uint_0
-               OpStore %35 %34 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %39
-         %40 = OpLabel
-         %41 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %42 = OpFunctionCall %void %fragment_main_inner %41
+%fragment_main = OpFunction %void None %29
+         %30 = OpLabel
+         %31 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %32 = OpISub %uint %31 %uint_1
+               OpStore %tint_subgroup_last_id %32 None
+         %33 = OpFunctionCall %int %subgroupShuffle_d4a772
+         %34 = OpAccessChain %_ptr_StorageBuffer_int %1 %uint_0
+               OpStore %34 %33 None
                OpReturn
                OpFunctionEnd
 ;
@@ -89,31 +76,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 43
+; Bound: 37
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %22 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_d4a772 "subgroupShuffle_d4a772"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
         %int = OpTypeInt 32 1
 %prevent_dce_block = OpTypeStruct %int
 %_ptr_StorageBuffer_prevent_dce_block = OpTypePointer StorageBuffer %prevent_dce_block
@@ -121,49 +105,40 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %int
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %int
 %_ptr_Function_int = OpTypePointer Function %int
       %int_1 = OpConstant %int 1
 %_ptr_Function_uint = OpTypePointer Function %uint
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %31 = OpTypeFunction %void %uint
+         %29 = OpTypeFunction %void
 %_ptr_StorageBuffer_int = OpTypePointer StorageBuffer %int
      %uint_0 = OpConstant %uint 0
-         %39 = OpTypeFunction %void
-%subgroupShuffle_d4a772 = OpFunction %int None %12
-         %13 = OpLabel
+%subgroupShuffle_d4a772 = OpFunction %int None %10
+         %11 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_int Function
       %arg_1 = OpVariable %_ptr_Function_uint Function
         %res = OpVariable %_ptr_Function_int Function
                OpStore %arg_0 %int_1
                OpStore %arg_1 %uint_1
-         %20 = OpLoad %int %arg_0 None
-         %21 = OpLoad %uint %arg_1 None
-         %22 = OpLoad %uint %tint_subgroup_size_mask None
-         %23 = OpBitwiseAnd %uint %21 %22
-         %24 = OpGroupNonUniformShuffle %int %uint_3 %20 %23
-               OpStore %res %24
-         %27 = OpLoad %int %res None
-               OpReturnValue %27
+         %18 = OpLoad %int %arg_0 None
+         %19 = OpLoad %uint %arg_1 None
+         %20 = OpLoad %uint %tint_subgroup_last_id None
+         %21 = OpExtInst %uint %22 UMin %19 %20
+         %23 = OpGroupNonUniformShuffle %int %uint_3 %18 %21
+               OpStore %res %23
+         %26 = OpLoad %int %res None
+               OpReturnValue %26
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %31
-%tint_subgroup_size = OpFunctionParameter %uint
-         %32 = OpLabel
-         %33 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %33 None
-         %34 = OpFunctionCall %int %subgroupShuffle_d4a772
-         %35 = OpAccessChain %_ptr_StorageBuffer_int %1 %uint_0
-               OpStore %35 %34 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %39
-         %40 = OpLabel
-         %41 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %42 = OpFunctionCall %void %compute_main_inner %41
+%compute_main = OpFunction %void None %29
+         %30 = OpLabel
+         %31 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %32 = OpISub %uint %31 %uint_1
+               OpStore %tint_subgroup_last_id %32 None
+         %33 = OpFunctionCall %int %subgroupShuffle_d4a772
+         %34 = OpAccessChain %_ptr_StorageBuffer_int %1 %uint_0
+               OpStore %34 %33 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/var/subgroupShuffle/d9ff67.wgsl.expected.spvasm b/test/tint/builtins/gen/var/subgroupShuffle/d9ff67.wgsl.expected.spvasm
index d5704a9..51554f1 100644
--- a/test/tint/builtins/gen/var/subgroupShuffle/d9ff67.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/var/subgroupShuffle/d9ff67.wgsl.expected.spvasm
@@ -4,32 +4,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 48
+; Bound: 42
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %26 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_d9ff67 "subgroupShuffle_d9ff67"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
       %float = OpTypeFloat 32
     %v2float = OpTypeVector %float 2
 %prevent_dce_block = OpTypeStruct %v2float
@@ -38,54 +34,45 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v2float
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v2float
 %_ptr_Function_v2float = OpTypePointer Function %v2float
     %float_1 = OpConstant %float 1
-         %17 = OpConstantComposite %v2float %float_1 %float_1
+         %15 = OpConstantComposite %v2float %float_1 %float_1
         %int = OpTypeInt 32 1
 %_ptr_Function_int = OpTypePointer Function %int
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %35 = OpTypeFunction %void %uint
+         %33 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_v2float = OpTypePointer StorageBuffer %v2float
      %uint_0 = OpConstant %uint 0
-         %44 = OpTypeFunction %void
-%subgroupShuffle_d9ff67 = OpFunction %v2float None %13
-         %14 = OpLabel
+%subgroupShuffle_d9ff67 = OpFunction %v2float None %11
+         %12 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v2float Function
       %arg_1 = OpVariable %_ptr_Function_int Function
         %res = OpVariable %_ptr_Function_v2float Function
-               OpStore %arg_0 %17
+               OpStore %arg_0 %15
                OpStore %arg_1 %int_1
-         %23 = OpLoad %v2float %arg_0 None
-         %24 = OpLoad %int %arg_1 None
-         %25 = OpBitcast %uint %24
-         %26 = OpLoad %uint %tint_subgroup_size_mask None
-         %27 = OpBitwiseAnd %uint %25 %26
-         %28 = OpGroupNonUniformShuffle %v2float %uint_3 %23 %27
-               OpStore %res %28
-         %31 = OpLoad %v2float %res None
-               OpReturnValue %31
+         %21 = OpLoad %v2float %arg_0 None
+         %22 = OpLoad %int %arg_1 None
+         %23 = OpBitcast %uint %22
+         %24 = OpLoad %uint %tint_subgroup_last_id None
+         %25 = OpExtInst %uint %26 UMin %23 %24
+         %27 = OpGroupNonUniformShuffle %v2float %uint_3 %21 %25
+               OpStore %res %27
+         %30 = OpLoad %v2float %res None
+               OpReturnValue %30
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %35
-%tint_subgroup_size = OpFunctionParameter %uint
-         %36 = OpLabel
-         %37 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %37 None
-         %39 = OpFunctionCall %v2float %subgroupShuffle_d9ff67
-         %40 = OpAccessChain %_ptr_StorageBuffer_v2float %1 %uint_0
-               OpStore %40 %39 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %44
-         %45 = OpLabel
-         %46 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %47 = OpFunctionCall %void %fragment_main_inner %46
+%fragment_main = OpFunction %void None %33
+         %34 = OpLabel
+         %35 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %37 = OpISub %uint %35 %uint_1
+               OpStore %tint_subgroup_last_id %37 None
+         %38 = OpFunctionCall %v2float %subgroupShuffle_d9ff67
+         %39 = OpAccessChain %_ptr_StorageBuffer_v2float %1 %uint_0
+               OpStore %39 %38 None
                OpReturn
                OpFunctionEnd
 ;
@@ -94,31 +81,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 48
+; Bound: 42
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %26 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_d9ff67 "subgroupShuffle_d9ff67"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
       %float = OpTypeFloat 32
     %v2float = OpTypeVector %float 2
 %prevent_dce_block = OpTypeStruct %v2float
@@ -127,53 +111,44 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v2float
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v2float
 %_ptr_Function_v2float = OpTypePointer Function %v2float
     %float_1 = OpConstant %float 1
-         %17 = OpConstantComposite %v2float %float_1 %float_1
+         %15 = OpConstantComposite %v2float %float_1 %float_1
         %int = OpTypeInt 32 1
 %_ptr_Function_int = OpTypePointer Function %int
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %35 = OpTypeFunction %void %uint
+         %33 = OpTypeFunction %void
      %uint_1 = OpConstant %uint 1
 %_ptr_StorageBuffer_v2float = OpTypePointer StorageBuffer %v2float
      %uint_0 = OpConstant %uint 0
-         %44 = OpTypeFunction %void
-%subgroupShuffle_d9ff67 = OpFunction %v2float None %13
-         %14 = OpLabel
+%subgroupShuffle_d9ff67 = OpFunction %v2float None %11
+         %12 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v2float Function
       %arg_1 = OpVariable %_ptr_Function_int Function
         %res = OpVariable %_ptr_Function_v2float Function
-               OpStore %arg_0 %17
+               OpStore %arg_0 %15
                OpStore %arg_1 %int_1
-         %23 = OpLoad %v2float %arg_0 None
-         %24 = OpLoad %int %arg_1 None
-         %25 = OpBitcast %uint %24
-         %26 = OpLoad %uint %tint_subgroup_size_mask None
-         %27 = OpBitwiseAnd %uint %25 %26
-         %28 = OpGroupNonUniformShuffle %v2float %uint_3 %23 %27
-               OpStore %res %28
-         %31 = OpLoad %v2float %res None
-               OpReturnValue %31
+         %21 = OpLoad %v2float %arg_0 None
+         %22 = OpLoad %int %arg_1 None
+         %23 = OpBitcast %uint %22
+         %24 = OpLoad %uint %tint_subgroup_last_id None
+         %25 = OpExtInst %uint %26 UMin %23 %24
+         %27 = OpGroupNonUniformShuffle %v2float %uint_3 %21 %25
+               OpStore %res %27
+         %30 = OpLoad %v2float %res None
+               OpReturnValue %30
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %35
-%tint_subgroup_size = OpFunctionParameter %uint
-         %36 = OpLabel
-         %37 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %37 None
-         %39 = OpFunctionCall %v2float %subgroupShuffle_d9ff67
-         %40 = OpAccessChain %_ptr_StorageBuffer_v2float %1 %uint_0
-               OpStore %40 %39 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %44
-         %45 = OpLabel
-         %46 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %47 = OpFunctionCall %void %compute_main_inner %46
+%compute_main = OpFunction %void None %33
+         %34 = OpLabel
+         %35 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %37 = OpISub %uint %35 %uint_1
+               OpStore %tint_subgroup_last_id %37 None
+         %38 = OpFunctionCall %v2float %subgroupShuffle_d9ff67
+         %39 = OpAccessChain %_ptr_StorageBuffer_v2float %1 %uint_0
+               OpStore %39 %38 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/var/subgroupShuffle/e13c81.wgsl.expected.spvasm b/test/tint/builtins/gen/var/subgroupShuffle/e13c81.wgsl.expected.spvasm
index 7925882..60d6bbb 100644
--- a/test/tint/builtins/gen/var/subgroupShuffle/e13c81.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/var/subgroupShuffle/e13c81.wgsl.expected.spvasm
@@ -4,32 +4,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 46
+; Bound: 40
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %25 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_e13c81 "subgroupShuffle_e13c81"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
        %uint = OpTypeInt 32 0
      %v4uint = OpTypeVector %uint 4
 %prevent_dce_block = OpTypeStruct %v4uint
@@ -37,53 +33,44 @@
           %1 = OpVariable %_ptr_StorageBuffer_prevent_dce_block StorageBuffer
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %v4uint
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %v4uint
 %_ptr_Function_v4uint = OpTypePointer Function %v4uint
      %uint_1 = OpConstant %uint 1
-         %16 = OpConstantComposite %v4uint %uint_1 %uint_1 %uint_1 %uint_1
+         %14 = OpConstantComposite %v4uint %uint_1 %uint_1 %uint_1 %uint_1
         %int = OpTypeInt 32 1
 %_ptr_Function_int = OpTypePointer Function %int
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %34 = OpTypeFunction %void %uint
+         %32 = OpTypeFunction %void
 %_ptr_StorageBuffer_v4uint = OpTypePointer StorageBuffer %v4uint
      %uint_0 = OpConstant %uint 0
-         %42 = OpTypeFunction %void
-%subgroupShuffle_e13c81 = OpFunction %v4uint None %12
-         %13 = OpLabel
+%subgroupShuffle_e13c81 = OpFunction %v4uint None %10
+         %11 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v4uint Function
       %arg_1 = OpVariable %_ptr_Function_int Function
         %res = OpVariable %_ptr_Function_v4uint Function
-               OpStore %arg_0 %16
+               OpStore %arg_0 %14
                OpStore %arg_1 %int_1
-         %22 = OpLoad %v4uint %arg_0 None
-         %23 = OpLoad %int %arg_1 None
-         %24 = OpBitcast %uint %23
-         %25 = OpLoad %uint %tint_subgroup_size_mask None
-         %26 = OpBitwiseAnd %uint %24 %25
-         %27 = OpGroupNonUniformShuffle %v4uint %uint_3 %22 %26
-               OpStore %res %27
-         %30 = OpLoad %v4uint %res None
-               OpReturnValue %30
+         %20 = OpLoad %v4uint %arg_0 None
+         %21 = OpLoad %int %arg_1 None
+         %22 = OpBitcast %uint %21
+         %23 = OpLoad %uint %tint_subgroup_last_id None
+         %24 = OpExtInst %uint %25 UMin %22 %23
+         %26 = OpGroupNonUniformShuffle %v4uint %uint_3 %20 %24
+               OpStore %res %26
+         %29 = OpLoad %v4uint %res None
+               OpReturnValue %29
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %34
-%tint_subgroup_size = OpFunctionParameter %uint
-         %35 = OpLabel
-         %36 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %36 None
-         %37 = OpFunctionCall %v4uint %subgroupShuffle_e13c81
-         %38 = OpAccessChain %_ptr_StorageBuffer_v4uint %1 %uint_0
-               OpStore %38 %37 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %42
-         %43 = OpLabel
-         %44 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %45 = OpFunctionCall %void %fragment_main_inner %44
+%fragment_main = OpFunction %void None %32
+         %33 = OpLabel
+         %34 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %35 = OpISub %uint %34 %uint_1
+               OpStore %tint_subgroup_last_id %35 None
+         %36 = OpFunctionCall %v4uint %subgroupShuffle_e13c81
+         %37 = OpAccessChain %_ptr_StorageBuffer_v4uint %1 %uint_0
+               OpStore %37 %36 None
                OpReturn
                OpFunctionEnd
 ;
@@ -92,31 +79,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 46
+; Bound: 40
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %25 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_e13c81 "subgroupShuffle_e13c81"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
        %uint = OpTypeInt 32 0
      %v4uint = OpTypeVector %uint 4
 %prevent_dce_block = OpTypeStruct %v4uint
@@ -124,52 +108,43 @@
           %1 = OpVariable %_ptr_StorageBuffer_prevent_dce_block StorageBuffer
 %_ptr_Private_uint = OpTypePointer Private %uint
           %8 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %8
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %12 = OpTypeFunction %v4uint
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %8
+         %10 = OpTypeFunction %v4uint
 %_ptr_Function_v4uint = OpTypePointer Function %v4uint
      %uint_1 = OpConstant %uint 1
-         %16 = OpConstantComposite %v4uint %uint_1 %uint_1 %uint_1 %uint_1
+         %14 = OpConstantComposite %v4uint %uint_1 %uint_1 %uint_1 %uint_1
         %int = OpTypeInt 32 1
 %_ptr_Function_int = OpTypePointer Function %int
       %int_1 = OpConstant %int 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %34 = OpTypeFunction %void %uint
+         %32 = OpTypeFunction %void
 %_ptr_StorageBuffer_v4uint = OpTypePointer StorageBuffer %v4uint
      %uint_0 = OpConstant %uint 0
-         %42 = OpTypeFunction %void
-%subgroupShuffle_e13c81 = OpFunction %v4uint None %12
-         %13 = OpLabel
+%subgroupShuffle_e13c81 = OpFunction %v4uint None %10
+         %11 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v4uint Function
       %arg_1 = OpVariable %_ptr_Function_int Function
         %res = OpVariable %_ptr_Function_v4uint Function
-               OpStore %arg_0 %16
+               OpStore %arg_0 %14
                OpStore %arg_1 %int_1
-         %22 = OpLoad %v4uint %arg_0 None
-         %23 = OpLoad %int %arg_1 None
-         %24 = OpBitcast %uint %23
-         %25 = OpLoad %uint %tint_subgroup_size_mask None
-         %26 = OpBitwiseAnd %uint %24 %25
-         %27 = OpGroupNonUniformShuffle %v4uint %uint_3 %22 %26
-               OpStore %res %27
-         %30 = OpLoad %v4uint %res None
-               OpReturnValue %30
+         %20 = OpLoad %v4uint %arg_0 None
+         %21 = OpLoad %int %arg_1 None
+         %22 = OpBitcast %uint %21
+         %23 = OpLoad %uint %tint_subgroup_last_id None
+         %24 = OpExtInst %uint %25 UMin %22 %23
+         %26 = OpGroupNonUniformShuffle %v4uint %uint_3 %20 %24
+               OpStore %res %26
+         %29 = OpLoad %v4uint %res None
+               OpReturnValue %29
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %34
-%tint_subgroup_size = OpFunctionParameter %uint
-         %35 = OpLabel
-         %36 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %36 None
-         %37 = OpFunctionCall %v4uint %subgroupShuffle_e13c81
-         %38 = OpAccessChain %_ptr_StorageBuffer_v4uint %1 %uint_0
-               OpStore %38 %37 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %42
-         %43 = OpLabel
-         %44 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %45 = OpFunctionCall %void %compute_main_inner %44
+%compute_main = OpFunction %void None %32
+         %33 = OpLabel
+         %34 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %35 = OpISub %uint %34 %uint_1
+               OpStore %tint_subgroup_last_id %35 None
+         %36 = OpFunctionCall %v4uint %subgroupShuffle_e13c81
+         %37 = OpAccessChain %_ptr_StorageBuffer_v4uint %1 %uint_0
+               OpStore %37 %36 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/var/subgroupShuffle/e854d5.wgsl.expected.spvasm b/test/tint/builtins/gen/var/subgroupShuffle/e854d5.wgsl.expected.spvasm
index 60f05e8..71c2c4a 100644
--- a/test/tint/builtins/gen/var/subgroupShuffle/e854d5.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/var/subgroupShuffle/e854d5.wgsl.expected.spvasm
@@ -4,32 +4,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 45
+; Bound: 39
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %24 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_e854d5 "subgroupShuffle_e854d5"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
         %int = OpTypeInt 32 1
       %v4int = OpTypeVector %int 4
 %prevent_dce_block = OpTypeStruct %v4int
@@ -38,51 +34,42 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v4int
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v4int
 %_ptr_Function_v4int = OpTypePointer Function %v4int
       %int_1 = OpConstant %int 1
-         %17 = OpConstantComposite %v4int %int_1 %int_1 %int_1 %int_1
+         %15 = OpConstantComposite %v4int %int_1 %int_1 %int_1 %int_1
 %_ptr_Function_uint = OpTypePointer Function %uint
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %33 = OpTypeFunction %void %uint
+         %31 = OpTypeFunction %void
 %_ptr_StorageBuffer_v4int = OpTypePointer StorageBuffer %v4int
      %uint_0 = OpConstant %uint 0
-         %41 = OpTypeFunction %void
-%subgroupShuffle_e854d5 = OpFunction %v4int None %13
-         %14 = OpLabel
+%subgroupShuffle_e854d5 = OpFunction %v4int None %11
+         %12 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v4int Function
       %arg_1 = OpVariable %_ptr_Function_uint Function
         %res = OpVariable %_ptr_Function_v4int Function
-               OpStore %arg_0 %17
+               OpStore %arg_0 %15
                OpStore %arg_1 %uint_1
-         %22 = OpLoad %v4int %arg_0 None
-         %23 = OpLoad %uint %arg_1 None
-         %24 = OpLoad %uint %tint_subgroup_size_mask None
-         %25 = OpBitwiseAnd %uint %23 %24
-         %26 = OpGroupNonUniformShuffle %v4int %uint_3 %22 %25
-               OpStore %res %26
-         %29 = OpLoad %v4int %res None
-               OpReturnValue %29
+         %20 = OpLoad %v4int %arg_0 None
+         %21 = OpLoad %uint %arg_1 None
+         %22 = OpLoad %uint %tint_subgroup_last_id None
+         %23 = OpExtInst %uint %24 UMin %21 %22
+         %25 = OpGroupNonUniformShuffle %v4int %uint_3 %20 %23
+               OpStore %res %25
+         %28 = OpLoad %v4int %res None
+               OpReturnValue %28
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %33
-%tint_subgroup_size = OpFunctionParameter %uint
-         %34 = OpLabel
-         %35 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %35 None
-         %36 = OpFunctionCall %v4int %subgroupShuffle_e854d5
-         %37 = OpAccessChain %_ptr_StorageBuffer_v4int %1 %uint_0
-               OpStore %37 %36 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %41
-         %42 = OpLabel
-         %43 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %44 = OpFunctionCall %void %fragment_main_inner %43
+%fragment_main = OpFunction %void None %31
+         %32 = OpLabel
+         %33 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %34 = OpISub %uint %33 %uint_1
+               OpStore %tint_subgroup_last_id %34 None
+         %35 = OpFunctionCall %v4int %subgroupShuffle_e854d5
+         %36 = OpAccessChain %_ptr_StorageBuffer_v4int %1 %uint_0
+               OpStore %36 %35 None
                OpReturn
                OpFunctionEnd
 ;
@@ -91,31 +78,28 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 45
+; Bound: 39
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %24 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_e854d5 "subgroupShuffle_e854d5"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
         %int = OpTypeInt 32 1
       %v4int = OpTypeVector %int 4
 %prevent_dce_block = OpTypeStruct %v4int
@@ -124,50 +108,41 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v4int
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v4int
 %_ptr_Function_v4int = OpTypePointer Function %v4int
       %int_1 = OpConstant %int 1
-         %17 = OpConstantComposite %v4int %int_1 %int_1 %int_1 %int_1
+         %15 = OpConstantComposite %v4int %int_1 %int_1 %int_1 %int_1
 %_ptr_Function_uint = OpTypePointer Function %uint
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %33 = OpTypeFunction %void %uint
+         %31 = OpTypeFunction %void
 %_ptr_StorageBuffer_v4int = OpTypePointer StorageBuffer %v4int
      %uint_0 = OpConstant %uint 0
-         %41 = OpTypeFunction %void
-%subgroupShuffle_e854d5 = OpFunction %v4int None %13
-         %14 = OpLabel
+%subgroupShuffle_e854d5 = OpFunction %v4int None %11
+         %12 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v4int Function
       %arg_1 = OpVariable %_ptr_Function_uint Function
         %res = OpVariable %_ptr_Function_v4int Function
-               OpStore %arg_0 %17
+               OpStore %arg_0 %15
                OpStore %arg_1 %uint_1
-         %22 = OpLoad %v4int %arg_0 None
-         %23 = OpLoad %uint %arg_1 None
-         %24 = OpLoad %uint %tint_subgroup_size_mask None
-         %25 = OpBitwiseAnd %uint %23 %24
-         %26 = OpGroupNonUniformShuffle %v4int %uint_3 %22 %25
-               OpStore %res %26
-         %29 = OpLoad %v4int %res None
-               OpReturnValue %29
+         %20 = OpLoad %v4int %arg_0 None
+         %21 = OpLoad %uint %arg_1 None
+         %22 = OpLoad %uint %tint_subgroup_last_id None
+         %23 = OpExtInst %uint %24 UMin %21 %22
+         %25 = OpGroupNonUniformShuffle %v4int %uint_3 %20 %23
+               OpStore %res %25
+         %28 = OpLoad %v4int %res None
+               OpReturnValue %28
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %33
-%tint_subgroup_size = OpFunctionParameter %uint
-         %34 = OpLabel
-         %35 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %35 None
-         %36 = OpFunctionCall %v4int %subgroupShuffle_e854d5
-         %37 = OpAccessChain %_ptr_StorageBuffer_v4int %1 %uint_0
-               OpStore %37 %36 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %41
-         %42 = OpLabel
-         %43 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %44 = OpFunctionCall %void %compute_main_inner %43
+%compute_main = OpFunction %void None %31
+         %32 = OpLabel
+         %33 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %34 = OpISub %uint %33 %uint_1
+               OpStore %tint_subgroup_last_id %34 None
+         %35 = OpFunctionCall %v4int %subgroupShuffle_e854d5
+         %36 = OpAccessChain %_ptr_StorageBuffer_v4int %1 %uint_0
+               OpStore %36 %35 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/var/subgroupShuffle/f194f5.wgsl.expected.spvasm b/test/tint/builtins/gen/var/subgroupShuffle/f194f5.wgsl.expected.spvasm
index 3205966..85b9bf7 100644
--- a/test/tint/builtins/gen/var/subgroupShuffle/f194f5.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/var/subgroupShuffle/f194f5.wgsl.expected.spvasm
@@ -4,80 +4,67 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 40
+; Bound: 34
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %19 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_f194f5 "subgroupShuffle_f194f5"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
        %uint = OpTypeInt 32 0
 %prevent_dce_block = OpTypeStruct %uint
 %_ptr_StorageBuffer_prevent_dce_block = OpTypePointer StorageBuffer %prevent_dce_block
           %1 = OpVariable %_ptr_StorageBuffer_prevent_dce_block StorageBuffer
 %_ptr_Private_uint = OpTypePointer Private %uint
           %7 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %7
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %11 = OpTypeFunction %uint
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %7
+          %9 = OpTypeFunction %uint
 %_ptr_Function_uint = OpTypePointer Function %uint
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %28 = OpTypeFunction %void %uint
+         %26 = OpTypeFunction %void
 %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
      %uint_0 = OpConstant %uint 0
-         %36 = OpTypeFunction %void
-%subgroupShuffle_f194f5 = OpFunction %uint None %11
-         %12 = OpLabel
+%subgroupShuffle_f194f5 = OpFunction %uint None %9
+         %10 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_uint Function
       %arg_1 = OpVariable %_ptr_Function_uint Function
         %res = OpVariable %_ptr_Function_uint Function
                OpStore %arg_0 %uint_1
                OpStore %arg_1 %uint_1
-         %17 = OpLoad %uint %arg_0 None
-         %18 = OpLoad %uint %arg_1 None
-         %19 = OpLoad %uint %tint_subgroup_size_mask None
-         %20 = OpBitwiseAnd %uint %18 %19
-         %21 = OpGroupNonUniformShuffle %uint %uint_3 %17 %20
-               OpStore %res %21
-         %24 = OpLoad %uint %res None
-               OpReturnValue %24
+         %15 = OpLoad %uint %arg_0 None
+         %16 = OpLoad %uint %arg_1 None
+         %17 = OpLoad %uint %tint_subgroup_last_id None
+         %18 = OpExtInst %uint %19 UMin %16 %17
+         %20 = OpGroupNonUniformShuffle %uint %uint_3 %15 %18
+               OpStore %res %20
+         %23 = OpLoad %uint %res None
+               OpReturnValue %23
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %28
-%tint_subgroup_size = OpFunctionParameter %uint
-         %29 = OpLabel
-         %30 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %30 None
-         %31 = OpFunctionCall %uint %subgroupShuffle_f194f5
-         %32 = OpAccessChain %_ptr_StorageBuffer_uint %1 %uint_0
-               OpStore %32 %31 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %36
-         %37 = OpLabel
-         %38 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %39 = OpFunctionCall %void %fragment_main_inner %38
+%fragment_main = OpFunction %void None %26
+         %27 = OpLabel
+         %28 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %29 = OpISub %uint %28 %uint_1
+               OpStore %tint_subgroup_last_id %29 None
+         %30 = OpFunctionCall %uint %subgroupShuffle_f194f5
+         %31 = OpAccessChain %_ptr_StorageBuffer_uint %1 %uint_0
+               OpStore %31 %30 None
                OpReturn
                OpFunctionEnd
 ;
@@ -86,78 +73,66 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 40
+; Bound: 34
 ; Schema: 0
                OpCapability Shader
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %19 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_f194f5 "subgroupShuffle_f194f5"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
        %uint = OpTypeInt 32 0
 %prevent_dce_block = OpTypeStruct %uint
 %_ptr_StorageBuffer_prevent_dce_block = OpTypePointer StorageBuffer %prevent_dce_block
           %1 = OpVariable %_ptr_StorageBuffer_prevent_dce_block StorageBuffer
 %_ptr_Private_uint = OpTypePointer Private %uint
           %7 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %7
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %11 = OpTypeFunction %uint
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %7
+          %9 = OpTypeFunction %uint
 %_ptr_Function_uint = OpTypePointer Function %uint
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %28 = OpTypeFunction %void %uint
+         %26 = OpTypeFunction %void
 %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
      %uint_0 = OpConstant %uint 0
-         %36 = OpTypeFunction %void
-%subgroupShuffle_f194f5 = OpFunction %uint None %11
-         %12 = OpLabel
+%subgroupShuffle_f194f5 = OpFunction %uint None %9
+         %10 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_uint Function
       %arg_1 = OpVariable %_ptr_Function_uint Function
         %res = OpVariable %_ptr_Function_uint Function
                OpStore %arg_0 %uint_1
                OpStore %arg_1 %uint_1
-         %17 = OpLoad %uint %arg_0 None
-         %18 = OpLoad %uint %arg_1 None
-         %19 = OpLoad %uint %tint_subgroup_size_mask None
-         %20 = OpBitwiseAnd %uint %18 %19
-         %21 = OpGroupNonUniformShuffle %uint %uint_3 %17 %20
-               OpStore %res %21
-         %24 = OpLoad %uint %res None
-               OpReturnValue %24
+         %15 = OpLoad %uint %arg_0 None
+         %16 = OpLoad %uint %arg_1 None
+         %17 = OpLoad %uint %tint_subgroup_last_id None
+         %18 = OpExtInst %uint %19 UMin %16 %17
+         %20 = OpGroupNonUniformShuffle %uint %uint_3 %15 %18
+               OpStore %res %20
+         %23 = OpLoad %uint %res None
+               OpReturnValue %23
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %28
-%tint_subgroup_size = OpFunctionParameter %uint
-         %29 = OpLabel
-         %30 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %30 None
-         %31 = OpFunctionCall %uint %subgroupShuffle_f194f5
-         %32 = OpAccessChain %_ptr_StorageBuffer_uint %1 %uint_0
-               OpStore %32 %31 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %36
-         %37 = OpLabel
-         %38 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %39 = OpFunctionCall %void %compute_main_inner %38
+%compute_main = OpFunction %void None %26
+         %27 = OpLabel
+         %28 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %29 = OpISub %uint %28 %uint_1
+               OpStore %tint_subgroup_last_id %29 None
+         %30 = OpFunctionCall %uint %subgroupShuffle_f194f5
+         %31 = OpAccessChain %_ptr_StorageBuffer_uint %1 %uint_0
+               OpStore %31 %30 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/var/subgroupShuffle/fb4ab9.wgsl.expected.spvasm b/test/tint/builtins/gen/var/subgroupShuffle/fb4ab9.wgsl.expected.spvasm
index 4adcfe7..53f55a0 100644
--- a/test/tint/builtins/gen/var/subgroupShuffle/fb4ab9.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/var/subgroupShuffle/fb4ab9.wgsl.expected.spvasm
@@ -4,34 +4,30 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 45
+; Bound: 39
 ; Schema: 0
                OpCapability Shader
                OpCapability Float16
                OpCapability StorageBuffer16BitAccess
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %24 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input
+               OpEntryPoint Fragment %fragment_main "fragment_main"
                OpExecutionMode %fragment_main OriginUpperLeft
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %fragment_main_subgroup_size_Input "fragment_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_fb4ab9 "subgroupShuffle_fb4ab9"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %fragment_main_inner "fragment_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %fragment_main "fragment_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %fragment_main_subgroup_size_Input Flat
-               OpDecorate %fragment_main_subgroup_size_Input BuiltIn SubgroupSize
        %half = OpTypeFloat 16
      %v3half = OpTypeVector %half 3
 %prevent_dce_block = OpTypeStruct %v3half
@@ -40,51 +36,42 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%fragment_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v3half
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v3half
 %_ptr_Function_v3half = OpTypePointer Function %v3half
 %half_0x1p_0 = OpConstant %half 0x1p+0
-         %17 = OpConstantComposite %v3half %half_0x1p_0 %half_0x1p_0 %half_0x1p_0
+         %15 = OpConstantComposite %v3half %half_0x1p_0 %half_0x1p_0 %half_0x1p_0
 %_ptr_Function_uint = OpTypePointer Function %uint
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %33 = OpTypeFunction %void %uint
+         %31 = OpTypeFunction %void
 %_ptr_StorageBuffer_v3half = OpTypePointer StorageBuffer %v3half
      %uint_0 = OpConstant %uint 0
-         %41 = OpTypeFunction %void
-%subgroupShuffle_fb4ab9 = OpFunction %v3half None %13
-         %14 = OpLabel
+%subgroupShuffle_fb4ab9 = OpFunction %v3half None %11
+         %12 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v3half Function
       %arg_1 = OpVariable %_ptr_Function_uint Function
         %res = OpVariable %_ptr_Function_v3half Function
-               OpStore %arg_0 %17
+               OpStore %arg_0 %15
                OpStore %arg_1 %uint_1
-         %22 = OpLoad %v3half %arg_0 None
-         %23 = OpLoad %uint %arg_1 None
-         %24 = OpLoad %uint %tint_subgroup_size_mask None
-         %25 = OpBitwiseAnd %uint %23 %24
-         %26 = OpGroupNonUniformShuffle %v3half %uint_3 %22 %25
-               OpStore %res %26
-         %29 = OpLoad %v3half %res None
-               OpReturnValue %29
+         %20 = OpLoad %v3half %arg_0 None
+         %21 = OpLoad %uint %arg_1 None
+         %22 = OpLoad %uint %tint_subgroup_last_id None
+         %23 = OpExtInst %uint %24 UMin %21 %22
+         %25 = OpGroupNonUniformShuffle %v3half %uint_3 %20 %23
+               OpStore %res %25
+         %28 = OpLoad %v3half %res None
+               OpReturnValue %28
                OpFunctionEnd
-%fragment_main_inner = OpFunction %void None %33
-%tint_subgroup_size = OpFunctionParameter %uint
-         %34 = OpLabel
-         %35 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %35 None
-         %36 = OpFunctionCall %v3half %subgroupShuffle_fb4ab9
-         %37 = OpAccessChain %_ptr_StorageBuffer_v3half %1 %uint_0
-               OpStore %37 %36 None
-               OpReturn
-               OpFunctionEnd
-%fragment_main = OpFunction %void None %41
-         %42 = OpLabel
-         %43 = OpLoad %uint %fragment_main_subgroup_size_Input None
-         %44 = OpFunctionCall %void %fragment_main_inner %43
+%fragment_main = OpFunction %void None %31
+         %32 = OpLabel
+         %33 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %34 = OpISub %uint %33 %uint_1
+               OpStore %tint_subgroup_last_id %34 None
+         %35 = OpFunctionCall %v3half %subgroupShuffle_fb4ab9
+         %36 = OpAccessChain %_ptr_StorageBuffer_v3half %1 %uint_0
+               OpStore %36 %35 None
                OpReturn
                OpFunctionEnd
 ;
@@ -93,33 +80,30 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 1
-; Bound: 45
+; Bound: 39
 ; Schema: 0
                OpCapability Shader
                OpCapability Float16
                OpCapability StorageBuffer16BitAccess
-               OpCapability GroupNonUniform
                OpCapability GroupNonUniformShuffle
+               OpCapability GroupNonUniformArithmetic
+         %24 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
-               OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input
+               OpEntryPoint GLCompute %compute_main "compute_main"
                OpExecutionMode %compute_main LocalSize 1 1 1
                OpMemberName %prevent_dce_block 0 "inner"
                OpName %prevent_dce_block "prevent_dce_block"
-               OpName %tint_subgroup_size_mask "tint_subgroup_size_mask"
-               OpName %compute_main_subgroup_size_Input "compute_main_subgroup_size_Input"
+               OpName %tint_subgroup_last_id "tint_subgroup_last_id"
                OpName %subgroupShuffle_fb4ab9 "subgroupShuffle_fb4ab9"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
                OpName %res "res"
-               OpName %compute_main_inner "compute_main_inner"
-               OpName %tint_subgroup_size "tint_subgroup_size"
                OpName %compute_main "compute_main"
                OpMemberDecorate %prevent_dce_block 0 Offset 0
                OpDecorate %prevent_dce_block Block
                OpDecorate %1 DescriptorSet 0
                OpDecorate %1 Binding 0
                OpDecorate %1 Coherent
-               OpDecorate %compute_main_subgroup_size_Input BuiltIn SubgroupSize
        %half = OpTypeFloat 16
      %v3half = OpTypeVector %half 3
 %prevent_dce_block = OpTypeStruct %v3half
@@ -128,50 +112,41 @@
        %uint = OpTypeInt 32 0
 %_ptr_Private_uint = OpTypePointer Private %uint
           %9 = OpConstantNull %uint
-%tint_subgroup_size_mask = OpVariable %_ptr_Private_uint Private %9
-%_ptr_Input_uint = OpTypePointer Input %uint
-%compute_main_subgroup_size_Input = OpVariable %_ptr_Input_uint Input
-         %13 = OpTypeFunction %v3half
+%tint_subgroup_last_id = OpVariable %_ptr_Private_uint Private %9
+         %11 = OpTypeFunction %v3half
 %_ptr_Function_v3half = OpTypePointer Function %v3half
 %half_0x1p_0 = OpConstant %half 0x1p+0
-         %17 = OpConstantComposite %v3half %half_0x1p_0 %half_0x1p_0 %half_0x1p_0
+         %15 = OpConstantComposite %v3half %half_0x1p_0 %half_0x1p_0 %half_0x1p_0
 %_ptr_Function_uint = OpTypePointer Function %uint
      %uint_1 = OpConstant %uint 1
      %uint_3 = OpConstant %uint 3
        %void = OpTypeVoid
-         %33 = OpTypeFunction %void %uint
+         %31 = OpTypeFunction %void
 %_ptr_StorageBuffer_v3half = OpTypePointer StorageBuffer %v3half
      %uint_0 = OpConstant %uint 0
-         %41 = OpTypeFunction %void
-%subgroupShuffle_fb4ab9 = OpFunction %v3half None %13
-         %14 = OpLabel
+%subgroupShuffle_fb4ab9 = OpFunction %v3half None %11
+         %12 = OpLabel
       %arg_0 = OpVariable %_ptr_Function_v3half Function
       %arg_1 = OpVariable %_ptr_Function_uint Function
         %res = OpVariable %_ptr_Function_v3half Function
-               OpStore %arg_0 %17
+               OpStore %arg_0 %15
                OpStore %arg_1 %uint_1
-         %22 = OpLoad %v3half %arg_0 None
-         %23 = OpLoad %uint %arg_1 None
-         %24 = OpLoad %uint %tint_subgroup_size_mask None
-         %25 = OpBitwiseAnd %uint %23 %24
-         %26 = OpGroupNonUniformShuffle %v3half %uint_3 %22 %25
-               OpStore %res %26
-         %29 = OpLoad %v3half %res None
-               OpReturnValue %29
+         %20 = OpLoad %v3half %arg_0 None
+         %21 = OpLoad %uint %arg_1 None
+         %22 = OpLoad %uint %tint_subgroup_last_id None
+         %23 = OpExtInst %uint %24 UMin %21 %22
+         %25 = OpGroupNonUniformShuffle %v3half %uint_3 %20 %23
+               OpStore %res %25
+         %28 = OpLoad %v3half %res None
+               OpReturnValue %28
                OpFunctionEnd
-%compute_main_inner = OpFunction %void None %33
-%tint_subgroup_size = OpFunctionParameter %uint
-         %34 = OpLabel
-         %35 = OpISub %uint %tint_subgroup_size %uint_1
-               OpStore %tint_subgroup_size_mask %35 None
-         %36 = OpFunctionCall %v3half %subgroupShuffle_fb4ab9
-         %37 = OpAccessChain %_ptr_StorageBuffer_v3half %1 %uint_0
-               OpStore %37 %36 None
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %41
-         %42 = OpLabel
-         %43 = OpLoad %uint %compute_main_subgroup_size_Input None
-         %44 = OpFunctionCall %void %compute_main_inner %43
+%compute_main = OpFunction %void None %31
+         %32 = OpLabel
+         %33 = OpGroupNonUniformIAdd %uint %uint_3 Reduce %uint_1
+         %34 = OpISub %uint %33 %uint_1
+               OpStore %tint_subgroup_last_id %34 None
+         %35 = OpFunctionCall %v3half %subgroupShuffle_fb4ab9
+         %36 = OpAccessChain %_ptr_StorageBuffer_v3half %1 %uint_0
+               OpStore %36 %35 None
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/var/textureSampleCompareLevel/4cf3a2.wgsl.expected.glsl b/test/tint/builtins/gen/var/textureSampleCompareLevel/4cf3a2.wgsl.expected.glsl
index 6d4ba06..04b21c3 100644
--- a/test/tint/builtins/gen/var/textureSampleCompareLevel/4cf3a2.wgsl.expected.glsl
+++ b/test/tint/builtins/gen/var/textureSampleCompareLevel/4cf3a2.wgsl.expected.glsl
@@ -1,4 +1,3 @@
-SKIP: INVALID   no textureSampleCompareLevel in compat
 //
 // fragment_main
 //
diff --git a/test/tint/builtins/gen/var/textureSampleCompareLevel/7f2b9a.wgsl.expected.glsl b/test/tint/builtins/gen/var/textureSampleCompareLevel/7f2b9a.wgsl.expected.glsl
index a501027..cc08f49 100644
--- a/test/tint/builtins/gen/var/textureSampleCompareLevel/7f2b9a.wgsl.expected.glsl
+++ b/test/tint/builtins/gen/var/textureSampleCompareLevel/7f2b9a.wgsl.expected.glsl
@@ -1,4 +1,3 @@
-SKIP: INVALID   no textureSampleCompareLevel in compat
 //
 // fragment_main
 //
diff --git a/test/tint/builtins/gen/var/textureSampleCompareLevel/958c87.wgsl.expected.glsl b/test/tint/builtins/gen/var/textureSampleCompareLevel/958c87.wgsl.expected.glsl
index 24ee210..f92edda 100644
--- a/test/tint/builtins/gen/var/textureSampleCompareLevel/958c87.wgsl.expected.glsl
+++ b/test/tint/builtins/gen/var/textureSampleCompareLevel/958c87.wgsl.expected.glsl
@@ -1,4 +1,3 @@
-SKIP: INVALID   no textureSampleCompareLevel in compat
 //
 // fragment_main
 //