Skip to content

Port GEMM/MoE/conv kernels to the layout API - #913

Draft
coderfeli wants to merge 5 commits into
mainfrom
port/layout-api-ports
Draft

Port GEMM/MoE/conv kernels to the layout API#913
coderfeli wants to merge 5 commits into
mainfrom
port/layout-api-ports

Conversation

@coderfeli

Copy link
Copy Markdown
Collaborator

Summary

Ports four GEMM / MoE / conv kernel families from manual buffer/byte-offset addressing to the FlyDSL layout API (the examples/04-preshuffle_gemm.py idiom: make_buffer_tensor + flat_divide + partition_S/D, make_composed_layout(SwizzleType) for LDS swizzle, make_tiled_mma/fx.gemm, crd2idx for swizzled offsets). Each port is cold-correct (FLYDSL_RUNTIME_ENABLE_CACHE=0) and perf-neutral (median-of-7 on gfx950, within clock noise).

moe_gemm_2stage is intentionally not in this PR (separate WIP).

Ports

  • gemm/preshuffle_gemm.pybuffer_ops removed; epilogue scale addressing on the layout API. Cold: fp8/int8/fp16/bf16/fp4/fp6/a8w8 + fused-epilogue modes + ragged-M. Perf parity (8192³ fp8 ~2237 TFLOPS, independently re-measured).
  • gemm/fp8_gemm_8wave.py + fp8_gemm_4wave.py — MMA via in-kernel make_tiled_mma; g2s + s2r LDS swizzle via prologue-hoisted crd2idx over make_composed_layout(SwizzleType(3,4,4)) (hot-loop ISA identical). Direct-DMA BufferCopyLDS + split-16@64 pack kept (repo idiom). fp8_gemm_utils.py untouched.
  • moe/mxfp_moe/gemm2.py — A-LDS read on real layout algebra (make_composed_layout(SwizzleType) + crd2idx, bit-for-bit vs the manual XOR), all gemm2 variants incl. a8w4 e2e stage-2. Cold 6/6 + 228/0 e2e; perf parity (fp4 1280.7, a8w4 828.4 TFLOPS).
  • conv/conv3d_implicit.py + conv3d_implicit_fp8.py — im2col gather via make_buffer_tensor/logical_divide/BufferCopyLDS128b (flat element index, OOB→sentinel); BIG_IN (>2GB) via make_buffer_ptr(rebased, num_records_bytes); fp8 MMA via in-kernel make_mma_atom(MFMA_Scale). Cold: bf16 26/26.

Documented "manual by necessity" (kept, with ISA evidence)

A few hot-loop sites are left manual on purpose — the layout-API form is op-count-identical but perturbs the tuned instruction schedule:

  • mxfp_moe gemm1 read: prologue-hoisted crd2idx is op-identical yet ~5.5% (fp4) / ~11% (fp8) slower (instruction-scheduling sensitivity). Documented in-code.
  • fp8_4wave interleaved AGPR s2r (~1.3%); direct-DMA op stays inline-asm (no register fragment; matches preshuffle_gemm.py::dma_a_to_lds); StoreC (final store, needs full wave-decomp, ~0 payoff).

Caveats

  • conv BIG_IN (>2GB) is compile-validated only — no >2GB test exists; the rebase arithmetic is byte-identical to the prior manual path and the mechanism is runtime-proven by the non-BIG path (26/26).
  • Pre-existing (not this PR): test_conv3d_implicit_fp8.py [1-96-4-8-9-96-1-1] cold flakiness (C=96 partial-K split-K, rel_err ~0.3075) reproduces on main.

Test plan

FLYDSL_RUNTIME_ENABLE_CACHE=0 python3 -m pytest \
  tests/kernels/test_preshuffle_gemm.py tests/kernels/test_fp8_gemm_rowscale.py \
  tests/kernels/test_moe_gemm.py tests/kernels/test_conv3d_implicit.py \
  tests/kernels/test_conv3d_implicit_fp8.py -v

🤖 Generated with Claude Code

Felix Li and others added 4 commits July 27, 2026 14:46
Remove buffer_ops; port the epilogue scale_a/scale_b (load_epi_operands)
addressing to the layout API. Perf-parity confirmed (median-of-7, within
gfx950 noise); cold-correct across fp8/int8/fp16/bf16/fp4/fp6/a8w8 +
fused-epilogue modes + ragged-M.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
MMA phase via in-kernel make_tiled_mma; g2s + s2r LDS swizzle expressed as
crd2idx over make_composed_layout(SwizzleType) (prologue-hoisted, ISA-identical
hot loop). Direct-DMA BufferCopyLDS and split-16@64 pack kept (repo idiom).
Scheduler-sensitive paths (interleaved AGPR s2r, StoreC) left manual by design,
ISA-verified. fp8_gemm_utils.py untouched. Perf parity, cold both preshuffle modes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
gemm2 A-LDS read uses make_composed_layout(SwizzleType)+crd2idx (bit-for-bit vs
the manual XOR mask), covering all gemm2 variants incl a8w4 e2e stage-2.
gemm1 read left manual with ISA evidence: prologue-hoisted crd2idx is
op-count-identical yet ~5.5-11% slower from instruction-scheduling sensitivity.
Cold 6/6 variants + 228/0 e2e; perf parity (fp4 1280.7, a8w4 828.4).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
im2col gather -> make_buffer_tensor + logical_divide + BufferCopyLDS128b with
flat element index and OOB->sentinel padding; BIG_IN (>2GB) paths via
make_buffer_ptr(rebased, num_records_bytes). fp8: Mfma16x16x128 -> in-kernel
make_mma_atom(MFMA_Scale)+fx.gemm, split-16@64 pack kept. Cold: bf16 26/26;
fp8 6/7 (1 case is a pre-existing main bug, not this port). BIG_IN is
compile-validated (no >2GB test). Perf no-regression (median-of-7).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderfeli
coderfeli marked this pull request as draft July 27, 2026 14:58
Cut verbose per-port rationale/ISA-evidence comments (~88 -> ~29 added lines)
to terse one-liners; code byte-identical (comments-only). black+ruff clean.

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