mirror of
https://github.com/deepseek-ai/DeepGEMM.git
synced 2026-11-05 00:47:26 +00:00
[PR #474] [Feat]Add native FP8 Tensor Core GEMM support for SM89 (Ada Lovelace) #476
Labels
No labels
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
deepseek-ai/DeepGEMM#476
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
📋 Pull Request Information
Original PR: https://github.com/deepseek-ai/DeepGEMM/pull/474
Author: @Ammar-Alnagar
Created: 10/14/2026
Status: 🔄 Open
Base:
main← Head:main📝 Commits (3)
4d2e2fcAdd SM80 and SM89 architecture support and fallbacks (#1)fc5729fRemove SM80 and SM89 hardware validation test suitefdcb2afAdd support for FP8 Tensor Cores on SM89 architecture📊 Changes
20 files changed (+1479 additions, -38 deletions)
View changed files
📝
README.md(+41 -13)📝
csrc/apis/attention.hpp(+22 -6)📝
csrc/apis/config.hpp(+3 -0)📝
csrc/apis/gemm.hpp(+47 -5)📝
csrc/apis/layout.hpp(+8 -4)➕
csrc/jit_kernels/heuristics/sm89.hpp(+170 -0)➕
csrc/jit_kernels/impls/sm89_fp8_gemm.hpp(+143 -0)📝
csrc/jit_kernels/impls/smxx_cublaslt.hpp(+5 -1)📝
csrc/utils/exception.hpp(+11 -0)📝
csrc/utils/layout.hpp(+13 -2)📝
deep_gemm/include/deep_gemm/common/types.cuh(+34 -0)➕
deep_gemm/include/deep_gemm/impls/sm89_fp8_gemm.cuh(+417 -0)📝
deep_gemm/include/deep_gemm/impls/smxx_layout.cuh(+3 -3)➕
deep_gemm/include/deep_gemm/mma/sm89.cuh(+40 -0)📝
deep_gemm/include/deep_gemm/ptx/ld_st.cuh(+19 -0)📝
deep_gemm/include/deep_gemm/ptx/utils.cuh(+9 -0)📝
deep_gemm/testing/utils.py(+14 -0)➕
docs/architecture_support.md(+158 -0)📝
tests/generators.py(+5 -4)➕
tests/test_sm89.py(+317 -0)📄 Description
Title
Add native FP8 Tensor Core GEMM support for SM89 (Ada Lovelace)
Body
Summary
This change adds a native FP8 Tensor Core GEMM for SM89 (Ada Lovelace). SM89 is the first architecture below Hopper that has FP8 Tensor Cores.
Previously, SM80 and SM89 used the same path. The path required SM90 or higher for FP8. This was correct for SM80 because Ampere has no FP8 Tensor Cores. It was wrong for SM89. SM89 implements the instruction
mma.sync.aligned.m16n8k32.row.col.f32.e4m3.e4m3.f32(QMMA.16832.F32.E4M3.E4M3). The change separates the two architectures and gives SM89 a real kernel.Why
mbarrier.try_wait.parity, no WGMMA, no clusters). It could not reuse the SM90 or SM100 kernels. It fell back to BF16 through cuBLASLt.Design
SM89 has no TMA and no asynchronous barriers. The kernel uses the pre-Hopper primitives.
mma.sync(wrapped indeep_gemm/mma/sm89.cuh, with A/B/C fragment layouts documented) andldmatrix.x4for operand staging.cp.asyncpipeline with a 128-byte XOR swizzle.csrc/jit_kernels/heuristics/sm89.hpp. The warp split uses one shared functionget_mma_sync_warps_n(). Host heuristics and device code both call it so they cannot disagree.Both SM90 SF recipes are supported:
(1, 1, 128)(per-token A and B scales) and(1, 128, 128)(per-token A, one B scale per 128-column N block).The second recipe is the default when FP32 scales are used. SM89 uses the same FP32 SF layouts as SM90. The function
transform_sf_into_required_layoutwas extended. It was not duplicated.Scope
Supported features:
dense FP8 GEMM, K-major (NT) operands only, FP32 and BF16 outputs,
D = C + A @ B, ragged M/N,k % 16 == 0, both aliases (fp8_fp4_gemm_nt,fp8_gemm_nt,fp4_gemm_nt), and shape specialization.Still rejected (with an explicit message that names the requirement):
grouped and K-grouped FP8, MN-major FP8 operands, FP4, custom epilogues,
alphascaling, PDL, and MQA/attention.BF16 keeps its cuBLASLt fallback.
Incidental fixes
set_pdl()now panics below SM90. It no longer sets a flag thatgriddepcontrolcannot honour.cudaGridDependencySynchronize()is wrapped in a no-op below__CUDA_ARCH__ >= 900so the SF-layout kernels compile for SM89.call_cublaslt_apiusedCUBLAS_COMPUTE_32F_FAST_TF32for non-FP32 operands. That mode only down-casts FP32 inputs to TF32. BF16/FP8 operands ran at TF32 precision by mistake. Now only FP32 inputs use that mode.DG_PANICmacro throws always and carries a message.Bug found during validation
The persistent loop primed its
cp.asyncpipeline only in the prologue before the tile loop. It relied on a cross-tile tail load to prime the next tile. A tile’s tail can only reach the stages that are already free of the current tile — prologue stagesp ∈ [0, kNumStages-2-num_k_blocks]. The next tile’s K loop consumesp = 0..num_k_blocks-1. Whennum_k_blocks < kNumStages-1(example:k=512, 4 blocks, 8 stages) the high stages were never reloaded. The next tile read the previous tile’s shared memory. Symptom: non-deterministicnanand values near 1e30. The problem appeared only for small M spread over many N tiles.The fix extracts the prologue into
prime_pipeline()and re-primes unconditionally after the epilogue. The re-prime is guarded bycp_async_wait<0>()and a__syncthreads().cp.asynccompletion is per-thread, so both are required before the stages can be reused. The change removes a prologue/epilogue overlap that was never correct. Measured cost is about 0–3.5 % (4096³: 2518 µs vs 2507 µs, within noise; 4096×4096×512: 420 µs vs 405 µs).tests/test_sm89.pyadded the shapes(1, 4096, 512),(64, 4096, 512)and(128, 4096, 128). Reverting the fix makes these tests fail (34 failures). They are real regression tests.Testing
Hardware: RTX 4060 Laptop (SM89, 24 SMs, 7.6 GiB), CUDA 13.0, PyTorch 2.14.1+cu130.
tests/test_sm89.py— 17 tests, OK from a cold JIT cache (~130 s).Covers both recipes × both output dtypes × accumulate × 12 shapes, explicit
recipe=(1,128,128),recipe_a/recipe_bpairs, entry-point aliases, compiled-dim specialization, bitwise determinism across repeats, accumulation-versus-zero-C equivalence, BF16 GEMM and all its layouts, cuBLASLt FP8/BF16, SF layout kernels, and one rejection case per unsupported feature.tests/test_layout.py— OK.tests/test_fp8_fp4.py::test_gemm— OK.The upstream shape grid reaches m=129280 / n=7168 and OOMs on a 7.6 GiB card. Shapes were clamped to m≤4096, n≤4096, k≤1280 by monkey-patching
enumerate_normalin a throw-away driver. The test body, recipes and assertions were not changed.tests/test_bf16.py::test_gemm— correctness OK, same clamping.The perf-print block was stubbed because
bench_kinetomatches on the kernel namebf16_gemm, which does not exist on SM89 (BF16 goes through the cuBLASLt fallback). Alldiff < 1e-5assertions ran without change.test_einsumraises the intended “Unsupported architecture”,test_lazy_initandtest_locality_domainneed multiple GPUs,test_bf16/test_legacyOOM at upstream shapes.Throughput, single GPU, FP8 in / BF16 out:
AI usage Disclaimer : Ai was used in the documentation and creation of this PR message
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.
cin SM90fp8_einsum("bhr,hdr->bhd")to prevent silent data corruption insm90_fp8_bmm#480