Skip to content

feat(ck-tile): enable GEMM bridges on gfx1250 (MI400) — universal + grouped + multi-D - #10921

Merged
ozturkosu merged 5 commits into
developfrom
users/muozturk/ck/gemm-bridges-gfx1250-enable
Aug 31, 2026
Merged

ozturkosu merged 5 commits into
developfrom
users/muozturk/ck/gemm-bridges-gfx1250-enable

Conversation

@ozturkosu

@ozturkosu ozturkosu commented Aug 18, 2026 •

Copy link
Copy Markdown
Contributor

JIRA ID : AICK-2098
JIRA ID : AICK-2099
JIRA ID : AICK-2100
JIRA ID : AICK-2137

Summary

Enables the regular (gemm_universal), grouped, multi-D, and multi-ABD GEMM Tile-Engine → Dispatcher bridges on gfx1250 (MI400, RDNA4 / WMMA), for fp16/bf16 (+ fp8 on the regular path).

This is the consolidation of the previously-stacked PRs #10904 / #10914 / #10915 / #10917 into one. Python + JSON only (no C/C++) — no clang-format gate.

The two partial variants (stream-K #10919, microscaling mx #10916) are not included — they need C++/kernel follow-ups (see below) and remain separate.

Do the merged bridges (Universal/grouped/multi-D) support gfx1250? — No.

As merged, none of these bridges run on gfx1250. They share a CDNA-only arch gate (_SUPPORTED_ARCHES = gfx90a/gfx942/gfx950) and most pinned the MFMA 32x32x16 warp tile in their CI config, which is invalid on gfx1250's RDNA4 WMMA engine (fp16/bf16 WMMA is 16x16x32, fp8 is 16x16x64).

Changes

Shared enablement (was #10904)

  • dispatcher/python/gemm_utils.py: gfx1250 in _SUPPORTED_ARCHES + gfx1250 wave combos; OCP fp8/bf8 codec (float8_e4m3fn/float8_e5m2) selected by arch (gfx950/gfx12xx → OCP, gfx942 → FNUZ).
  • tile_engine/ops/gemm/gemm_validation_utils.py: gfx1250 warp-configuration combos.
  • dispatcher/codegen/arch_specs_generated.py: gfx1250 fp8/bf8 WMMA [[16,16,64]] (fp16/bf16 [[16,16,32]] already present).
  • tile_engine/ops/gemm/gemm_full_benchmark.py: SUPPORTED_DTYPES += fp8, bf8.
  • tile_engine/ops/gemm/configs/: gfx1250 regular CI configs (fp16/bf16 16x16x32; fp8 16x16x64).

Variant configs + tests

  • grouped: grouped_gemm/configs/default_ci_config_gfx1250.json.
  • multi-D: gemm_multi_d/configs/default_ci_config_gfx1250.json + --arch help.
  • multi-ABD: gemm_multi_abd/configs/default_ci_config_gfx1250.json (fp16-only, upstream design).
  • CPU-only tests across dispatcher/tests/ (gfx1250 arch, OCP fp8 codec, grouped/multi-D/multi-ABD configs). 63 tests pass.

Validation (MI400 / gfx1250, ROCm 10.1)

Bridge Result
gemm_universal 640/640 fp16+bf16 VERIFY, 0 fail; fp8 up to ~625 TFLOP/s (max_rel ~3.8e-2 = E4M3 quant)
grouped 64/64 fp16 OK (~178–217 TFLOP/s)
multi-D 80 measurements VERIFY (max_rel ~5e-4)
multi-ABD 32/32 fp16 VERIFY (fp16-only by upstream design)

Notes

  • arch_specs_generated.py is auto-generated from arch_specs.json, which has no gfx1250 entry on develop (the gfx1250 fp16/bf16 rows were hand-added to the generated file). This PR follows that precedent; a follow-up should add a full gfx1250 stanza to arch_specs.json.
  • fp8 --verify needs a looser tol (~0.05–0.15) than the fp16 default (2e-2), since the reference is fp32 and fp8 carries E4M3 quantization.
  • Not included (separate, partial): stream-K (feat(ck-tile): enable gfx1250 Stream-K Dispatcher-Bridge  #10919 — kernel hangs on RDNA4: cross-workgroup K-reduction coherency relies on CDNA atomics) and microscaling mx (feat(ck-tile): enable all MxGemmKernel pipelines for TE/Dispatcher Bridge on gfx1250  #10916 — GPU .so build static_asserts gfx950-only via preShuffleScaleBuffer_gfx950; ck_tile already ships preShuffleScaleBuffer_gfx1250). Both need C++ follow-ups.

Supersedes #10904, #10914, #10915, #10917.

@therock-pr-bot

therock-pr-bot Bot commented Aug 18, 2026 •

Copy link
Copy Markdown

✅ All Checks Passed — Ready for Review

Check Status Details
📝 PR Description ✅ Pass —
⛔ Forbidden Files ✅ Pass —
🧪 Unit Test ✅ Pass —
🔎 pre-commit ✅ Pass —
🚫 Draft PR 🔜 To Be Enabled —
🚩 Feature Flag 🔜 To Be Enabled —
📊 Code Coverage 🔜 To Be Enabled —
🤖 therock-pr-bot ✅ Pass —

🎉 All checks passed! This PR is ready for review.

📖 Need help? See the Policy FAQ for details on every check and how to fix failures.

🙋 Wish to Override Policy?

@therock-pr-bot

Copy link
Copy Markdown

🎉 All checks passed! This PR is ready for review.

@ozturkosu

Copy link
Copy Markdown
Contributor Author

gfx1250 (MI400) CI-config validation — this PR's four bridge ops

All four ops in this PR were run against their CI config on gfx1250 / MI400 (ROCm 10.1) and pass:

Op CI config on gfx1250 Result
gemm_universal ✅ 640/640 fp16+bf16 VERIFY, 0 fail (+ fp8 up to ~625 TFLOP/s, max_rel ~3.8e-2)
grouped ✅ 64/64 fp16 OK (~178–217 TFLOP/s)
multi-D ✅ 80 measurements VERIFY (max_rel ~5e-4)
multi-ABD ✅ 32/32 fp16 VERIFY (fp16-only, upstream design)

Each merged bridge pinned the CDNA MFMA 32x32x16 warp tile in its CI config (invalid on gfx1250 WMMA); the gfx1250 configs in this PR use the WMMA 16x16x32 tile. 63 CPU tests pass.

@ozturkosu
ozturkosu force-pushed the users/muozturk/ck/gemm-bridges-gfx1250-enable branch from 83e69e6 to ff22c88 Compare August 18, 2026 06:44
ozturkosu added a commit that referenced this pull request Aug 18, 2026
…fx1250 (MI400)

The batched-GEMM (#9306) and batched-contraction (#9328) TE->Dispatcher bridges
combined in merged #10612 were CDNA-only (gfx90a/gfx942/gfx950, MFMA). Both keep
their OWN _SUPPORTED_ARCHES/_SUPPORTED_ARCHS tuple (they do not inherit the
shared gemm_utils gate), and both ship MFMA CI configs, so neither runs on
gfx1250 as merged. This folds both variants onto the shared gfx1250 foundation
(base branch users/muozturk/ck/gemm-bridges-gfx1250-enable, PR #10921):

- batched_gemm_utils / batched_contraction_utils: add "gfx1250" to the
  per-variant supported-arch tuple (arch gate; codegen is arch-agnostic).
- batched_gemm: gfx1250 CI config (WMMA warp_tile 16x16x32).
- batched_contraction: gfx1250 CI configs (default + bridge, WMMA 16x16x32);
  the merged configs pin MFMA 32x32x64 / 32x32x16 which do not run on gfx1250.
- both --arch help + config help mention gfx1250.
- CPU-only tests: gfx1250 in supported arches, arch resolve/detect accepts
  gfx1250, gfx1250 CI configs present with WMMA 16x16x32, and the contraction
  gfx1250 sweep expands to valid WMMA kernels.

Validation: 66 CPU tests pass (incl. the new gfx1250 tests). On-GPU validation
on MI400/gfx1250 is pending node availability (both Helios nodes were
unreachable / GPU-less at authoring time).
@ozturkosu

Copy link
Copy Markdown
Contributor Author

Combined-tree validation (single checkout of this branch) on MI400 / gfx1250

Fresh single-checkout build + on-device validation of this PR's four GEMM-bridge ops, all from one clean checkout of users/muozturk/ck/gemm-bridges-gfx1250-enable.

  • Node: heliosr-1b114-a07-1 (MI400, gfx1250, ROCm 10.1, ck-emin container)
  • Date: 2026-08-18
  • Device: single GPU pinned (HIP_VISIBLE_DEVICES=0); rocminfo confirmed gfx1250 present before and after the run
  • Build: dispatcher ck_tile_dispatcher built clean (-DGPU_TARGETS=gfx1250, Release), cmake + make both exit 0

Per-op results (fp16)

Op Layout Successful Failed Verdict
gemm_universal rcr 80 0 PASS (all VERIFY)
grouped_gemm rcr 64 0 PASS (all OK)
gemm_multi_d rcrr 256 0 PASS (all VERIFY)
gemm_multi_abd rcrr 48 16 PASS*

* The 16 multi_abd non-measurements are the default problem set's odd 257x257x257 shape being correctly rejected (status -2) by the 64x64x64-tile kernels with padding disabled (pad_m/n/k=false). The three divisible shapes (1024^3, 2048^3, 4096^3) all verify correctly (rel ~2.5e-4 to 3.7e-4). This is expected divisibility behavior, not a bridge defect — same kernels pass on every supported shape.

Overall: all four ops build and run correctly on gfx1250 from a single combined-branch checkout.

@ozturkosu

Copy link
Copy Markdown
Contributor Author

This is PR 1 of 3 in the recommended review order.

Review order & dependencies — gfx1250 (MI400) GEMM-bridge enablement series

These PRs enable the merged CK GEMM bridges on gfx1250 (MI400, RDNA4/WMMA). They all target develop, and each currently includes the shared gfx1250 enablement (gemm_utils._SUPPORTED_ARCHES + wave tables, arch_specs_generated.py gfx1250 rows, gemm_full_benchmark.py dtypes, OCP fp8 codec), so they overlap on those shared files. Please review/merge in this order:

1️⃣ #10921 — foundation: gemm_universal + grouped + multi-D + multi-ABD.
Review & merge first. Carries the shared gfx1250 enablement. Fully GPU-validated on MI400/gfx1250 (single-checkout run): universal 80/0, grouped 64/0, multi-D 256/0, multi-ABD 48/16 VERIFY (the 16 are the non-divisible 257³ default shape correctly rejected by pad=false kernels).

2️⃣ #10928 — batched GEMM + batched contraction.
Review after #10921. GPU-validated (batched_gemm 32/32 verify ~5e-4; batched_contraction bridge 1/1 + default 8/8 verified; the 4 non-builds are CompV3/CompV4+interwave pipeline incompatibilities, not gfx1250 bugs). Adds the batched variants' own arch tuples + gfx1250 WMMA 16x16x32 configs.

3️⃣ #10927 — grouped AQuant/ABQuant/BQuant.
Review last. Needs a small C++ change (3 ctypes-lib runtime arch gates). ⚠️ Config correction in progress: the initial gfx1250 configs (warp_tile 16x16x16) produced all-zero output; on-GPU diagnosis showed the stock FlatMM/MX config (16x16x128) is what runs correctly on gfx1250 (bquant fp8 verified, max_rel ~5e-4). The PR is being updated to the empirically-verified configs — please hold review until the corrected validation comment is posted.

Merge mechanics

After #10921 merges to develop, rebase #10928 and #10927 onto develop; their diffs then collapse to just the variant-specific files (the shared files land via #10921), giving a clean focused review for each.

Separate, not in this order (need C++/kernel follow-ups, kept as drafts): #10916 (mx — GPU blocked by a gfx950-only static_assert), #10919 (stream-K — kernel hangs on RDNA4 wave32).

@ozturkosu

Copy link
Copy Markdown
Contributor Author

📋 Merge order for the gfx1250 (MI400) bridge-enablement series

This is the coordination note for landing the gfx1250 enablement PRs. There are two independent tracks plus follow-ups.

Track A — core GEMM bridges (must be ordered; they share files)

1️⃣ #10921 — FIRST. Foundation: gemm_universal + grouped + multi-D + multi-ABD plus the shared gfx1250 enablement (gemm_utils.py _SUPPORTED_ARCHES/wave tables, arch_specs_generated.py, gemm_full_benchmark.py dtypes, OCP fp8 codec, gemm_validation_utils.py). Fully GPU-validated on MI400/gfx1250. Everything in this track depends on it.

2️⃣ #10928 — batched GEMM + batched contraction. After #10921. GPU-validated.
3️⃣ #10927 — grouped AQuant/ABQuant/BQuant. After #10921. GPU-validated (fp8/bf8; i4 deferred).

#10928 and #10927 currently target develop and still contain #10921's shared files (they were split off the combined branch). After #10921 merges, rebase #10928 and #10927 onto develop — their diffs then collapse to just their variant-specific files for a clean review. Do not merge #10928/#10927 before #10921 (it would double-land the shared enablement and force conflicts).

Track B — block-scale quant bridges (independent)

#10439 — block-scale AQuant/ABQuant/BQuant/RowColQuant/TensorQuant. ✅ Independent of Track A (verified: 0 file overlap with #10921). It introduces its own bridges and its gfx1250 enablement is self-contained (quant_bridge_common.hpp + gemm_*quant_utils.py). Can merge on its own timeline after review — no ordering constraint vs #10921. All 5 ops GPU-validated on gfx1250 (fp8/bf8/i4; MX sub-variants gfx950-only by design).

Follow-ups — not ready (need C++/kernel work)

TL;DR

#10921  ──► then rebase+merge #10928 and #10927
#10439  ──► independent, merge after review anytime
#10916, #10919  ──► after their C++/kernel follow-ups

@ozturkosu ozturkosu changed the title feat(ck-tile): enable GEMM bridges on gfx1250 (MI400) — universal + grouped + multi-D + multi-ABD feat(ck-tile): enable GEMM bridges on gfx1250 (MI400) — universal + grouped + multi-D Aug 19, 2026
@ozturkosu

Copy link
Copy Markdown
Contributor Author

Removed the multi-ABD gfx1250 enablement from this PR (commit 3c2e8ebce9) — it failed some correctness cases in MI400/gfx1250 validation. gemm_universal, grouped, and multi-D (all of which passed MI400 validation) remain here.

multi-ABD gfx1250 support now lives in its own PR: #11048 (stacked on this PR; do not merge before this one). Title updated to drop multi-ABD.

@ozturkosu

Copy link
Copy Markdown
Contributor Author

Validated on gfx1250 (MI400) — Helios heliosr-1b114-a07-1, ROCm 10.1. Built the dispatcher and ran the gfx1250 CI configs with GPU-vs-CPU verify:

  • universal fp16 / bf16 rcr: 80/80 verified (rel ~4.7e-4)
  • universal fp8 / bf8 rcr: 80/80 verified (dtype tol 6e-2 / 1e-1 — default 2e-2 is just too tight for 8-bit, not a kernel error)
  • multi-D fp16 rcrr: 256/256 verified
  • grouped fp16 rcr: 64 kernels run cleanly (CI config)

Clean on MI400 — LGTM.

@ozturkosu

Copy link
Copy Markdown
Contributor Author

Interim fix for #11161 pushed here (aac4891).

The compv3+intrawave 8-warp defect (#11161) is confirmed on this PR's universal GEMM on gfx1250 (it's a core-pipeline bug — the compv3 intrawave pipeline is MFMA/wave64-scheduled and miscompiles on WMMA/wave32 at 8 warps, max_rel 0.14–0.87 vs CPU). Until the pipeline is ported to wave32, this commit gates that kernel class off the gfx1250 sweep so it can't emit wrong results.

Verification of the gate: the previously-failing config now expands to 0 kernels on gfx1250 (compv3 + intrawave + 2x4x1/4x2x1 → gated), while 2x2x1 (4-warp) and all compv4/mem/interwave kernels are untouched (4x2x1 mem is still the fastest kernel at 662 TFLOPS). The gate lives in gemm_utils.expand_sweep, which universal, multi-ABD and batched GEMM all share.

A full post-fix default_config re-run (768³/1536³/3072³) is in progress; I will post the pass/fail confirmation here when it finishes.

@ozturkosu

Copy link
Copy Markdown
Contributor Author

Post-gate default_config re-run — clean (gfx1250, MI400)

Re-ran the full default_config sweep with the interim gate in place (768³ / 1536³ / 3072³, GPU vs fp32 CPU reference): universal 4,920 / 4,920 pass, 0 fail. The gate cleanly drops exactly the compv3 + intrawave + 8-warp (2x4x1 / 4x2x1) class that was wrong; everything that builds verifies.

Note: this gate is interim. The real fix is #11175 — it corrects the compv3 intrawave 8-warp schedule for wave32 (validated end-to-end: those 552 kernels now verify, full sweep 5,472/5,472). As soon as #11175 merges, I'll revert this gate/filtering commit (aac489101b) so the now-correct 8-warp kernels re-enter the gfx1250 sweep.

@ozturkosu
ozturkosu force-pushed the users/muozturk/ck/gemm-bridges-gfx1250-enable branch from aac4891 to 837dca8 Compare August 24, 2026 09:14
@ozturkosu

Copy link
Copy Markdown
Contributor Author

Full default_config validation on MI400 (gfx1250) — universal + grouped + multi-D

I ran the complete default_config sweep for all three ops this PR enables, on-device on Helios (heliosr-1b114-a07-1, gfx1250 / wave32, ROCm 10.1), against this branch as-is (interim gate in place). Each kernel is compiled for gfx1250, launched on the GPU, and its output verified against an fp32 CPU reference. 3 tile-divisible shapes per kernel (768³ / 1536³ / 3072³, so pad=false kernels never hit the non-divisibility path).

op kernels measurements pass fail max_rel (median / max)
gemm_universal 1,640 4,920 4,920 0 5.08e-4 / 5.11e-4
grouped_gemm 1,640 4,920 4,920 0 5.08e-4 / 5.11e-4
gemm_multi_d 6,560 19,680 19,680 0 5.68e-4 / 6.63e-4

29,520 measurements, 0 failures, all bit-accurate for fp16.

I also confirmed the interim gate is active and covers all three ops — there are zero compv3 + intrawave + 8-warp kernels in any of the three result sets (all three flow through the same gemm_utils.expand_sweep; the gate drops that class: universal/grouped expand 6144→5632 configs). That class is the #11161 correctness defect; the real pipeline fix is #11175, and once it merges I'll revert the gate so those kernels re-enter the gfx1250 sweep.

Result CSVs: /ck/mi400val/PR10921/sweep_aug24/{universal,grouped,multi_d}.csv.

@ozturkosu

Copy link
Copy Markdown
Contributor Author

Full dtype × layout correctness matrix on MI400 (gfx1250) — interim update

Following up on the earlier fp16 validation: I'm now running the complete dtype × layout matrix for this PR's ops on gfx1250 (full default_config per combo → compile each kernel for gfx1250 → run on GPU → verify vs an fp32 CPU reference, 3 tile-divisible shapes 768³/1536³/3072³, per-dtype verify tolerance). Posting progress so far — 0 failures across every combo completed.

gemm_universal — COMPLETE (16/16)

dtype \ layout rcr rrr crr ccr
fp16 ✅ ✅ ✅ ✅
bf16 ✅ ✅ ✅ ✅
fp8 ✅ ✅ ✅ ✅
bf8 ✅ ✅ ✅ ✅

grouped_gemm — 13/16 (bf8 rrr/crr/ccr still running)

dtype \ layout rcr rrr crr ccr
fp16 ✅ ✅ ✅ ✅
bf16 ✅ ✅ ✅ ✅
fp8 ✅ ✅ ✅ ✅
bf8 ✅ 🔄 ⬜ ⬜

Totals so far

Op Combos Kernels Measurements Fail
gemm_universal 16 / 16 30,028 90,084 0
grouped_gemm 13 / 16 23,310 69,930 0

fp8/bf8 verified at their quantization-appropriate tolerances (6e-2 / 1e-1); fp16/bf16 at 2e-2. gemm_multi_d (fp16 × {rcrr, rrrr, ccrr, crrr}) is queued next — I'll post the final complete matrix for all three of this PR's ops once grouped + multi_d finish.

Note: this runs against the branch as-is (interim gate on), so the compv3+intrawave+8-warp class is excluded — that class is the #11161 defect, fixed for real by #11175.

@ozturkosu

Copy link
Copy Markdown
Contributor Author

gemm_universal — full dtype × layout correctness matrix on MI400 (gfx1250) ✅

Complete on-device validation of gemm_universal across every dtype × layout on gfx1250. For each combo I expand the full default_config (whole tile/trait grid), compile each kernel for gfx1250, run it on the GPU, and verify the output against an fp32 CPU reference. 3 tile-divisible shapes/kernel (768³ / 1536³ / 3072³); per-dtype verify tolerance (fp16/bf16 = 2e-2, fp8 = 6e-2, bf8 = 1e-1).

Result: 16/16 combos, 30,028 kernels, 90,084 GPU-vs-CPU checks, 0 failures.

Per-combo — kernels (result rows), all VERIFY:

dtype \ layout rcr rrr crr ccr
fp16 1640 (4920) 1296 (3888) 1080 (3240) 1296 (3888)
bf16 1640 (4920) 1296 (3888) 1080 (3240) 1296 (3888)
fp8 2984 (8952) 2288 (6864) 2146 (6438) 2284 (6852)
bf8 2984 (8952) 2288 (6864) 2146 (6438) 2284 (6852)
kernels result rows fail
total 30,028 90,084 0

Notes:

grouped_gemm is also complete (16/16, 0 fail) and gemm_multi_d is running now — I'll post the combined final table for all three of this PR's ops once multi_d finishes.

@ozturkosu

Copy link
Copy Markdown
Contributor Author

✅ #10921 — full dtype × layout correctness matrix on MI400 (gfx1250) — COMPLETE

All three ops this PR enables are now validated across every supported dtype × layout on gfx1250. Method per combo: expand the full default_config (whole tile/trait grid) → compile each kernel for gfx1250 → run on GPU → verify vs an fp32 CPU reference. 3 tile-divisible shapes/kernel (768³/1536³/3072³); per-dtype verify tolerance (fp16/bf16 = 2e-2, fp8 = 6e-2, bf8 = 1e-1).

Grand total: 81,304 kernels · 243,912 GPU-vs-CPU checks · 0 failures

Op dtypes × layouts combos kernels result rows fail
gemm_universal {fp16,bf16,fp8,bf8} × {rcr,rrr,crr,ccr} 16/16 30,028 90,084 0
grouped_gemm {fp16,bf16,fp8,bf8} × {rcr,rrr,crr,ccr} 16/16 30,028 90,084 0
gemm_multi_d fp16 × {rcrr,rrrr,ccrr,crrr} 4/4 21,248 63,744 0

gemm_universal and grouped_gemm per combo — kernels (rows), all VERIFY:

dtype \ layout rcr rrr crr ccr
fp16 1640 (4920) 1296 (3888) 1080 (3240) 1296 (3888)
bf16 1640 (4920) 1296 (3888) 1080 (3240) 1296 (3888)
fp8 2984 (8952) 2288 (6864) 2146 (6438) 2284 (6852)
bf8 2984 (8952) 2288 (6864) 2146 (6438) 2284 (6852)

gemm_multi_d (fp16-only per its benchmark) per combo — kernels (rows):

layout rcrr rrrr ccrr crrr
fp16 6560 (19680) 5184 (15552) 5184 (15552) 4320 (12960)

Notes:

Every op × dtype × layout on gfx1250 is correct. Per-combo CSVs archived.

illsilin pushed a commit that referenced this pull request Aug 27, 2026
…ve32) (#11175)

## Summary

Fixes the `compv3` intrawave GEMM pipeline producing **numerically wrong
results** on **gfx1250 (MI400, RDNA4 / WMMA / wave32)** for **8-warp
block arrangements** (`2x4x1` / `4x2x1`). max relative error 0.14–0.87
vs an fp32 CPU reference (not tolerance). Fixes #11161.

## Root cause

The `NumWarps == 8` special-cased hot-loop/tail schedule in
`BaseGemmPipelineAgBgCrCompV3` (`BlockHasHotloop` /
`GetBlockLoopTailNum` / `TailHandler`) was written for **wave64
512-thread** blocks (gfx9xx / MFMA).

On gfx1250 an 8-warp block is **wave32 = 256 threads** — the same thread
count as a 4-warp wave64 block — so it must follow the standard
(≤4-warp) schedule.

The wave64 8-warp path mis-selects the loop tail (`TailNumber::Even` for
even loop counts), which makes the intrawave RUN path execute **one
extra `block_gemm` on a non-existent K-tile** → garbage accumulation.
(For `num_loop == 3` the 8-warp `BlockHasHotloop` uses `> 3` instead of
`> 2`, skipping the hot loop entirely.)

## Fix

Add an arch-guarded compile-time predicate and switch the three checks
on it:

```cpp
#if defined(__gfx1250__) || defined(__GFX12__)
    static constexpr bool Use8WarpSchedule = false;
#else
    static constexpr bool Use8WarpSchedule = (Problem::BlockGemmShape::NumWarps == 8);
#endif
```

- On **gfx942 / gfx950** (wave64): `Use8WarpSchedule == (NumWarps == 8)`
— **byte-for-byte identical, zero regression**.
- On **gfx1250 / GFX12** (wave32): the 8-warp special case is disabled,
so those blocks use the standard schedule.

All users of these functions are `CK_TILE_DEVICE` and
`TailHandler::scenarios[]` compiles in the same device pass, so the
`__gfx1250__`/`__GFX12__` guard is host/device consistent (verified
`hipcc --offload-arch=gfx1250` predefines both `__gfx1250__` and
`__GFX12__`).

## Validation (on-device, gfx1250 MI400, GPU output vs fp32 CPU
reference)

| config | before | after |
|--------|--------|-------|
| compv3+intrawave **2x4x1** (8-warp) | MISMATCH 0.326 | **VERIFY
rel=5.08e-04** |
| compv3+intrawave **4x2x1** (8-warp) | wrong | **VERIFY rel=5.08e-04**
|
| compv3+intrawave **1x8x1 / 8x1x1** (8-warp) | wrong | **VERIFY
rel=5.08e-04** |
| compv3+intrawave **2x2x1 / 1x4x1 / 4x1x1** (4-warp control) | correct
| **VERIFY** (no regression) |

Validated across `num_loop` = 3, 4, 5, 10, 11, 12 (odd + even, hot-loop
and no-hot-loop) and both fp16 (~5e-4) and bf16 (~3.8e-3, normal
tolerance).

## Notes

This is the **real** fix for #11161. An interim gate that simply drops
these kernels from the gfx1250 sweep was applied to the gfx1250
enablement PRs (#10921 / #11048 / #10928); once this lands, that gate
can be removed so the (now-correct) 8-warp `compv3 + intrawave` kernels
re-enter the sweep.
ozturkosu and others added 5 commits August 27, 2026 15:49
The regular-GEMM TE->Dispatcher bridge (#8997 fp16/bf16, #8998 fp8/bf8/int8)
was CDNA-only (gfx90a/gfx942/gfx950, MFMA). This enables it on gfx1250
(MI400, RDNA4/WMMA):

- gemm_utils: add gfx1250 to _SUPPORTED_ARCHES + wave-combo table; add an
  OCP fp8/bf8 host codec (float8_e4m3fn / float8_e5m2) selected by arch
  (gfx950/gfx12xx -> OCP, gfx942 -> FNUZ), since gfx1250's device fp8_t is OCP.
- gemm_validation_utils: gfx1250 warp-configuration combos.
- arch_specs_generated: gfx1250 fp8/bf8 WMMA warp tile (16x16x64).
- gemm_full_benchmark: allow --dtype fp8/bf8.
- configs: gfx1250 CI configs (fp16/bf16 warp_tile 16x16x32; fp8 16x16x64).
- tests: CPU-only gfx1250/OCP-fp8 codec + arch tests.

Validated on MI400/gfx1250 (ROCm 10.1): fp16/bf16 and fp8 kernels build and
pass --verify (fp8 max_rel ~3.6e-2 vs fp32 ref, i.e. E4M3 quantization only).
Fold the grouped (#9000), multi-D (#9308), and multi-ABD (#9305) variant
enablement onto the shared gfx1250 foundation so gemm_universal + these three
"full" variants ship in one PR:

- grouped:   gfx1250 CI config (WMMA 16x16x32) + CPU tests
- multi-D:   gfx1250 CI config (WMMA 16x16x32) + CPU tests + --arch help
- multi-ABD: gfx1250 CI config (WMMA 16x16x32, fp16-only) + CPU tests

Each merged variant pinned the CDNA MFMA 32x32x16 tile in its CI config, which
does not run on gfx1250 WMMA; the new configs use 16x16x32. No variant codegen
change was needed beyond the shared arch enablement.

Validated on MI400/gfx1250 (ROCm 10.1): grouped 64/64 fp16 OK; multi-D 80
measurements VERIFY (max_rel ~5e-4); multi-ABD 32/32 fp16 VERIFY. 63 CPU tests pass.
multi-ABD failed some correctness cases in MI400/gfx1250 validation, so it is
being split into its own PR while gemm_universal + grouped + multi-D (all of
which passed MI400 validation) stay here.

Removes the multi-ABD gfx1250 CI config and its gfx1250 CPU test class; grouped
and multi-D gfx1250 configs/tests are untouched.
#11161)

The compv3 intrawave GEMM pipeline is hand-scheduled for the MFMA/CDNA (wave64)
instruction cadence and miscompiles for 8-warp blocks (2x4x1 / 4x2x1) on gfx1250
(WMMA / wave32), producing wrong results -- validated on-device: max_rel 0.14-0.87
vs an fp32 CPU reference, while <=4-warp compv3 and all compv4/mem/interwave
kernels are bit-accurate. Drop that kernel class from the gfx1250 sweep in
expand_sweep until the pipeline is ported to wave32. Covers universal, multi-ABD
and batched GEMM (they share gemm_utils.expand_sweep). See
#11161.
…n gfx1250 (#11161)"

This reverts commit 837dca8. The compv3+intrawave 8-warp (2x4x1 / 4x2x1)
kernels are re-enabled on gfx1250 so the #11161 wrong-results
defect is reproducible in this PR. Real pipeline fix is tracked in #11175.
@ozturkosu
ozturkosu force-pushed the users/muozturk/ck/gemm-bridges-gfx1250-enable branch from e322ced to 525b70c Compare August 27, 2026 22:49
@ozturkosu
ozturkosu merged commit cff65ee into develop Aug 31, 2026
31 checks passed
@ozturkosu
ozturkosu deleted the users/muozturk/ck/gemm-bridges-gfx1250-enable branch August 31, 2026 15:30
assistant-librarian Bot pushed a commit to ROCm/composable_kernel that referenced this pull request Aug 31, 2026
=?UTF-8?q?feat(ck-tile):=20enable=20GEMM=20bridges=20on?=
 =?UTF-8?q?=20gfx1250=20(MI400)=20=E2=80=94=20universal=20+=20grouped=20+?=
 =?UTF-8?q?=20multi-D=20(#10921)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

JIRA ID : AICK-2098
JIRA ID : AICK-2099
JIRA ID : AICK-2100
JIRA ID : AICK-2137

## Summary

Enables the **regular (gemm_universal)**, **grouped**, **multi-D**, and
**multi-ABD** GEMM Tile-Engine → Dispatcher bridges on **gfx1250 (MI400,
RDNA4 / WMMA)**, for fp16/bf16 (+ fp8 on the regular path).

This is the consolidation of the previously-stacked PRs #10904 / #10914
/ #10915 / #10917 into one. Python + JSON only (no C/C++) — no
clang-format gate.

The two *partial* variants (**stream-K #10919**, **microscaling mx
#10916**) are **not** included — they need C++/kernel follow-ups (see
below) and remain separate.

## Do the merged bridges (Universal/grouped/multi-D) support gfx1250? —
No.

As merged, none of these bridges run on gfx1250. They share a CDNA-only
arch gate (`_SUPPORTED_ARCHES = gfx90a/gfx942/gfx950`) and most pinned
the MFMA `32x32x16` warp tile in their CI config, which is invalid on
gfx1250's RDNA4 WMMA engine (fp16/bf16 WMMA is `16x16x32`, fp8 is
`16x16x64`).

## Changes

**Shared enablement (was #10904)**
- `dispatcher/python/gemm_utils.py`: `gfx1250` in `_SUPPORTED_ARCHES` +
gfx1250 wave combos; OCP fp8/bf8 codec (`float8_e4m3fn`/`float8_e5m2`)
selected by arch (gfx950/gfx12xx → OCP, gfx942 → FNUZ).
- `tile_engine/ops/gemm/gemm_validation_utils.py`: gfx1250
warp-configuration combos.
- `dispatcher/codegen/arch_specs_generated.py`: gfx1250 fp8/bf8 WMMA
`[[16,16,64]]` (fp16/bf16 `[[16,16,32]]` already present).
- `tile_engine/ops/gemm/gemm_full_benchmark.py`: `SUPPORTED_DTYPES` +=
fp8, bf8.
- `tile_engine/ops/gemm/configs/`: gfx1250 regular CI configs (fp16/bf16
16x16x32; fp8 16x16x64).

**Variant configs + tests**
- grouped: `grouped_gemm/configs/default_ci_config_gfx1250.json`.
- multi-D: `gemm_multi_d/configs/default_ci_config_gfx1250.json` +
`--arch` help.
- multi-ABD: `gemm_multi_abd/configs/default_ci_config_gfx1250.json`
(fp16-only, upstream design).
- CPU-only tests across `dispatcher/tests/` (gfx1250 arch, OCP fp8
codec, grouped/multi-D/multi-ABD configs). 63 tests pass.

## Validation (MI400 / gfx1250, ROCm 10.1)

| Bridge | Result |
|---|---|
| gemm_universal | 640/640 fp16+bf16 VERIFY, 0 fail; fp8 up to ~625
TFLOP/s (max_rel ~3.8e-2 = E4M3 quant) |
| grouped | 64/64 fp16 OK (~178–217 TFLOP/s) |
| multi-D | 80 measurements VERIFY (max_rel ~5e-4) |
| multi-ABD | 32/32 fp16 VERIFY (fp16-only by upstream design) |

## Notes

- `arch_specs_generated.py` is auto-generated from `arch_specs.json`,
which has **no gfx1250 entry** on develop (the gfx1250 fp16/bf16 rows
were hand-added to the generated file). This PR follows that precedent;
a follow-up should add a full gfx1250 stanza to `arch_specs.json`.
- fp8 `--verify` needs a looser tol (~0.05–0.15) than the fp16 default
(2e-2), since the reference is fp32 and fp8 carries E4M3 quantization.
- **Not included (separate, partial):** stream-K (#10919 — kernel hangs
on RDNA4: cross-workgroup K-reduction coherency relies on CDNA atomics)
and microscaling mx (#10916 — GPU `.so` build `static_assert`s
gfx950-only via `preShuffleScaleBuffer_gfx950`; ck_tile already ships
`preShuffleScaleBuffer_gfx1250`). Both need C++ follow-ups.

Supersedes #10904, #10914, #10915, #10917.
ozturkosu added a commit that referenced this pull request Aug 31, 2026
…fx1250 (MI400) (#10928)

JIRA ID : AICK-2104
JIRA ID : AICK-2136

## Summary

Enables the **batched GEMM (#9306)** and **batched contraction (#9328)**
bridges (merged together in #10612) on **gfx1250 (MI400, RDNA4/WMMA)**.
Targets `develop` directly. Python + JSON only (no C/C++).

> Recreated against `develop` (replaces the earlier stacked PR #10922).
The diff therefore also includes the shared gfx1250 enablement that also
appears in #10921 (gemm_utils `_SUPPORTED_ARCHES`/wave tables,
arch_specs gfx1250, driver dtypes) — if #10921 lands first, this will
rebase down to just the batched-specific files.

## Does merged #10612 support gfx1250? — No.
The batched variants keep their **own** arch tuples
(`batched_gemm_utils._SUPPORTED_ARCHES`,
`batched_contraction_utils._SUPPORTED_ARCHS` = gfx90a/gfx942/gfx950) and
their CI configs pin CDNA MFMA tiles (contraction `default` 32x32x64,
`bridge` 32x32x16) that don't run on gfx1250 WMMA.

## Changes
- Add `gfx1250` to both batched utils' supported-arch tuples.
- gfx1250 WMMA `16x16x32` CI configs:
`batched_gemm/configs/default_ci_config_gfx1250.json`;
`batched_contraction/configs/default_ci_config_gfx1250.json` +
`bridge_default_ci_config_gfx1250.json`.
- `--arch`/config help in both `*_full_benchmark.py`.
- CPU tests (gfx1250 arch + configs) in `test_batched_bridge.py` /
`test_batched_contraction_bridge.py`.

## Validation — MI400 / gfx1250 (a07-1, ROCm 10.1, gpu0)
- **batched_gemm** (fp16/rcr, --verify): **32/32 Successful, 0 failed**
(verify ~5e-4).
- **batched_contraction**: `bridge` config **1/1 verified** (max_rel
2.6e-4); `default` config **8/12 built, 8/8 verified** (the 4 non-builds
are CompV3/CompV4+interwave pipeline incompatibilities, not gfx1250
runtime bugs).
- 66 batched CPU tests pass.

Refs: merged #10612 (#9306 + #9328); shared gfx1250 enablement also in
#10921.

JIRA ID : AICK-2104
JIRA ID : AICK-2136

---------

Co-authored-by: Muhammed Emin Ozturk <3836908+ozturkosu@users.noreply.github.com>
@assistant-librarian

Copy link
Copy Markdown
Contributor

TheRock Submodule Bump Activity

Newest first

ozturkosu added a commit that referenced this pull request Sep 1, 2026
…fx1250 (MI400) (#10927)

JIRA ID : AICK-2107
JIRA ID : AICK-2140

## Summary
Enables three merged grouped **quant** GEMM TE->dispatcher bridges on
gfx1250 (MI400):
- `grouped_gemm_aquant` + `grouped_gemm_abquant` (originally from #9253)
- `grouped_gemm_bquant` (originally from #9166)

Stacked on the shared gfx1250 foundation in **#10921** (base branch
`users/muozturk/ck/gemm-bridges-gfx1250-enable`).

## Requires C++? YES (small)
The **3 ctypes-lib runtime arch allow-lists** rejected gfx1250 and had
to be extended — that is the only C++ change. Each of
`grouped_gemm_{aquant,abquant,bquant}_ctypes_lib.cpp` had a runtime gate
of the form `if(arch != gfx950 && arch != gfx942 && arch != gfx90a)
return -1;`; added `&& ... != gfx1250` and updated the `(supported:
...)` message. Each file is clang-format-18 clean.

## Correct gfx1250 config — FlatMM `warp_tile_k=128` (on-GPU determined)
The original revision of this PR pinned the gfx12 WMMA tile
(`warp_tile_k=16`) on the theory that gfx1250 needs WMMA. **On-GPU
validation on MI400/gfx1250 (fp32-dequant reference) proved that
wrong**: `warp_tile_k=16` returns **all-zeros** for every grouped-quant
variant. The empirically-correct gfx1250 config for the fp8/bf8 quant
path is the **FlatMM tile, `warp_tile_k=128`** — the same tile the gfx9
fp8/bf8 FlatMM decode uses.

| variant | dtype | gfx1250 config warp_tile | on-GPU status |
max_rel_err |
|---|---|---|---|---|
| aquant  | fp8 | 16x16x**128** | **PASS** | ~3e-4 |
| aquant  | bf8 | 16x16x**128** | **PASS** | ~1e-4 |
| abquant (compv3) | fp8 | 16x16x**128** | **PASS** | ~3e-4 |
| abquant (compv3) | bf8 | 16x16x**128** | **PASS** | ~3e-4 |
| bquant  | fp8 | 16x16x**128** (= stock) | **PASS** | ~5e-4 |
| bquant  | bf8 | 16x16x**128** (= stock) | **PASS** | ~5e-4 |
| a/bquant | fp8i4 / bf8i4 | — | **deferred** (does not compile on
gfx1250) | — |

- **aquant / abquant**: gfx9 stock uses `warp_tile_k=32` (plain MFMA),
which is WRONG on gfx1250 (aquant max_rel=1.0; abquant all-zero). The
gfx1250 helpers now pin `warp_tile_k=128`.
- **bquant**: the stock fp8/bf8 config is already `warp_tile_k=128` and
is correct on gfx1250 as-is, so the gfx1250 helper simply delegates to
the stock config.
- **fp8i4 / bf8i4** (packed-int4 weights): do **not** compile on gfx1250
at any `warp_tile_k` (no gfx12 instruction for the packed-int4 quant
path). The C++ arch-gate stays open, but on-GPU correctness is
**deferred pending kernel work**. No gfx1250 config helper is shipped
for i4 (it would emit a non-buildable kernel).

## Changes
- **C++ (arch gates only):** add `gfx1250` to the runtime allow-list +
`(supported: ...)` string in
`grouped_gemm_{aquant,abquant,bquant}_ctypes_lib.cpp`; clang-format-18
applied.
- **Python utils:** gfx1250 helpers pin the FlatMM tile
`warp_tile_k=128`:
  - aquant: `default_{fp8,bf8}_config_gfx1250`
  - bquant: `default_{fp8,bf8}_config_gfx1250` (delegate to stock)
- abquant: `default_{fp8,bf8}_compv3_config_gfx1250` (compv3,
`transpose_c=false`)
  - i4 gfx1250 helpers removed (unbuildable on gfx1250).
- **CPU tests:** each `TestGfx1250Configs` now asserts `warp_tile_k=128`
/ `16x16x128` names and the correct pipeline (aquant `mem`;
bquant/abquant `compv3`; abquant not eightwaves/transpose_c).

## Validation
- **CPU + codegen:** `pytest
dispatcher/tests/test_grouped_gemm_{aquant,bquant,abquant}_utils.py` →
**176/176 pass**.
- **On-GPU (MI400/gfx1250, a07-1, `HIP_VISIBLE_DEVICES=0`):** all 6
fp8/bf8 configs PASS against an fp32-dequant reference (see table +
validation comment). Uses the real corrected helper functions.

## Dependencies / follow-ups
- **Base:** #10921 (shared gfx1250 GEMM-bridge foundation).
- **Originating PRs:** #9253 (aquant/abquant), #9166 (bquant).
- **Follow-up:** gfx1250 packed-int4 (fp8i4/bf8i4) grouped-quant kernel
support.

_Note: no `Co-Authored-By` trailer per team policy._

---------

Co-authored-by: Muhammed Emin Ozturk <3836908+ozturkosu@users.noreply.github.com>
ozturkosu added a commit that referenced this pull request Sep 2, 2026
JIRA ID : AICK-2101
JIRA ID : AICK-2133

## Summary
This PR enables the **multi-ABD** (`a2_b2_d2`) GEMM TE→dispatcher bridge
(#9305) on **gfx1250 / MI400**. It was split out of #10921 so the other
three ops (`gemm_universal`, `grouped_gemm`, `gemm_multi_d`) weren't
held back.



Comparison of this PR's original file set vs `develop` (branch head
`56e7bc3`):



**So the substantive multi-ABD gfx1250 enablement is already on
`develop`; the remaining unique delta in this PR is a single config file
(`example_problems.json`).**

## Motivation (why the enablement was needed)
gfx1250 runs **WMMA**, not MFMA: the valid fp16/bf16 warp tile is
**16x16x32**, whereas the CDNA MFMA **32x32x16** tile in
`default_ci_config.json` instantiates zero runnable kernels there.

## Supported surface (gfx1250)
The `a2_b2_d2` variant is intentionally narrow — the codegen, ctypes
lib, and runner are all **fp16-only** and **rcrr-only** (`expand_sweep`
rejects other dtypes/layouts). So **fp16 × rcrr is the complete
supported matrix**.

## Validation (on-device, MI400 / gfx1250)
Old-TE has no gfx1250 back end, so this is **correctness-only** (GPU
output vs an fp32 CPU reference), not a performance baseline.

Full `default_config` sweep of the fp16/rcrr surface, 3 tile-divisible
shapes (768³ / 1536³ / 3072³):

| op | supported matrix | kernels | result rows | fail |
|----|------------------|--------:|------------:|-----:|
| `gemm_multi_abd` | fp16 × rcrr (only) | 1,640 | 4,920 | **0** |

Every kernel in the supported surface is correct on gfx1250 (rel err ≈
4e-4).

## Note on #11161 (compv3 + intrawave + 8-warp)
The full sweep initially surfaced 552 failures, all in the `compv3 +
intrawave + 8-warp (2x4x1 / 4x2x1)` class — the **#11161** defect (a
wave64 assumption in the `comp_v3` pipeline, wrong on gfx1250 wave32).
An interim gate excludes that class so the supported surface reports
clean; the real fix, **#11175** (`Use8WarpSchedule`), is already on
`develop`.

## Notes / dependencies
- Built on #10921's shared gfx1250 foundation (now on `develop` via the
sibling series).
- Supersedes the earlier closed attempt **#10917**.
- Sibling gfx1250 bridge PRs: #10921 (universal / grouped / multi-D),
#10927 (grouped quant), #10928 (batched GEMM + contraction), #11043
(rowcol / tensor quant), #10934 (contraction multi-ABD).

---------

Co-authored-by: Muhammed Emin Ozturk <3836908+ozturkosu@users.noreply.github.com>
ozturkosu added a commit that referenced this pull request Sep 17, 2026
JIRA ID : AICK-2249

## Summary

gfx1250 is labelled **RDNA4** in several comments and one CI config
string. The product generation is **CDNA5**. This corrects the label.

Comments and one JSON `_comment` only — no code, no behaviour change.

Raised in review of #12173, where the same value was corrected in
`arch_specs.json`. Split out because renaming terminology across the
tree does not belong in an LDS-capacity change.

## Why the RDNA4 label was there

It was not arbitrary. gfx1250 has no MFMA units and multiplies through
**WMMA**, which is an RDNA-family instruction, and the `gfx12xx`
numbering points the same way. The observation about the *instruction
path* was right; using it as a *generation* label was not.

`arch.hpp` already draws exactly this distinction:

> GFX1250 is its own standalone family. Although it **shares the RDNA
architecture** with the GFX12 family, its MMA builtins and data-type ABI
differ, so it must not be treated as a GFX12-family device.

Sharing an ISA lineage is not the same as belonging to that generation.
So there are two separate claims in play, and only the second one holds.

## Changes

Where a generation label is meant, it now says CDNA5. Where only the
instruction path matters, the generation is dropped rather than replaced
— a WMMA path is a WMMA path regardless of which generation the part
belongs to.

| file | before | after |
|---|---|---|
| `dispatcher/tests/test_gemm_utils.py` | `gfx1250 (MI400 / RDNA4-WMMA)
enablement` | `gfx1250 (MI400 / CDNA5, WMMA) enablement` |
| `dispatcher/tests/test_batched_bridge.py` | same | same |
| `dispatcher/tests/test_batched_contraction_bridge.py` | same | same |
| `dispatcher/tests/test_multi_d_bridge.py` | `it runs the RDNA4 WMMA
path` | `it runs the WMMA path` |
| `dispatcher/codegen/grouped_conv/grouped_config_rules_full.py` | `such
as rdna4/gfx1250` | `such as gfx1250` |
| `tile_engine/.../bridge_default_ci_config_gfx1250.json` | `(MI400,
RDNA4/WMMA)` | `(MI400, CDNA5/WMMA)` |

## Deliberately not changed

- **`include/ck_tile/core/arch/arch.hpp`** and
**`.../mma/scale/wmma/selector.hpp`** describe the ISA lineage and the
selector strategy as RDNA. Both are accurate — the first is the quote
above, the second documents an RDNA-style selector. Renaming these would
replace a correct statement with a wrong one.
- **`dispatcher/codegen/arch_specs_generated.py`** still reads `rdna4`.
It is generated, and its source is the gfx1250 entry in
`arch_specs.json` that #12173 adds; the value is corrected there.
Hand-editing a generated file is the exact trap this codebase keeps
hitting, so it is not done here.

That last point means the tree is briefly inconsistent until #12173
lands. The affected field is metadata: nothing branches on its value,
and its only consumer is a `None` check that rejects unknown
architectures in strict mode.

## Test plan

- [x] `test_gemm_utils`, `test_batched_bridge`,
`test_batched_contraction_bridge`, `test_multi_d_bridge`,
`test_grouped_conv_codegen` all pass
- [x] The edited CI config still parses as JSON
- [x] No `gfx1250`/`MI400` reference to RDNA4 remains outside the two
files listed above as intentionally kept

## Note for the reviewer

The label originated in #10921, the gfx1250 bridge enablement PR, and
spread from there; AICK-2082 uses the same wording. So this is a
retroactive terminology correction rather than a one-off typo. If
**CDNA5 is not the right generation either**, say so before this merges
— I have taken it from review feedback on #12173 and have not
independently confirmed it.

---------

Co-authored-by: Muhammed Emin Ozturk <3836908+ozturkosu@users.noreply.github.com>
ozturkosu added a commit that referenced this pull request Sep 26, 2026
…bridge (#12544)

JIRA ID: AICK-2427
JIRA ID: AICK-2137
JIRA ID: AICK-2136
JIRA ID: AICK-2142
JIRA ID: AICK-2429

Related PRs: #12508 #10921 #10927 #10928 #11043 #11048 #10916

## Summary

This PR enables the gfx1250-only GEMM pipelines in the tile_engine (TE)
/ dispatcher bridge:
- `comp_tdm` (TDM V1) and `comp_tdm_v2` (TDM V2);
- `comp_async`;
- the TDM epilogue.

They are enabled for GEMM universal and batched GEMM, whose gfx1250
bridge enablement is already merged. GEMM multi-ABD and the grouped
quant ops only gain reject-guards: their kernels have no async/TDM
pipeline yet.

Most of the change is in `tile_engine/` and `dispatcher/`. It also fixes
two CK-Tile kernel defects in pipelines this PR enables (see Kernel
fixes), with gtest coverage. On gfx942 and gfx950 the generated bridge
code is byte-identical.

## Motivation

The gfx1250 bridge enablement PRs (#10921, #10928, #11048) exposed only
the pipelines shared with gfx942/gfx950. The TDM and async pipelines
exist in CK-Tile for gfx1250, and #10916 already uses them for mx GEMM,
but the bridge could not generate or benchmark them for the other GEMM
ops.

## Design note

- **TDM pipelines** (`comp_tdm`, `comp_tdm_v2`):
- They are intrawave only, always use the TDM epilogue, and are
non-persistent.
- They require `pad_m = pad_n = pad_k = false`. TDM clips A/B/E in
hardware, and right-padding N/K inflates the bound-clip extents, which
gives wrong results on unaligned shapes. This matches the CK-Tile TDM
gtests, which pin padding off.
- The TE builders and dispatcher codegen reject any other combination
with a reason string.
- **`comp_async` on gfx1250:**
- It is emitted only for row-major A / col-major B. Other layouts hit
the transpose-load `static_assert` with the gfx1250 WMMA tiles.
- For non-MX ops it is also emitted only fully padded (`pad_m = pad_n =
pad_k = true`). On develop, unpadded `comp_async` on gfx1250 has a
kernel defect: the async K-prefetch reads past the A/B extent, and the
`TailNumber::Two` path has no LDS fence. The kernel fix goes into
#12508; this restriction can be relaxed once it merges.
  - fp8/bf8 `comp_async` on gfx1250 requires `warp_tile_k >= 128`.
  - mx GEMM is unaffected.
- **TDM LDS budget:** the gfx1250 TDM pipelines share the `comp_async`
LDS budget (aliases in `arch_specs.json`, emitted by
`generate_arch_specs.py`). The LDS check adds the TDM
16-byte-per-row-group descriptor padding and checks that the TDM output
tile fits. The tile_engine and the dispatcher ArchFilter use the same
rule. Non-MX `comp_async` GEMM on gfx1250 uses the same base LDS
descriptor, so it gets the same row padding in both gates (without it,
fp16/bf16 64x256x256, 192x128x256 and 256x64x256 fail to link at 337856
B > 327680 B); MX `comp_async` keeps its own rule from #10916.
- **GEMM multi-ABD:** reject-guards only for `comp_async`, `comp_tdm`,
`comp_tdm_v2` and the TDM epilogue.
- **Grouped quant ops** (`aquant`, `bquant`, `abquant`, `rowcolquant`,
`tensorquant`):
- These files only gain reject-guards for `comp_async`, `comp_tdm`,
`comp_tdm_v2` and the TDM epilogue. Nothing is enabled for them.
- The quant GEMM pipelines have no TDM/async implementation yet, so an
unguarded config would fail to compile instead of being filtered.
- **Runtime reject = SKIP.** The dispatcher returns status `-1` when a
kernel's `IsSupportedArgument` rejects a problem (for example TDM
alignment at `N % 8 != 0`). It is exposed as `GemmResult.unsupported`
(also on grouped and multi-D results). The gfx1250 tests and
`test_gemm_search_space` count it as a skip, not a failure, and a lane
still fails if nothing was verified.
- **Trait parsing** now goes through one shared helper (`trait_parse.py`
/ `gemm_trait_parse.cmake`), so the CMake and Python sides split kernel
trait strings the same way.

### Deferred ops

grouped GEMM, GEMM multi-D, batched contraction and contraction
multi-ABD are not enabled here. Their kernels need the core changes in
#12508 before they can host a TDM pipeline. A follow-up PR will enable
them after #12508 merges.

## Kernel fixes

Found by a gfx1250 tuning sweep with `--verify` (bf16 `rcr`,
5608x4096x2048):

- **`comp_async` with `persistent=true` wrote only part of the output
(9-36% of tiles non-zero).**
- Cause: `GemmPipelineAgBgCrCompAsync` did not expose
`UsePersistentKernel`. The host launched a persistent-sized grid, but
the device took the one-block-per-tile entry, so most tiles were never
written and out-of-range tile indices could fault.
- Fix: the pipeline now exposes `UsePersistentKernel` for plain GEMM
problems. MX problems stay non-persistent, because their host path
launches a split-K grid that the persistent loop does not read.
- The same pipeline is used on gfx950. The gfx950 persistent comp_async
tests pass with the fix.
- **`comp_tdm` / `comp_tdm_v2` returned all-NaN when the TDM policy
picks `sub_tile_num > 1`.**
- The TDM policy picks `sub_tile_num > 1` from its VGPR estimate. In the
sweep this happened at 4 waves with 128x128x256 and 128x256x128 tiles.
- Cause: the hot loop in `block_gemm_areg_breg_creg_v1.hpp` ran over the
full `KIterPerWarp` instead of one K sub-tile (`KIterPerWarp /
KSubTileNum`), so it read past the sub-tile register window.
- Fix: the loop now runs over one K sub-tile. With `KSubTileNum == 1` it
is unchanged; the compv4 code object is byte-identical.
- **`comp_tdm_v2`:** the 4-wave `static_assert` is now written as
`NumWarps == 4`. It is equivalent to the old block-size form, and the
pipeline body hardcodes four wave roles.
- **Tests:**
  - A Persistent variant is added to the comp_async WMMA gtest list.
- New `test_ck_tile_gemm_pipeline_tdm_subtile_wmma`: fp16/bf16, V1/V2,
with sub-tile 2 cases plus sub-tile 1 controls.
  - Both tests fail on the old kernel and pass with the fix.
- **Scope:** `comp_async_v2` (sub-tiling policy) shares the block GEMM
fix but has no gtest here and is not emitted by the bridge.

## Changes

| Area | Change |
|---|---|
| `dispatcher/codegen/arch_filter.py`, `codegen_common.py`,
`unified_gemm_codegen.py` | gfx1250 pipeline/epilogue emission and
validity rules (TDM pad/scheduler/persistent, `comp_async` layout + pad)
|
| `dispatcher/codegen/arch_specs_generated.py`,
`include/.../arch_specs_generated.hpp`, `kernel_key.hpp` | New
pipeline/epilogue enum values and names |
| `dispatcher/codegen/unified_grouped_gemm_*quant_codegen.py` |
Reject-guards only |
| `dispatcher/codegen/arch_specs.json`, `generate_arch_specs.py` | TDM
LDS budget aliases (generated, not hand-edited) |
| `dispatcher/python/gemm_utils.py` | Pipeline names,
`GemmResult.unsupported` for status `-1` |
| `dispatcher/tests/CMakeLists.txt` | Registers the gfx1250 pipeline,
gate-equivalence, arch-specs regeneration and result-status tests |
| `tile_engine/ops/gemm/gemm_instance_builder.py`,
`gemm_validation_utils.py` | Shared gfx1250 validity checks |
| `tile_engine/ops/gemm/gemm_universal/*`, `batched_gemm/*`,
`gemm_multi_abd/*` | Builders, CMake, gfx1250 default and CI configs |
| `tile_engine/ops/gemm/grouped_gemm_quant/*` | Reject-guards only |
| `dispatcher/codegen/codegen_common.py`,
`tile_engine/ops/gemm/gemm_validation_utils.py` | One shared async/TDM
reject guard per layer; the grouped quant codegens and the multi-ABD /
grouped quant builders bind it to their op name with `functools.partial`
instead of keeping a local copy |
| `tile_engine/ops/gemm/trait_parse.py`, `gemm_trait_parse.cmake` |
Shared trait-string parsing |
| `include/ck_tile/ops/gemm/block/block_gemm_areg_breg_creg_v1.hpp`,
`pipeline/gemm_pipeline_ag_bg_cr_comp_async.hpp`,
`pipeline/gemm_pipeline_ag_bg_cr_comp_tdm_v2.hpp` | Kernel fixes (see
above) |
| `test/ck_tile/gemm/*` | Persistent comp_async gtest variant, new TDM
sub-tile gtest |
| `test_*.py` (dispatcher and tile_engine) | Unit tests for the gates,
configs and guards |

## Testing

| Check | Result |
|---|---|
| gfx942 / gfx950 generated-code byte identity (before vs after, all
ops) | Identical |
| TDM V1/V2 native on gfx1250, pad false | Correct (18/18) |
| `comp_async` native on gfx1250, fully padded | Correct |
| clang-format-18 on the C++ headers | Clean |
| Dispatcher unit tests (targeted gfx1250 + new tests) | 109 passed |
| tile_engine gfx1250 tests | 92/92 passed |
| ArchFilter vs tile_engine gate equivalence (gfx1250 enumeration) |
Identical |
| gfx1250 build + `--verify` of every comp_async / comp_tdm /
comp_tdm_v2 default_config instance (7323 kernels x 9 shapes) | 0 wrong
results; the LDS gate rejects exactly the 90 instances that fail to
link, 0 false rejects |
| Generated arch specs reproducible from `arch_specs.json` | Identical |
| ruff check (F, E9) on the changed Python | Clean |
| gfx1250 end-to-end bridge run (TE + dispatcher, universal / batched /
multi-ABD) | 0 failures. TE 1188 pass / 1102 skip; dispatcher universal
620/840 and batched 94/96 verified, the rest are runtime-unsupported
skips; multi-ABD 18/22 with the 4 negative cases correctly rejected;
codegen gate vs emitted kernels and ArchFilter vs codegen: 0 mismatches
|
| gfx1250 kernel-fix gtests | TDM sub-tile 24/24, comp_async WMMA 14/14
(incl. Persistent), persistent WMMA 14/14 |
| gfx1250 tile_engine re-run of the reported configs (bf16 `rcr`, 5
shapes incl. 5608x4096x2048) | comp_async 40/40 pass (20 with
`persistent=true`); comp_tdm / comp_tdm_v2 72/72 pass, including
128x128x256 and 128x256x128 at 2x2x1 |
| Mutation check (gfx1250, old kernel code restored) | Persistent cases
fail without the comp_async fix; all sub-tile 2 cases fail without the
block GEMM fix; controls pass |
| gfx950 regression (comp_async, eight-waves, persistent async, MX async
rcr/rrr/crr/ccr) | All pass |

---------

Co-authored-by: Muhammed Emin Ozturk <3836908+ozturkosu@users.noreply.github.com>
ozturkosu added a commit that referenced this pull request Oct 16, 2026
…ched contraction kernels (#12508)

JIRA ID: AICK-2082
JIRA ID: AICK-2099
JIRA ID: AICK-2100
JIRA ID: AICK-2104
JIRA ID: AICK-2109

Related PRs: #10921 #10927 #10928 #10934 #11048 #10931 #12544

## Summary

This PR lets three CK-Tile kernels host the gfx1250 TDM GEMM pipelines
(`GemmPipelineAgBgCrCompTDMV1` / `V2`):
- grouped GEMM;
- GEMM multi-D;
- batched contraction (and multi-ABD contraction, which wraps it).

It also fixes two problems in the `comp_async` pipelines
(`GemmPipelineAgBgCrCompAsync` and `...V2`), see "CompAsync fix" below:
- an out-of-bounds K prefetch when K is not padded;
- on gfx125, a CompAsyncV2 hot-loop wait that could leave async LDS
loads in flight in blocks that reach past the A/B tensor (padded tiles
and M/N tails).

It changes only `include/` and `test/`. Enabling these pipelines in the
TE/dispatcher bridge is a separate follow-up PR that depends on this
one.

For the non-CompAsync grouped GEMM, multi-D and contraction kernels, the
compiled device code is byte-identical on gfx942 and gfx950. The
CompAsync V1/V2 fixes change those pipelines on gfx950; their tail
regressions and V1 performance measurements are listed below.

## Motivation

gfx1250 bridge enablement is merged for grouped GEMM, multi-D and
batched contraction (#10921, #10928, #10934). These kernels still cannot
use the TDM pipelines, for three reasons:
- **Tuple-only windows.** The TDM pipelines take A/B windows only as
tuples. The grouped and contraction kernels call the pipeline with
single windows, so a TDM instance does not compile.
- **Hardware clipping, no padding.** TDM clips A/B/E in hardware and
expects `kPadM/kPadN/kPadK == false`. The kernels need a path that
builds unpadded tensor views.
- **No D tensors in `TdmEpilogue`.** `TdmEpilogue` rejects D tensors, so
multi-D GEMM has no epilogue to store E through TDM.

## Design note

- **Detecting a TDM pipeline.** Only the TDM pipelines define
`skipCheckValidLaunchParams`. `UniversalGemmKernel::kIsTdmPipeline`
wraps the existing `has_skip_check_valid_launch_params` trait, and the
grouped, multi-D and contraction kernels all use it. A non-TDM pipeline
cannot take the TDM path by accident: it would also need a TDM epilogue
(`is_tdm_epilogue_v`, which also accepts `TdmMultiDEpilogue`) to pass
the new `static_assert`s.
- **Shared TDM host checks.**
`UniversalGemmKernel::IsTdmArgumentSupported` (k_batch == 1, K > 0,
A/B/E aligned to their element size) and `IsTdmDeviceSupported` (gfx125
only) are shared by the three kernels, so they reject the same arguments
with the same messages.
- **New `TdmMultiDEpilogue`, separate from `TdmEpilogue`.**
- It is a new type on purpose, so current `TdmEpilogue` users (grouped
conv, mx flatmm, ...) keep rejecting D tensors.
- It reuses `TdmEpilogue`'s LDS view, store distribution and TDM store.
- It loads each D tile with the accumulator distribution and fuses it on
the fp32 accumulator before the single cast to E.
  - It supports row-major E and row-major D only, with no ScaleM/ScaleN.
- **Forced N pad on D loads.** TDM kernels run with `kPadN == false`,
but the epilogue still reads D with regular tile loads. For TDM kernels
with D tensors, `universal_gemm_kernel` forces the N pad on those loads,
so a partial N tile reads zeros instead of running into the next row.
- **Batched contraction host checks.** TDM uses one stride per merged
dimension. The host checks that every merged G/M/N/K group collapses to
a single stride, with K (and N for E) innermost; otherwise it throws
`std::invalid_argument`. The batch stride comes from the fastest G
dimension whose length is not 1.
- **Arguments rejected on the TDM path:** padding (`kPadM/kPadN/kPadK`
must be false, enforced with `static_assert` in the grouped and multi-D
kernels), split-K (`k_batch != 1`), K <= 0, A/B/E pointers not aligned
to their element size, persistent mode, cluster launch, and devices
other than gfx125x. Batched contraction also rejects zero or negative
strides in a merged dimension. They fail with `IsSupportedArgument(s)`,
or with `static_assert` where the type decides. The TDM store always
overwrites E, so split-K accumulation is not possible.
- **Multi-ABD contraction.** A `static_assert` limits TDM to a single A
and a single B tensor, because `TdmEpilogue` overwrites E.
- **Contraction epilogue.** `RunGemmTdm` requires a TDM epilogue
(`static_assert(is_tdm_epilogue_v<EpiloguePipeline>)`), so a CShuffle
epilogue with a TDM pipeline fails to compile instead of producing wrong
stores.

### CompAsync fix

- **Bug.** With `kPadK == false`, the `comp_async` pipelines issue async
prefetches for K tiles that do not exist:
- the prologue loads tile 1 even when there is only one K tile (tail
One);
- with an even `num_loop` (tail Two), the last hot-loop iteration
prefetches tile `num_loop`.

On gfx1250 this reads past the A/B extent and gives wrong results on
unpadded shapes. CI misses it because the gtests default to `PadK =
true`.
- **V1 fix:**
  - skip the tile-1 prologue prefetch for tail One;
- for tail Two, peel the last hot-loop iteration and run it with a
compile-time "no prefetch" flag. The steady-state loop body has no
runtime branch, so gfx950 CompAsync performance is unchanged (see
Testing). For tail Three the loop is not peeled;
- add a `block_sync_lds_direct_load()` fence before the tail Two local
read. Today the fence is redundant, but it protects the tail if the
hot-loop fences are ever relaxed.
- **V2 fix:** the same gating for the prologue and in-loop prefetches,
plus a corrected tail handler.
- **Pre-existing develop bug fixed in V2.** `CompAsyncV2` aliased the V1
base, so for an odd `num_loop` it dispatched tail Three, which V2 does
not implement. K tiles were dropped and the output was wrong (for
example K = 192, 320, 4160, 8256). The new V2 gtests fail 4/4 on develop
headers and pass 4/4 with this PR.
- **V2 async-load wait on gfx125 (also pre-existing in develop).**
- The V2 hot loop waits with `s_wait_asynccnt(AB_Async_Load_Inst_Num)`,
so only the loads of the newest window may still be in flight.
- On gfx125 a lane whose element is out of bounds does not issue its
async load (it zero-fills LDS instead). A wave can then issue fewer
loads than `AB_Async_Load_Inst_Num`, the partial wait lets loads of the
window about to be read stay in flight, and the block reads stale LDS.
- This happens in padded tiles and also without padding, in the last
block of an M (or N) tail, e.g. row-major A with M not a multiple of the
tile.
- Fix: before the loop each block checks whether the farthest A/B
element it reads over the K loop is out of bounds (or a pad flag is
set). Such blocks wait for all async loads; the other blocks keep the
partial wait. The check is block uniform (scalar branch, about two SALU
instructions per half iteration) and only exists on gfx125; other
targets keep the partial wait at compile time, and the gfx950 V2 ISA is
unchanged.
- **Tests:**
- new V2 tail-case gtests covering `num_loop` 1, 2, 3, 4, 5, 7 and 32,
for XDL and WMMA, plus a padded tile and an unpadded M tail
(`PaddedTailCoverage`, `UnpaddedMTailCoverage`). On gfx1250 the padded
case fails 10/10 without the wait fix;
  - the CompAsync WMMA tests are added to `CK_TILE_GEMM_TEST_TARGETS`;
- a new CMake helper `ck_tile_restrict_archs` limits the gfx125-only
WMMA tests (TDM and CompAsync async LDS) to gfx125 targets, because the
`_wmma` suffix only drops gfx9.
- **Follow-up in #12544.** Once this PR merges, #12544 can drop its
gfx1250 gate that forces non-MX `comp_async` to pad TTT.

## Changes

### New

| File | Purpose |
|---|---|
| `include/ck_tile/ops/epilogue/tdm_multi_d_epilogue.hpp` | TDM epilogue
with fused row-major D tensors |
| `test/ck_tile/grouped_gemm/test_grouped_gemm_tdm_wmma.cpp`,
`test_grouped_gemm_tdm_ut_cases.inc` | Grouped GEMM TDM V1/V2 gtests |
| `test/ck_tile/gemm_multi_d/test_gemm_multi_d_tdm_wmma.cpp` | Multi-D
TDM gtests |
|
`test/ck_tile/batched_contraction/test_batched_contraction_tdm_wmma.cpp`
| Batched contraction TDM gtests (compared against the CPU reference
with tolerances) |
|
`test/ck_tile/batched_contraction/test_batched_contraction_tdm_compile_fail.cpp`,
`CMakeLists.txt` | Compile-fail tests for the TDM contraction
`static_assert`s |

### Modified

| File | Change |
|---|---|
| `ops/gemm/kernel/grouped_gemm_kernel.hpp` | Tuple-form `RunGemm` for
TDM; no-padding `static_assert` for TDM; split-K, persistent,
cluster-launch and D-tensor rejection; `_tdm` name suffix;
`UsePersistentKernel` now uses the base kernel's detection |
| `ops/gemm/kernel/gemm_multi_d_kernel.hpp` | Requires
`TdmMultiDEpilogue` and no padding, row-major E and no cluster launch
for TDM; gfx125 check |
| `ops/gemm/kernel/universal_gemm_kernel.hpp` | Forced N pad on D loads
for TDM kernels with D tensors; `kIsTdmPipeline`, shared
`IsTdmArgumentSupported` / `IsTdmDeviceSupported` host checks |
| `ops/epilogue/tdm_epilogue.hpp` | `is_tdm_epilogue_v` trait (true for
`TdmEpilogue` and types derived from it) |
| `ops/batched_contraction/kernel/batched_contraction_kernel.hpp` |
`RunGemmTdm` (requires a TDM epilogue); host check that merged
dimensions collapse to one positive stride; TDM batch stride; shared TDM
host checks |
|
`ops/batched_contraction/kernel/batched_contraction_multi_abd_kernel.hpp`
| `static_assert` limiting TDM to single A/B |
| `ops/epilogue.hpp` | Includes the new epilogue |
| `ops/gemm/pipeline/gemm_pipeline_ag_bg_cr_comp_async.hpp`,
`..._comp_async_v2.hpp` | CompAsync K-prefetch bound gating and tail
fixes; V2 full async-load wait on gfx125 for blocks that reach past A/B
|
| `test/ck_tile/gemm/*comp_async*`,
`test_gemm_pipeline_{kernel_types,util}.hpp`, `CMakeLists.txt` |
CompAsync V2 tail-case tests (XDL + WMMA, unpadded, padded, unpadded M
tail) with a shared tail-coverage loop; CompAsync WMMA tests in
`CK_TILE_GEMM_TEST_TARGETS` |
| `test/ck_tile/{CMakeLists.txt, grouped_gemm/*, gemm_multi_d/*}` |
Registers the new tests; `ck_tile_restrict_archs`; TDM instance helpers
in the test utils |

## Testing

Results below are at head b38f77a unless noted. Every gfx1250 suite
was run several times in a row (5 repeats for the TDM suites, 10 for the
V2 tail cases) with no failures and no skips.

The grouped TDM host validation rejects non-positive K in retained
kernel arguments before a device query. `MakeKargs` continues to drop
zero-sized groups, covered by the existing passing `EmptyGroup` cases.

| Arch | Tests | Result |
|---|---|---|
| gfx1250 | Grouped GEMM TDM | 70/70 pass, including KTail, RaggedMN
(M/N not multiples of the tile) and negative-K rejection |
| gfx1250 | GEMM multi-D TDM | 360/360 pass |
| gfx1250 | Batched contraction TDM | 80/80 pass, including ragged
200x136x100 and RejectZeroStrideMDim |
| gfx1250 | Contraction TDM compile-fail | 4/4 fail to compile as
expected (num D, pad N, multi-ABD, CShuffle epilogue) |
| gfx1250 | CompAsync V1 WMMA suite (incl. unpadded-K tail cases) |
16/16 pass |
| gfx1250 | CompAsync V2 tail cases (WMMA: unpadded, unpadded M tail,
padded) | 3/3 pass, 10/10 repeats; the padded case fails 10/10 without
the wait fix |
| gfx1250 | TDM sub-tile gtests | 24/24 pass |
| gfx1250 | Existing grouped GEMM / multi-D (cshuffle 231/231, default2d
294/294) / contraction tests | all pass |
| gfx1250 | Combined with #12544 (comp_async, comp_async_v2, TDM
sub-tile gtests) | 16/16, 2/2, 24/24 pass |
| MI350X (gfx950) | CompAsync V1 / V2 tail cases (XDL) | V1 58/58, V2
4/4 pass. V2 fails 4/4 without the fix. At b38f77a the V2 tail cases
(incl. padded and M tail) pass 5/5 repeats and the V2 device ISA is
identical to the previous head. |
| MI350X (gfx950) | CompAsync V1 perf vs develop, fp8, 10 shapes (even
and odd `num_loop`) | median -0.22%, range -1.32% to +0.70% |
| MI350X (gfx950) | grouped GEMM, multi-D, contraction suites | Same
pass/skip counts before and after; non-CompAsync device ISA
byte-identical (measured at a2ed839; later commits only change host
checks and TDM-only code) |
| MI300X (gfx942) | grouped GEMM, multi-D, contraction suites | Same
pass/skip counts before and after (ctest 553 tests); device ISA
byte-identical |
| gfx90a (C++17 CI stage) | host build with `-Werror` | No new warnings
(rebuilt at b38f77a) |

A mutation check confirms the new stride test: with the stride check
removed, RejectZeroStrideMDim fails 4/4.

The gfx1250 CompAsync perf numbers from the previous revision (V2 fp16
4096^3 about +1%, other shapes within +/-0.6%) were measured before the
loop peel and were not re-measured.

All C++ files are formatted with clang-format-18.

The V1 and V2 tail regressions share one tail-coverage loop between the
XDL and WMMA suites. The V1 unpadded tail regression and covers
`num_loop` = 1, 2, 3, 4, 5, 7 and 32 over four M/N shapes, with `k_batch
= 1`. At head 26992d2 the gfx950/XDL regression passed 8/8 typed
tests without skips (224 typed shape/loop combinations).

## Known limitations / reviewer notes

- **Universal-GEMM TDM gtest not run here.**
`test_ck_tile_gemm_pipeline_tdm_wmma` skipped all 112 of its cases
because the gfx1250 part we tested on has no cluster launch. This PR
does not change the universal TDM pipeline; it only changes how D
tensors are padded.
- **Pre-existing CompAsync issues, not changed by this PR:** CompAsyncV2
with a 256x256x64 block tile (32x32 warp tile) gives wrong results on
gfx95x, and CompAsync/V2 faults when both N and K are padded. Both
reproduce on develop and will be tracked separately.
- **Host API change.** `BatchedContractionKernel::IsSupportedArguments`
is no longer `constexpr`, because it now queries the device and checks
pointer alignment. No in-tree caller uses it in a constant expression.
- **Split-K.** Rejected on every TDM path.
- **Multi-ABD `static_assert`.** It is only instantiated for gfx1250 TDM
builds.
- **Out of scope.** PRESHUFFLE_TDM is tracked in #10931; stream-K is
excluded.
- **Follow-up bridge PR.** It will enable COMPUTE_TDM_V1/V2 for grouped
GEMM, multi-D and contraction in the TE/dispatcher bridge once this PR
merges.

---------

Co-authored-by: Muhammed Emin Ozturk <3836908+ozturkosu@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants