Repository navigation
feat(tir): declare the sm_89 e4m3 warp mma - #261
Conversation
Test planThese ran on a single RTX 6000 Ada Generation (compute capability 8.9) with Python 3.12, PyTorch 2.11 for CUDA 12.9 and nvcc 12.8:
Before this change the new tests fail. The two files that use A/B on a single sm_89 GPU
The new nodes are the sm80 and sm89 CuTe comparisons (replacing one unparametrized test), the sm_89 typing case, the The other 21 failures are the same tests on both sides: 19 launch kernels built for sm_90, and 2 need a second GPU. |
…ayout (#263) ## Why `ops::copy_async` walked the source in vectors but addressed the destination by element index. When a thread's slice holds more than one vector and its contiguous run is not the slice's first mode, later vectors can land at the wrong destination address. An E4M3 GEMM that stages its K slices through shared memory on sm_89, written on top of #261, found it: each thread's slice there is (2, 1, 1, 8) with strides (256, -, -, 1), its second 8-byte vector went to byte 4 instead of byte 256, and in that GEMM this caused a misaligned address error. The GPU tests so far move one vector per thread, so none of them reached it. ## What `CopyAsync` now recasts the destination to the source's vector type and copies vector `i` of the source to vector `i` of the destination. The scalar width it used for the element index is gone. The new fixture `tests/fixtures/tir/split_stage.py` holds `SplitStage`, in which each of 128 threads stages two 16-byte runs of f32 that lie 512 elements apart; `tests/ops/tir/test_copy_async.py` checks on each CUDA target that the staged tile equals its input exactly, and the TIR roundtrip test picks the fixture up as it does the others. ## Contract None. [runtime §2.6.2](docs/spec/runtime.md#262-opscopycuh) already states that the entry copies exactly the slice `local_tensor` hands each thread; this makes the asynchronous entry do so. ## Risk None. Co-authored-by: Zheng QiHang <zhengqihang0915@qq.com>
## Why #261 declared the sm_89 E4M3 warp MMA and tested it as one atom whose fragments come straight from global memory. Nothing yet ran a GEMM with it: K slices staged through shared memory, the atom's fragments gathered from there, the product accumulated over K. Writing that kernel found the `cp.async` addressing fixed in #263. ## What One 16 x 8 x 128 E4M3 product, accumulated in F32 on sm_89, from its schedule down to the GPU. The schedule is three new fixtures, `tests/fixtures/schedule/{plain,hir,tir}/sm89_e4m3_gemm.py`: the plain program (each 32-wide K slice loaded into registers, where the SM89 atom reads, and multiplied), the scheduled program (one warp; per K slice, `T.copy_async` into shared memory, `T.copy` into the atom's fragments, `T.tiled_mma`), and the TIR `schedule finalize` writes for it. `tests/schedule/test_fixtures.py` adds their entries to the fixture tables and two `FixtureCase`s that run `tilefoundry check` on both programs against torch with `--atol 0 --rtol 0`: the inputs are integers in [-4, 4], so every partial sum is exact and the results must equal the product. The kernel, `tests/fixtures/tir/e4m3_gemm.py` (run from `tests/cuda/ops/tir/test_mma.py`), implements that finalized TIR with its allocation and order: both staging tiles sit at offset 0 of 512 bytes of dynamic shared memory, and each K step stages and gathers A, then B, then issues the MMA. It adds what finalize leaves to the implementation: the commit, wait and warp syncs between those steps, and the split of each copy over the warp's threads. The test is parametrized over the H200 and sm_89 targets, the sm_89 case under the `sm89` marker, and requires the tile to equal the F32 product exactly. ## Contract None. ## Risk The kernel's H200 case runs only in CI, on an H200; CI on the previous head passed with 2301 passed and 18 skipped. The kernel and the fixtures cover one warp, one 16 x 8 tile and integer inputs, and say nothing about performance. --------- Co-authored-by: Zheng QiHang <zhengqihang0915@qq.com>
Why
sm_89 adds an FP8 warp MMA,
mma.sync.aligned.m16n8k32.row.col.f32.e4m3.e4m3.f32, which the sm_89 target from #259 could not select:T.cuda.sm80.Mmatakes BF16 only, so an E4M3 product in registers had no instruction to lower to. It was suggested in #256 as the change to make after the sm_89 documents.What
T.cuda.sm89.Mmadeclares the instruction: 16 x 8 x 32, E4M3 A and B in registers, and an F32 accumulator in registers laid out as the SM80 atom's. Its A and B fragments follow the PTX fragment table and match CuTe'sMMA_Traits<SM89_16x8x32_F32E4M3E4M3F32_TN>thread for thread. It requiresmma.sync, which sm_89, sm_90 and sm_100 all list and all run in the E4M3 form.TiledMmaaccepts it after the SM80 atom, and the register fragment pattern both atoms build moves intomma_atom.py.The runtime keeps one
ops::mmaentry. The element type of A selects the CuTe atom; B must hold the same type, C must hold f32, and each fragment must have the selected atom's length, or astatic_assertfails. Codegen emits the same call for both atoms.schedule factsnames each capability once per instruction, soT.tiled_mmastill listswgmma.mma_async, mma.syncwith three atoms behind it.Tests:
tests/ir/cuda/atoms/test_mma.pycompares both atoms' fragments with CuTe's traitstests/ops/tir/cuda/test_mma.pyruns an E4M3 product on the GPU against the F32 product of the same values, once for H200 and once for sm_89 through thesm89markertests/ops/ir/test_matmul.pytypes an E4M3 register by register matmul on sm_89tests/runtime/test_cuda_static_asserts.pychecks thatops::mmarefuses an E4M3 A with a BF16 B, a C that is not F32, and a B with the BF16 atom's lengthContract
docs/spec/tir.mdlistsT.cuda.sm89.Mmaamong the public declarations and the declarations the CUDA emitter accepts.docs/spec/runtime.md§2.6.5 states howops::mmaselects its atom and each atom's fragment sizes.Risk
mma.syncnames the instruction family, so every architecture document that lists it admits the E4M3 atom. A document for an architecture below 8.9, such as a user supplied sm_80 document, would admit an instruction that hardware lacks. No installed document is affected.