inference/research
verifiedhigh · 0.93majorupdated 2026-10-04

Native NVFP4 compute exists only on sm100/103 and sm120/121 with CUDA 12.8+: every other NVIDIA part, including Hopper, has no NVFP4 GEMM at all and the engine raises NOT_IMPLEMENTED

[major] hardware

Fields

id
gotchas/w4q-nvfp4-native-only-sm100-sm120-cuda128
Class
hardware
Severity
major
Concepts
nvfp4block-scaled-gemmcutlasscompute-capability-100sm100sm120cuda-version-gatew4a16-fallbackcapacity-planning
Symptom
An NVFP4 checkpoint on an H100, an H200, an A100, an L40S or a 4090 either (a) loads and runs with no tensor-core FP4 benefit, the FP4 weights dequantized and the FP4 activations upcast, so the memory saving appears and the compute speedup does not, or (b) fails with STD_TORCH_CHECK_NOT_IMPLEMENTED('No compiled nvfp4 mm kernel for SM <n>. Recompile with CUDA >= 12.8 and CC >= 100.') depending on which kernel the selector reaches. The two outcomes are the same underlying fact and which one you get depends on whether optional packages are installed - which is why this reads as two unrelated problems until you check the architecture. Neither outcome tells you the format is wrong for the model; the format is Blackwell-native and the parts are not Blackwell.
Root cause
The gate is cutlass_scaled_mm_supports_fp4 in csrc/libtorch_stable/quantization/fp4/nvfp4_scaled_mm_entry.cu. Its body: read the CUDA runtime version and return false if it is < 12080; then return true only for cuda_device_capability in [100,120) when ENABLE_NVFP4_SM100 was compiled in, or in [120,130) when ENABLE_NVFP4_SM120 was compiled in; otherwise return false. There is no branch for cc < 100 at all, and none for cc >= 130. The dispatch function cutlass_scaled_fp4_mm mirrors exactly that and otherwise raises the NOT_IMPLEMENTED above. The in-code rationale is worth quoting because it explains the whole failure class: 'Only report support when the SM-specific kernel was actually compiled in, so the Python-side backend selector does not choose CUTLASS and then hit TORCH_CHECK_NOT_IMPLEMENTED (or worse, fall through to Marlin).' So the architecture answer is clean - native NVFP4 compute is sm100/103 (B200, B300) and sm120/121 (RTX 5090, RTX PRO 6000 Blackwell) only, and sm107 is covered because it falls in the [100,120) branch - and it is additionally a CUDA-runtime claim of 12.8 or newer, which no Y/. support table can express. On every other part vLLM still serves the checkpoint: MarlinNvFp4LinearKernel is admitted at is_fp4_marlin_supported() = is_cuda() and has_device_capability(75), which is a W4A16 kernel, and EmulationNvFp4LinearKernel returns (True, None) unconditionally as 'Always available as a last-resort fallback'. TorchNvFp4LinearKernel is a useful sanity check because it states its own gate plainly: 'Torch NVFP4 requires sm_10x (Blackwell)'.
Workaround
Treat NVFP4 as a Blackwell-only format and gate the deployment on the architecture, not on the checkpoint. Before planning NVFP4 capacity on any part, evaluate torch.ops._C.cutlass_scaled_mm_supports_fp4(capability) for the exact device - it returns false below cc 100 and false at cc >= 130 even on a fast part, and it additionally encodes the CUDA 12.8 requirement. If it is false and you want NVFP4's compression on an older part, accept that you are getting W4A16 Marlin storage with FP16 compute and price it as such: the weight bytes drop, the activation bytes do not, so the decode-time memory-bound speedup is strictly smaller than the format implies. That is the same conclusion this repo already records in qhw-silent-precision-degradation and flops/qhw-decode-gemm-memory-bound, now with an explicit architecture predicate attached instead of a heuristic. If the compression is the goal rather than the compute, INT8 W4A16 or a 4-bit AWQ/GPTQ checkpoint via Marlin gets you most of the memory saving on SM75 and up without pretending to W4A4.
notes
CONFIRMED 2026-10-04 against vLLM main and csrc. VERIFIED NEGATIVE WITH EVIDENCE, not a blank cell: for native NVFP4 compute the closed enumeration is cc in [100,120) or [120,130) AND runtime CUDA >= 12.8. That makes these VERIFIED NEGATIVES with a decidable predicate rather than an absence of research: H100/H200 (SM90), A100/A10 (SM80/SM86), L40S (SM89), RTX 4090 and RTX 6000 Ada (SM89) - none has an NVFP4 GEMM. Two refinements worth carrying. First, sm107 (Rubin) IS covered by the native path because 107 falls inside [100,120) and takes the sm100a kernel, so the correct negative list is 'Hopper and older, plus anything at cc 130 or above', not 'everything except sm100'. Second, the CUDA-version half of the gate is real and routinely missed: a Blackwell part running a CUDA older than 12.8 build reports false even though the silicon supports FP4, and the practical symptom is the fallback rather than an error. Related and confirmed in the same pass: MXFP4 is the mirror-image case - TensorRT-LLM's matrix marks MXFP4 Y on sm120 while vLLM main has no native MXFP4 dense GEMM there without the optional b12x extra (see the gotcha w4q-vllm-mxfp4-no-native-kernel-sm120) - and FP8 per-token activation scaling has the mirror-image version problem on Ampere (see w4q-vllm-fp8-per-token-silently-downgrades-to-per-tensor). Together these three are the cases where a matrix cell marked available is not a native compute path, which is exactly the error class this pass was asked to find.

Notes

CONFIRMED 2026-10-04 against vLLM main and csrc. VERIFIED NEGATIVE WITH EVIDENCE, not a blank cell: for native NVFP4 compute the closed enumeration is cc in [100,120) or [120,130) AND runtime CUDA >= 12.8. That makes these VERIFIED NEGATIVES with a decidable predicate rather than an absence of research: H100/H200 (SM90), A100/A10 (SM80/SM86), L40S (SM89), RTX 4090 and RTX 6000 Ada (SM89) - none has an NVFP4 GEMM. Two refinements worth carrying. First, sm107 (Rubin) IS covered by the native path because 107 falls inside [100,120) and takes the sm100a kernel, so the correct negative list is 'Hopper and older, plus anything at cc 130 or above', not 'everything except sm100'. Second, the CUDA-version half of the gate is real and routinely missed: a Blackwell part running a CUDA older than 12.8 build reports false even though the silicon supports FP4, and the practical symptom is the fallback rather than an error. Related and confirmed in the same pass: MXFP4 is the mirror-image case - TensorRT-LLM's matrix marks MXFP4 Y on sm120 while vLLM main has no native MXFP4 dense GEMM there without the optional b12x extra (see the gotcha w4q-vllm-mxfp4-no-native-kernel-sm120) - and FP8 per-token activation scaling has the mirror-image version problem on Ampere (see w4q-vllm-fp8-per-token-silently-downgrades-to-per-tensor). Together these three are the cases where a matrix cell marked available is not a native compute path, which is exactly the error class this pass was asked to find.

Cross-references