Skip to content

fix(jit): warn when CUDA toolkit < 12.8 drops capability flags from JIT builds - #4429

Open
rishabhsinha17 wants to merge 2 commits into
flashinfer-ai:mainfrom
rishabhsinha17:fix/fused-moe-fp4-toolkit-guard
Open

rishabhsinha17 wants to merge 2 commits into
flashinfer-ai:mainfrom
rishabhsinha17:fix/fused-moe-fp4-toolkit-guard

Conversation

@rishabhsinha17

@rishabhsinha17 rishabhsinha17 commented Aug 9, 2026

Copy link
Copy Markdown

📌 Description

When the JIT toolchain is older than CUDA 12.8, version-gated nvcc flags are dropped silently: -DENABLE_FP4 in the fp4_quantization generators and -DENABLE_FP8_BLOCK_SCALE in the CUTLASS fused_moe 89/90 and fp8_blockscale_gemm_90 generators. The module builds fine without the capability and the first gated call fails deep in kernel-runner construction with a misleading dtype-combination error (see #3951, hit through vLLM W4A16-MXFP4 serving on a 12.4 toolkit).

  • Add version_gated_nvcc_flag() in flashinfer/jit/cpp_ext.py: dropping a flag now logs a warning at flag-generation time naming the module, the flag, the toolkit version found, and the 12.8 requirement.
  • Use it at all version-gated flag drop sites (jit/fused_moe.py, jit/fp4_quantization.py, quantization/fp4_quantization.py, jit/gemm/fp8_blockscale.py). One warning per generated module, not one per flag list.
  • AOT-aware: when a prebuilt AOT artifact exists for the module (flashinfer-jit-cache), try_load() serves it and the JIT flag list is never compiled, so the drop is logged at info level instead of warning. The check goes through a new has_prebuilt_aot_module() helper mirroring JitSpecNvcc.aot_path. AOT wheel builds compile into a separate build dir and never read FLASHINFER_AOT_DIR, so self-builds with an old toolkit still warn loudly.
  • Replace the vague use_deepseek_fp8_block_scale early error ("not implemented for CUDA 12.6 or lower") in fused_moe/core.py with one naming the actual cause and remedies, backed by a new cutlass_fused_moe_fp8_block_scale_supported() capability probe. The probe also accepts a prebuilt AOT fused_moe_90 module, so flashinfer-jit-cache installs with an older local toolkit are no longer falsely rejected.
  • Document why SM90 fused_moe keeps -DENABLE_FP4 unconditionally after perf: optimize MXFP4xBF16 & INT4xFP8 and add MXFP4xFP8 CUTLASS MoE backend for SM90 #3738 (Hopper path uses cutlass::float_e2m1_t from fp4_compat.h, no <cuda_fp4.h> needed) and pin it with a regression test, since that unconditional flag is what fixed the original fp4 repro on main.

🔍 Related Issues

Closes #3951

🚀 Pull Request Checklist

Thank you for contributing to FlashInfer! Before we review your pull request, please make sure the following items are complete.

✅ Pre-commit Checks

  • I have installed pre-commit by running pip install pre-commit (or used your preferred method).
  • I have installed the hooks with pre-commit install.
  • I have run the hooks manually with pre-commit run --all-files and fixed any reported issues.

🧪 Tests

  • Tests have been added or updated as needed.
  • All tests are passing (unittest, etc.).

tests/jit/test_toolkit_version_gated_flags.py (14 tests) is CPU-only: it monkeypatches the toolkit-version probe to 12.4 and 12.8 and asserts flag presence, warning content (module name, dropped flag, found and required versions), warning count, info-level demotion when an AOT artifact exists, and the AOT escape hatch of the capability probe. Tests isolate FLASHINFER_AOT_DIR so a host jit-cache install cannot skew results. No nvcc or GPU required.

Reviewer Notes

Two behavior changes with flashinfer-jit-cache installed and a local toolkit < 12.8: cutlass_fused_moe(use_deepseek_fp8_block_scale=True) previously raised NotImplementedError based on the local toolkit alone and now proceeds because the AOT module contains the kernels, and flag generation for AOT-served modules logs info instead of warning. Both assume AOT modules are built with a 12.8+ toolkit, which holds for the official wheels (cu128/cu129/cu130). Issue request 2 (a public has_fp4_support() query) is left out to keep this focused; the capability-probe pattern here is the template for it.

Summary by CodeRabbit

  • New Features

    • Added CUDA toolkit-aware support detection for FP4 and FP8 block-scale operations.
    • Preserved support when compatible prebuilt modules are available, even with older CUDA versions.
    • Added clearer status messages when required compilation features are unavailable.
  • Bug Fixes

    • Prevented unsupported compiler flags from being applied during JIT compilation.
  • Tests

    • Added coverage for CUDA version gating, prebuilt modules, capability detection, and diagnostic messages.

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 97c19da2-4e80-4f41-b454-9c5249093e5b

📥 Commits

Reviewing files that changed from the base of the PR and between 9ac29d2 and 5dd6978.

📒 Files selected for processing (3)
  • flashinfer/jit/__init__.py
  • flashinfer/jit/fp4_quantization.py
  • tests/jit/test_toolkit_version_gated_flags.py

Included review availability: Your plan includes up to 8 reviews per rolling hour; 7 remain after this review.


📝 Walkthrough

Walkthrough

The PR adds shared CUDA toolkit and AOT-module gating for JIT compiler flags. FP4 and FP8 paths use the gating logic. Fused-MoE validation reports unsupported builds and toolkit versions. CPU-only tests cover toolkit and AOT scenarios.

Changes

Toolkit-gated JIT support

Layer / File(s) Summary
Version and AOT gating helpers
flashinfer/jit/cpp_ext.py
Adds module-specific AOT detection and conditional NVCC flag generation with informational or warning logs.
Capability probing and compilation wiring
flashinfer/jit/fused_moe.py, flashinfer/jit/gemm/fp8_blockscale.py, flashinfer/jit/fp4_quantization.py, flashinfer/quantization/fp4_quantization.py, flashinfer/jit/__init__.py
Adds cached FP4 and fused-MoE FP8 capability probes. Applies version-gated flags to FP4 and FP8 compilation paths. Re-exports has_fp4_support.
Runtime validation and coverage
flashinfer/fused_moe/core.py, tests/jit/test_toolkit_version_gated_flags.py
Validates fused-MoE FP8 support through built-module capability and tests supported, unsupported, and AOT-backed configurations.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Merge Risk: ⚪ Minimal · up to 5dd69

The change makes unsupported CUDA toolkit behavior explicit and preserves AOT-backed execution paths; no actionable merge-blocking risk remains after normal checks and review.

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant fused_moe
  participant cpp_ext
  participant AOTCache
  Caller->>fused_moe: request FP8 block-scale capability
  fused_moe->>cpp_ext: check CUDA version and AOT module
  cpp_ext->>AOTCache: inspect matching prebuilt module
  AOTCache-->>cpp_ext: module present or absent
  cpp_ext-->>fused_moe: capability result
  fused_moe-->>Caller: supported or unsupported
Loading

Possibly related PRs

  • flashinfer-ai/flashinfer#4290: This PR also changes FP4 fused-MoE support, while this PR adds CUDA toolkit and AOT capability gating.
  • flashinfer-ai/flashinfer#4365: This PR also modifies FP4 and FP8 kernel support, while this PR changes toolkit-gated compilation and capability detection.

Suggested labels: op: misc

Suggested reviewers: aleozlx, yzh119, jimmyzho

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the primary change: warnings for dropped capability flags with CUDA toolkits older than 12.8.
Description check ✅ Passed The description follows the template, explains the changes, links issue #3951, documents tests, and completes the checklist.
Linked Issues check ✅ Passed The changes satisfy issue #3951 by adding diagnostics, AOT-aware capability checks, and the requested public FP4 support query.
Out of Scope Changes check ✅ Passed The changes remain focused on version-gated JIT flags, FP4 and FP8 capability detection, AOT handling, diagnostics, and related tests.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@flashinfer/jit/cpp_ext.py`:
- Around line 94-101: The AOT presence check must not imply that the artifact is
usable. Update has_prebuilt_aot_module() and the related support-probe gating to
validate the AOT load result, or track presence separately from successful
loading, so stale, corrupt, or incompatible artifacts fall back through
JitSpecNvcc.try_load() and do not report unsupported CUDA paths as supported;
retain the JIT-flag warning downgrade only after usability is confirmed. Update
tests/jit/test_toolkit_version_gated_flags.py lines 44-48 to cover an unloadable
AOT artifact and verify the support probe and warning behavior.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 757b9371-69d8-48f8-9396-d0c40616f572

📥 Commits

Reviewing files that changed from the base of the PR and between 4fbac49 and 069e17a3db6d2ccde91fc28dd38ce4a3b8cf69c8.

📒 Files selected for processing (7)
  • flashinfer/fused_moe/core.py
  • flashinfer/jit/cpp_ext.py
  • flashinfer/jit/fp4_quantization.py
  • flashinfer/jit/fused_moe.py
  • flashinfer/jit/gemm/fp8_blockscale.py
  • flashinfer/quantization/fp4_quantization.py
  • tests/jit/test_toolkit_version_gated_flags.py

Comment thread flashinfer/jit/cpp_ext.py
…IT builds

Flags gated on the JIT toolkit version (-DENABLE_FP4 in fp4_quantization,
-DENABLE_FP8_BLOCK_SCALE in cutlass fused_moe 89/90 and fp8_blockscale_gemm_90)
were dropped silently, so the module built fine and the first gated call
failed deep in kernel-runner construction with a misleading dtype-combination
error (flashinfer-ai#3951).

- Add version_gated_nvcc_flag() which emits a loud warning naming the module,
  the dropped flag, the toolkit version found, and the 12.8 requirement.
- Use it at every version-gated flag drop site: jit/fused_moe.py,
  jit/fp4_quantization.py, quantization/fp4_quantization.py, and
  jit/gemm/fp8_blockscale.py.
- Demote the warning to info when a prebuilt AOT artifact exists for the
  module: JitSpecNvcc.try_load() serves such modules from the AOT cache, so
  the JIT flag list is never compiled and the gated kernels stay available.
  Without this, the recommended flashinfer-jit-cache install with an older
  local toolkit warned spuriously, even recommending the wheel already
  installed. The check mirrors the AOT resolution rule through a new
  has_prebuilt_aot_module() helper (shared with the capability probe below)
  instead of moving the warning to build time, which would require threading
  dropped-flag metadata through JitSpec for a strictly larger diff. AOT wheel
  builds themselves compile into a separate build dir and never read
  FLASHINFER_AOT_DIR, so self-builds with an old toolkit still warn loudly.
- Make the existing use_deepseek_fp8_block_scale early check name the actual
  cause and stop rejecting AOT/jit-cache installs, via a new
  cutlass_fused_moe_fp8_block_scale_supported() capability probe.
- Document why SM90 fused_moe keeps -DENABLE_FP4 unconditionally
  (cutlass::float_e2m1_t path from flashinfer-ai#3738, no <cuda_fp4.h> needed).
- Add CPU-only tests that monkeypatch the toolkit-version probe to both sides
  of 12.8 and assert the flag, warning, and AOT-demotion behavior; tests
  isolate FLASHINFER_AOT_DIR so host jit-cache installs cannot skew results.
@rishabhsinha17
rishabhsinha17 force-pushed the fix/fused-moe-fp4-toolkit-guard branch from 069e17a to 9ac29d2 Compare August 9, 2026 17:21
@rishabhsinha17

Copy link
Copy Markdown
Author

@yzh119 @cyx-6 ping: quiet since Aug 9. The CodeRabbit thread is settled and the branch is conflict-free; full CI has not been triggered yet. Anything needed from my side to get it running?

Issue flashinfer-ai#3951 request 2: frameworks selecting between MoE backends need a
public probe for fp4 availability before committing to a multi-minute JIT
build; the only options were probing private jit internals or try/except.

- Add has_fp4_support(device_arch="100") to jit/fp4_quantization.py,
  mirroring cutlass_fused_moe_fp8_block_scale_supported(): True when a
  prebuilt AOT fp4_quantization module for the arch exists or the local
  CUDA toolkit is 12.8+, i.e. when -DENABLE_FP4 survives
  version_gated_nvcc_flag(). Presence-based, no module load.
- Re-export from flashinfer/jit/__init__.py so the spelling requested in
  the issue, flashinfer.jit.has_fp4_support(), works.
- Extend the CPU-only gated-flags tests: toolkit 12.4 -> False, 12.8 ->
  True (no-arg form), AOT artifact with a 12.4 toolkit -> True for the
  covered arch only, and the flashinfer.jit export identity.
@kahyunnam kahyunnam added the op: misc norm, activation, sampling, RoPE, quantization, etc. label Sep 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

op: gemm op: misc norm, activation, sampling, RoPE, quantization, etc. op: moe

Projects

None yet

Development

Successfully merging this pull request may close these issues.

cutlass fused_moe: silent fp4 omission when built with CUDA < 12.8

3 participants