Skip to content

feat(rocke): IR dtypes in TileMma, a storage type under every Fragment, and MMA issue from the measured backend coverage - #14537

Merged
cgmillette merged 7 commits into
users/cgmillette/rocke/mma-catalogfrom
users/cgmillette/rocke/tiling-dtypes
Oct 31, 2026
Merged

cgmillette merged 7 commits into
users/cgmillette/rocke/mma-catalogfrom
users/cgmillette/rocke/tiling-dtypes

Conversation

@cgmillette

Copy link
Copy Markdown
Contributor

Motivation

The tiling layer named MMA dtypes with strings, held every Fragment in its logical vector type, and found the backend instruction by searching on dtypes and shape. That last part could pick a different instruction from the catalog row it had selected. As a result:

  • sub-byte (fp4, fp6, i4) and tf32 operands could not be moved or fed;
  • mixed A/B dtypes were refused;
  • integer rows with selectable signedness issued the signed instruction for unsigned data;
  • a row whose result dtype differs from its accumulator issued the wrong instruction.

This PR makes the tiling layer speak IR dtypes end to end. Every Fragment gets a storage type under its logical dtype, and every MMA instruction is issued as the measured backend coverage record says.

Stacked on #14329 (MMA catalog). Review only the last seven commits.

ISSUE ID : AICK-2576

Technical Details

Seven commits:

  1. feat(rocke): hold Fragment registers in the storage type of their dtype
    • Storage per dtype: the logical vector for arithmetic dtypes, i32 for tf32, and whole i32 words for packed sub-byte dtypes, packed low bit first.
    • Load, store and fill move storage units in global memory and LDS; a packed access moves whole 32-bit words.
    • Refusals name the fix.
    • IR for byte-or-wider dtypes is unchanged.
  2. feat(rocke): take IR dtypes for A, B, C and the result in TileMma
    • a/b/c and a new d= are scalar IR types, e.g. rocke.core.ir.F16; a string is refused with the constant to pass.
    • A selection miss lists what the target offers.
  3. feat(rocke): pin MMA instructions by full signature and accept mixed A/B dtypes
    • atom_override= is the one way to pin a row. Its dtypes are optional checks; any left out are taken from the row.
    • Mixed A/B instructions (e.g. gfx942 fp8 x bf8) select and draw at each operand's own width.
  4. feat(rocke): issue MMA instructions as rocke's measured backend coverage says
  5. feat(rocke): feed MMA operands from their fragments' storage registers
    • Operands are sliced from storage registers and bitcast only to the instruction's operand form: packed words for sub-byte dtypes, i32 reinterpreted as tf32.
    • F32 fragments feed xf32 MFMAs, which truncate the low mantissa bits; the docs say when to convert to TF32 first.
  6. fix(rocke): pair A and B K through the instruction's canonical coupling
    • Mixed-width f8f6f4 instructions hold K differently in A and B. The K check now pairs positions through the instruction's canonical layouts, so the canonical fp8 x fp4 pair is accepted and a mis-loaded operand is refused.
    • Same-format instructions are unchanged.
  7. feat(rocke): move fp8, bf8 and i8 fragments with vector loads and LDS stores
    • A contiguous register run of these 8-bit types moves as one <N x i8> access instead of one byte at a time, in global memory and LDS.

No core or C++ file changes, so byte identity is unaffected.

Test Plan

  • Storage: the storage table and every refusal; bit-exact GPU round trips on gfx90a for tf32 through LDS and for fp4, fp6 and i4 in gfx950's canonical f8f6f4 layout through global memory and LDS, including a clipped packed window.
  • Dtypes: IR-dtype refusals with the constant name of every scalar type, derived and default dtypes, selection by IR type, mixed and integer selection.
  • Issue: emit_op of every issuable coverage-record entry, per operand-dtype variant, returns the recorded op; every refusal text.
  • Drive: a single-instruction TileMma for every issuable dense (row, target) pair lowers to the row's intrinsic, compiled where the host clang targets the arch. This covers WMMA, gfx11 16-bit result, fp8 x bf8, xf32 from F32 and TF32, fp4 words, and bf16-result tiles.
  • K coupling: canonical mixed pairs accepted, mis-loaded operands refused.

Test Result

  • Byte identity green at llvm20, llvm22 and llvm23.
  • ctest 43 / 43.
  • Portable IR against a freshly built shared engine: 187 passed.
  • The 21 touched test files, both engines strict: 1321 passed. 62 skipped, all compile-only cases for gfx1250 and gfx1154 that the host clang cannot target.
  • Full platform suite: no failures.
  • The other platform test files: only the ones develop also fails.
  • Library smoke: no new failures.
  • pre-commit passes.
  • Every commit builds and passes its own tests on its own.

Submission Checklist

🤖 Generated with Claude Code

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unresolved fragment-transform and unsigned multi-tile failures remain, alongside repeated backend-table loading and missing numerical validation of MMA K pairing.

4 open issues
What changed in this PR

This PR builds on the MMA catalog work in #14329 to carry IR dtypes through rocKE’s tiling layer, separate fragment storage from logical types, and issue the exact backend instruction recorded for each target.

Changes:

  • Adds storage-backed fragments and IR-typed MMA operands, accumulators, and results.
  • Uses measured backend coverage for instruction selection and canonical layouts for mixed-width K pairing.
  • Updates validation, visualization, tests, demos, and API documentation.

Paths below are relative to dnn-providers/hip-kernel-provider/rocke/.

