Skip to content

A4: shared cost-aware MMA selector (lift ROCm's model to all targets) - #309

Merged
gstoner merged 1 commit into
mainfrom
a4-shared-mma-selector
Jul 8, 2026
Merged

gstoner merged 1 commit into
mainfrom
a4-shared-mma-selector

Conversation

@gstoner

@gstoner gstoner commented Jul 8, 2026

Copy link
Copy Markdown
Owner

Workstream A4 (COMPILER_REFACTOR_PLAN): the one place a lead abstraction lifts upward. ROCm already models matrix-core selection as a cost-aware choice — a per-arch shape table ranked by the M×N // lanes accumulator footprint. NVIDIA, Apple, and x86 had no cost-aware MMA selector. This promotes ROCm's model into one lane_count-parameterized selector so every cooperative-matrix target gets the same footprint-ranked selection, keyed by (target, arch, dtype) — the shape_table/cost_model the D1 arbiter parks here (Decision #28).

compiler/mma_selector.py

  • MmaIsa — arch-neutral ISA record: mma_class, cooperative + lane_count, the legal (M,N,K) shape table, dtype→K.
  • accumulator_regs_per_lane(shape, lane_count) = M*N // lane_count — the promoted footprint, delegating to rocm_target.mfma_accumulator_regs so the arithmetic + validation stay single-sourced with the lead.
  • rank_shapes_by_footprint / cheapest_shape / select_mma → MmaSelection — the cost model + the target-neutral chosen-MMA descriptor (shape anchor + derived nt operands + per-lane footprint).
  • Per-arch ISA records: ROCm built from the live rocm_target/rocm_mma tables; NVIDIA mma.sync m16n8k{8,16,32,64} (warp 32); Apple simdgroup_matrix<8,8> (simdgroup 32); x86 AMX tile-register (honestly cooperative=False/lane_count=None).

Lead-safety (Theory rule #1)

ROCm stays the reference and cannot be silently perturbed:

  • The ROCm ISA's dtype→K is derived from rocm_mma.select_mma itself, so every feature gate — no FP8 WMMA on gfx1151, no fp32 WMMA on RDNA, fp4/xf32 gating — is inherited by construction, never re-encoded.
  • test_mma_selector.py gates that rank_shapes_by_footprint on a ROCm ISA is byte-identical to ROCm's own rank_mfma_shapes_by_footprint, and that the ISA's dtype set is exactly what rocm_mma.select_mma accepts.
  • No emit path changes — a hardware-free selector object (Decision Apple GPU Tier-2/3: reductions, native GQA, fused batched attention #19).

The lift (verified)

target dtype shape acc regs/lane
nvidia bf16/fp16 m16n8k16 4
nvidia fp8 m16n8k32 4
nvidia fp4 m16n8k64 4
apple fp16 8×8×8 2
rocm gfx1151 bf16 16×16×16 8
x86 bf16 16×16×32 (AMX) — (tile, not lane)

Verification

  • test_mma_selector.py19 tests (ROCm equivalence, cross-target selection, feature gates, error paths).
  • ruff + mypy clean; rocm_mma consumers unaffected (59 tests); generated-doc drift gate green (no dashboard changes — fully additive).

Follow-on (own PR — it touches drift-gated dashboards): wire get_isa/select_mma as backend_manifest's cross-target MMA-metadata source (today ROCm-only via _rocm_mma_descriptor_for) and as the D1 arbiter's cost_model.

🤖 Generated with Claude Code

Promote ROCm's per-arch matrix-core model into one lane-count-parameterized
selector so NVIDIA / Apple gain the cost-aware MMA selection they lacked, while
ROCm stays the byte-identical reference (COMPILER_REFACTOR_PLAN A4).

compiler/mma_selector.py:
- MmaIsa: arch-neutral ISA record (target/arch/mma_class, cooperative +
  lane_count, legal shape table, dtype->K).
- accumulator_regs_per_lane(shape, lane_count) = M*N // lane_count — the
  promoted footprint, delegating to rocm_target.mfma_accumulator_regs so the
  arithmetic + validation stay single-sourced with the lead.
- rank_shapes_by_footprint / cheapest_shape / select_mma -> MmaSelection (the
  target-neutral chosen-MMA descriptor + operands + per-lane footprint).
- Per-arch ISA records: ROCm built FROM the live rocm_target/rocm_mma tables
  (feature gates inherited by construction — no FP8 WMMA on gfx1151, no fp32
  WMMA on RDNA — never re-encoded); NVIDIA mma.sync m16n8k{8,16,32,64} (warp 32);
  Apple simdgroup_matrix<8,8> (simdgroup 32); x86 AMX as tile-register (honestly
  cooperative=False / lane_count=None, per-lane footprint N/A).

Lead-safe (Theory rule #1): no emit path changes — hardware-free selector
(Decision #19). test_mma_selector.py (19 tests) gates that the shared footprint
ranking on a ROCm ISA is byte-identical to ROCm's own rank_mfma_shapes_by_footprint,
and that the ROCm ISA's dtype set matches exactly what rocm_mma.select_mma accepts.
Cross-target selection verified: nvidia bf16/fp16->m16n8k16 (4 regs/lane), fp8->k32,
fp4->k64; apple fp16->8x8x8 (2 regs); x86 amx bf16->16x16x32 (None). ruff + mypy
clean; rocm_mma consumers unaffected (59 tests); generated-doc drift gate green.

Follow-on (own PR — touches drift-gated dashboards): wire get_isa/select_mma as
backend_manifest's cross-target MMA-metadata source + the D1 arbiter cost_model.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: eba55474bb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +265 to +266
shapes=((16, 16, 32),),
k_by_dtype={"bf16": 32, "int8": 64},

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Add the missing AMX int8 shape or stop advertising it

For get_isa("x86", "amx"), this advertises int8 in isa.dtypes with K=64, but the only AMX shape listed has K=32. As a result, select_mma(M.get_isa("x86", "amx"), "int8") always raises MmaSelectorError from cheapest_shape even though the ISA record says int8 is supported; either include the legal int8 shape or remove the dtype mapping.

Useful? React with 👍 / 👎.

Comment on lines +184 to +188
if prefer_shape not in isa.shapes:
raise MmaSelectorError(
f"prefer_shape {prefer_shape} is not legal on {isa.target}:"
f"{isa.arch} (legal: {sorted(isa.shapes)})")
shape = prefer_shape

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Validate preferred shapes against the dtype K family

When callers pass prefer_shape, this only checks that the tuple exists somewhere on the ISA, not that its K matches isa.k_by_dtype[dtype]. On multi-K ISAs this can return impossible descriptors, e.g. NVIDIA bf16 with prefer_shape=(16, 8, 32) produces a bf16 selection at K=32 even though bf16 is mapped to K=16, so downstream metadata/lowering can see an invalid dtype/shape pairing instead of the promised MmaSelectorError.

Useful? React with 👍 / 👎.

@gstoner
gstoner merged commit 41227b1 into main Jul 8, 2026
14 checks passed
@gstoner
gstoner deleted the a4-shared-mma-selector branch July 8, 2026 19:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant