Repository navigation
[Kernel][Feature][Dialect][DSL][Perf][Doc][Test] Add gfx120x RDNA4 wave32 ops - #1223
Draft
dimitri91209 wants to merge 23 commits into
Draft
dimitri91209 wants to merge 23 commits into
dimitri91209 wants to merge 23 commits into
Conversation
dimitri91209
force-pushed
the
gfx120x-overhaul-ops-fa-etc
branch
from
October 1, 2026 17:29
b4f7d0a to
f9261af
Compare
dimitri91209
force-pushed
the
gfx120x-overhaul-ops-fa-etc
branch
from
October 2, 2026 02:47
92d7a12 to
fba0948
Compare
dimitri91209
marked this pull request as ready for review
October 2, 2026 02:50
dimitri91209
marked this pull request as draft
October 3, 2026 02:30
dimitri91209
force-pushed
the
gfx120x-overhaul-ops-fa-etc
branch
4 times, most recently
from
October 3, 2026 16:00
1320e7c to
13a60a5
Compare
dimitri91209
force-pushed
the
gfx120x-overhaul-ops-fa-etc
branch
8 times, most recently
from
October 7, 2026 02:20
59219ef to
5f22e04
Compare
dimitri91209
added a commit
to dimitri91209/gfx120x-ops
that referenced
this pull request
Oct 7, 2026
…ragged Breaking correctness fixes for gfx120x overhaul (ROCm#1223): 1. FA tests: drop dead monkeypatches on deleted ext helpers (splitk_online_softmax_attn / packed_varlen_to_dense / gather_paged_kv with raising=False). Keep real dense/ref asserts. Restore sink-norm inequality (remove neutralizing or True). 2. fused_mlp_nmajor: inreg@K=FFN=16 must not compare to nmajor (routes into inreg). Compare to reference_swiglu_mlp instead. 3. allreduce harness: incomplete rank_results or empty all_results after attempted configs → sys.exit(1), not soft return 0. 4. flash_attn_interface: dense (non-varlen) + paged KV + ragged per-batch seqlen_k → NotImplementedError; require varlen / cu_seqlens. Do not plumb dense ragged (gfx120x + gfx950 paths). Signed-off-by: dimitri91209 <dimitri.spencer912@gmail.com>
dimitri91209
added a commit
to dimitri91209/gfx120x-ops
that referenced
this pull request
Oct 7, 2026
…ve32 ops Summary: Squashed gfx120x RDNA4 wave32 product stack for FlyDSL (FA, GEMM/linear, quant, SwiGLU/MLP, RoPE/AdaLN, dialect atoms) including soft-pad, stream-aware host soft-contig, and empty early-outs. Motivation: Ship a single reviewable tip for ROCm#1223. Changes: - Dense FA bf16/fp16/fp8/int8/iu4 hosts + soft-pad/stream bind - GEMM/linear/quant/SwiGLU/RoPE/AdaLN gfx120x surfaces - Dialect WMMA/SWMMAC atoms, examples 07-22, tests/docs Testing: Prior full suite recorded on branch history; tip squash preserves tree. Signed-off-by: dimitri91209 <dimitri.spencer912@gmail.com>
dimitri91209
force-pushed
the
gfx120x-overhaul-ops-fa-etc
branch
from
October 7, 2026 06:28
5481452 to
d9fc04d
Compare
dimitri91209
added a commit
to dimitri91209/gfx120x-ops
that referenced
this pull request
Oct 7, 2026
…ve32 ops Summary: Squashed gfx120x RDNA4 wave32 product stack for FlyDSL (FA, GEMM/linear, quant, SwiGLU/MLP, RoPE/AdaLN, dialect atoms) including soft-pad, stream-aware host soft-contig, and empty early-outs. Removes FLYDSL_DISPATCH_MODE / dispatch_mode env override; ConvRot keeps try-native-int4 then unpack→iu8. Motivation: Ship a single reviewable tip for ROCm#1223. Changes: - Dense FA bf16/fp16/fp8/int8/iu4 hosts + soft-pad/stream bind - GEMM/linear/quant/SwiGLU/RoPE/AdaLN gfx120x surfaces - Dialect WMMA/SWMMAC atoms, examples 07-22, tests/docs - Remove FLYDSL_DISPATCH_MODE, kernels.common.dispatch_mode, force_flydsl Testing: Prior full suite recorded on branch history; tip squash preserves tree. Style: bash scripts/check_python_style.sh --base origin/main --head HEAD PASS. Signed-off-by: dimitri91209 <dimitri.spencer912@gmail.com>
dimitri91209
force-pushed
the
gfx120x-overhaul-ops-fa-etc
branch
from
October 7, 2026 06:52
a20058c to
86e46e6
Compare
dimitri91209
added a commit
to dimitri91209/gfx120x-ops
that referenced
this pull request
Oct 7, 2026
…ve32 ops Summary: Squashed gfx120x RDNA4 wave32 product stack for FlyDSL (FA, GEMM/linear, quant, SwiGLU/MLP, RoPE/AdaLN, dialect atoms) including soft-pad, stream-aware host soft-contig, and empty early-outs. Removes FLYDSL_DISPATCH_MODE / dispatch_mode env override. ConvRot W4A4 linear_dtype="int4" soft-pads to the Hadamard/quant/iu4 K contract and always stays on native iu4_gemm (no silent unpack→iu8 demotion); linear_dtype="int8" remains the explicit unpack path. Motivation: Ship a single reviewable tip for ROCm#1223 with industry-standard soft-pad / stay-native ConvRot int4 like the rest of gfx120x. Changes: - Dense FA bf16/fp16/fp8/int8/iu4 hosts + soft-pad/stream bind - GEMM/linear/quant/SwiGLU/RoPE/AdaLN gfx120x surfaces - Dialect WMMA/SWMMAC atoms, examples 07-22, tests/docs - Remove FLYDSL_DISPATCH_MODE, kernels.common.dispatch_mode, force_flydsl - ConvRot int4: always native iu4 + soft-pad; ABI fails still raise Testing: Prior full suite recorded on branch history; tip squash preserves tree. Style: bash scripts/check_python_style.sh --base origin/main --head HEAD PASS. Signed-off-by: dimitri91209 <dimitri.spencer912@gmail.com>
dimitri91209
force-pushed
the
gfx120x-overhaul-ops-fa-etc
branch
from
October 7, 2026 07:05
86e46e6 to
503565b
Compare
dimitri91209
added a commit
to dimitri91209/gfx120x-ops
that referenced
this pull request
Oct 7, 2026
…ve32 ops Summary: Squashed gfx120x RDNA4 wave32 product stack for FlyDSL (FA, GEMM/linear, quant, SwiGLU/MLP, RoPE/AdaLN, dialect atoms) including soft-pad, stream-aware host soft-contig, and empty early-outs. Removes FLYDSL_DISPATCH_MODE / dispatch_mode env override. ConvRot W4A4 linear_dtype="int4" soft-pads to the Hadamard/quant/iu4 K contract and always stays on native iu4_gemm (no silent unpack→iu8 demotion); linear_dtype="int8" remains the explicit unpack path. Shared gfx950/gfx942 FA paged/dense host behavior matches origin/main; gfx120x dense-paged ragged seqlen_k hardening stays on the gfx120x arm only. Motivation: Ship a single reviewable tip for ROCm#1223 with industry-standard soft-pad / stay-native ConvRot int4 like the rest of gfx120x, without changing other-arch FA contracts. Changes: - Dense FA bf16/fp16/fp8/int8/iu4 hosts + soft-pad/stream bind - GEMM/linear/quant/SwiGLU/RoPE/AdaLN gfx120x surfaces - Dialect WMMA/SWMMAC atoms, examples 07-22, tests/docs - Remove FLYDSL_DISPATCH_MODE, kernels.common.dispatch_mode, force_flydsl - ConvRot int4: always native iu4 + soft-pad; ABI fails still raise - Restore shared FA: dense paged ragged raise only with bias; skip seqlen_k .tolist() when max_seqlen_kv set and no bias; dense out soft .contiguous() (no shared ValueError). gfx120x-only dense-paged ragged reject remains. Testing: Prior full suite recorded on branch history; tip squash preserves tree. Style: black --check + ruff check on flash_attn_interface.py PASS. Signed-off-by: dimitri91209 <dimitri.spencer912@gmail.com>
dimitri91209
force-pushed
the
gfx120x-overhaul-ops-fa-etc
branch
from
October 7, 2026 07:20
503565b to
9738b84
Compare
dimitri91209
added a commit
to dimitri91209/gfx120x-ops
that referenced
this pull request
Oct 7, 2026
…ve32 ops Summary: Squashed gfx120x RDNA4 wave32 product stack for FlyDSL (FA, GEMM/linear, quant, SwiGLU/MLP, RoPE/AdaLN, dialect atoms) including soft-pad, stream-aware host soft-contig, and empty early-outs. Removes FLYDSL_DISPATCH_MODE / dispatch_mode env override. ConvRot W4A4 linear_dtype="int4" soft-pads to the Hadamard/quant/iu4 K contract and always stays on native iu4_gemm (no silent unpack→iu8 demotion); linear_dtype="int8" remains the explicit unpack path. Shared gfx950/gfx942 FA paged/dense host behavior matches origin/main; gfx120x dense-paged ragged seqlen_k hardening and dense out= contiguous raise stay on the gfx120x arm/host only. Motivation: Ship a single reviewable tip for ROCm#1223 with industry-standard soft-pad / stay-native ConvRot int4 like the rest of gfx120x, without changing other-arch FA contracts. Changes: - Dense FA bf16/fp16/fp8/int8/iu4 hosts + soft-pad/stream bind - GEMM/linear/quant/SwiGLU/RoPE/AdaLN gfx120x surfaces - Dialect WMMA/SWMMAC atoms, examples 07-22, tests/docs - Remove FLYDSL_DISPATCH_MODE, kernels.common.dispatch_mode, force_flydsl - ConvRot int4: always native iu4 + soft-pad; ABI fails still raise - Restore shared FA: dense paged ragged raise only with bias; skip seqlen_k .tolist() when max_seqlen_kv set and no bias; dense out soft .contiguous() (no shared ValueError). gfx120x-only dense-paged ragged reject remains; gfx120x dense host raises ValueError if out= is non-contiguous. Testing: Prior full suite recorded on branch history; tip squash preserves tree. Style: black --check + ruff check on flash_attn_gfx120x_host.py PASS. Signed-off-by: dimitri91209 <dimitri.spencer912@gmail.com>
dimitri91209
force-pushed
the
gfx120x-overhaul-ops-fa-etc
branch
from
October 7, 2026 07:26
9738b84 to
ec5b015
Compare
dimitri91209
added a commit
to dimitri91209/gfx120x-ops
that referenced
this pull request
Oct 7, 2026
…ve32 ops Summary: Squashed gfx120x RDNA4 wave32 product stack for FlyDSL (FA, GEMM/linear, quant, SwiGLU/MLP, RoPE/AdaLN, dialect atoms) including soft-pad, stream-aware host soft-contig, and empty early-outs. On gfx120x, dense-paged + ragged seqlen_k auto-routes to varlen-paged (builds cu_seqlens_* from per-batch Q length and seqlen_k); uniform seqlen_k stays on the dense paged host. Shared gfx950/gfx942 FA paged/dense host behavior matches origin/main. Motivation: Ship a single reviewable tip for ROCm#1223 with industry-standard soft-pad / stay-native ConvRot int4 like the rest of gfx120x, without changing other-arch FA contracts. Changes: - Dense FA bf16/fp16/fp8/int8/iu4 hosts + soft-pad/stream bind - GEMM/linear/quant/SwiGLU/RoPE/AdaLN gfx120x surfaces - Dialect WMMA/SWMMAC atoms, examples 07-22, tests/docs - gfx120x dense-paged ragged seqlen_k → varlen-paged auto-route (host) - Shared FA: dense paged ragged raise only with bias (unchanged) Testing: Prior full suite recorded on branch history; tip squash preserves tree. Style: black --check + ruff check on touched FA routing files PASS. Signed-off-by: dimitri91209 <dimitri.spencer912@gmail.com>
dimitri91209
force-pushed
the
gfx120x-overhaul-ops-fa-etc
branch
5 times, most recently
from
October 10, 2026 17:33
337786d to
c582d71
Compare
The gfx120x launches sit in their own modules and the shared flash-attention entry returns before the gfx950 and gfx942 bodies. Each new launch checks get_rocm_arch() inline. The RDNA4 WMMA and SWMMAC atoms are included. The per-kernel examples and the separate arch module are not. Signed-off-by: dimitri91209 <dimitri.spencer912@gmail.com>
Each gfx120x launch calls get_rocm_arch and checks startswith gfx120. The copied helper function is gone. The attention routing guards live in the gfx120x host, which is what the shared flash-attention entry calls. Signed-off-by: dimitri91209 <dimitri.spencer912@gmail.com>
dimitri91209
force-pushed
the
gfx120x-overhaul-ops-fa-etc
branch
from
October 11, 2026 06:37
2bad539 to
578e37a
Compare
flydsl_flash_attn_func on gfx120x returns into the host. The host keeps the layout table, stores attn_mask in bias, and leaves the lru_cache launchers in place. Signed-off-by: dimitri91209 <dimitri.spencer912@gmail.com>
The interface docstring keeps main's sentences. gfx120x notes are added after those sentences. Signed-off-by: dimitri91209 <dimitri.spencer912@gmail.com>
The interface export list is main's two names. gfx120x comments fill the line before they wrap. Signed-off-by: dimitri91209 <dimitri.spencer912@gmail.com>
kernels.rst keeps one bullet per module. The gfx120x attention kernels are included. Function names are not. Signed-off-by: dimitri91209 <dimitri.spencer912@gmail.com>
The check sits on the function that contains @flyc.jit, before that definition, matching compile_mxfp8_gemm_8w. Existing ValueError gates are asserts. A gfx950 arch override raises before those builders run. Signed-off-by: dimitri91209 <dimitri.spencer912@gmail.com>
build_gemm_nmajor_lds_module calls flyc.jit without a decorator, so the sweep missed it. dequantize_int8_rowwise had the arch assert twice. Signed-off-by: dimitri91209 <dimitri.spencer912@gmail.com>
FlashAttention's dtype multiplier replaces a cosine floor of 0.99. fp16 and bf16 use 2x the PyTorch error, fp8 and int8 use 4x, against an fp32 reference. Signed-off-by: dimitri91209 <dimitri.spencer912@gmail.com>
The paged fp8 and int8 helper is _gfx120x_quant_paged. The previous name was a splice of the helper and the public function. Signed-off-by: dimitri91209 <dimitri.spencer912@gmail.com>
A head is padded to a multiple of 32. A prefetch that does not fit in 64 KiB is split into LDS chunks. Softmax weights round to bf16. The shape grid covers the mechanisms that already exist. Signed-off-by: dimitri91209 <dimitri.spencer912@gmail.com>
Q and K use the query head. V and the output use the value head on bf16 dense, varlen, paged, and split-K, and on fp8 and int8. A caller sm_scale replaces 1/sqrt(D). Softcap is tanh of the scaled score, computed with exp2. Signed-off-by: dimitri91209 <dimitri.spencer912@gmail.com>
Softcap uses the exp2 form of tanh on bf16, fp16, fp8, and int8, including varlen and paged. Masked scores stay at the -inf bit pattern. Dropout probability 0 keeps that kernel. A positive probability draws Philox from the logical column, row, batch, and head and matches that seeded mask. Signed-off-by: dimitri91209 <dimitri.spencer912@gmail.com>
Vectorized V is [blocks, Hkv, page/vec, Dv, vec]. The paged host was reading the vector width as the value head, so the output was eight elements wide. Decode uses that cache layout and the existing WMMA paged kernel. Query length 1 attends the valid cache. Signed-off-by: dimitri91209 <dimitri.spencer912@gmail.com>
Contributor
Author
|
If anyone is looking at this, honestly just don't. It'll get there eventually, the attention stack is close. Like really really lose to being a drop in for Rdna4 for pretty much everything that's industry standard. Jit should be able to build kernels by going through the attention host with args passed from the program host and build pretty much anything one needs for Rdna4. Currently waiting on a true16 pr on LLVM before any of that works for qwen though. In order to avoid a lds round trip for attention. |
Paged decode accepts the workspace tensors main always passes and a sliding window. MLA reads the latent cache through the WMMA paged kernel. Linear attention is the prefix recurrence. Quant QK-norm applies RMSNorm, rotates the tail, and stores fp8 or int8. Signed-off-by: dimitri91209 <dimitri.spencer912@gmail.com>
A ragged seqlen_k route packed the query and then reshaped the output with the query head. The varlen paged launch now writes the value width. Signed-off-by: dimitri91209 <dimitri.spencer912@gmail.com>
Paged and varlen fp8 were indexing V with the query-head stride. The value width now has its own index, and the bytes still arrive as a dword bitcast. Decode and MLA cover fp16, fp8, and int8. A causal window plus a sink matches the formula. Signed-off-by: dimitri91209 <dimitri.spencer912@gmail.com>
Main's m16x8 entry is an MFMA kernel for a query width of 576 and a value width of 512. The gfx120x launch keeps those arguments and uses the flash kernel. A wide fp8 row grows the block so one load covers the row. Signed-off-by: dimitri91209 <dimitri.spencer912@gmail.com>
Both dtypes stay in the flat m16x8 launch. Int8 meets the bf16 same-dtype bar. fp8 e5m2 is compared with an e5m2 product rounded in K=16 groups, which is that format's matmul error. Signed-off-by: dimitri91209 <dimitri.spencer912@gmail.com>
The 576 by 512 latent already passed on bf16 and fp8 e4m3. The same launch now passes on fp16, fp8 e5m2, and int8. Signed-off-by: dimitri91209 <dimitri.spencer912@gmail.com>
One wave holds the row in registers and reduces there. Head 1, 40, and 128 pass, including an odd width and a width that does not fit the old pair-per-thread block. Signed-off-by: dimitri91209 <dimitri.spencer912@gmail.com>
Linear attention keeps the value column in registers instead of rescanning the prefix. Quant QK-norm reloads each pair after the wave reduction. An unaligned paged value head is zero-extended to the tile and cropped back. Paged decode builds a block table from the page CSR and dequants only the referenced pages when the query dtype differs. MLA writes the one-partition split buffers from the same WMMA launch. fp8 e5m2 accumulates PV in f32 after dequantizing V. Signed-off-by: dimitri91209 <dimitri.spencer912@gmail.com>
Quant and varlen paged attention zero-extend a value head that is not a multiple of 32, then crop the output. e5m2 QK and PV both use the e5m2 matrix product. Quant QK-norm keeps each normalized pair in registers, and an empty row does not launch. Signed-off-by: dimitri91209 <dimitri.spencer912@gmail.com>
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.
Summary
gfx120x (RDNA4, wave32, WMMA) kernels for flash attention, GEMM, quantization, SwiGLU, RoPE, and AdaLN. The host does not copy Q, K, or V to round K or the head dimension up to a tile. Lanes past the real shape are zero.
Versus
main(43ec5da9): 106 files, +38582 / −27. Tip21a11efb. The quant paged helper is_gfx120x_quant_paged. Every positive head is padded to a multiple of 32. A head whose KV prefetch does not fit in 64 KiB is split into LDS chunks. The value head can differ from the query head, including a ragged paged cache on bf16, fp16, fp8, and int8. Quant paged and varlen paged zero-extend a value head that is not a multiple of 32 and crop the output. e5m2 QK and PV both use the e5m2 matrix product. Quant QK-norm keeps each normalized pair in registers. Logit softcap istanh(score * scale / softcap) * softcapon bf16, fp16, fp8, and int8, including varlen and paged. Dropout probability 0 leaves that kernel unchanged. A positive probability uses an explicit Philox seed. The accuracy check is one step of the output format at that output's size. Near 1.0 the step is 0.00098 for fp16, 0.0078 for bf16, 0.125 for e4m3, and 0.25 for e5m2. The step doubles when the value doubles. Int8 is half a code, the max absolute value divided by 254. Main's flash-attention sentences stay. gfx120x notes are added after them. The function that contains@flyc.jitassertsget_rocm_arch().startswith("gfx120")before that definition. There is nogfx120x_arch.py. On gfx120x,flydsl_flash_attn_funcreturns intoflash_attn_gfx120x_host.flydsl_flash_attn_func. That host storesattn_maskinbiasand launches dense, varlen, paged, fp8, and int8. The value head, softcap, and dropout probability are cache keys. Paged decode, MLA, linear attention, and quant QK-norm are separate gfx120x modules. Decode takes the same arguments as main, including a sliding window. MLA reads the latent cache through the WMMA paged kernel. Linear attention is the prefix recurrence. Quant QK-norm is RMSNorm, tail RoPE, then fp8 or int8.#1223 stays a draft and stays targeted at
main. Shared compiler bugfixes that are not gfx120x kernels are on #1240. This branch does not carry that PR's CDNA5tensor2tdmnull check.There is no packed-int4 flash attention.
iu4_gemmis the int4 GEMM, and the atom is K=32 only (wmma_i32_16x16x32_iu4). Attention dtypes are bf16, fp16, fp8 e4m3, fp8 e5m2, and int8.fx.Int64is the index and offset type.fx.Indexis deprecated, same asmain. The disk cache stores compiled IR only. Source IR is not persisted.Still copied on the host, on purpose: the nmajor wrapper around the shared f16 GEMM, which requires a tile multiple, and a direct call to the in-register SwiGLU kernel when K or the FFN width is below 16. The product SwiGLU host does not send those shapes there.
Bug fixes
File:
kernels/attention/flash_attn_gfx120x_host.py(_pad_narrow_value_cache)Bug: Quant paged and varlen paged launched a value head that is not a multiple of 32 at the query tile, so heads 40, 48, and 80 read past V.
Fix: The value cache is zero-extended to the WMMA stride and the output is cropped back to the caller width. The uniform bf16 paged path uses the same helper.
Notes: e4m3 and e5m2 pass those heads at one step of the fp8 format. int8 no longer overflows.
File:
kernels/attention/flash_attn_gfx120x_host.py(apply_sliding_window)Bug: A causal window was measured from
q_row. A decode query (Sq=1) kept the start of the cache.Fix: The band origin is
q_row + (Sk - Sq)when the mask is causal, andq_rowotherwise.Notes: Equal lengths are unchanged. A decode window
(left=4, right=0)matches the bottom-right mask at cosine 1.0 and does not match the old key range.File:
kernels/attention/flash_attn_gfx120x_host.py,flash_attn_gfx120x.py,flash_attn_fp8_gfx120x.pyBug: Ragged varlen ALiBi was the top-left of a bias built at the max lengths, so a shorter sequence used
|i + max_k - max_q - j|.Fix: A 2D ALiBi is copied from the bottom-right slice of each sequence. A per-head ALiBi tensor sets
bias_bottom_right, and the kernel adds(max_q - sq, max_k - sk).Notes: A per-head user mask stays top-left. Scalar ALiBi plus a 2D user mask is expanded separately, then added. Lengths 8/20 against 24/12 match a per-sequence fold at cosine 0.99999.
File:
kernels/attention/flash_attn_gfx120x_host.py(add_alibi_scores),flash_attn_gfx120x.py,flash_attn_fp8_gfx120x.pyBug: A ragged varlen call with both a per-head user mask and per-head ALiBi had one bias tensor. The mask is top-left and ALiBi is bottom-right, so the ALiBi term used the max lengths.
Fix: That mix passes the slopes into the kernel.
add_alibi_scoresadds-slope * |i + sk - sq - j|, scaled like the user bias, and adds 0 on a pad column. Equal lengths, pure ALiBi, and a scalar slope plus a 2D mask still fold into one bias.Notes: Lengths 8/20 against 24/12 match a per-sequence fold. fp8 and int8 use
1/(sm_scale * q_descale * k_descale). The AOT export passes the slopes pointer.File:
kernels/attention/flash_attn_gfx120x_host.py(flydsl_flash_attn_quant_paged_func)Bug: Quant paged attention that is not packed-varlen kept a shared ALiBi tensor when
seqlen_kdiffered across the batch, so the kernel read column 0 instead ofmax_k - sk.Fix: The host packs Q and calls the varlen-paged path, the same handoff the float paged host already uses. Uniform lengths stay on the dense paged path.
Notes: fp8 e4m3 and int8,
seqlen_k32 and 16, match a per-batch bottom-right fold and a bottom-right causal mask. Output stays bf16.File:
kernels/attention/flash_attn_gfx120x.py,flash_attn_fp8_gfx120x.pyBug: Bias and ALiBi were added to unscaled WMMA scores. The contract is
softmax(qk * sm_scale + bias).Fix: bf16 divides the bias by
sm_scale. fp8 and int8 divide bysm_scale * q_descale * k_descale.Notes: Coverage bias, per-head bias, and ALiBi sections pass. Causal alignment stays bottom-right. It is not PyTorch
is_causalwhenSq != Sk.File:
kernels/attention/flash_attn_fp8_gfx120x.py,flash_attn_gfx120x_host.pyBug: A quant split narrower than the KV tile counted those columns twice. A dense split whose head was shorter than the tile wrote the tile stride into the output. The split workspace was uninitialized. A quant varlen shared bias record was too small, and a per-head mask was squeezed away.
Fix: Split columns outside
[kv_lo, kv_hi)are masked. The combine writes a tile buffer, then copies the real head. Workspacemis-infandlandoare zero. The varlen bias record covers the packed rows.[H, Sq, Sk]withH > 1stays per-head.Notes: Split-K versus the same kernel stays at cosine ≥ 0.99. Odd head 80 is in the coverage test.
File:
kernels/gemm/rdna4_int8_linear_fused.pyBug: Fused int8 activation quant clamped to
[-127, 127]and rounded with±0.5, so-128never appeared and ties rounded away from zero.Fix:
roundeven, then clamp to[-128, 127].Notes:
-127.5and-128store-128.2.5stores2.-2.5stores-2. Matches the torch reference exactly.File:
kernels/gemm/rdna4_scaled_mm_fp8.py,rdna4_scaled_mm_fp8_fused.py,rdna4_w8a16_linear.py,rdna4_int8_linear.py,rdna4_int8_linear_fused.pyBug:
K=0withM>0andN>0still launched, and an out-of-range lane reloaded byte 0 of an empty allocation.Fix: Return zeros of shape
[M, N]. Where the host has a bias, add it after. Scales are still checked.Notes: Covered for scaled-mm, its fused and multi paths, W8A16, int8 linear, and both fused int8 paths.
File:
kernels/quant/rdna4_asym_w4a8.pyBug: Asymmetric mode used
(max(|v|) - min(v)) / 15, so a larger negative peak widened the scale and collapsed the codes. Codes and the correction were chosen from the f32 ratio, thens_relwas cast to e4m3.Fix: Mode 2 uses
(max(v) - min(v)) / 15. Whens_relis e4m3, that cast is rounded first and the codes and correction use the stored value.Notes: Modes 0 and 1 still use abs-max. For
[-1, -0.2, 0.1]the codes are[0, 11, 15], including after the e4m3 round-trip.File:
kernels/quant/rdna4_svdquant_w4a4.pyBug: Int4 codes were
roundeven(x / scale_f32)while the stored scale was bf16 or fp16 of that value. The linear then cast the scale again.Fix: Round the scale through the stored dtype before the reciprocal.
svdquant_w4a4_linearquantizes inwscales.dtypeand does not cast afterward.Notes:
-0.2138671875with scale1/7is code-2on the stored bf16 scale and would be-1on the f32 scale. The kernel stores-2.File:
kernels/quant/rdna4_quantize_int8_tensorwise.pyBug: A caller-supplied scale was replaced by its absolute value, so a negative scale no longer flipped the codes.
Fix:
invis the reciprocal of the signed scale. The magnitude is still clamped at1e-30.Notes:
scale=-0.5matchesround(x / -0.5). Abs-max quant is unchanged.File:
kernels/quant/rdna4_stoch_fp8.pyBug: Stochastic rounding pre-rounded through fp16.
Fix: The value stays f32 (
fx.Float32(raw)).Notes:
test_stoch_fp8_uses_f32_not_fp16passed. The cast still stores no scale.File:
kernels/quant/rdna4_int8_convrot.pyBug: The int8 Hadamard quant stored only the logical K and dropped the rest of the orthogonal group.
Fix: The kernel loads
logical_kcolumns and zero-fills the rest. It stores the full Hadamard width. The host returns[..., k_pad].Notes:
test_int8_linear_convrot_odd_k_stays_in_kernelpassed. The FWHT helper still returns the caller's K.File:
kernels/gemm/rdna4_w8a16_linear.py,rdna4_scaled_mm_fp8_fused.py,rdna4_int8_linear_fused.pyBug: A partial N tile could load a scale past N. A fused LoRA row could be negative when the column was out of range.
Fix: The scale column is clamped to 0 when
skip_boundsis false. The LoRA row is 0 when the column is out of range.Notes: The existing W8A16 and fused GEMM tests passed in the full suite.
File:
tests/python/examples/aot_gfx120x_example.py,kernels/attention/flash_attn_gfx120x_splitk.pyBug: The AOT pack skipped MXFP GEMM and quant, SiLU, FP8 dequant, split-K, ALiBi, the bool mask, AWQ dequant, and int8 ConvRot dequant. AdaLN and RMS+RoPE were given tensor ranks the kernels do not index.
Fix:
--allexports those kernels. AdaLN scale and shift are[rows, N]. RMS+RoPE frequencies are[rows, pairs, 2, 2]. Split-K exposes its jit launcher for export. The host wrapper is unchanged.Notes: The broaden export compiled every one of those objects.
File:
kernels/common/gfx120x_autotune_tables.pyBug: The block-size table was a size gate left from an old measurement. The hosts already mask lanes past the real row.
Fix: The file is gone. AdaLN, RoPE, RMS+RoPE, int8 rowwise quant, and asymmetric W4A8 use 256 threads unless the caller passes a block.
Notes: Flash attention
BLOCK_Mand the scaled FP8 tile pick stay in their own hosts.File:
tests/kernels/oracles.pyBug: The numeric references were split across nine modules.
Fix: They live in
tests/kernels/oracles.py. The tests import that module.Notes: The reference math is unchanged.
File:
tests/kernels/test_gfx120x_odd_shapes.pyBug: Product tests mostly used tile multiples of 64 and 128.
Fix: One sweep calls the hosts with no block override at other widths: AdaLN 96/160/384, RoPE and RMS+RoPE head 80 and 96, int8 rowwise K 100/300/700, scaled FP8 and e5m2 off the 64 tile, int8 13×27×41, MXFP8 17×23×96, attention seq 17/97/129 and head 72/80/96, and SwiGLU 7×24×40.
Notes: Each section is compared to the same reference the tile tests use. Cosine stayed at or above 0.98. The sweep does not assert a size-based block pick.
File:
kernels/common/gfx120x_swiglu.pyBug:
swiglu_chunkstored packed row-major fromdata_ptr()intoout, including whenoutwas a non-contiguous slice.Fix: A non-contiguous
outis written through a contiguous temporary and copied back on the same stream.Notes:
buf[:, :H]matchessilu(gate) * up. A contiguousoutis still launched directly.Tests
On the kernel commit,
scripts/run_tests.shwas 3831 passed, 2074 skipped, 33 deselected, 1 failed. The failure istests/unit/test_max_blocks_per_cu.py: the installedbuild-flypackage does not haveCompiledFunction.max_blocks_per_cu, which this tree's source does. FileCheck passed, includingwmma_gfx120x.mlirandswmmac_gfx120x.mlir. After the arch check, routing guards, public entries, scaled FP8, and RoPE passed (26 tests).7d961b1bkeeps that behavior.16f2607bpassed the routing guards, the interface route, a dense causal cross launch, andtest_gfx120x_attention_covers_implemented_ops(11 passed). That coverage test goes through the interface, including sliding window, varlen, paged, fp8, and int8. The full suite was not re-run.tests/kernels/test_gfx120x_attn_rest.pypassed (9 tests). The wide latent decode covers bf16, fp16, fp8 e4m3, fp8 e5m2, and int8 at query width 576 and value width 512. Quant QK-norm also passes head widths 1, 40, and 128. The follow-up tests passed (30 tests) on the previous tip: register linear attention, quant QK-norm, one-partition MLA splits, CSR block tables and mixed-dtype decode, and an unaligned paged value head. This commit pads quant and varlen paged value heads that are not a multiple of 32. The e5m2 short test checks one step of that format and passed. An e5m2 grid of 70 shapes passed. Quant QK-norm passed 49 shapes, including heads 1, 17, 40, 65, 128, 256, and 512, and an empty row. Repeat calls are about 0.055 ms. The full suite was not re-run after this commit. Examples 01, 02, and 05 pass on this GPU. Examples 03, 04, and 06 abort because they emit CDNA MFMA instructions. Examples 07–22 are not in this tree. Tests skip unless the process arch starts withgfx120, the same way the gfx950 suites skip.The earlier bug fixes are inside that suite. The attention cases, including the ragged mixed ALiBi and the ragged quant paged cases, are in
tests/kernels/test_flash_attn_gfx120x_coverage.py, which names the section if it fails. The value-head pad, the e5m2 matrix product, and the register QK-norm are the checks named above.