File Description
style/​API_DESIGN_STANDARD.md Updates the K-pairing validation signature.
platform/​python/​rocke/​tests/​helpers/​tiling/​visualization/​test_layout_render.py Migrates rendering tests to IR dtypes.
platform/​python/​rocke/​tests/​helpers/​tiling/​visualization/​test_auto_pipeline.py Tests recorded operand dtypes and mixed-input rendering.
platform/​python/​rocke/​tests/​helpers/​tiling/​traits/​test_mma_traits.py Tests IR-typed catalog selection and diagnostics.
platform/​python/​rocke/​tests/​helpers/​tiling/​test_transforms.py Supplies canonical layouts to K-pairing tests.
platform/​python/​rocke/​tests/​helpers/​tiling/​test_scheduling.py Migrates scheduling tests to IR dtypes.
platform/​python/​rocke/​tests/​helpers/​tiling/​test_lds_descriptor_addressing.py Migrates addressing tests to IR dtypes.
platform/​python/​rocke/​tests/​helpers/​tiling/​test_layout_optimizer.py Supplies partner canonical layouts to optimizer tests.
platform/​python/​rocke/​tests/​helpers/​tiling/​test_interleave_all_dense.py Checks mixed-width interleaving rejection.
platform/​python/​rocke/​tests/​helpers/​tiling/​test_fragment.py Migrates fragment test setup to IR dtypes.
platform/​python/​rocke/​tests/​helpers/​tiling/​test_emit_wide_access.py Migrates wide-access tests to IR dtypes.
platform/​python/​rocke/​tests/​helpers/​tiling/​test_coalescing_probe.py Migrates coalescing tests to IR dtypes.
platform/​python/​rocke/​tests/​helpers/​tiling/​mma/​test_mma_validation_recipe.py Updates dtype and canonical-layout validation inputs.
platform/​python/​rocke/​tests/​helpers/​tiling/​mma/​test_mma_operation.py Tests dtype validation, pinning, and mixed selection.
platform/​python/​rocke/​tests/​helpers/​tiling/​mma/​test_mma_operand_feed.py Tests TF32 and packed operand feeding.
platform/​python/​rocke/​tests/​helpers/​tiling/​mma/​test_mma_k_coupling.py Tests canonical K coupling and its consumers.
platform/​python/​rocke/​tests/​helpers/​tiling/​mma/​test_mma_issue.py Tests recorded instruction issue and result dtypes.
platform/​python/​rocke/​tests/​helpers/​tiling/​mma/​test_mma_issuable_pairs.py Sweeps issuable dense instruction variants.
platform/​python/​rocke/​tests/​helpers/​tiling/​mma/​test_mma_dtypes.py Tests 8-bit vector accesses and visualization labels.
platform/​python/​rocke/​tests/​helpers/​tiling/​mma/​test_layout_styles.py Migrates layout-style tests to IR dtypes.
platform/​python/​rocke/​tests/​helpers/​tiling/​mma/​test_layout_oracle.py Migrates oracle selection to IR dtypes.
platform/​python/​rocke/​helpers/​tiling/​visualization/​layout_render.py Uses operand-specific labels and canonical pairing diagnostics.
platform/​python/​rocke/​helpers/​tiling/​visualization/​auto_pipeline.py Reads operand widths from recorded MMA dtypes.
platform/​python/​rocke/​helpers/​tiling/​transforms/​observers.py Validates K alignment at coupled positions.
platform/​python/​rocke/​helpers/​tiling/​transforms/​_core.py Derives K coupling from canonical layouts.
platform/​python/​rocke/​helpers/​tiling/​traits/​README.md Documents typed selection and coverage-driven issue.
platform/​python/​rocke/​helpers/​tiling/​traits/​mma_traits.py Accepts IR dtypes and improves selection diagnostics.
platform/​python/​rocke/​helpers/​tiling/​tiling_recorder.py Records each MMA operand’s dtype.
platform/​python/​rocke/​helpers/​tiling/​README.md Updates the introductory example to IR dtypes.
platform/​python/​rocke/​helpers/​tiling/​mma/​plan.py Resolves typed plans and recorded backend operations.
platform/​python/​rocke/​helpers/​tiling/​mma/​mma_operation.py Exposes operand and result dtypes.
platform/​python/​rocke/​helpers/​tiling/​mma/​driver.py Feeds storage registers and handles distinct result types.
platform/​python/​rocke/​helpers/​tiling/​memory.py Clarifies storage-unit vector-width documentation.
platform/​python/​rocke/​helpers/​tiling/​lds_conflict.py Updates width handling and rejects packed byte-address analysis.
platform/​python/​rocke/​helpers/​tiling/​layout_optimizer.py Requires canonical references for partner K validation.
platform/​python/​rocke/​helpers/​tiling/​kernels/​tiling_gemm_interleaved_demo.py Migrates the GEMM demo to IR dtypes.
platform/​python/​rocke/​helpers/​tiling/​kernels/​tiling_gemm_crc_demo/​crc_interleaved_gemm.py Migrates both operand-order paths to IR dtypes.
platform/​python/​rocke/​helpers/​tiling/​fragments.py Defines and validates dtype-specific fragment storage.
platform/​python/​rocke/​helpers/​tiling/​docs/​visualization_api_surface.md Clarifies visualization dtype sources.
platform/​python/​rocke/​helpers/​tiling/​docs/​tiling_interleaving_design.md Documents canonical K coupling and optimizer arguments.
platform/​python/​rocke/​helpers/​tiling/​docs/​tiling_api_surface.md Documents storage types, typed MMA calls, and pinning.
platform/​python/​rocke/​helpers/​tiling/​docs/​mma_is_machinery.md Explains mixed-width and repeated-M-block coupling.
platform/​python/​rocke/​helpers/​tiling/​docs/​api_proposals/​PROPOSAL_c_transpose_crossed_ab.md Updates proposal examples to IR dtypes.
platform/​python/​rocke/​helpers/​tiling/​analysis/​soundness.py Clarifies canonical coupling in soundness documentation.
platform/​python/​rocke/​helpers/​tiling/​analysis/​geometry.py Derives element widths from dtype metadata.
platform/​python/​rocke/​helpers/​tiling/​.claude/​skills/​layout-viz/​SKILL.md Updates visualization and pairing API guidance.
platform/​dsl_docs/​optimization/​arch/​gfx942.md Documents TF32 truncation and pre-conversion.

Review effort: Balanced

@cgmillette
cgmillette force-pushed the users/cgmillette/rocke/mma-catalog branch from c20aad0 to 59ac8e1 Compare October 28, 2026 23:06
@cgmillette
cgmillette requested review from a team as code owners October 28, 2026 23:07
@cgmillette
cgmillette force-pushed the users/cgmillette/rocke/tiling-dtypes branch from 8d461df to 2660d12 Compare October 28, 2026 23:09
@cgmillette

Copy link
Copy Markdown
Contributor Author

Automated review: Model - qwen3.6:35b-a3b-coding-mtp-q4_K_M, effort: max

PR #14537 — IR dtypes in TileMma, a storage type under every Fragment, and MMA issue from the measured backend coverage (cgmillette, AICK-2576) — 🟠 First-round: not merge-ready — the stack must rebase onto develop (11 conflicting files, ABI 5); this PR's own commits hold up at IR level, apart from an fp6 index overflow

