[None][feat] Add GPU SM capability checks to all AutoDeploy quantization and MOE transforms
@Fridah-nv is already working on this.
Since Mar 18, 2026.
- Dominant language
- Python
- Stars
- 14.7k
- Forks
- 2.8k
- Avg merge
- 2d 23h
- Merged PRs (30d)
- 489
Description
Summary
AutoDeploy quantization and MOE transforms should validate GPU SM (compute capability) before attempting to apply architecture-specific kernels. Today, none of the transforms perform this check, so running an incompatible quant config on the wrong GPU leads to cryptic runtime failures instead of a clear early skip with a warning.
Problem
Different quantization formats require specific GPU architectures:
| Format | Minimum SM | Architecture |
|---|---|---|
| FP8 (standard) | 89 | Ada Lovelace / Hopper |
| FP8 (fine-grained / block-scaled) | 90 | Hopper (with SM 120 Blackwell variant path) |
| NVFP4 | 100 | Blackwell |
| MXFP4 | TBD | TBD |
| INT4 (GPTQ / W4A16) | None currently known | — |
When a user runs e.g. an NVFP4 model config on a pre-Blackwell GPU, the transform pipeline proceeds without error until it hits an unsupported kernel at runtime. The resulting error is hard to diagnose.
Example: What the guard would look like per-transform
As a concrete illustration, here is what a guard on FuseNVFP4Linear would look like:
from tensorrt_llm._utils import get_sm_version
from ...utils.logger import ad_logger
@TransformRegistry.register("fuse_nvfp4_linear")
class FuseNVFP4Linear(BaseTransform):
def _apply(self, gm, cm, factory, shared_config):
sm = get_sm_version()
if sm < 100:
ad_logger.warning(
"Skipping FuseNVFP4Linear: NVFP4 requires Blackwell (SM >= 100), "
"but current GPU has SM %d.",
sm,
)
return gm, TransformInfo(skipped=True)
# ... rest of transform
This pattern should be applied systematically to all quantization and MOE transforms listed below.
Transforms That Need SM Guards
Quantized Linear Transforms
fuse_fp8_linear(fuse_quant.py) — needs SM >= 89fuse_nvfp4_linear(fuse_quant.py) — needs SM >= 100fuse_finegrained_fp8_linear(fuse_quant.py) — needs SM >= 90fuse_relu2_quant_nvfp4(fuse_relu2_quant_nvfp4.py) — needs SM >= 100quantize_fp8_linear_from_config(quantization.py) — needs SM >= 89quantize_nvfp4_linear_from_config(quantization.py) — needs SM >= 100quantize_fp8_from_graph(quantization.py) — needs SM >= 89quantize_nvfp4_from_graph(quantization.py) — needs SM >= 100quantize_finegrained_fp8_linear_from_config(quantization.py) — needs SM >= 90quantize_int4_linear_from_config(quantization.py) — verify if any SM floor existsquantize_int4_gptq_linear_from_config(quantization.py) — verify if any SM floor existsquantize_fp8_bmm_from_config(quantization.py) — needs SM >= 89
Fusion Transforms
fuse_fp8_gemms(fusion.py) — needs SM >= 89fuse_fp4_gemms(fusion.py) — needs SM >= 100fuse_finegrained_fp8_gemms(fusion.py) — needs SM >= 90match_nvfp4_swiglu_pattern/fuse_nvfp4_swiglu(fuse_swiglu.py) — needs SM >= 100match_finegrained_fp8_swiglu_pattern/fuse_finegrained_fp8_swiglu(fuse_swiglu.py) — needs SM >= 90
MOE Transforms
quantize_fp8_moe(quantize_moe.py) — needs SM >= 89quantize_nvfp4_moe(quantize_moe.py) — needs SM >= 100quantize_finegrained_fp8_moe(quantize_moe.py) — needs SM >= 90match_fp8_moe_pattern/fuse_fp8_moe(fused_moe.py) — needs SM >= 89match_nvfp4_moe_pattern/fuse_nvfp4_moe(fused_moe.py) — needs SM >= 100fuse_finegrained_fp8_moe(fused_moe.py) — needs SM >= 90quantize_mxfp4_moe(mxfp4_moe.py) — verify SM floor
Proposed Solution
Option A: Per-transform guard (as shown in example above)
Each transform's _apply() method checks get_sm_version() and returns TransformInfo(skipped=True) with a warning when the GPU is incompatible.
Pros: Simple, explicit, easy to understand per-transform.
Cons: Repetitive boilerplate across 25+ transforms; easy to forget on new transforms.
Option B: Declarative SM requirement on TransformConfig / BaseTransform
Add an optional min_sm: int | None field to BaseTransform or TransformConfig. The base class apply() method checks SM before calling _apply() and auto-skips with a standard warning.
class FuseNVFP4LinearConfig(TransformConfig):
min_sm: int = 100 # Blackwell
...
Pros: DRY, impossible to forget, consistent skip/warning behavior.
Cons: Slightly more abstraction; SM requirement must be statically known.
Recommendation
Option B is preferred for maintainability. The SM floor is a static property of the quantization format and fits naturally as a declarative config field. Individual transforms can still override _apply() for more nuanced checks (e.g., fine-grained FP8's SM 90 vs SM 120 code paths).
Acceptance Criteria
- All NVFP4 transforms (linear, MOE, SwiGLU, fusion) skip gracefully on SM < 100
- All FP8 transforms skip gracefully on SM < 89
- All fine-grained FP8 transforms skip gracefully on SM < 90
- A clear warning message is logged indicating which transform was skipped and why
- New transforms get SM validation automatically (Option B) or via documented pattern (Option A)
- Unit tests verify skip behavior with mocked SM versions
References
get_sm_version()utility:tensorrt_llm/_utils.py- SM-dependent code paths already exist in
custom_ops/quantization/torch_quant.pyandcustom_ops/fused_moe/trtllm_moe.py
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.