Skip to content

Commit b6a6177

Browse files
committed
docs+route(nvfp4): backward GENUINELY datacenter-only on sm_12x — fail-loud is correct, not a build-flag gap
Conclusion from TE source (parked analysis from the rebuild investigation): the FP4 stochastic-rounding cvt (cvt.rs.satfinite.e2m1x4) + RHT fused-quant backward kernels are source-gated in TransformerEngine to ArchSpecific<100>/<103> (sm_100a/sm_103a, datacenter B200/B300). The SM12x family (consumer/Spark Blackwell, sm_121/GB10) exposes only plain sm_120/sm_121 — NO 120a/120f/121f code target for these kernels, and RHT needs the SM100 TMEM/tcgen05 pipeline sm_12x does not implement. So rebuilding TE with a 120f family target does NOT unblock nvfp4 backward; it stays fail-loud (Nvfp4CudaKernelMiscompiled) with WHERE+WHAT. Forward NVFP4 GEMM remains working (ffb3069). RULE #1: no fake unblock, no silent bf16 fallback. Refines the route's capability detection + error text + doc with the source-gating evidence.
1 parent a319599 commit b6a6177

3 files changed

Lines changed: 241 additions & 113 deletions

File tree

docs/NVFP4-TRAINING-KERNELS.md