Prior item Status
Scope 🟢 Stacked on #14329 (59ac8e1d, unchanged since our 10-29 review), which is stacked on #14328. This review covers the last seven commits (2489ce16…2660d124), as the description asks
Copilot (10-28) ×3: tf32/packed transform_fragment breaks; u8 multi-instruction tiles fail in _read_subvector; load_backend_coverage() is reread on every emit_op 🟢 FIXED — 2489ce16: identity transforms of filled tf32, u8, fp4 and fp6 fragments keep their storage type (ran: probe). fedd3309: u8 is sliced through i8, and u8×i8 gfx1250 tiles of 2, 4 and 8 instructions issue every WMMA with A unsigned and B signed (ran: probe). ea56555f: committed_backend_coverage() is cached, and 5 emit_op calls load the record once (ran). Threads still unresolved
Copilot (10-28): the mixed-width K-pairing test checks no numerics 🟡 DEFERRED — the two exact-product GPU tests exist, but each carries an unconditional @pytest.mark.skip (test_mma_k_coupling.py:287, :294). Author: "Neither has run on hardware yet". Deferring the hardware run is acceptable, but the skip goes further than that: the tests already skip off-target, so it only stops a gfx950 or gfx1250 runner from running them, and the module docstring and commit message still say they run there → drop the skip, or correct the text
CongMa13 (10-29): reply on and resolve the four Copilot threads 🟡 OPEN, housekeeping — the author had already replied to all four on 10-28; the threads were still unresolved at 10-29 15:30 UTC → resolve the three fixed ones (read)
Merge with develop 🟠 Rebase needed — against 470e78bc (33 behind, 30 ahead) the head conflicts in 11 files, 21 hunks: arch/data.cpp, lower_llvm/{data,mma}.cpp, abi.h, arch_specs.json, isa/backend.py, lower_llvm.py, backend_details.md, the representative golden, and gen_arch_domain.py with its test (ran: merge-tree). All 11 come from #14328: its head ed900bfe alone gives the same set, and this PR's 51 files touch none of them. Develop's side is #14415 (LLVM24 lane), #13936 (split-K wgrad) and #14394, plus golden entries from #13889, #14385 and #14392 (ran)
ABI (stack) 🟠 Both sides only append. Develop's ABI 4 (#13936) appends has_global_float_atomic_add to rocke_memory_caps_t. The stack's ABI 4 (#14328 73928afc) appends dst_dtype to rocke_mma_op_t and a trailing dst_dtype to four catalog calls. Only the abi.h comment conflicts: the merge keeps ROCKE_ABI_VERSION 4, and portable_ir/src/abi.py auto-merges BINARY_ABI = 4, so two layouts would share one number → the rebase must take 5 in both files. Develop's data.cpp now makes an omitted field a compile error, so #14328's positional target rows need the new flag (ran)
Bots / CI 🟠 Inherited, not this PR — at 2660d124, TheRock Multi-Arch is red only on Windows gfx110X. Each shard fails 1 of 114 ctests, rocke_tiling_pytest, on one test: develop's test_the_range_marker_is_stated_only_by_its_checked_callers (#13876) parses every source with read_text(), which decodes cp1252 on Windows, and stops at examples/gfx950/qwen3_30b_a3b_decode.py (byte 0x90 at offset 11340). The lane is #14329's 59ac8e1d; neither the test nor that file changes in the stack (ran: a cp1252 replay matches CI's file, byte and offset; with a cp1252 default the test fails the same way on head and on develop). Already raised on #14329 (our 10-29 N1). gfx94X passes both shards (the lane: 2,440 passed); the new tests' 360 compile-and-link steps skip in the installed tree, after their IR asserts. The hipDNN superbuilds pass; no gfx950 or gfx125X tests ran (read)
Our checks 🟢
• IR (ran: base 59ac8e1d vs head): f16, bf16 and f32 tiles on gfx90a, gfx942 and gfx950, including a runtime-clipped window and an LDS round trip, emit identical rocke and LLVM IR, and the f16 demo snapshots pass in CI. i8 and fp8 tiles change as commit 7 intends (fp8 32x32x32: 32 global loads → 4). Nothing outside the tiling package uses TileMma, so no shipped kernel moves (read).
• Issue (ran): all 120 selectable-signedness variants (six gfx11, gfx12 and gfx1250 WMMAs) set the A/B sign flags from the author's dtypes. d=BF16 on gfx1250 drives a 2×2 grid and refuses two K steps. fp8×bf8 on gfx942 issues 8 MFMAs, and F32 and TF32 fragments both feed mfma.f32.16x16x8.xf32.
• K coupling (ran): all 48 mixed-width canonical pairs (gfx950 MFMA, gfx1250 WMMA) pass, and B loaded with A's register map is refused in all 36 cases where the two maps differ.
• Build, byte identity and goldens were not run: there is no merged tree until #14328 is rebased. Rules 1–3 clean (ran)
# Sev file:line Finding
N1 🟠 helpers/tiling/emit.py:79-81 The fp6 word index overflows i32. _unit_index turns the tensor-wide element index of a global access into a word index as idx * 3 / 16 (mul nsw i32 …, 3, then sdiv …, 16; ran: IR probe of an fp6 operand load). Past about 716 M elements (about 537 MB of fp6) the product wraps (poison in IR), so loads and stores of a large fp6 tensor hit the wrong words, while every other dtype keeps the full i32 element range (fp4 and i4 only divide) → compute (idx / 16) * 3, which is exact because packed runs start on 16-element groups, and test a large row offset
N2 🟡 helpers/tiling/emit.py:941, core/lower_llvm.py:3964 fp8/bf8 LDS reads claim twice their alignment. Commit 7 sends 8-bit runs through smem_load_vN, whose lowering sizes fp8/bf8 at 2 bytes (mirrored in C++ mem.cpp:697 for byte identity). Every <8 x i8> read therefore says align 16, while the matching LDS store says align 8, and half the lanes of a gfx942 fp8 32x32x16 operand start at 8 mod 16 (ran: probe). The false claim is UB and can let the backend merge neighbouring reads into a misaligned ds_read_b128 → read 8-bit runs as I8: the same <N x i8> load, at the right alignment

Utility: 🟢 Positive — typed, storage-backed fragments and record-driven MMA issue; IR-verified, hardware numerics pending.


Legend: 🔴 blocking · 🟠 should-fix · 🟡 minor nit · 🟢 info/good · ⚪ retracted

First-round review: a local qwen3.6 model made the independent first pass. The orchestrator (Claude Opus 5.5) verified it. The checks were a merge-tree against develop, with each conflict and both ABI changes traced to their PRs, and the CI logs at head, with a cp1252 replay and single-test runs of the failing test on head and develop. They also included IR probes against the base 59ac8e1d and CPU probes of the storage types, operand feed, signedness, result dtype and K coupling. Build, byte identity and goldens were not run: the stack does not merge with develop until #14328 is rebased. The orchestrator owns this merge-worthiness call. It flags whether a closer look is needed; it is not an approval or a rejection.

@cgmillette

Copy link
Copy Markdown
Contributor Author

Restacked on the new #14329 head (a5e14fd8541), which sits on the rebased #14328. The 11 conflicting
files the review traced to #14328 are resolved there, including the binary ABI: develop keeps 4 and
#14328 takes 5. The seven commits are otherwise unchanged, apart from the fix below.

Automated review 10-29

# Item What happened
N1 The fp6 word index overflows i32 Fixed in "feat(rocke): hold Fragment registers in the storage type of their dtype". _unit_index now divides the element index by the elements of one whole-word group before it multiplies by that group's words, so for fp6 it computes (idx / 16) * 3. This is exact because every packed access starts on a whole group, and it stays in the i32 range wherever the element index does. fp4 and i4 were already division only. New test: the word index of the largest whole-group element index i32 can hold, evaluated in i32 arithmetic, for fp6, fp4 and i4. It fails for fp6 without the fix.
N2 fp8/bf8 LDS reads claim twice their alignment Confirmed: smem_load_vN sizes fp8 and bf8 elements at 2 bytes, so an <8 x i8> LDS read claims align 16 while its store claims 8. This comes from core's element-size table, which other fp8 LDS readers share too (the fp8 attention kernels). #13944 fixes that table for every caller (fp8 and bf8 at 1 byte). We did not add a tiling-only workaround that would become dead code once #13944 lands. #13944's table gives fp8 and bf8 1 byte, so an 8-element read claims 8 once it lands (not yet run against this branch).
-- The two exact-product GPU tests carry an unconditional skip The fp8 x fp4 test has now run and passed on gfx950 hardware (MI355X, 2026-10-30), so its skip is removed in this update. The gfx1250 test stays disabled until it can run on gfx1250 hardware.
-- CongMa13 (10-29): reply to and resolve the four Copilot threads All four have replies from 10-28. The three fixed threads can be resolved.

Checks (head 423dae4762e; the only change since 0f82ca4c58c is the removed gfx950 skip, and the k-coupling test file passes)

  • Every commit passes ctest and its own tests with both engines in strict mode (run before the last
    restack; the commits have not changed since, apart from formatting).
  • Byte identity: GREEN at llvm20, llvm22 and llvm23. ctest 43 / 43. The portable-IR tests: 193 passed.
    pre-commit is clean.
  • The touched tests with both engines in strict mode: 1334 passed. The full platform suite: 9171
    passed, 0 failed. The other platform test files and the library smoke: no new failure against the base.
  • The representative-IR golden is OK at all four lanes. The differential golden (ll and canonical) is
    OK, with 0 unblessed changes.

@cgmillette

Copy link
Copy Markdown
Contributor Author

Automated review: Model - qwen3.6:35b-a3b-coding-mtp-q4_K_M, effort: max

PR #14537 — IR dtypes in TileMma, a storage type under every Fragment, and MMA issue from the measured backend coverage (cgmillette, AICK-2576) — 🟢 Follow-up: fp6 overflow fixed, CI pending

Prior item Status
Scope: last seven commits, restacked on #14329 a5e14fd8 🟢 Reviewed 33373c18…423dae47
• vs 2660d124: commits 2–5 and 7 identical (ran: range-diff)
• commit 1: fp6 index fix + test; commit 6: gfx950 skip dropped
Copilot (10-28) ×3: tf32/packed transform_fragment; u8 multi-instruction tiles; coverage reloaded per emit_op 🟢 FIXED 33373c18, dfad6cbe, 68719fd8
• transform_fragment keeps tf32, u8, fp4, fp6 storage: 4 ✓ (ran)
• u8 slicing, cached coverage: commits unchanged since 10-29 (ran: range-diff)
• threads unresolved (read)
Copilot (10-28): mixed-width K pairing has no numeric check (test_mma_k_coupling.py) 🟡 DEFERRED, half done 088c343e
• gfx950 test unskipped; author reports a gfx950 pass (read)
• gfx1250 skip kept (:293) "until it can run on gfx1250 hardware": acceptable
• docstring :13-16, comment :296, commit 6 still say it runs → fix the text
CongMa13 (10-29): reply on and resolve the four Copilot threads 🟡 OPEN, housekeeping
• all four have replies from 10-28 (read)
• 4 of 4 unresolved at 15:13 UTC → cgmillette resolves the three fixed (read)
Our 10-29 N1 🟠: fp6 word index overflows i32 🟢 FIXED 33373c18
• (idx / 16) * 3 at emit.py:79-80: sdiv by 16, then mul by 3 (ran: IR probe)
• word-index test at the i32 limit, fp6/fp4/i4: 3 ✓ (ran)
• all four _unit_index callers use it (read)
Our 10-29 N2 🟡: fp8/bf8 LDS reads claim align 16 (emit.py:940, lower_llvm.py:3776) 🟡 DEFERRED
• still <8 x i8> reads at align 16, stores at align 8 (ran: probe)
• author defers to #13944's shared size table, fp8 at 1 byte: acceptable (read)
• #13944 open, blocked → re-probe once it lands
Our 10-29: merge with develop, 11 conflicting files 🟡 OPEN, inherited from #14328
• 10 of the 11 now merge (ran: merge-tree)
• left: golden, tests/CMakeLists.txt (#14494) → #14328, then restack
• this PR's diff touches neither (ran)
Our 10-29: ABI (stack) must take 5 🟡 Coordination only
• #14328 9a72c774: 5 in abi.h and abi.py; develop 4 (ran)
• lane order: #14706 5, #14616 6, this stack 7 (read)
• this PR's diff touches no ABI file (ran)
Bots / CI 🟡 Running
• Windows gfx110X tiling lane not run yet: inherited cp1252 fix unproven
• queued: gfx94X, gfx110X sanity; 28 ✓; gfx950/gfx125X tests skipped
• merge: clean into #14329's branch; auto-merge off
Our checks 🟡 Conflicts, inherited
• merge vs b33ff848 (18 behind / 30 ahead): 2 files, 7 hunks (ran)
• build, ctest, byte identity, goldens: skipped, no merged tree; no core/C++ files (ran)
• test_fragment_storage 50 ✓ / 9 skip (gfx90a only); rules 1–3 clean (ran)

Net-new: none.

Utility: 🟢 Positive — typed, storage-backed fragments and record-driven MMA issue; fp6 fix verified.


Legend: 🔴 blocking · 🟠 should-fix · 🟡 minor nit · 🟢 info/good · ⚪ retracted

Follow-up review: first pass by a local qwen3.6 model, verified by the orchestrator (Claude Opus 5.5). Checks: range-diff since our review, merge-trees against develop, an IR probe of our N1/N2, test_fragment_storage, CI at head. Flags whether a closer look is needed; not an approval or rejection.

cgmillette and others added 7 commits October 31, 2026 04:18
A Fragment's dtype is the logical number format; its value now holds the
registers in Fragment.storage_type, derived from the dtype: the logical
vector for every arithmetic dtype, i32 for tf32, and whole i32 words for a
packed sub-byte dtype (fp4, fp6, i4), packed low bit first by
core.storage.register_packing. A value of another type is refused; a
logical tf32 vector names the bitcast to i32 that fixes it, and a packed
fragment names the verbs that build its words.

load_fragment, store_fragment and fill_fragment move storage units, in
global memory and LDS. Element and unit widths come from
core.dtypes.dtype_info, replacing the byte-width table. For every
byte-or-wider dtype a unit is an element, so their IR is unchanged. A
packed access moves whole 32-bit words: each lane's registers must form
whole-word runs along the tensor's stride-1 axis, starting on a word
boundary, and a clipped packed window must be bounded on whole words; a
clipped global tile masks one whole-word group at a time. A packed LDS
buffer holds i32 words, sized from the descriptor; any other buffer, and
an LDS swizzle of packed data, is refused. A packed access's word index is
its element index divided by the elements of one whole-word group, then
multiplied by that group's words, so it is exact and stays in the i32
range wherever the element index does.

A u8 fragment is held as vec<u8 x n> and stores like any byte dtype.
fill_fragment and load_fragment refuse it, because they start from a zero
vector of the storage type and core's zero_vec has no u8 form; the message
names the route that works: an I8 fragment whose value is bitcast to
vec<u8 x n>.

transform_fragment reorders the storage registers: the elements of a
byte-or-wider dtype (i32 for tf32; a u8 fragment through the i8 registers
of the same bits) and the words of a packed fragment. A packed reorder
must move whole word groups, the fewest elements that fill whole words,
in order onto another group; one that would move elements within a word
is refused, since repacking bits is not implemented.

The byte-addressed views (the LDS bank model) refuse a sub-byte dtype
instead of mis-sizing it.

Tests cover the storage table, every refusal and its message, the word
index of the largest whole-group element index i32 holds, in i32
arithmetic,
transform_fragment on tf32, u8, fp4 and fp6 fragments, and on gfx90a
bit-exact round trips of a tf32 tile through LDS, of fp4, fp6 and i4
operand tiles in gfx950's canonical f8f6f4 layout through global memory
and an i32 LDS buffer, checking the loaded words against
FragmentPacking.pack, plus a clipped packed window, and of tf32, u8 and
fp4 tiles moved to another register order by transform_fragment.

Co-Authored-By: Claude <noreply@anthropic.com>
TileMma, TileMmaPlan and MmaTraitsCatalog.select take their dtypes as
scalar IR types from rocke.core.ir (F16, F32, FP8E4M3, ...) instead of
strings. A string, or a composite type such as a vector, is refused with
the constant to pass, e.g. "a= must be a scalar IR type such as
rocke.core.ir.F16, not the string 'f16' -- pass rocke.core.ir.F16".

A new d= names the result dtype; omitted, it equals the accumulator c,
as for every accumulate-in-place instruction. Selection keys on it, so
it tells apart two instructions that differ only in their result dtype.
The plan and TileMma expose a_dtype, b_dtype, c_dtype and d_dtype as IR
types; atom_override derives them from the row through the new
MmaTraits.ir_dtypes(). The driver compares fragment dtypes with them
directly.

When no instruction matches, select names the query and lists what the
target offers in IR type names, e.g. "no MMA instruction found for
a=f16, b=f16, c=f32, shape=(13, 16, 16), family='dense', target='gfx90a'
-- available on 'gfx90a' (a x b -> c, MxNxK): ['f16 x f16 -> f32,
16x16x16', ...]".

MmaTee.from_mma labels its inputs and result from the MMA's IR dtypes;
mma_input_label is the one home of the input label ("f16", or
"fp8e4m3/bf8e5m2" when A and B differ). Labels and widths are
unchanged.

Every call site, example and doc in the tiling package passes IR types.
New tests cover the refusals (including the constant name of every
scalar IR type), the derived and default dtypes, selection by IR types,
that gfx950 has no tf32 instruction, the fp8 and bf8 wave tiles lowering
to one MFMA per atom on gfx942, and the tee's widths and labels.

Co-Authored-By: Claude <noreply@anthropic.com>
…A/B dtypes

TileMma(atom_override=...) is the one way to pin an instruction by name.
Its a/b/c/d are now optional checks rather than ignored: each dtype given
must be one the instruction takes (for an integer row with selectable
signedness that includes the unsigned twin, kept as given), and each one
left out is taken from the instruction, the result dtype included. A
mismatch names every wrong dtype and the constant to pass, e.g. "MMA
instruction dtype mismatch for 'mfma_f32_16x16x16f16' -- a=bf16 but it
takes A=f16; c=f16 but it takes C=f32 -- pass a=rocke.core.ir.F16,
c=rocke.core.ir.F32, or omit a/b/c to take them from the instruction".
An instruction the target does not list is refused as "MMA instruction
not available on target".

Tiling(atom_shape=...) takes only an (M, N, K) shape; an instruction name
there is refused with the atom_override call to make instead. Without a
pinned instruction, a/b/c are required.

A and B may now differ: selection finds a mixed instruction such as the
gfx942 fp8 x bf8 MFMA, and a pair with no instruction fails with the
usual "no MMA instruction found".

The recorder stores the MMA's A and B dtypes on its op, and the compute
and epilogue views read operand widths and the input label from there
instead of from an LDS read, so a mixed MMA is drawn with each operand at
its own width and labelled "fp8e4m3/bf8e5m2". The docs show the
atom_override forms and the mixed example.

Tests cover the derived and checked dtypes, the mismatch, wrong-target
and Tiling-name refusals, mixed and integer selection, the recorded
dtypes, the views refusing an op without them, and a recorded fp8 x bf8
MMA's compute tee.

Co-Authored-By: Claude <noreply@anthropic.com>
…age says

TileMmaPlan.emit_op() now returns the backend op the backend coverage
record names for the plan's (instruction, target) pair, fetched from
core by that op id instead of searched for by operand dtypes and shape,
which several backend ops can share. A pair the record does not class
issuable raises NotImplementedError naming its class. An integer
instruction with selectable operand signedness passes the plan's A and
B dtypes, so u8 operands issue the unsigned op; a scaled instruction
takes scale_format=, which the record requires when it holds more than
one scale format. TileMma.emit_op() forwards scale_format. emit_op reads
the committed record through committed_backend_coverage, which loads and
validates it once per process; load_backend_coverage still reads a given
path on every call.

The driver checks, before any IR and in this order: operand dtypes;
that the instruction's family is one it feeds (dense; a scaled or
sparse instruction raises NotImplementedError); that an instruction
whose result dtype differs from its accumulator takes one instruction
along K per C subtile; that rocke issues the instruction; then the
layout validation. Its result Fragment is typed by the instruction's
result dtype, and the grid walk assembles a result of another dtype
into a zero vector of that dtype's storage type. The plan no longer
refuses such an instruction, so TileMma(..., d=BF16) on gfx1250 and
atom_override="wmma_bf16f32_16x16x32_bf16" now drive it.

Tests: emit_op of every issuable record entry, per variant, returns the
recorded op; emit_op loads the committed record once; the refusals and their texts; the dense op chosen where
scaled ops share its operands; the bf16-result tiles; WMMA, gfx11
16-bit-result, fp8 x bf8 and f32 16x16x4 tiles lower to their
intrinsics, compiled where the host clang targets the arch. The traits
README and the API surface doc say how issue follows the record.

Co-Authored-By: Claude <noreply@anthropic.com>
The TileMma driver now slices each instruction's A and B operand out of
the fragment's storage registers and hands b.mma the vector type the
instruction's A or B dtype takes (mma_io.mma_operand_ir_type),
bitcasting only when the two differ. A packed sub-byte operand is sliced
as the whole 32-bit words that hold its elements (packed_word_range); a
TF32 operand held as i32 is reinterpreted as tf32. A u8 operand is sliced
as the i8 registers of the same bits, since core's zero_vec has no u8
form, and handed over as u8. Every other dtype is sliced and passed
exactly as before, so its IR is unchanged.

A TF32 instruction also reads F32 fragments, dropping their low mantissa
bits (_MMA_TRUNCATING_SOURCES), so F32 tensors feed xf32 MFMAs with no
conversion. The operand dtype error names that accepted source.

Docs: the TileMma section states the operand feed and TF32 rule and how
a hand-written b.mma call passes operands; the gfx942 arch doc's atom
catalog gains the note on when to convert to TF32 first (round to
nearest even instead of truncation).

Tests: xf32 tiles on gfx942 from F32 and from TF32 tensors issue one
MFMA per atom and compile; an f16 fragment on a TF32 plan is refused;
a two-instruction gfx950 fp4 tile feeds words [0, 4) and [4, 8) to the
f8f6f4 instruction and compiles; u8 x i8 gfx1250 tiles of two K steps,
four C subtiles and both issue every instruction with a u8 A operand.

Co-Authored-By: Claude <noreply@anthropic.com>
The K check compared A and B slot for slot. That is how every same-format
MMA instruction pairs its operands, but not a mixed-width f8f6f4 one: its
8-bit operand holds K in two runs of 16 per lane and its 6/4-bit operand in
one run of 32. The slot rule therefore refused the canonical fp8 x fp4
pair and accepted an fp4 B loaded with fp8's map, which multiplies the
wrong K.

mma_pair_k_aligned now takes the instruction's canonical A and B layouts as
required arguments. It reads from them which A and B positions hold the
same hardware K, moves B's K labels into A's slot order through that
coupling and runs the unchanged three-tier comparison. For a same-format
instruction the coupling is the identity, so every result and message
stays as it was. mma_pair_compatible forwards its canonicals, so the
driver's issue check, verify_mma_soundness and the MmaTee diagnostic all
pair K through the coupling. The MmaTee diagnostic moves into
MmaTee.pairing_diagnostic() with one branch: a tee without canonicals has
no coupling and judges no pairing. evaluate_transform and optimize_layout
take k_partner_canon and refuse a k_partner without both canonicals.

An instruction whose lane holds several M blocks of A multiplies each block
with the same B registers. The coupling pairs every M block of A with the
lane's one B column through K, and the driver's atom-contiguity check
takes such a lane's atom block as that many runs of one M row each, all in
one K step. A whole wave tile compared with too few atoms, whose B lane
holds several columns, still gets no coupling.

The interleaved construction lays A and B out with one K map, so the dense
interleave sweep now proves its mixed-width f8f6f4 pairs K-misaligned
instead of passing them.

Tests: the mixed-width cases on gfx950 16x16x128 canonicals through both
checks; a driven gfx950 fp8 x fp4 tile that issues and compiles; the
soundness gate on a recorded fp8 x fp4 pipeline; the MmaTee diagnostic; the
optimizer refusal; and one test that drives every pair the backend coverage
record issues for a dense instruction (each operand-dtype variant,
unsigned ones included) and checks the tile lowers to the instruction's
intrinsic and returns the instruction's result dtype, the instruction
whose lane holds two M blocks of A included. For that instruction: the
canonical pair passes both checks, a K mismatch on the second M block alone
fails them, and a tile of two atoms along M, N and K issues all eight.
Where the current GPU is the target, the driven gfx950 fp8 x fp4 tile and
that gfx1250 tile also run on random K-dependent operands and must equal
an independent numpy product exactly; elsewhere they skip.

Docs: mma_is_machinery.md condition 3 (with the coupling of several M
blocks), its consequences and trap 1; the interleaving design, the
layout-viz skill and the API design standard show the new signatures.

Co-Authored-By: Claude <noreply@anthropic.com>
… stores

Add fp8e4m3, bf8e5m2 and i8 to the storage elements the tiling memory
verbs move with vector accesses. A register run of these 8-bit types that
is contiguous along the tensor's stride-1 axis is now read from global
memory, read from LDS and written to LDS as one <N x i8> access instead of
one byte at a time; the comment on the set names those three users.

Tests: an fp8 or bf8 32x32x64 wave tile loads its operands as eight
8-byte global loads with no single-byte load, and an fp8, bf8 or i8
fragment staged through an LDS buffer uses only vector LDS loads and
stores and compiles for gfx942 (compile-verified, not run).

Co-Authored-By: Claude <noreply@anthropic.com>
@cgmillette
cgmillette force-pushed the users/cgmillette/rocke/mma-catalog branch from a5e14fd to 0d432f2 Compare October 31, 2026 11:18
@cgmillette
cgmillette force-pushed the users/cgmillette/rocke/tiling-dtypes branch from 423dae4 to ec941cd Compare October 31, 2026 11:18
@cgmillette

Copy link
Copy Markdown
Contributor Author

Restacked on the new #14329 head (0d432f26abf, which sits on #14328 rebased onto develop 7cd54ff9cd7); head ec941cded35. The seven commits applied without conflict and are unchanged. This PR touches no ABI number, golden or arch-domain cell. Checks at the head: every commit passes ctest and its own tests with both engines in strict mode, and ruff reports nothing new against each commit's parent. Byte identity is GREEN at llvm20, llvm22, llvm23 and llvm24. ctest passes 45/45 and portable IR 196. Touched tests: 1334 passed in strict mode. The full platform suite has 9353 passed and 0 failed. The representative-IR and differential goldens are OK. The other platform test files and the library smoke show no new failure against the base; test_binding_compiler_selection fails on develop too. The branch merges cleanly with develop.

@cgmillette

Copy link
Copy Markdown
Contributor Author

Automated review: Model - qwen3.6:35b-a3b-coding-mtp-q4_K_M, effort: max

PR #14537 — IR dtypes in TileMma, a storage type under every Fragment, and MMA issue from the measured backend coverage (cgmillette, AICK-2576) — 🟡 Follow-up: restack exact, base conflicts again

Prior item Status
Scope: last seven commits, restacked on 14329 0d432f26 🟢 Reviewed 28816932…ec941cde
• vs 423dae47: all 7 commits identical, same patch-id (ran: range-diff)
• only the base moved: 14328 rebased onto develop 7cd54ff9
Copilot (10-28) ×3: tf32/packed transform_fragment; u8 multi-instruction tiles; coverage reloaded per emit_op 🟢 FIXED 28816932, 7d2414ce, ab9d8ad4
• tf32/u8/fp4/fp6 keep storage; u8×i8 gfx1250 tiles of 2/4/8 WMMAs compile: 7 ✓ (ran)
• record loads once per process: 1 ✓ (ran)
• threads still unresolved (read)
Copilot (10-28): mixed-width K pairing has no numeric check 🟡 DEFERRED, half done 4476e074
• gfx950 test target-gated; author reports a gfx950 pass (read)
• gfx1250 skip kept (:293) until hardware: acceptable
• docstring :14-16, comment :296, commit 6 still say it runs → fix the text (read)
CongMa13 (10-29): reply on and resolve the four Copilot threads 🟡 OPEN, housekeeping
• all four answered 10-28 (read)
• 4 of 4 unresolved → cgmillette resolves the three fixed (read)
Our 10-29 N1 🟠: fp6 word index overflows i32 🟢 FIXED 28816932
• sdiv by 16, then mul by 3 (ran: IR probe)
• word-index test at the i32 limit, fp6/fp4/i4: 3 ✓ (ran)
Our 10-29 N2 🟡: fp8/bf8 LDS reads claim align 16 (emit.py:940, lower_llvm.py:3830) 🟡 DEFERRED
• <8 x i8> reads still align 16, stores align 8 (ran: probe)
• 13944 still open and conflicting → re-probe once it lands
Our 10-29: merge with develop 🟡 OPEN, inherited from 14328
• since 14692 (11:35Z): lower_llvm.py, data.cpp, lower_llvm_internal.h conflict (ran)
• 14328 alone gives the same 3; this PR touches none (ran) → 14328 fixes, then restack
• no llvm24 data of its own; CI never compiles its pairs → recheck at llvm24 after restack
Our 10-29: ABI (stack) 🟡 Coordination only
• this PR touches no ABI file (ran)
• develop is 6; takes develop + 1 when it lands
Bots / CI 🟢 Green, complete
• tiling lane ✓ on all 4 shards, Windows gfx110X included (read: logs)
• ctests per shard: Linux gfx94X 56 ✓ / 5 skip, Windows 108 ✓ / 7 skip
• 41 ✓, 0 ✗; merge: clean into the base branch
Our checks 🟡 Inherited conflicts
• merge vs 37e8aeb8: 3 conflicts, all the base's; not built, no core/C++ here (ran)
• head: 40 test files incl. the PR's 21: 3061 ✓ / 194 skip (ran)
• issuable pairs compiled at llvm24: 340 ✓; catalog checker 21 ✓; rules 1–3 clean (ran)

Net-new: none.

Utility: 🟢 Positive — typed, storage-backed fragments and record-driven MMA issue; commits unchanged, CI green.


Legend: 🔴 blocking · 🟠 should-fix · 🟡 minor nit · 🟢 info/good · ⚪ retracted

Follow-up review: first pass by a local qwen3.6 model, verified by the orchestrator (Claude Opus 5.5). Checks: range-diff since our review, merge-trees of head, base and 14328 against develop, tests at head (Copilot items, issuable pairs with compile, catalog checker), an IR probe of our N1/N2, CI logs at head. Flags whether a closer look is needed; not an approval or rejection.

@cgmillette
cgmillette merged commit 385f5f0 into users/cgmillette/rocke/mma-catalog Oct 31, 2026
92 checks passed
@cgmillette
cgmillette deleted the users/cgmillette/rocke/tiling-dtypes branch October 31, 2026 22:54
shumway pushed a commit that referenced this pull request Nov 2, 2026
…R dtypes through the tiling layer (#14329)

## Motivation

The tiling layer's MMA catalog
(`helpers/tiling/traits/data/mma_traits.json`) is the table the tiling
layer selects MMA instructions from and lays out their registers with.
It had three problems:
- **Rows clashed.** Rows were keyed by `op_id`, so the multi-format
f8f6f4 builtins loaded "last one wins".
- **Operand types were name tokens** (`fp8bf8`, `iu8`, ...), some of
them wrong, instead of real dtypes.
- **Layouts disagreed with themselves.** Many rows stored two register
layouts that did not match each other, or that described a K order the
hardware does not use.

On top of the catalog, the tiling layer named MMA dtypes with strings,
held every Fragment in its logical vector type, and found the backend
instruction by searching on dtypes and shape, which could pick a
different instruction from the catalog row it had selected. As a result:
- sub-byte (fp4, fp6, i4) and tf32 operands could not be moved or fed;
- mixed A/B dtypes were refused;
- integer rows with selectable signedness issued the signed instruction
for unsigned data;
- a row whose result dtype differs from its accumulator could not be
issued correctly.

This PR does both halves:
- **Catalog.** Each row describes one instruction variant exactly, with
one hardware-exact layout, real dtypes, and real targets and intrinsics.
It adds a compiler cross-check tool for the catalog, the unscaled gfx950
f8f6f4 MFMA rows, and a committed record of which rows rocke's backend
issues. CTest runs the tiling package's tests.
- **Dtypes.** The tiling layer speaks IR dtypes end to end. Every
Fragment gets a storage type under its logical dtype, and every MMA
instruction is issued as the measured backend coverage record says.

**Stacked on #14328** (backend completeness); review only the last
fourteen commits. The dtypes half (commits 8 to 14) came from #14537 and
is now part of this one.

## Technical Details

### Catalog (commits 1 to 7)

1. **`fix(rocke): describe one MMA instruction variant per catalog
row`**
   - Catalog schema version 2:
- per-operand dtypes `a_dtype`, `b_dtype`, `c_dtype` and `d_dtype`, in
canonical `core.dtypes` names;
     - integer operand signedness, stated as selectable or signed;
     - one row per (A format, B format) for each f8f6f4 builtin;
     - integer dims and one `layout_params` object;
     - a scale contract on scaled rows;
     - the index layout on sparse rows;
     - `auto_select: false` on pin-only rows.
- The loader is strict: any malformed row fails with a message naming
the row. A dtype must be one `core.dtypes.dtype_info` knows, spelled by
its canonical name, so an alias, a typo or a retired token (`iu8`)
fails.
- `select()` takes `a=`, `b=`, `c=`, an optional `d=`, and
`scale_block_k=`. The selection key is (target, family, A, B, C, D,
shape, scale block size).
- `TileMma` refuses a row whose result dtype differs from its
accumulator dtype; commit 11 lifts this.
   - Multi-block rows now load. The encoder refuses them by name.
2. **`fix(rocke): store hardware-exact register layouts for every MMA
catalog row`**
   - Each row stores one layout, the same in both of its forms.
- The values follow the independent arbiter where one exists: the public
Matrix Instruction Calculator, the public CDNA4 ISA tables, or rocKE
core's lane maps. Otherwise they follow Composable Kernel's parameters.
3. **`fix(rocke): list the real gfx targets and LLVM intrinsic of every
MMA instruction`**
- Every row lists real target ids, never family names, and every listed
target is a backend target.
   - Every row names its LLVM intrinsic.
   - Targets that are excluded are recorded with a reason.
4. **`feat(rocke): add a compiler cross-check tool for the MMA
catalog`**
- `tools/check_mma_catalog.py` asks the installed clang four questions
about the catalog: on which targets each row's builtin compiles and
links, which LLVM intrinsic it lowers to, which scale formats a scaled
builtin accepts, and whether every matrix builtin that compiles on a
backend target has a row.
- It exits 1 on any disagreement. It names what the clang cannot judge
without failing.
- Its unit tests run no compiler and stay in the source tree. The
README's edit procedure runs the tool.
5. **`feat(rocke): add the unscaled gfx950 f8f6f4 MFMA variants to the
MMA catalog`**
- One dense row per (A format, B format) pair at 16x16x128 and 32x32x64.
They name the scaled builtin, which the compiler issues unscaled when
both scales are zero.
   - Their layouts equal their scaled twins'.
6. **`feat(rocke): record which MMA catalog instructions rocke's backend
issues`**
- `traits/data/backend_coverage.json` records one measured class and the
matched backend op for every (row, target) pair. It is read through
`load_backend_coverage()`.
- Only `issuable` means the backend issues the row's instruction there.
The other classes say why not, for example `no_backend_op`,
`other_instruction`, `multi_block`, `operand_form_words_only` or
`lane_map_differs`.
- `helpers/mma_io.mma_operand_ir_type` is the one home of the
operand-form rule.
- A test measures the record again and requires it to equal the
committed file.
7. **`test(rocke): run the tiling package's tests in CTest`**
- New CTest entry `rocke_tiling_pytest`. It runs
`rocke/tests/helpers/tiling` from the installed package. It is listed in
the quick and ffm-quick categories.
- The interleaved GEMM demo's launching tests skip unless the current
GPU is a gfx90a. This includes a host whose HIP runtime loads but sees
no device; before, they failed there.

### IR dtypes through the tiling layer (commits 8 to 14)

8. **`feat(rocke): hold Fragment registers in the storage type of their
dtype`**
- Storage per dtype: the logical vector for arithmetic dtypes, i32 for
tf32, and whole i32 words for packed sub-byte dtypes, packed low bit
first.
- Load, store and fill move storage units in global memory and LDS; a
packed access moves whole 32-bit words.
   - Refusals name the fix.
   - IR for byte-or-wider dtypes is unchanged.
9. **`feat(rocke): take IR dtypes for A, B, C and the result in
TileMma`**
- `a/b/c` and a new `d=` are scalar IR types, e.g. `rocke.core.ir.F16`;
a string is refused with the constant to pass.
   - A selection miss lists what the target offers.
- Every in-tree `TileMma` call, including the gfx942 and gfx950 target
coverage develop added to the MMA operation tests, passes IR types.
10. **`feat(rocke): pin MMA instructions by full signature and accept
mixed A/B dtypes`**
- `atom_override=` is the one way to pin a row. Its dtypes are optional
checks; any left out are taken from the row.
- Mixed A/B instructions (e.g. gfx942 fp8 x bf8) select and draw at each
operand's own width.
11. **`feat(rocke): issue MMA instructions as rocke's measured backend
coverage says`**
- `emit_op()` returns the backend op the coverage record names for the
(row, target) pair, using the author's A/B dtypes for
selectable-signedness rows and `scale_format=` for multi-format scaled
rows.
    - A pair that is not issuable raises with its class.
- The driver types its result by the row's result dtype. This lifts
commit 1's refusal of rows whose result dtype differs from the
accumulator.
12. **`feat(rocke): feed MMA operands from their fragments' storage
registers`**
- Operands are sliced from storage registers and bitcast only to the
instruction's operand form: packed words for sub-byte dtypes, i32
reinterpreted as tf32.
- F32 fragments feed xf32 MFMAs, which truncate the low mantissa bits;
the docs say when to convert to TF32 first.
13. **`fix(rocke): pair A and B K through the instruction's canonical
coupling`**
- Mixed-width f8f6f4 instructions hold K differently in A and B. The K
check now pairs positions through the instruction's canonical layouts,
so the canonical fp8 x fp4 pair is accepted and a mis-loaded operand is
refused.
    - Same-format instructions are unchanged.
14. **`feat(rocke): move fp8, bf8 and i8 fragments with vector loads and
LDS stores`**
- A contiguous register run of these 8-bit types moves as one `<N x i8>`
access instead of one byte at a time, in global memory and LDS.

No core or C++ engine file changes, and no emitted kernel IR changes, so
byte identity is unaffected.

## Test Plan

- **Catalog load:** a strict-schema test for every refusal, including an
unknown dtype name and a retired token; selection tests on every target,
including the scaled block-size key and the multi-block refusal.
- **Layouts:** a layout check for every row (the two forms agree and
match their arbiter); the interleave sweep over every dense row.
- **Targets:** every listed target is a backend target, excluded targets
never appear, and every intrinsic is an `llvm.amdgcn.*` name.
- **Cross-check tool:** unit tests that classify hand-written compiler
answers against real catalog rows.
- **Backend coverage:** the record is measured again and compared with
the committed file; operand counts, the scaled pairs, the result-dtype
pairs and the reader's errors are pinned.
- **CTest:** the tiling tree run from a fresh `cmake --install` with the
entry's command and `PYTHONPATH`, with no GPU visible.
- **Storage:** the storage table and every refusal; bit-exact GPU round
trips on gfx90a for tf32 through LDS and for fp4, fp6 and i4 in gfx950's
canonical f8f6f4 layout through global memory and LDS, including a
clipped packed window.
- **Dtypes:** IR-dtype refusals with the constant name of every scalar
type, derived and default dtypes, selection by IR type on gfx90a, gfx942
and gfx950, wrong-target pins refused on gfx90a and gfx942, mixed and
integer selection.
- **Issue:** `emit_op` of every issuable coverage-record entry, per
operand-dtype variant, returns the recorded op; every refusal text.
- **Drive:** a single-instruction TileMma for every issuable dense (row,
target) pair lowers to the row's intrinsic, compiled where the host
clang targets the arch. This covers WMMA, gfx11 16-bit result, fp8 x
bf8, xf32 from F32 and TF32, fp4 words, and bf16-result tiles.
- **K coupling:** canonical mixed pairs accepted, mis-loaded operands
refused. A numeric check of a driven gfx950 fp8 x fp4 tile runs where
the current GPU is a gfx950; the gfx1250 tile's numeric check is skipped
until it has run on gfx1250 hardware.

## Test Result

- Byte identity green at llvm20, llvm22, llvm23 and llvm24.
- Differential goldens (ll at every flavor, canonical IR) and the
representative IR golden: no change.
- ctest passes.
- Portable IR against a freshly built shared engine passes.
- The touched test files, the whole tiling test tree and the in-tree
test files develop's gfx942 and gfx950 coverage change touched pass with
both engines in strict mode.
- Full platform suite: no failures. The other platform test files: only
the ones develop also fails.
- Library smoke: no new failures.
- pre-commit passes.
- Every commit builds, passes ctest and passes its own tests on its own.

ISSUE ID : AICK-2572
ISSUE ID : AICK-2576

## Submission Checklist

- [x] Look over the contributing guidelines at
https://github.com/ROCm/TheRock/blob/main/GOVERNANCE.md#pull-requests.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude <noreply@anthropic.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.

3 participants