Repository navigation
[Kernel][FA] Fix ds_read_tr waitcnt hazard and stagger SCC clobber (1/8) - #1245
Open
xinyazhang wants to merge 1 commit into
Open
xinyazhang wants to merge 1 commit into
xinyazhang wants to merge 1 commit into
Conversation
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
The critical LDS wait hazard lacks automated regression coverage capable of exercising or detecting it.
1 open finding
What changed in this PR
Fixes gfx950 flash-attention LDS wait hazards and SCC clobber handling while adding signed arithmetic utilities.
Changes:
- Replaces inline-assembly transpose reads with visible ROCDL operations.
- Adds LDS alias scopes and SCC clobber metadata.
- Adds signed integer and vector-type helpers.
| File | Description |
|---|---|
kernels/attention/flash_attn_utils.py |
Fixes LDS hazard tracking, aliasing, and SCC clobber declaration. |
kernels/common/utils.py |
Adds signed arithmetic and vector element-type helpers. |
🧠 Review effort: Balanced
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
… signed helpers `_ds_read_tr16_b64_imm` / `_ds_read_tr8_b64_imm` emitted the LDS transpose reads as inline asm. SIInsertWaitcnts cannot see DS ops inside asm, so no lgkmcnt wait guards uses of the result; above head_dim 128 the allocator places v_accvgpr_write copies ahead of the kernel's own wait and the result is non-deterministic NaN. Emit the ROCDL ops instead (pointer formed as a GEP so the immediate folds into the DS offset field) and tag the dual-wave V reads with the LDS alias scopes the K reads already use, which keeps the backend from inserting a vmcnt(0) drain of the KV prefetch. Equivalent of FlyDSL 0a9c590 on main's helpers. `_stagger_extra_barrier_if_zero`'s asm runs s_cmp/s_cbranch_scc0 but its constraint string did not declare the SCC clobber; LLVM could keep an SCC-producing compare live across it (equivalent of e87210f). Both helpers are shared with the fp8 kernels, so they are fixed in place. Also add ssel/smin/smax/sdiv_rd_pow2/vector_elem_type to kernels/common/utils.py for the upcoming attention kernels. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
xinyazhang
force-pushed
the
xinyazhang/file-aotriton-0.14.2-gfx950-port/pr1-shared-fixes
branch
from
October 15, 2026 16:59
51aedab to
b7936d1
Compare
Contributor
|
This pr will cause fp8 dense kernel perf regression, such as |
binding7012
reviewed
Oct 18, 2026
| def unflatten_k(k_flat, qkhe_loop: int = 2): | ||
| n = qkhe_loop * 2 | ||
| return [[k_flat[td * n + j] for j in range(n)] for td in range(len(k_flat) // n)] | ||
|
|
Contributor
There was a problem hiding this comment.
like these five helper aren't use in this pr? Will this be needed for subsequent PRs?
This branch has not been deployed
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.

Part 1 of 8 of the gfx950 attention port from AOTriton 0.14.2b production kernel; base
main.Summary
kernels/attention/flash_attn_utils.py: emit the LDS transpose reads(
_ds_read_tr16_b64_imm,_ds_read_tr8_b64_imm) as ROCDL ops instead ofinline asm, so
SIInsertWaitcntssees them and inserts thelgkmcntwait.already use, so the backend does not insert a
vmcnt(0)drain of the KVprefetch.
~{scc}clobber on the stagger barrier asm(
_stagger_extra_barrier_if_zero).kernels/common/utils.py: add the signed helpersssel,smin,smax,sdiv_rd_pow2andvector_elem_type, used by later PRs in the stack.Both fixes were carried from FlyDSL
0a9c5906ande87210fe, which lived on aside branch and never reached
main; they were found during the AOTriton 0.14integration.
Why this fix
The
ds_read_trhelpers wrapped the instruction in inline asm. LLVM cannotsee a DS op inside asm, so
SIInsertWaitcntsnever emitted ans_waitcnt lgkmcntbefore the uses of the result. Once head_dim > 128 spillsto AGPRs, the allocator places
v_accvgpr_writecopies ahead of the kernel'sown wait and reads registers the LDS load has not yet written. The result is
non-deterministic NaN. With the ROCDL op (pointer formed as a GEP so the
immediate still folds into the DS offset field) the hazard tracker owns the
wait.
The stagger barrier asm runs
s_cmp/s_cbranch_scc0, which destroys SCC,but its constraint string did not say so. A compare scheduled above the asm
could be kept live across it and read stale, which made the LSE store skip.
Performance
MI355X (gfx950), HIP 6 (amd-smi row 6), idle-checked before every launch; bf16; ROCm 10.1, flydsl 0.4.0, torch 2.14.0+rocm10.1.0. Device kernel time (profiler), median TFLOP/s; FLOPs 4BHSqSk*D, halved for causal. Full data:
port950-perf-results.md.Method: each code base runs in its own process and the launches alternate A,B,B,A,A,B,B,A (4 launches each, the table shows the median); inside a process the variants are interleaved with the order flipped every round; 10 rounds x 20 reps per launch. The
±is the launch-to-launch spread (max-min)/median. Both sides callflydsl_flash_attn_funcwith its defaults (main's old dual-wave kernel); upstream/main 1941889 vs this PR's tip 51aedab.Result: neutral, every row within -0.4% .. +0.1% of main (launch spread about +-1%). The D=192 row cannot be measured:
main and this PR both fail to build it (the generic kernel asserts
block_size % threads_per_row_loadinflash_attn_utils.py), so there is no before/after pair.Validation
51aedab3(MI355X/gfx950,-m "not large_shape"):tests/kernels/test_flash_attn_fwd.py: 1033 passed, 2 failed (the two knowntest_paged_fp8_*side_stream*failures, which also fail on unmodifiedmain).python3 scripts/check_repo.py --base upstream/mainpasses.ds_read_b64_tr_b16, 0 unwaited uses, and the stagger asmdeclares
~{scc}.Scope
Shared helpers, also used by
main's fp8 attention kernels, which get thefixes too. No kernel algorithm change.
AI model disclosure
(1M context).
🤖 Generated with Claude Code