Lines changed: 85 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -126,29 +126,71 @@ thread):
126126
Try recompiling with sm_XXXa instead of sm_XXX.
127127
```
128128

129-
**Root cause (proven via cuobjdump on the TE .so):** the installed
130-
`libtransformer_engine.so` embeds SASS for:
129+
The installed `libtransformer_engine.so` (TE editable build at
130+
`/home/dave/TransformerEngine`, git `8d1d79bf`) embeds SASS for
131+
(`cuobjdump --list-elf`, 2026-06-01):
131132

132133
```
133134
sm_75, sm_80, sm_89, sm_90, sm_90a, sm_100, sm_100a, sm_103a, sm_120 (PLAIN)
134135
```
135136

136-
i.e. TE's default CUDA-13 arch list `75;80;89;90;100;120``sm_120` is built
137-
**PLAIN**, and the architecture-specific `a` variants exist only for datacenter
138-
Blackwell (`sm_100a`, `sm_103a`). GB10 is `sm_121`, runs the `sm_120` plain
139-
SASS, which lacks the arch-specific FP4 cvt / RHT instructions → the asserts
140-
above.
141-
142-
**The `a` variant is NOT the fix on desktop/consumer Blackwell.** Per
143-
NVIDIA/cutlass#3096 and flashinfer-ai/flashinfer#2723, forcing `compute_120a`
144-
gencode SEGFAULTS on desktop Blackwell ("RTX PRO 6000 reports compute capability
145-
12.0, not 12.0a; the `a`-specific instructions are not available on desktop
146-
Blackwell"). The working target is the **family-specific `compute_120f`** added
147-
in CUDA 13.0, which "enables the full SM120 feature set with working TMA WS
148-
grouped-GEMM tactics" (compute_120f took a CUTLASS NVFP4 MoE from 14.6 → 39.0
149-
tok/s vs compute_120a). So the enablement for gb10 backward is to rebuild TE/
150-
cuBLASLt-path FP4 kernels under CUDA ≥ 13 targeting `120f`, once TE's build
151-
emits the `f` family target.
137+
i.e. TE's default CUDA-13 arch list — `sm_120` built **PLAIN**, no `sm_121`,
138+
and the `a` variants only for datacenter Blackwell (`sm_100a`, `sm_103a`). GB10
139+
(`sm_121`) runs the `sm_120` plain SASS.
140+
141+
**ROOT CAUSE — corrected verdict (2026-06-01): the backward is GENUINELY
142+
DATACENTER-ONLY, NOT a build-flag gap. A TE rebuild for any sm_12x target
143+
CANNOT unblock it.** The earlier `compute_120f` rebuild hypothesis was
144+
investigated against the TE source on gb10 and **disproven**. Three independent,
145+
load-bearing reasons, each verified directly:
146+
147+
1. **TE source-gates SR to datacenter `a` archs.** In
148+
`transformer_engine/common/util/ptx.cuh`:
149+
150+
```cpp
151+
#define ARCH_HAS_STOCHASTIC_ROUNDING \
152+
NVTE_CUDA_ARCH_MATCHES(ptx::ArchSpecific<100>, ptx::ArchSpecific<103>)
153+
```
154+
155+
`ArchSpecific<N>` is true only when `__CUDA_ARCH__ == N*10` **and** the build
156+
is the arch-specific `a` variant (`__CUDA_ARCH_SPECIFIC__` defined). So SR is
157+
enabled **only** for `sm_100a` / `sm_103a`. It is deliberately **excluded
158+
from the Blackwell family set** (the sibling `ARCH_BLACKWELL_FAMILY` macro
159+
lists `FamilySpecific<100>,<110>,<120>`, but `ARCH_HAS_STOCHASTIC_ROUNDING`
160+
does **not**). Therefore **even an `sm_120f`/`sm_121f` build leaves
161+
`has_rs == false`**, and every SR FP4 cast (`cvt.rs.satfinite.e2m1x4.f32`)
162+
compiles to the device-error path `NVTE_DEVICE_ERROR("FP4 cvt PTX
163+
instructions are architecture-specific. Try recompiling with sm_XXXa instead
164+
of sm_XXX.")`. This gate is in **C++ source, not gencode** — no compiler flag
165+
changes it. (Same instruction + same gate is used by the RHT kernel's
166+
`StochasticNumericConverterBase`.)
167+
168+
2. **nvcc 13.x has no `sm_12x` `a`/`f` code target.** `nvcc --list-gpu-code` on
169+
CUDA 13.0 / 13.1 / 13.2 / 13.3 emits, for the 12x family, **only** plain
170+
`sm_120` and `sm_121` — there is no `sm_120a`, `sm_120f`, `sm_121a`, or
171+
`sm_121f` to compile for. (The `120f` family target that helped CUTLASS NVFP4
172+
*MoE forward* tactics — cf. cutlass#3096 — is not exposed as an nvcc gencode
173+
here, and per (1) would not flip the SR gate anyway.)
174+
175+
3. **No hardware path: sm_12x lacks `tcgen05` / TMEM.** The RHT fused kernel
176+
(`row_cast_col_hadamard_transform_cast_fusion.cu`) is built on the CUTLASS
177+
**SM100 blockscaled pipeline** — `SM100::TMEM::LOAD`, `SM100_MMA_F16BF16_SS`,
178+
`cutlass/detail/sm100_blockscaled_layout.hpp`, cluster launch — i.e.
179+
`tcgen05`/TMEM. NVIDIA staff (johnny_nv, NVIDIA Developer Forums) state plainly:
180+
*"SM12x (GB10 / DGX Spark / RTX 50) does **not** implement `tcgen05`, and
181+
therefore it also doesn't support the associated FP4 Tensor Core path."* The
182+
TMEM-backed blockscaled FP4 path is gated to datacenter SM100/SM110. This is
183+
exactly why the RHT kernel raises `CUDA Error: invalid argument` on gb10 —
184+
TMEM ops do not exist on this SM. (The sm_121 forward NVFP4 GEMM that *does*
185+
work goes through a **different**, non-tcgen05 cuBLASLt/CuTe-geforce pipeline.)
186+
187+
**Conclusion:** VERIFIED BROKEN **and** verified UNFIXABLE-BY-REBUILD on gb10.
188+
The enablement is **not in our hands** — it requires NVIDIA to ship
189+
**SM12x-native (non-tcgen05) FP4 stochastic-rounding + RHT backward kernels** in
190+
a future TransformerEngine / cuBLASLt release (and to widen
191+
`ARCH_HAS_STOCHASTIC_ROUNDING` to the 120 family once an `f`/`a` SR cvt exists
192+
for it). Until then the nvfp4 **backward** stays fail-loud on consumer/Spark
193+
Blackwell. The **forward** nvfp4 GEMM remains real and working (§3a).
152194
153195
**Danger note (why we fail loud):** the backward FP4 error is ASYNC. Without
154196
`CUDA_LAUNCH_BLOCKING=1` AND a fresh `te.Linear`, TE quantizer-workspace state
@@ -204,7 +246,7 @@ each; it does NOT bf16-fallback:
204246
205247
| Op | Why | Enablement |
206248
|----|-----|-----------|
207-
| `nvfp4_gemm_backward_vjp_te_cuda_sm121` | TE FP4-cvt/RHT PTX is arch-specific; TE built `sm_120` plain (not the `f` family)asserts / CUDA invalid-argument on gb10 | Rebuild TE under CUDA ≥ 13 with family target `compute_120f` (NOT `sm_120a`, which SEGFAULTS on desktop Blackwell; cf. cutlass#3096) |
249+
| `nvfp4_gemm_backward_vjp_te_cuda_sm121` | **Datacenter-only, NOT a build gap.** SR FP4 cvt (`cvt.rs.satfinite.e2m1x4`) is TE-source-gated to `sm_100a`/`sm_103a`; RHT kernel needs SM100 TMEM/`tcgen05` which sm_12x does not implement. nvcc 13.x has no sm_12x `a`/`f` targeta TE rebuild **cannot** fix it (see §3b) | **UPSTREAM ONLY**: needs NVIDIA to ship SM12x-native (non-`tcgen05`) FP4 SR + RHT backward kernels in a future TE/cuBLASLt release |
208250
| `cuda_blackwell_nvfp4_gemm_metal_only` | The Metal fwd GEMM is Metal-only; it RAISES on CUDA | Use the TE/cuBLASLt CUDA forward path above |
209251
| `gemm_backward_vjp` | No nvfp4 grad kernel for the Metal e2m1 GEMM | Implement an nvfp4 VJP for `mxfp4_matmul_path_c` |
210252
| `optimizer_state_and_update` | AdamW moments are fp32-only; no nvfp4 optimizer state | Implement nvfp4 optimizer-state kernels |
@@ -242,10 +284,11 @@ assertions run when torch+TE+CUDA+NVFP4 present.
242284
* `test_metal_forward_nvfp4_gemm_matches_bf16` — real Metal fwd GEMM < 0.5 rel.
243285
* `test_cuda_forward_nvfp4_gemm_matches_bf16` — **real gb10 NVFP4 fwd GEMM
244286
< 0.3 rel** (measured 0.147).
245-
* `test_cuda_backward_nvfp4_gemm_fails_loud_on_miscompiled_te` — the broken gb10
246-
backward RAISES `Nvfp4CudaKernelMiscompiled` naming the `compute_120f`
247-
enablement. (Skips, expecting pass, when `NVFP4_BACKWARD_FIXED=1` once TE is
248-
rebuilt with `120f`.)
287+
* `test_cuda_backward_nvfp4_gemm_fails_loud_datacenter_only` — the broken gb10
288+
backward RAISES `Nvfp4CudaKernelMiscompiled` naming the REAL, evidence-backed
289+
blocker (SR cvt source-gated to `sm_100a`/`sm_103a`; RHT needs SM100
290+
TMEM/`tcgen05` absent on sm_12x). The fail-loud is **permanent** on sm_12x
291+
(no `NVFP4_BACKWARD_FIXED` escape hatch — a rebuild cannot fix it; §3b).
249292
250293
**Results:**
251294
@@ -283,10 +326,28 @@ cd <dir> && /home/dave/cppmega-venv/bin/python -m pytest tests/test_nvfp4_route.
283326
https://github.com/NVIDIA/TransformerEngine
284327
* cuBLAS 12.9 block-scaled FP4 (CUDA_R_4F_E2M1 + CUDA_R_UE4M3, 16-elem blocks) —
285328
https://developer.nvidia.com/blog/boosting-matrix-multiplication-speed-and-flexibility-with-nvidia-cublas-12-9/
286-
* CUTLASS SM120 NVFP4: sm_120a SEGFAULT, compute_120f fix (CUDA 13.0) —
329+
* CUTLASS SM120 NVFP4: sm_120a SEGFAULT, compute_120f fix (CUDA 13.0) — note
330+
this `120f` finding is for the *forward MoE* tactic path; it does NOT enable
331+
the FP4 *stochastic-rounding backward* (see §3b) —
287332
https://github.com/NVIDIA/cutlass/issues/3096
288333
* FlashInfer SM120 NVFP4 grouped GEMM patching —
289334
https://github.com/flashinfer-ai/flashinfer/issues/2723
335+
* **NVIDIA staff (johnny_nv): SM12x (GB10/DGX Spark/RTX50) does NOT implement
336+
`tcgen05`, hence no associated FP4 Tensor-Core/TMEM blockscaled path** (the
337+
decisive datacenter-only evidence for the broken RHT backward) —
338+
https://forums.developer.nvidia.com/t/dearest-cutlass-team-when-the-hell-are-you-going-to-properly-fix-tcgen05-fp4-support-for-dgx-spark-gb10-sm121/359598
339+
* CUTLASS issue #2800: BlockScaledMmaOp restricts FP4 to `sm_100a`, blocking
340+
sm_120/sm_121 — https://github.com/NVIDIA/cutlass/issues/2800
341+
* PyTorch issue #172807: auto-detected arch flags drop the accelerated suffix
342+
(sm_120a → sm_120), breaking Blackwell NVFP4/block-scaled MMA —
343+
https://github.com/pytorch/pytorch/issues/172807
344+
* TE source gate (the SR FP4 cvt is source-restricted to sm_100a/sm_103a):
345+
`transformer_engine/common/util/ptx.cuh` `ARCH_HAS_STOCHASTIC_ROUNDING` =
346+
`NVTE_CUDA_ARCH_MATCHES(ptx::ArchSpecific<100>, ptx::ArchSpecific<103>)`;
347+
RHT kernel `common/hadamard_transform/row_cast_col_hadamard_transform_cast_fusion.cu`
348+
builds on the CUTLASS SM100 TMEM/tcgen05 pipeline.
349+
* PTX ISA `cvt.rs.satfinite.e2m1x4` (round-with-select stochastic-rounding FP4
350+
cvt) — https://docs.nvidia.com/cuda/parallel-thread-execution/index.html
290351
* CUTLASS NVFP4 GEMM example —
291352
https://github.com/NVIDIA/cutlass/blob/main/examples/72_blackwell_narrow_precision_gemm/72b_blackwell_nvfp4_nvfp4_gemm.cu
292353
* Community nvfp4 training (cuBLASLt + Microxcaling) —

0 commit comments

Comments
 (0)