CVE-2026-87592
Overview
Background
- Tint
- Dawn’s WGSL-to-SPIR-V shader compiler; it lowers WebGPU shaders into the SPIR-V that the GPU process hands to the Vulkan driver.
- `subgroupShuffle` family
- WGSL builtins (
subgroupShuffle,subgroupShuffleDown,subgroupShuffleUp,subgroupShuffleXor) that exchange a value between invocations in a subgroup, lowered toOpGroupNonUniformShuffle; the second argument (id/delta/mask) selects the source lane. - SPIR-V shuffle constraint
OpGroupNonUniformShufflerequires the source invocationidto be strictly less than the actualSubgroupSize, or the result is a poison/undefined value that reads out-of-range lane data.- `SubgroupSize`
- a hardware builtin, guaranteed a power of two on Vulkan, so
SubgroupSize - 1is a valid low-bit mask for clamping an index into[0, SubgroupSize).
Root Cause Analysis
The SPIR-V polyfill in SubgroupShuffle was meant to clamp the attacker-supplied lane index (arg2) so it stayed within the subgroup, but it clamped with a hardcoded constant core::u32(tint::internal_limits::kMaxSubgroupSize - 1) — i.e. AND with 127u, the maximum possible subgroup size minus one. On any device whose real SubgroupSize is smaller than 128 (commonly 4/8/16/32/64), an id in [SubgroupSize, 128) survives the mask unchanged and is fed straight into OpGroupNonUniformShuffle, violating the spec’s id < SubgroupSize requirement and producing an out-of-bounds read of another lane’s value. The clamp was also gated behind the Toggle::SubgroupShuffleClamped device toggle (and the subgroup_shuffle_clamped workaround/config bool), so on SPIR-V paths where the toggle was not defaulted on, no clamping happened at all.
The fix removes the toggle, makes the polyfill unconditional for all SPIR-V generation, and computes the mask dynamically from the real builtin: SetSubgroupSizeMaskForEntryPoint stores SubgroupSize - 1 into a private tint_subgroup_size_mask variable, and SubgroupShuffle masks arg2 with that value, correctly clamping the index to [0, SubgroupSize).
kMaxSubgroupSize - 1) instead of the run-time actual SubgroupSize, so indices between the real size and 128 escaped the bound. The fix derives the mask from the live SubgroupSize builtin (SubgroupSize - 1) and applies it unconditionally, guaranteeing every shuffled lane index is in range.Attack Path
- Craft a WGSL shader using a shuffle builtin
An attacker authors a WebGPU compute or fragment shader that calls
subgroupShuffle/subgroupShuffleDown/Up/Xorwith a lane index it controls. - Supply an out-of-range lane index
The shader passes an
id/delta/maskvalue that is< 128but>=the device’s actualSubgroupSize, so the oldAND 127uclamp (or absent clamp) leaves it unchanged. - Emit the unclamped shuffle
Tint lowers the call to
OpGroupNonUniformShufflewith the oversized index because the polyfill masked againstkMaxSubgroupSize - 1rather than the real size (or was disabled by toggle). - Trigger the out-of-bounds read
At GPU execution the shuffle reads a source lane outside
[0, SubgroupSize), yielding a poison/undefined value sourced from out-of-range invocation data (inferredas to what adjacent data is exposed; the patch shows only the missing bound).
Impact Assessment
SubgroupSize is below the hardcoded 128 maximum (or a SPIR-V path where the clamp toggle was off) plus shader access to a subgroupShuffle builtin. The advisory classifies this as an out-of-bounds read in Tint; any use as an information-disclosure primitive or step toward further compromise is (inferred) and not demonstrated by the patch.Changed Functions
| Function | Change | Notes |
|---|---|---|
ifsrc/tint/lang/spirv/writer/raise/builtin_polyfill.cc |
modified | |
forsrc/tint/lang/spirv/writer/raise/builtin_polyfill.cc |
modified |
Files Changed
test/tint/builtins/gen/literal/subgroupShuffleDown/7f8886.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffle/824702.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffleUp/bbf7f4.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleDown/7a0cf5.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffleXor/1e247f.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleXor/2e033d.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffleDown/10eb45.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffleUp/a2075a.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffle/7c5d64.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleXor/d224ab.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleXor/bdddba.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleXor/caa816.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleXor/c88290.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffle/54f328.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleUp/db5bcb.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffle/4752bd.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffleDown/57b1e8.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffle/8bfbcd.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffle/030422.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffle/4f5711.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffleDown/642789.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffleXor/9f945a.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffleUp/b58804.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleUp/3e609f.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffleXor/80b6e9.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffleDown/313d9b.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffleUp/1bb93f.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffleXor/445e83.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleXor/e3c10b.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffle/bbb06c.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffleXor/1d36b6.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffle/8c3fd2.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffle/b4bbb7.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleUp/87c9d6.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffle/84f261.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleXor/7435fe.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffle/e13c81.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffle/7d7b1e.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffle/e854d5.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffle/8890a5.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleDown/b41899.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleDown/1b530f.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffle/fb4ab9.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleDown/9c6714.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffle/1f664c.wgsl.expected.spvasmsrc/tint/lang/spirv/writer/raise/builtin_polyfill.cctest/tint/builtins/gen/literal/subgroupShuffle/821df9.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffle/647034.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffle/d4a772.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffle/21f083.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffleXor/7435fe.wgsl.expected.spvasmsrc/dawn/native/vulkan/PhysicalDeviceVk.cpptest/tint/builtins/gen/var/subgroupShuffleUp/3e609f.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffle/f194f5.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffle/323416.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleDown/d269eb.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffleUp/3242a6.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffle/7c5d64.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffleUp/87c9d6.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleDown/313d9b.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffleXor/f7b453.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffle/8bfbcd.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffleUp/8a63f3.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffle/030422.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffle/d9ff67.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffle/4752bd.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffle/f194f5.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffle/5ef5a2.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleUp/23c7ca.wgsl.expected.spvasmsrc/tint/lang/spirv/writer/raise/raise.cctest/tint/builtins/gen/literal/subgroupShuffle/e13c81.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffleXor/08f588.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleDown/10eb45.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffleUp/88eb07.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleUp/868e52.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleXor/071aa0.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleUp/abaea0.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffleDown/9c6714.wgsl.expected.spvasmsrc/dawn/native/vulkan/ShaderModuleVk.cpptest/tint/builtins/gen/literal/subgroupShuffle/bbb06c.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleDown/63fdb0.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffle/5dfeab.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffle/1f664c.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffleXor/1f2590.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffle/824702.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffleUp/33d495.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffle/fb4ab9.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffle/8890a5.wgsl.expected.spvasmsrc/tint/lang/spirv/writer/common/options.htest/tint/builtins/gen/var/subgroupShuffle/e854d5.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffle/b0f28d.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleUp/1bb93f.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffle/85587b.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleDown/642789.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffleDown/b41899.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleXor/1e247f.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffle/5dfeab.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffleXor/2e033d.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleUp/a2075a.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffle/2ee993.wgsl.expected.spvasmsrc/tint/lang/spirv/writer/writer_fuzz.cctest/tint/builtins/gen/literal/subgroupShuffleDown/57b1e8.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffle/647034.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffleXor/caa816.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffle/2ee993.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleUp/b58804.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffleDown/c9f1c4.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffleXor/c88290.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleDown/d90c2f.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffle/d9ff67.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffleUp/db5bcb.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleDown/257ff0.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleUp/0990cd.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleXor/1d36b6.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffleDown/7a0cf5.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleXor/9f945a.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffle/821df9.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffleXor/d224ab.wgsl.expected.spvasmsrc/tint/lang/spirv/writer/raise/builtin_polyfill.htest/tint/builtins/gen/var/subgroupShuffleXor/e3c10b.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleDown/d46304.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffleDown/d269eb.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleXor/445e83.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffle/5ef5a2.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffleXor/bdddba.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffle/7ba2d5.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffleUp/58de69.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffle/85587b.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffle/b0f28d.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffle/4cbb69.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffle/84f261.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleUp/58de69.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffle/54f328.wgsl.expected.spvasmsrc/tint/lang/spirv/writer/raise/builtin_polyfill_test.cctest/tint/builtins/gen/var/subgroupShuffleDown/257ff0.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffle/7ba2d5.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffle/7d7b1e.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleUp/8a63f3.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleUp/3242a6.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleDown/5d8b9f.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffle/4f5711.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffleDown/63fdb0.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffle/8c3fd2.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffleUp/868e52.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleDown/c9f1c4.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleXor/80b6e9.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffleDown/5d8b9f.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffle/aa1d5c.wgsl.expected.spvasmsrc/dawn/native/Toggles.cpptest/tint/builtins/gen/var/subgroupShuffleUp/0990cd.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffle/aa1d5c.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffleXor/071aa0.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffleDown/7f8886.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffle/323416.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffleDown/d90c2f.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleXor/f7b453.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleUp/bbf7f4.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffleDown/1b530f.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleXor/1f2590.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffle/21f083.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffle/d4a772.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffle/b4bbb7.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleXor/08f588.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffleDown/d46304.wgsl.expected.spvasmtest/tint/builtins/gen/var/subgroupShuffleUp/abaea0.wgsl.expected.spvasmsrc/dawn/native/Toggles.htest/tint/builtins/gen/var/subgroupShuffleUp/23c7ca.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffle/4cbb69.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleUp/33d495.wgsl.expected.spvasmtest/tint/builtins/gen/literal/subgroupShuffleUp/88eb07.wgsl.expected.spvasm
Audit Directions
- Fixed-max clamps vs. runtime limitsSearch other SPIR-V/MSL/HLSL polyfills for masking or clamping against compile-time constants like
kMaxSubgroupSizewhen the true bound is a runtime builtin (SubgroupSize, workgroup size, sample count). - Toggle-gated safety polyfillsReview workarounds/polyfills gated behind a device
Toggleor config bool that are only defaulted on for specific vendors; a spec-mandated bound (not a driver quirk) should be unconditional. - Attacker-controlled indices into lane/group builtinsAudit lowering of
subgroupBroadcast,quadSwap/quadBroadcast, and other invocation-indexed group operations for missingindex < groupSizeclamps before the SPIR-V op is emitted.
Patch
From c50a11059c92ab26a349732afcf5e0fb2afda438 Mon Sep 17 00:00:00 2001 From: Natalie Chouinard <[email protected]> Date: Wed, 03 Jun 2026 19:30:48 -0700 Subject: [PATCH] [tint][spirv] Clamp subgroupShuffle to actual size Replace the hardcoded max subgroup size mask in the SPIR-V subgroupShuffle polyfill with the actual subgroup size from the builtin value. Because SubgroupSize is guaranteed to be a power-of-2 in Vulkan, it is still safe to subtract 1 and mask to clamp. This polyfill is also now enabled for all SPIR-V generation, rather than limited by a toggle, since the requirement of invocation ID to be less than the subgroup size is a general SPIR-V spec requirement to avoid poison values, not specific to a driver issue. https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpGroupNonUniformShuffle Fixes: 513947572 Change-Id: Id6e68170e467284152212e8c014d2c9688760175 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/313515 Commit-Queue: Natalie Chouinard <[email protected]> SLSA-Policy-Verified: SLSA Policy Verification Service <[email protected]> Reviewed-by: James Price <[email protected]> --- diff --git a/src/dawn/native/Toggles.cpp b/src/dawn/native/Toggles.cpp index 58df017..a18adb6 100644 --- a/src/dawn/native/Toggles.cpp +++ b/src/dawn/native/Toggles.cpp @@ -622,10 +622,6 @@ {Toggle::MetalPolyfillClampFloat, {"metal_polyfill_clamp_float", "Polyfill clamp function for floating point (metal).", "https://crbug.com/407109056", ToggleStage::Device}}, - {Toggle::SubgroupShuffleClamped, - {"subgroup_shuffle_clamped", - "Polyfill subgroupShuffle by clamping the id param to within maximum possible subgroup size.", - "https://crbug.com/dawn/2502", ToggleStage::Device}}, {Toggle::VulkanSampleCompareDepthCubeArrayWorkaround, {"vulkan_sample_compare_depth_cube_array_workaround", "Polyfill specific case of textureSampleCompare(Level) with workaround.", diff --git a/src/dawn/native/Toggles.h b/src/dawn/native/Toggles.h index 38a8a90..02fde65 100644 --- a/src/dawn/native/Toggles.h +++ b/src/dawn/native/Toggles.h @@ -152,7 +152,6 @@ ScalarizeMaxMinClamp, SaturateAsMinMaxF16, MetalPolyfillClampFloat, - SubgroupShuffleClamped, VulkanSampleCompareDepthCubeArrayWorkaround, VulkanSampleCompare2DWorkaround, MetalDisableModuleConstantF16, diff --git a/src/dawn/native/vulkan/PhysicalDeviceVk.cpp b/src/dawn/native/vulkan/PhysicalDeviceVk.cpp index 2176cd0..82a60c5 100644 --- a/src/dawn/native/vulkan/PhysicalDeviceVk.cpp +++ b/src/dawn/native/vulkan/PhysicalDeviceVk.cpp @@ -1109,10 +1109,6 @@ // chromium:448873316: Non-scalar (vector) saturate from uniform fails. deviceToggles->Default(Toggle::SaturateAsMinMaxF16, true); - // Polyfill a clamp of `id` param in subgroupShuffle to follow spec limitations. - // See crbug.com/435246627 - deviceToggles->Default(Toggle::SubgroupShuffleClamped, true); - if (gpu_info::IsIntelGen12LP(GetVendorId(), GetDeviceId())) { // dawn:1688: Intel Mesa driver has a bug about reusing the VkDeviceMemory that was // previously bound to a 2D VkImage. To work around that bug we have to disable the diff --git a/src/dawn/native/vulkan/ShaderModuleVk.cpp b/src/dawn/native/vulkan/ShaderModuleVk.cpp index 74fe3d7..a3c77c7 100644 --- a/src/dawn/native/vulkan/ShaderModuleVk.cpp +++ b/src/dawn/native/vulkan/ShaderModuleVk.cpp @@ -317,8 +317,6 @@ req.tintOptions.extensions.use_uniform_buffers = !GetDevice()->IsToggleEnabled(Toggle::DecomposeUniformBuffers); - req.tintOptions.workarounds.subgroup_shuffle_clamped = - GetDevice()->IsToggleEnabled(Toggle::SubgroupShuffleClamped); req.tintOptions.workarounds.texture_sample_compare_depth_cube_array = GetDevice()->IsToggleEnabled(Toggle::VulkanSampleCompareDepthCubeArrayWorkaround); req.tintOptions.workarounds.texture_sample_compare_2d_polyfill = diff --git a/src/tint/lang/spirv/writer/common/options.h b/src/tint/lang/spirv/writer/common/options.h index 8c4d22d..c9a5dd9 100644 --- a/src/tint/lang/spirv/writer/common/options.h +++ b/src/tint/lang/spirv/writer/common/options.h @@ -87,10 +87,6 @@ /// and `unpack4x8unorm` builtins bool polyfill_pack_unpack_4x8_norm = false; - /// Set to `true` to generate a polyfill clamp of `id` param of subgroupShuffle to within - /// the spec max subgroup size. - bool subgroup_shuffle_clamped = false; - /// Set to 'true' to force workaround for 'textureSampleCompare(Level)' for texture arrays /// of cube depth. bool texture_sample_compare_depth_cube_array = false; @@ -132,7 +128,6 @@ scalarize_max_min_clamp, dva_transform_handle, polyfill_pack_unpack_4x8_norm, - subgroup_shuffle_clamped, texture_sample_compare_depth_cube_array, texture_sample_compare_2d_polyfill, polyfill_subgroup_broadcast_f16, diff --git a/src/tint/lang/spirv/writer/raise/builtin_polyfill.cc b/src/tint/lang/spirv/writer/raise/builtin_polyfill.cc index 326b351..7d6c803 100644 --- a/src/tint/lang/spirv/writer/raise/builtin_polyfill.cc +++ b/src/tint/lang/spirv/writer/raise/builtin_polyfill.cc @@ -184,6 +184,9 @@ /// The type manager. core::type::Manager& ty{ir.Types()}; + /// Module-scoped variable for subgroup size mask. + core::ir::Var* subgroup_size_mask_ = nullptr; + /// Process the module. void Process() { // Find the builtins that need replacing. @@ -249,9 +252,7 @@ case core::BuiltinFn::kSubgroupShuffleDown: case core::BuiltinFn::kSubgroupShuffleUp: case core::BuiltinFn::kSubgroupShuffleXor: { - bool clamped = config.subgroup_shuffle_clamped; - worklist.push_back( - [this, builtin, clamped] { SubgroupShuffle(builtin, clamped); }); + worklist.push_back([this, builtin] { SubgroupShuffle(builtin); }); break; } case core::BuiltinFn::kTextureDimensions: @@ -364,6 +365,48 @@ }); construct->SetArg(0, value); } + + if (subgroup_size_mask_) { + for (auto func : ir.functions) { + if (func->IsEntryPoint()) { + SetSubgroupSizeMaskForEntryPoint(func); + } + } + } + } + + /// Set the subgroup_size_mask variable from an entry point. + void SetSubgroupSizeMaskForEntryPoint(core::ir::Function* ep) { + b.InsertBefore(ep->Block()->Front(), [&] { + core::ir::Value* subgroup_size = nullptr; + for (auto* param : ep->Params()) { + if (param->Attributes().builtin == core::BuiltinValue::kSubgroupSize) { + subgroup_size = param; + break; + } + if (auto* str = param->Type()->As<core::type::Struct>()) { + for (auto* member : str->Members()) { + if (member->Attributes().builtin == core::BuiltinValue::kSubgroupSize) { + subgroup_size = + b.Access(ty.u32(), param, u32(member->Index()))->Result(); + break; + } + } + if (subgroup_size) { + break; + } + } + } + if (!subgroup_size) { + auto* param = b.FunctionParam("tint_subgroup_size", ty.u32()); + param->SetBuiltin(core::BuiltinValue::kSubgroupSize); + ep->AppendParam(param); + subgroup_size = param; + } + + auto* mask = b.Subtract(subgroup_size, 1_u); + b.Store(subgroup_size_mask_, mask); + }); } /// Create a literal operand. @@ -1248,10 +1291,10 @@ /// Handles SubgroupShuffle(), SubgroupShuffleDown(), SubgroupShuffleUp(), SubgroupShuffleXor() /// builtins. /// @param builtin the builtin call instruction - void SubgroupShuffle(core::ir::CoreBuiltinCall* builtin, bool clamp_subgroup_shuffle) { + void SubgroupShuffle(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, 128) + // 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()) { @@ -1261,15 +1304,18 @@ } /// Polyfill a `subgroupShuffleX` builtin call with one that has clamped the arg2 param - if (clamp_subgroup_shuffle) { - auto* shuffle_id = builtin->Args()[1]; - auto* mask_max_subgroup_size = - b.Constant(core::u32(tint::internal_limits::kMaxSubgroupSize - 1)); - b.InsertBefore(builtin, [&] { - auto* clamp_via_masking_and = b.And(shuffle_id, mask_max_subgroup_size); - builtin->SetArg(1, clamp_via_masking_and->Result()); + auto* shuffle_id = builtin->Args()[1]; + if (!subgroup_size_mask_) { + b.Append(ir.root_block, [&] { + subgroup_size_mask_ = + b.Var<core::AddressSpace::kPrivate, u32>("tint_subgroup_size_mask"); }); } + b.InsertBefore(builtin, [&] { + auto* subgroup_size_mask = b.Load(subgroup_size_mask_); + auto* clamp_via_masking_and = b.And(shuffle_id, subgroup_size_mask); + builtin->SetArg(1, clamp_via_masking_and->Result()); + }); } /// Handle a SubgroupBroadcast() builtin. diff --git a/src/tint/lang/spirv/writer/raise/builtin_polyfill.h b/src/tint/lang/spirv/writer/raise/builtin_polyfill.h index c03f556..4e19350 100644 --- a/src/tint/lang/spirv/writer/raise/builtin_polyfill.h +++ b/src/tint/lang/spirv/writer/raise/builtin_polyfill.h @@ -41,7 +41,6 @@ struct PolyfillConfig { bool use_vulkan_memory_model = false; SpvVersion version = SpvVersion::kSpv13; - bool subgroup_shuffle_clamped = false; bool texture_sample_compare_depth_cube_array = false; bool texture_sample_compare_2d_polyfill = false; bool cooperative_matrix_stride_is_matrix_elements = false; diff --git a/src/tint/lang/spirv/writer/raise/raise.cc b/src/tint/lang/spirv/writer/raise/raise.cc index cd58980..1f41cc4 100644 --- a/src/tint/lang/spirv/writer/raise/raise.cc +++ b/src/tint/lang/spirv/writer/raise/raise.cc @@ -214,7 +214,6 @@ raise::PolyfillConfig config = { .use_vulkan_memory_model = options.extensions.use_vulkan_memory_model, .version = options.spirv_version, - .subgroup_shuffle_clamped = options.workarounds.subgroup_shuffle_clamped, .texture_sample_compare_depth_cube_array = options.workarounds.texture_sample_compare_depth_cube_array, .texture_sample_compare_2d_polyfill = diff --git a/src/tint/lang/spirv/writer/writer_fuzz.cc b/src/tint/lang/spirv/writer/writer_fuzz.cc index 130b0b0..5b4d36b 100644 --- a/src/tint/lang/spirv/writer/writer_fuzz.cc +++ b/src/tint/lang/spirv/writer/writer_fuzz.cc @@ -312,7 +312,6 @@ options.workarounds.dva_transform_handle = fuzzed_options.dva_transform_handle; options.workarounds.polyfill_pack_unpack_4x8_norm = fuzzed_options.polyfill_pack_unpack_4x8_norm; - options.workarounds.subgroup_shuffle_clamped = fuzzed_options.subgroup_shuffle_clamped; options.workarounds.polyfill_subgroup_broadcast_f16 = fuzzed_options.polyfill_subgroup_broadcast_f16; options.workarounds.pass_matrix_by_pointer = fuzzed_options.pass_matrix_by_pointer; 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 619fb81..fc8da8f 100644 --- a/test/tint/builtins/gen/literal/subgroupShuffle/030422.wgsl.expected.spvasm +++ b/test/tint/builtins/gen/literal/subgroupShuffle/030422.wgsl.expected.spvasm @@ -4,52 +4,77 @@ ; SPIR-V ; Version: 1.3 ; Generator: Google Tint Compiler; 1 -; Bound: 26 +; Bound: 41 ; Schema: 0 OpCapability Shader + OpCapability GroupNonUniform OpCapability GroupNonUniformShuffle OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %fragment_main "fragment_main" + OpEntryPoint Fragment %fragment_main "fragment_main" %fragment_main_subgroup_size_Input 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 %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 %1 = OpVariable %_ptr_StorageBuffer_prevent_dce_block StorageBuffer - %6 = OpTypeFunction %float %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 %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 - %20 = OpTypeFunction %void + %28 = OpTypeFunction %void %uint + %uint_1 = OpConstant %uint 1 %_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float %uint_0 = OpConstant %uint 0 -%subgroupShuffle_030422 = OpFunction %float None %6 - %7 = OpLabel + %37 = OpTypeFunction %void +%subgroupShuffle_030422 = OpFunction %float None %12 + %13 = OpLabel %res = OpVariable %_ptr_Function_float Function - %9 = OpBitcast %uint %int_1 - %12 = OpGroupNonUniformShuffle %float %uint_3 %float_1 %9 - OpStore %res %12 - %17 = OpLoad %float %res None - OpReturnValue %17 + %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 OpFunctionEnd -%fragment_main = OpFunction %void None %20 - %21 = OpLabel - %22 = OpFunctionCall %float %subgroupShuffle_030422 - %23 = OpAccessChain %_ptr_StorageBuffer_float %1 %uint_0 - OpStore %23 %22 None +%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 OpReturn OpFunctionEnd ; @@ -58,51 +83,75 @@ ; SPIR-V ; Version: 1.3 ; Generator: Google Tint Compiler; 1 -; Bound: 26 +; Bound: 41 ; Schema: 0 OpCapability Shader + OpCapability GroupNonUniform OpCapability GroupNonUniformShuffle OpMemoryModel Logical GLSL450 - OpEntryPoint GLCompute %compute_main "compute_main" + OpEntryPoint GLCompute %compute_main "compute_main" %compute_main_subgroup_size_Input 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 %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 %1 = OpVariable %_ptr_StorageBuffer_prevent_dce_block StorageBuffer - %6 = OpTypeFunction %float %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 %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 - %20 = OpTypeFunction %void + %28 = OpTypeFunction %void %uint + %uint_1 = OpConstant %uint 1 %_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float ... (file diff truncated)
Regression Test / PoC
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 6b406ed..5004c46 100644
--- a/src/tint/lang/spirv/writer/raise/builtin_polyfill_test.cc
+++ b/src/tint/lang/spirv/writer/raise/builtin_polyfill_test.cc
@@ -1387,19 +1387,22 @@
}
TEST_F(SpirvWriter_BuiltinPolyfillTest, SubgroupShuffleDown_Clamped) {
- auto* val = b.FunctionParam("val", ty.i32());
- auto* delta = b.FunctionParam("delta", ty.u32());
auto* func = b.Function("foo", ty.i32());
- func->SetParams({val, delta});
+ func->SetStage(core::ir::Function::PipelineStage::kFragment);
+ func->SetReturnLocation(0);
b.Append(func->Block(), [&] {
+ auto* val = b.Let("val", 1_i);
+ auto* delta = b.Let("delta", 1_u);
auto* result = b.Call(ty.i32(), core::BuiltinFn::kSubgroupShuffleDown, val, delta);
b.Return(func, result);
});
auto* src = R"(
-%foo = func(%val:i32, %delta:u32):i32 {
+%foo = @fragment func():i32 [@location(0)] {
$B1: {
+ %val:i32 = let 1i
+ %delta:u32 = let 1u
%4:i32 = subgroupShuffleDown %val, %delta
ret %4
}
@@ -1408,35 +1411,46 @@
EXPECT_EQ(src, str());
auto* expect = R"(
-%foo = func(%val:i32, %delta:u32):i32 {
- $B1: {
- %4:u32 = and %delta, 127u
- %5:i32 = subgroupShuffleDown %val, %4
- ret %5
+$B1: { # root
+ %tint_subgroup_size_mask:ptr<private, u32, read_write> = var undef
+}
+
+%foo = @fragment func(%tint_subgroup_size:u32 [@subgroup_size]):i32 [@location(0)] {
+ $B2: {
+ %4:u32 = sub %tint_subgroup_size, 1u
+ store %tint_subgroup_size_mask, %4
+ %val:i32 = let 1i
+ %delta:u32 = let 1u
+ %7:u32 = load %tint_subgroup_size_mask
+ %8:u32 = and %delta, %7
+ %9:i32 = subgroupShuffleDown %val, %8
+ ret %9
}
}
)";
- PolyfillConfig config{.subgroup_shuffle_clamped = true};
- Run(BuiltinPolyfill, config);
+ Run(BuiltinPolyfill, PolyfillConfig{});
EXPECT_EQ(expect, str());
}
TEST_F(SpirvWriter_BuiltinPolyfillTest, SubgroupShuffleDown_SignedDelta_Clamped) {
- auto* val = b.FunctionParam("val", ty.i32());
- auto* delta = b.FunctionParam("delta", ty.u32());
auto* func = b.Function("foo", ty.i32());
- func->SetParams({val, delta});
+ func->SetStage(core::ir::Function::PipelineStage::kFragment);
+ func->SetReturnLocation(0);
b.Append(func->Block(), [&] {
+ auto* val = b.Let("val", 1_i);
+ auto* delta = b.Let("delta", 1_u);
auto* result = b.Call(ty.i32(), core::BuiltinFn::kSubgroupShuffleDown, val, delta);
b.Return(func, result);
});
auto* src = R"(
-%foo = func(%val:i32, %delta:u32):i32 {
+%foo = @fragment func():i32 [@location(0)] {
$B1: {
+ %val:i32 = let 1i
+ %delta:u32 = let 1u
%4:i32 = subgroupShuffleDown %val, %delta
ret %4
}
@@ -1445,98 +1459,46 @@
EXPECT_EQ(src, str());
auto* expect = R"(
-%foo = func(%val:i32, %delta:u32):i32 {
- $B1: {
- %4:u32 = and %delta, 127u
- %5:i32 = subgroupShuffleDown %val, %4
- ret %5
+$B1: { # root
+ %tint_subgroup_size_mask:ptr<private, u32, read_write> = var undef
+}
+
+%foo = @fragment func(%tint_subgroup_size:u32 [@subgroup_size]):i32 [@location(0)] {
+ $B2: {
+ %4:u32 = sub %tint_subgroup_size, 1u
+ store %tint_subgroup_size_mask, %4
+ %val:i32 = let 1i
+ %delta:u32 = let 1u
+ %7:u32 = load %tint_subgroup_size_mask
+ %8:u32 = and %delta, %7
+ %9:i32 = subgroupShuffleDown %val, %8
+ ret %9
}
}
)";
- PolyfillConfig config{.subgroup_shuffle_clamped = true};
- Run(BuiltinPolyfill, config);
-
- EXPECT_EQ(expect, str());
-}
-
-TEST_F(SpirvWriter_BuiltinPolyfillTest, SubgroupShuffleDown_Unclamped) {
- auto* val = b.FunctionParam("val", ty.i32());
- auto* delta = b.FunctionParam("delta", ty.u32());
- auto* func = b.Function("foo", ty.i32());
- func->SetParams({val, delta});
-
- b.Append(func->Block(), [&] {
- auto* result = b.Call(ty.i32(), core::BuiltinFn::kSubgroupShuffleDown, val, delta);
- b.Return(func, result);
- });
-
- auto* src = R"(
-%foo = func(%val:i32, %delta:u32):i32 {
- $B1: {
- %4:i32 = subgroupShuffleDown %val, %delta
- ret %4
- }
-}
-)";
- EXPECT_EQ(src, str());
-
- PolyfillConfig config{.subgroup_shuffle_clamped = false};
- Run(BuiltinPolyfill, config);
-
- EXPECT_EQ(src, str());
-}
-
-TEST_F(SpirvWriter_BuiltinPolyfillTest, SubgroupShuffleDown_SignedDelta_Unclamped) {
- auto* val = b.FunctionParam("val", ty.i32());
- auto* delta = b.FunctionParam("delta", ty.u32());
- auto* func = b.Function("foo", ty.i32());
- func->SetParams({val, delta});
-
- b.Append(func->Block(), [&] {
- auto* result = b.Call(ty.i32(), core::BuiltinFn::kSubgroupShuffleDown, val, delta);
- b.Return(func, result);
- });
-
- auto* src = R"(
-%foo = func(%val:i32, %delta:u32):i32 {
- $B1: {
- %4:i32 = subgroupShuffleDown %val, %delta
- ret %4
- }
-}
-)";
- EXPECT_EQ(src, str());
-
- auto* expect = R"(
-%foo = func(%val:i32, %delta:u32):i32 {
- $B1: {
- %4:i32 = subgroupShuffleDown %val, %delta
- ret %4
- }
-}
-)";
-
- PolyfillConfig config{.subgroup_shuffle_clamped = false};
- Run(BuiltinPolyfill, config);
+ Run(BuiltinPolyfill, PolyfillConfig{});
EXPECT_EQ(expect, str());
}
TEST_F(SpirvWriter_BuiltinPolyfillTest, SubgroupShuffleUp_Clamped) {
- auto* val = b.FunctionParam("val", ty.i32());
- auto* delta = b.FunctionParam("delta", ty.u32());
auto* func = b.Function("foo", ty.i32());
- func->SetParams({val, delta});
+ func->SetStage(core::ir::Function::PipelineStage::kFragment);
+ func->SetReturnLocation(0);
b.Append(func->Block(), [&] {
+ auto* val = b.Let("val", 1_i);
+ auto* delta = b.Let("delta", 1_u);
auto* result = b.Call(ty.i32(), core::BuiltinFn::kSubgroupShuffleUp, val, delta);
b.Return(func, result);
});
auto* src = R"(
-%foo = func(%val:i32, %delta:u32):i32 {
+%foo = @fragment func():i32 [@location(0)] {
$B1: {
+ %val:i32 = let 1i
+ %delta:u32 = let 1u
%4:i32 = subgroupShuffleUp %val, %delta
ret %4
}
@@ -1545,35 +1507,46 @@
EXPECT_EQ(src, str());
auto* expect = R"(
-%foo = func(%val:i32, %delta:u32):i32 {
- $B1: {
- %4:u32 = and %delta, 127u
- %5:i32 = subgroupShuffleUp %val, %4
- ret %5
+$B1: { # root
+ %tint_subgroup_size_mask:ptr<private, u32, read_write> = var undef
+}
+
+%foo = @fragment func(%tint_subgroup_size:u32 [@subgroup_size]):i32 [@location(0)] {
+ $B2: {
+ %4:u32 = sub %tint_subgroup_size, 1u
+ store %tint_subgroup_size_mask, %4
+ %val:i32 = let 1i
+ %delta:u32 = let 1u
+ %7:u32 = load %tint_subgroup_size_mask
+ %8:u32 = and %delta, %7
+ %9:i32 = subgroupShuffleUp %val, %8
+ ret %9
}
}
)";
- PolyfillConfig config{.subgroup_shuffle_clamped = true};
- Run(BuiltinPolyfill, config);
+ Run(BuiltinPolyfill, PolyfillConfig{});
EXPECT_EQ(expect, str());
}
TEST_F(SpirvWriter_BuiltinPolyfillTest, SubgroupShuffleUp_SignedDelta_Clamped) {
- auto* val = b.FunctionParam("val", ty.i32());
- auto* delta = b.FunctionParam("delta", ty.u32());
auto* func = b.Function("foo", ty.i32());
- func->SetParams({val, delta});
+ func->SetStage(core::ir::Function::PipelineStage::kFragment);
+ func->SetReturnLocation(0);
b.Append(func->Block(), [&] {
+ auto* val = b.Let("val", 1_i);
+ auto* delta = b.Let("delta", 1_u);
auto* result = b.Call(ty.i32(), core::BuiltinFn::kSubgroupShuffleUp, val, delta);
b.Return(func, result);
});
auto* src = R"(
-%foo = func(%val:i32, %delta:u32):i32 {
+%foo = @fragment func():i32 [@location(0)] {
$B1: {
+ %val:i32 = let 1i
+ %delta:u32 = let 1u
%4:i32 = subgroupShuffleUp %val, %delta
ret %4
}
@@ -1582,62 +1555,46 @@
EXPECT_EQ(src, str());
auto* expect = R"(
-%foo = func(%val:i32, %delta:u32):i32 {
- $B1: {
- %4:u32 = and %delta, 127u
- %5:i32 = subgroupShuffleUp %val, %4
- ret %5
+$B1: { # root
+ %tint_subgroup_size_mask:ptr<private, u32, read_write> = var undef
+}
+
+%foo = @fragment func(%tint_subgroup_size:u32 [@subgroup_size]):i32 [@location(0)] {
+ $B2: {
+ %4:u32 = sub %tint_subgroup_size, 1u
+ store %tint_subgroup_size_mask, %4
+ %val:i32 = let 1i
+ %delta:u32 = let 1u
+ %7:u32 = load %tint_subgroup_size_mask
+ %8:u32 = and %delta, %7
+ %9:i32 = subgroupShuffleUp %val, %8
+ ret %9
}
}
)";
- PolyfillConfig config{.subgroup_shuffle_clamped = true};
- Run(BuiltinPolyfill, config);
+ Run(BuiltinPolyfill, PolyfillConfig{});
EXPECT_EQ(expect, str());
... (truncated)