Repository navigation
fix(shader): read lane 63 of a wave64 v_max_f32/v_min_f32 half-wave scan - #2451
Merged
oneandonlydean merged 1 commit intoOct 10, 2026
Merged
Conversation
Contributor
|
Tested on Linux (CachyOS x86_64, Intel RPL-S iGPU / Mesa 26.3.0-devel / Vulkan 1.4.363, GCC 16.2.1) at
LGTM! |
Contributor
|
Native Windows run, since no Windows results were posted. Setup: Windows 10 (19045), RTX 3060 Laptop (NVIDIA 616.92), MinGW-w64 GCC 15.2.0 (WinLibs r7), Release. Head
No title was run. 🤖 Addressed by Claude Code |
9 tasks done
A wave64 vertex program reduces a float key across the wave with the same shape as the integer half-wave reductions: keys selected under the all-lanes EXEC with -inf (v_max_f32) or +inf (v_min_f32) outside the entry EXEC, four DPP row_shr steps, v_permlanex16_b32, then v_readlane_b32 of lanes 31 and 63, combined by one more v_max_f32. On a 32-lane host subgroup the read of lane 63 threw that it is outside the subgroup. The matcher now also accepts FPMax32 and FPMin32 steps, with their BitCasts and the f32 denormal flush the float mode may add around operands and results; the flush leaves the -inf and +inf keys unchanged. When the entry EXEC proves that lanes 32-63 hold the constant key, every step there combines that constant with itself. The existing v_max_f32/v_min_f32 lowering returns the operand unchanged for equal operands (NaN included), so lane 63 is exactly that constant, and the read returns it. No subgroup float reduction is emitted. Lane 31, the lanes on a 64-lane subgroup, and the combining v_max_f32 keep their existing lowering. So NaN and signed-zero results are the ones the shader computes today.
oneandonlydean
force-pushed
the
up639/half-wave-fp-reduce
branch
from
October 10, 2026 05:20
5435cb2 to
1008b91
Compare
SleglJan
pushed a commit
to SleglJan/AnyPS5
that referenced
this pull request
Oct 10, 2026
…e-fp-reduce fix(shader): read lane 63 of a wave64 v_max_f32/v_min_f32 half-wave scan
This was referenced Oct 12, 2026
10 tasks done
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
#1268 reads lanes 31 and 63 of a wave64 DPP row scan as half-wave reductions, but only for integer steps (UMin/UMax/SMin/SMax/IAdd/AND/OR). A wave64 vertex program does the same scan with
v_max_f32:row_shrDPP steps andv_permlanex16_b32follow;v_readlane_b32of lanes 31 and 63, combined by one morev_max_f32.On a 32-lane host subgroup the read of lane 63 threw:
The matcher now also accepts
FPMax32andFPMin32steps, with theirBitCasts, and identities -inf and +inf. It also looks through the f32 denormal flush the float mode adds around each operand and result ((x & 0x7f800000) == 0 ? x & 0x80000000 : x, #1850); the flush leaves -inf and +inf unchanged.The emission adds no float arithmetic. Once the entry EXEC proves that lanes 32-63 hold the constant key, every step there combines the constant with itself. Main's
v_max_f32/v_min_f32lowering (EmitMinMaxF32Value) returns the operand for equal operands, NaN included. So lane 63 is exactly that constant, and the read returns it.Everything else keeps its existing lowering, so NaN and signed-zero results are the ones the shader already computes:
v_max_f32.No
OpGroupNonUniformFMax/FMinis emitted, because their NaN and signed-zero results are not defined to matchv_max_f32.Touches
core/shader/recompiler/SpirvBackend/src/SpirvAlu/SpirvAluEmitterMath.cpp.The level in the test below needs this and "fix(shader): match half-wave reductions in vertex programs" together; the two are independent and either can go in first.
This and #2450 add a test at the same place in
tests/ShaderMemory.cpp, so whichever lands second needs a small rebase of that file; the code changes merge cleanly.Tested
maina8b032b: ctest 495/495.tools/check_conventions.pypasses.agc_shader_memory,verifyHalfWaveReduction:v_max_f32and av_min_f32scan build on 32 lanes with no subgroup arithmetic, and on 64 lanes. Onmainthe 32-lane case throws the line above.v_max_f32scan joined byv_min_f32, and av_max_f32scan of 0 outside the live lanes.Checklist
main; no other open PR implements the same functionsNotImplemented_nid_no_patch); silent stubs are listed in TechnicalDebt.mdfiles or images added to the repository (attach them to this PR)