Skip to content

[Kernel][Feature][Dialect][DSL][Perf][Doc][Test] Add gfx120x RDNA4 wave32 ops - #1223

Draft
dimitri91209 wants to merge 23 commits into
ROCm:mainfrom
dimitri91209:gfx120x-overhaul-ops-fa-etc
Draft

dimitri91209 wants to merge 23 commits into
ROCm:mainfrom
dimitri91209:gfx120x-overhaul-ops-fa-etc

Conversation

@dimitri91209

@dimitri91209 dimitri91209 commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

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. Tip 21a11efb. 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 is tanh(score * scale / softcap) * softcap on 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.jit asserts get_rocm_arch().startswith("gfx120") before that definition. There is no gfx120x_arch.py. On gfx120x, flydsl_flash_attn_func returns into flash_attn_gfx120x_host.flydsl_flash_attn_func. That host stores attn_mask in bias and 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 CDNA5 tensor2tdm null check.

There is no packed-int4 flash attention. iu4_gemm is 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.Int64 is the index and offset type. fx.Index is deprecated, same as main. 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, and q_row otherwise.
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.py
Bug: 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.py
Bug: 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_scores adds -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_k differed across the batch, so the kernel read column 0 instead of max_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_k 32 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.py
Bug: 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 by sm_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_causal when Sq != Sk.

File: kernels/attention/flash_attn_fp8_gfx120x.py, flash_attn_gfx120x_host.py
Bug: 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. Workspace m is -inf and l and o are zero. The varlen bias record covers the packed rows. [H, Sq, Sk] with H > 1 stays 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.py
Bug: Fused int8 activation quant clamped to [-127, 127] and rounded with ±0.5, so -128 never appeared and ties rounded away from zero.
Fix: roundeven, then clamp to [-128, 127].
Notes: -127.5 and -128 store -128. 2.5 stores 2. -2.5 stores -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.py
Bug: K=0 with M>0 and N>0 still 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.py
Bug: 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, then s_rel was cast to e4m3.
Fix: Mode 2 uses (max(v) - min(v)) / 15. When s_rel is 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.py
Bug: 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_linear quantizes in wscales.dtype and does not cast afterward.
Notes: -0.2138671875 with scale 1/7 is code -2 on the stored bf16 scale and would be -1 on the f32 scale. The kernel stores -2.

File: kernels/quant/rdna4_quantize_int8_tensorwise.py
Bug: A caller-supplied scale was replaced by its absolute value, so a negative scale no longer flipped the codes.
Fix: inv is the reciprocal of the signed scale. The magnitude is still clamped at 1e-30.
Notes: scale=-0.5 matches round(x / -0.5). Abs-max quant is unchanged.

File: kernels/quant/rdna4_stoch_fp8.py
Bug: Stochastic rounding pre-rounded through fp16.
Fix: The value stays f32 (fx.Float32(raw)).
Notes: test_stoch_fp8_uses_f32_not_fp16 passed. The cast still stores no scale.

File: kernels/quant/rdna4_int8_convrot.py
Bug: The int8 Hadamard quant stored only the logical K and dropped the rest of the orthogonal group.
Fix: The kernel loads logical_k columns 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_kernel passed. 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.py
Bug: 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_bounds is 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.py
Bug: 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: --all exports 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.py
Bug: 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_M and the scaled FP8 tile pick stay in their own hosts.

File: tests/kernels/oracles.py
Bug: 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.py
Bug: 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.py
Bug: swiglu_chunk stored packed row-major from data_ptr() into out, including when out was a non-contiguous slice.
Fix: A non-contiguous out is written through a contiguous temporary and copied back on the same stream.
Notes: buf[:, :H] matches silu(gate) * up. A contiguous out is still launched directly.

Tests

On the kernel commit, scripts/run_tests.sh was 3831 passed, 2074 skipped, 33 deselected, 1 failed. The failure is tests/unit/test_max_blocks_per_cu.py: the installed build-fly package does not have CompiledFunction.max_blocks_per_cu, which this tree's source does. FileCheck passed, including wmma_gfx120x.mlir and swmmac_gfx120x.mlir. After the arch check, routing guards, public entries, scaled FP8, and RoPE passed (26 tests). 7d961b1b keeps that behavior. 16f2607b passed the routing guards, the interface route, a dense causal cross launch, and test_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.py passed (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 with gfx120, 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.

@dimitri91209
dimitri91209 force-pushed the gfx120x-overhaul-ops-fa-etc branch from b4f7d0a to f9261af Compare October 1, 2026 17:29
@dimitri91209
dimitri91209 force-pushed the gfx120x-overhaul-ops-fa-etc branch from 92d7a12 to fba0948 Compare October 2, 2026 02:47
@dimitri91209
dimitri91209 marked this pull request as ready for review October 2, 2026 02:50
@dimitri91209
dimitri91209 marked this pull request as draft October 3, 2026 02:30
@dimitri91209
dimitri91209 force-pushed the gfx120x-overhaul-ops-fa-etc branch 4 times, most recently from 1320e7c to 13a60a5 Compare October 3, 2026 16:00
@dimitri91209 dimitri91209 changed the title [Kernel][FA][AOT][Feature][Dialect][DSL][ROCDL][Perf][Doc][Test] Add … [Kernel][Feature][Dialect][DSL][Perf][Doc][Test] Add gfx120x RDNA4 wave32 ops Oct 3, 2026
@dimitri91209
dimitri91209 force-pushed the gfx120x-overhaul-ops-fa-etc branch 8 times, most recently from 59219ef to 5f22e04 Compare October 7, 2026 02:20
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
dimitri91209 force-pushed the gfx120x-overhaul-ops-fa-etc branch from 5481452 to d9fc04d Compare October 7, 2026 06:28
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
dimitri91209 force-pushed the gfx120x-overhaul-ops-fa-etc branch from a20058c to 86e46e6 Compare October 7, 2026 06:52
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
dimitri91209 force-pushed the gfx120x-overhaul-ops-fa-etc branch from 86e46e6 to 503565b Compare October 7, 2026 07:05
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
dimitri91209 force-pushed the gfx120x-overhaul-ops-fa-etc branch from 503565b to 9738b84 Compare October 7, 2026 07:20
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
dimitri91209 force-pushed the gfx120x-overhaul-ops-fa-etc branch from 9738b84 to ec5b015 Compare October 7, 2026 07:26
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
dimitri91209 force-pushed the gfx120x-overhaul-ops-fa-etc branch 5 times, most recently from 337786d to c582d71 Compare October 10, 2026 17:33
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
dimitri91209 force-pushed the gfx120x-overhaul-ops-fa-etc branch from 2bad539 to 578e37a Compare October 11, 2026 06:37
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>
@dimitri91209

Copy link
Copy Markdown
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

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants