Skip to content

wave-reduction-pixel-without-helper-attribute

Status: shipped (Phase 4) — see CHANGELOG.

(via ADR 0010)

What it detects

A pixel-shader entry that performs a wave reduction (WaveActiveSum, WaveActiveProduct, WaveActiveCountBits, WaveActiveBallot, etc.) whose result then flows into a derivative-bearing operation (ddx, ddy, an implicit-derivative texture sample) without [WaveOpsIncludeHelperLanes] declared on the entry. The Phase 4 data-flow analysis traces the reduction's output to the derivative operation; the rule fires when both occur and the attribute is absent.

Why it matters on a GPU

By default, pixel-shader wave intrinsics exclude helper lanes from the active mask: a WaveActiveSum(x) that sees a partially-covered quad sums only the covered lanes and ignores the helpers. This is usually what the author wants — helpers don't contribute meaningful values for non-derivative work. But when the reduction's result then flows into a derivative operation, the derivative computation needs the full quad to be coherent: ddx(uniform) is zero only when all four quad lanes have the same value.

If the helper lanes saw a different reduction result than the covered lanes (because they were excluded from the reduction), the derivative is contaminated. On NVIDIA Turing/Ada Lovelace and AMD RDNA 2/3 the contamination produces wrong texture-sample mip levels (because the derivative drives mip selection); on Intel Xe-HPG the same effect appears.

[WaveOpsIncludeHelperLanes] (SM 6.7) opts the entry into including helpers in wave intrinsics. When the reduction's result reaches a derivative, the attribute is required for correctness. The Phase 4 data-flow rule catches the missing-attribute case.

The fix is to add the attribute to the entry. The rule is suggestion-tier because in some kernels the derivative is intentionally allowed to be approximate (e.g., a debug visualisation); the diagnostic emits the candidate attribute as a comment.

Examples

Bad

hlsl
// PS: reduction excludes helpers; derivative on the result is contaminated.
Texture2D<float4> g_Albedo : register(t0);
SamplerState      g_Sampler : register(s0);

float4 main(float2 uv : TEXCOORD0) : SV_Target0 {
    float waveAvg = WaveActiveSum(uv.x) / WaveActiveCountBits(true);
    float dudx    = ddx(waveAvg);     // helper lanes had wrong waveAvg
    return g_Albedo.Sample(g_Sampler, uv + float2(dudx, 0));
}

Good

hlsl
[WaveOpsIncludeHelperLanes]
float4 main(float2 uv : TEXCOORD0) : SV_Target0 {
    float waveAvg = WaveActiveSum(uv.x) / WaveActiveCountBits(true);
    float dudx    = ddx(waveAvg);
    return g_Albedo.Sample(g_Sampler, uv + float2(dudx, 0));
}

Options

none

Fix availability

suggestion — Adding the attribute is a one-line change but requires confirming that the helper-lane values are well-defined for the reduction. The diagnostic emits the candidate as a comment.

See also


Edit this page

© 2026 NelCit, CC-BY-4.0.

© 2026 NelCit — Apache-2.0 (code), CC-BY-4.0 (docs).