Skip to content

feat(moe_ep): SM120 MXFP8 swap-AB CuTeDSL MegaMoE kernel - #4387

Merged
Anerudhan merged 17 commits into
flashinfer-ai:mainfrom
mhoqueanik:sm120_megakernel_1
Sep 2, 2026
Merged

Anerudhan merged 17 commits into
flashinfer-ai:mainfrom
mhoqueanik:sm120_megakernel_1

Conversation

@mhoqueanik

@mhoqueanik mhoqueanik commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator

feat(moe_ep): SM120 MXFP8 swap-AB CuTeDSL MegaMoE kernel

Summary

Adds an SM120 (sm_120/sm_121) MXFP8 MegaMoE backend to flashinfer.moe_ep — the swap-AB CuTeDSL megakernel (fused dispatch + grouped GEMM + combine) for the RTX PRO 6000 / GB10 (DGX Spark) class of Blackwell parts. Registered as sm120_mxfp8_mxfp8_bf16_cutedsl behind the standard MegaKernelBackend contract, on the same taxonomy layout as the SM100/SM90 backends.

Status: functional correctness is validated; performance tuning and benchmarking are ongoing. The backend currently takes a knob dict only (no autotune yet), and no performance numbers are quoted in this PR — perf tables will follow once the tuning sweep lands.

What's included

  • Vendored kernel drop: kernel_src/sm120/ — verbatim snapshot of the four kernel packages (common/, src/, moe_sm120_mxfp8_swapab/, moe_mxfp8_glu/) from the sm120_swapab_wt fork at d19d30a (branch run/sm120-mxfp8-perf), including two uncommitted worktree edits recorded in VENDOR.md. src/ stays byte-for-byte upstream; all adaptation lives in the shim.
  • Shim layer: mirrors the sm90 fork-tree conventions — _paths sibling-tree guard, per-tree comm.py (plus zero_local_counter_regions; this drop's kernel does not tail-clean its local counters), all-lazy kernel_helpers, and the SM120 MXFP8 frontend with combine_output + topk-reduce second stage, per-expert epilogue args, K-major weight views, and a mirrored-ABI-constant guard.
  • Backend: backends/mega/kernel/sm120/mxfp8_mxfp8_bf16_cutedsl/ with Sm120_Mxfp8_Mxfp8_Bf16_Cutedsl_MegaMoeConfig (native token_back_mode enum), K-major + interleave-8 weight preprocessing, torch-composed staging (no fused DataPreprocess in this tree), validate_mega_arch_sm120 (exact sm_120/sm_121 family), and the sm120 runtime-requirements alias. Exported from flashinfer.moe_ep.
  • Rank-sharing bootstrap for single-GPU sm_12x boxes: sm_12x cluster nodes have one GPU, and the drop's own harness runs N ranks per GPU. The FI runtime now folds LOCAL_RANK onto the physical GPUs (identity when there are enough), and under MEGA_SINGLE_GPU_GLOO=1 inits the process group as gloo with a CPU-side NVSHMEM UID broadcast (NCCL cannot host two ranks on one device).
  • Tests: sm120 mxfp8 mega multirank suite mirroring the sm100 one (layer-vs-shim parity across staged/prestaged/token-back profiles, all-gather torch-oracle anchor, registry/preprocess checks), a shared arch-free term-magnitude oracle-compare module, new arch_sm120 pytest marker (with arch_blackwell tightened to the sm_10x family so sm100 suites stop collecting on sm_11x/12x hosts), and a mega_sm120 entry in run_tests.sh.

Upstream gaps found and guarded

Each was pinned by A/B against the drop's own runner and is recorded in VENDOR.md as a pending-upstream item; the FI backend rejects the broken configuration rather than silently running it:

gap disposition
in_kernel_fc2_reduce crashes with cudaErrorIllegalAddress (verified RTX PRO 6000, 4 ranks / 1 GPU, DSL 4.6.1); absent from the kernel team's own test scripts rejected by the backend; ikr tests skipped with documented reason; shim keeps the plumbing for a fixed drop
cluster_m > 1 fails cute.compile ("expects num_multicast to be 1 for non multicast G2S copies"); upstream scripts always use (1,1,1) config pinned to cluster (1,1,1)
gate_up_clamp is dead plumbing — kernel_fc12 stores it but never reads it; output bit-identical with/without (invisible to the drop's ±0.5-sparse test data) backend rejects a set clamp; tests run clampless
world_size=1 (MEGA_NO_DIST) numerics silently wrong for mma_tiler N=128 (5-20% of cells; reproduced upstream at their own standard geometry); same tile bit-exact at world_size=4 documented in VENDOR.md; multirank is the validated path

Two harness-level fixes that the correctness claims depend on: the oracle's all_gather is CPU-staged under the rank-sharing gloo group (gloo has no CUDA all_gather — the reference was previously built from corrupted operands), and the shim's _main smoke device folds onto physical GPUs.

Usage

from flashinfer.moe_ep import (
    BootstrapConfig, FleetParams, MegaConfig, MoEEpLayer, MoEEpTensors, MoEWeightPack,
    Sm120_Mxfp8_Mxfp8_Bf16_Cutedsl_MegaMoeConfig,
)

layer = MoEEpLayer(
    BootstrapConfig(world_size=world_size, rank=rank),
    FleetParams(num_experts=256, max_tokens_per_rank=tokens, token_hidden_size=7168),
    weights=MoEWeightPack(w13=w13_bf16, w2=w2_bf16),
    backend=MegaConfig(
        megakernel=Sm120_Mxfp8_Mxfp8_Bf16_Cutedsl_MegaMoeConfig(intermediate_size=2048, top_k=8),
    ),
)
out = layer.forward(MoEEpTensors(hidden_states=x_bf16, topk_ids=ids, topk_weights=w))

On a single-GPU sm_12x box, run multirank via the drop's env: MEGA_SINGLE_GPU_GLOO=1 torchrun --nproc_per_node=4 ....

Constraints

  • Exact sm_120 / sm_121 family only (validate_mega_arch_sm120).
  • in_kernel_fc2_reduce, cluster != (1,1,1), and gate_up_clamp are rejected until the upstream drop fixes them (see table above).
  • Validated against nvidia-cutlass-dsl 4.6.1.
  • No autotuner yet — kernel knobs are passed as an explicit dict.

Testing

  • sm120 mxfp8 mega multirank suite green on RTX PRO 6000 (4 ranks / 1 GPU via the rank-sharing gloo bootstrap), DSL 4.6.1: layer-vs-direct-shim parity across staged / prestaged / large-token dispatch token-back profiles, plus the all-gather torch-oracle anchor (the sm120 reference pins gate_up_interleave=8 + apply_topk_in_fc1=True itself).
  • Registry, config-validation, and weight-preprocess checks.
  • run_tests.sh mega_sm120 (own torchrun process; kernel trees are process-exclusive).

Performance

Ongoing. Kernel-level tuning (tiler/knob sweeps) and the standalone microbenchmark/e2e runs are in progress; numbers will be posted to this PR (or a follow-up) once the tuning sweep completes. Nothing in this PR should be read as a perf claim yet.

Summary by CodeRabbit

  • New Features

    • Added SM120 MXFP8 MegaMoE support, including fused execution, quantized inputs and weights, token communication, top-k reduction, and single- or multi-rank operation.
    • Added offline and collective autotuning for NVFP4 and MXFP8 workloads.
    • Added architecture-specific backend configurations and runtime validation for SM90, SM100, and SM120 hardware.
  • Improvements

    • Introduced clearer backend and kernel names while preserving deprecated aliases for compatibility.
    • Improved workspace cleanup, distributed initialization, CUDA graph safeguards, and input validation.
  • Documentation

    • Expanded architecture, tuning, compatibility, testing, and vendored-source guidance.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: bc86bc65-a099-4589-ab42-8fdbcec5115a

📥 Commits

Reviewing files that changed from the base of the PR and between ba6bf4e and 34444e8.

📒 Files selected for processing (235)
  • .pre-commit-config.yaml
  • benchmarks/bench_moe_ep_sm90_mega.py
  • docs/design_docs/moe_ep_architecture.md
  • docs/design_docs/moe_ep_runbook.md
  • flashinfer/moe_ep/__init__.py
  • flashinfer/moe_ep/backends/mega/kernel/__init__.py
  • flashinfer/moe_ep/backends/mega/kernel/sm100/__init__.py
  • flashinfer/moe_ep/backends/mega/kernel/sm100/fp8_fp4_bf16_deepgemm/__init__.py
  • flashinfer/moe_ep/backends/mega/kernel/sm100/fp8_fp4_bf16_deepgemm/backend.py
  • flashinfer/moe_ep/backends/mega/kernel/sm100/fp8_fp4_bf16_deepgemm/config.py
  • flashinfer/moe_ep/backends/mega/kernel/sm100/fp8_fp4_bf16_deepgemm/staging.py
  • flashinfer/moe_ep/backends/mega/kernel/sm100/fp8_fp4_bf16_deepgemm/weights.py
  • flashinfer/moe_ep/backends/mega/kernel/sm100/mxfp8_mxfp8_bf16_cutedsl/__init__.py
  • flashinfer/moe_ep/backends/mega/kernel/sm100/mxfp8_mxfp8_bf16_cutedsl/backend.py
  • flashinfer/moe_ep/backends/mega/kernel/sm100/mxfp8_mxfp8_bf16_cutedsl/config.py
  • flashinfer/moe_ep/backends/mega/kernel/sm100/mxfp8_mxfp8_bf16_cutedsl/staging.py
  • flashinfer/moe_ep/backends/mega/kernel/sm100/mxfp8_mxfp8_bf16_cutedsl/tuner.py
  • flashinfer/moe_ep/backends/mega/kernel/sm100/mxfp8_mxfp8_bf16_cutedsl/weights.py
  • flashinfer/moe_ep/backends/mega/kernel/sm100/nvfp4_nvfp4_bf16_cutedsl/__init__.py
  • flashinfer/moe_ep/backends/mega/kernel/sm100/nvfp4_nvfp4_bf16_cutedsl/backend.py
  • flashinfer/moe_ep/backends/mega/kernel/sm100/nvfp4_nvfp4_bf16_cutedsl/config.py
  • flashinfer/moe_ep/backends/mega/kernel/sm100/nvfp4_nvfp4_bf16_cutedsl/staging.py
  • flashinfer/moe_ep/backends/mega/kernel/sm100/nvfp4_nvfp4_bf16_cutedsl/tuner.py
  • flashinfer/moe_ep/backends/mega/kernel/sm100/nvfp4_nvfp4_bf16_cutedsl/weights.py
  • flashinfer/moe_ep/backends/mega/kernel/sm120/__init__.py
  • flashinfer/moe_ep/backends/mega/kernel/sm120/mxfp8_mxfp8_bf16_cutedsl/__init__.py
  • flashinfer/moe_ep/backends/mega/kernel/sm120/mxfp8_mxfp8_bf16_cutedsl/backend.py
  • flashinfer/moe_ep/backends/mega/kernel/sm120/mxfp8_mxfp8_bf16_cutedsl/config.py
  • flashinfer/moe_ep/backends/mega/kernel/sm120/mxfp8_mxfp8_bf16_cutedsl/staging.py
  • flashinfer/moe_ep/backends/mega/kernel/sm120/mxfp8_mxfp8_bf16_cutedsl/weights.py
  • flashinfer/moe_ep/backends/mega/kernel/sm90/__init__.py
  • flashinfer/moe_ep/backends/mega/kernel/sm90/fp8_fp8_bf16_pull_cutedsl/__init__.py
  • flashinfer/moe_ep/backends/mega/kernel/sm90/fp8_fp8_bf16_pull_cutedsl/backend.py
  • flashinfer/moe_ep/backends/mega/kernel/sm90/fp8_fp8_bf16_pull_cutedsl/config.py
  • flashinfer/moe_ep/backends/mega/kernel/sm90/fp8_fp8_bf16_pull_cutedsl/staging.py
  • flashinfer/moe_ep/backends/mega/kernel/sm90/fp8_fp8_bf16_pull_cutedsl/weights.py
  • flashinfer/moe_ep/backends/mega/kernel/sm90/fp8_fp8_bf16_push_cuda/__init__.py
  • flashinfer/moe_ep/backends/mega/kernel/sm90/fp8_fp8_bf16_push_cuda/backend.py
  • flashinfer/moe_ep/backends/mega/kernel/sm90/fp8_fp8_bf16_push_cuda/config.py
  • flashinfer/moe_ep/backends/mega/kernel/sm90/fp8_fp8_bf16_push_cuda/staging.py
  • flashinfer/moe_ep/backends/mega/kernel/sm90/fp8_fp8_bf16_push_cuda/weights.py
  • flashinfer/moe_ep/backends/mega/kernel/tuning.py
  • flashinfer/moe_ep/core/kernel/registry.py
  • flashinfer/moe_ep/core/runtime/__init__.py
  • flashinfer/moe_ep/core/runtime/bootstrap.py
  • flashinfer/moe_ep/core/validation/common.py
  • flashinfer/moe_ep/kernel_src/README.md
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/ACKNOWLEDGEMENT.md
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/SKILL.md
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/TUNING.md
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/VENDOR.md
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/__init__.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/shim/__init__.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/shim/__main__.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/shim/_paths.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/shim/autotune.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/shim/comm.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/shim/correctness.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/shim/kernel_helpers.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/shim/knob_cache.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/shim/mxfp8.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/shim/nvfp4.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/shim/quant_stage.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/shim/tuner.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/common/__init__.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/common/host_utils.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/common/megamoe_constants.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/common/moe_utils.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/moe_mxfp8_glu/__init__.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/moe_mxfp8_glu/epilogue_mxfp8.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/moe_mxfp8_glu/kernel_mxfp8_glu_fc12.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/moe_mxfp8_glu/mega_reference_mxfp8.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/moe_mxfp8_glu/mega_runner.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/moe_mxfp8_glu/megamoe_kernel_mxfp8.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/moe_mxfp8_glu/run_functional_tests.sh
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/moe_mxfp8_glu/run_mega_tests.sh
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/moe_mxfp8_glu/runner_common.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/moe_mxfp8_glu/runner_fc12.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/moe_nvfp4_swapab/__init__.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/moe_nvfp4_swapab/benchmark_p2p.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/moe_nvfp4_swapab/contract.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/moe_nvfp4_swapab/custom_ext.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/moe_nvfp4_swapab/dynamic_mainloop.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/moe_nvfp4_swapab/epilogue.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/moe_nvfp4_swapab/epilogue_refactor.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/moe_nvfp4_swapab/fc1_fc2_fuse_sched.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/moe_nvfp4_swapab/kernel_fc12.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/moe_nvfp4_swapab/mega_reference.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/moe_nvfp4_swapab/mega_runner.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/moe_nvfp4_swapab/megamoe_kernel.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/moe_nvfp4_swapab/moe_persistent_scheduler.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/moe_nvfp4_swapab/moe_utils.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/moe_nvfp4_swapab/run_functional_tests.sh
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/moe_nvfp4_swapab/run_mega_tests.sh
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/moe_nvfp4_swapab/runner_common.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/moe_nvfp4_swapab/runner_fc12.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/moe_nvfp4_swapab/runner_fc12_common.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/moe_nvfp4_swapab/simulate_fc1_fc2_sched.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/moe_nvfp4_swapab/topk_reduce.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/src/__init__.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/src/bootstrap.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/src/cleanup_kernel.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/src/config.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/src/dispatch_kernel.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/src/flag_batch.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/src/grid_sync.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/src/iket_compat.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/src/inputs_process.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/src/ptx_helpers.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/src/reference.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/src/sf_swizzle.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/src/sym_buffer.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/src/token_comm.py
  • flashinfer/moe_ep/kernel_src/sm120/__init__.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/SKILL.md
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/VENDOR.md
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/__init__.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/shim/__init__.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/shim/_paths.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/shim/comm.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/shim/kernel_helpers.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/shim/mxfp8.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/common/__init__.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/common/host_utils.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/common/megamoe_constants.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/common/moe_utils.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_mxfp8_glu/__init__.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_mxfp8_glu/custom_ext.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_mxfp8_glu/epilogue_mxfp8.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_mxfp8_glu/kernel_mxfp8_glu_fc12.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_mxfp8_glu/mega_reference_mxfp8.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_mxfp8_glu/mega_runner.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_mxfp8_glu/megamoe_kernel_mxfp8.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_mxfp8_glu/run_functional_tests.sh
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_mxfp8_glu/run_mega_tests.sh
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_mxfp8_glu/runner_common.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_mxfp8_glu/runner_fc12.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_nvfp4_swapab/__init__.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_nvfp4_swapab/benchmark_p2p.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_nvfp4_swapab/contract.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_nvfp4_swapab/custom_ext.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_nvfp4_swapab/cute_ref_ops.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_nvfp4_swapab/dynamic_mainloop.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_nvfp4_swapab/epilogue.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_nvfp4_swapab/epilogue_refactor.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_nvfp4_swapab/fc1_fc2_fuse_sched.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_nvfp4_swapab/kernel_fc12.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_nvfp4_swapab/mega_reference.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_nvfp4_swapab/mega_runner.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_nvfp4_swapab/megamoe_kernel.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_nvfp4_swapab/moe_persistent_scheduler.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_nvfp4_swapab/moe_utils.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_nvfp4_swapab/run_functional_tests.sh
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_nvfp4_swapab/run_mega_tests.sh
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_nvfp4_swapab/runner_common.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_nvfp4_swapab/runner_fc12.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_nvfp4_swapab/runner_fc12_common.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_nvfp4_swapab/simulate_fc1_fc2_sched.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_nvfp4_swapab/topk_reduce.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_sm120_mxfp8_swapab/__init__.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_sm120_mxfp8_swapab/custom_ext.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_sm120_mxfp8_swapab/fc1_fc2_fuse_sched.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_sm120_mxfp8_swapab/kernel_fc12.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_sm120_mxfp8_swapab/mega_reference.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_sm120_mxfp8_swapab/mega_runner.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_sm120_mxfp8_swapab/megamoe_kernel.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_sm120_mxfp8_swapab/moe_persistent_scheduler.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_sm120_mxfp8_swapab/moe_utils.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_sm120_mxfp8_swapab/run_functional_tests.sh
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_sm120_mxfp8_swapab/run_mega_tests.sh
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_sm120_mxfp8_swapab/runner_common.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_sm120_mxfp8_swapab/runner_fc12.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_sm120_mxfp8_swapab/runner_fc12_common.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_sm120_mxfp8_swapab/sm120_mma.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_sm120_mxfp8_swapab/sm120_ptx_helpers.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_sm120_mxfp8_swapab/token_comm.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_sm120_mxfp8_swapab/topk_reduce.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/src/__init__.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/src/bootstrap.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/src/cleanup_kernel.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/src/config.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/src/dispatch_kernel.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/src/flag_batch.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/src/grid_sync.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/src/iket_compat.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/src/inputs_process.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/src/ptx_helpers.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/src/reference.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/src/sf_swizzle.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/src/sym_buffer.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/src/token_comm.py
  • flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/SKILL.md
  • flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/TUNING.md
  • flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/__init__.py
  • flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/shim/__init__.py
  • flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/shim/_paths.py
  • flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/shim/comm.py
  • flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/shim/hopper_fp8.py
  • flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/shim/kernel_helpers.py
  • flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/src/moe_nvfp4_swapab/mega_reference.py
  • flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/src/moe_nvfp4_swapab/moe_persistent_scheduler.py
  • flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/src/moe_nvfp4_swapab/moe_utils.py
  • flashinfer/moe_ep/kernel_src/sm90/push_style_megamoe/VENDOR.md
  • flashinfer/moe_ep/tune.py
  • pyproject.toml
  • tests/conftest.py
  • tests/moe_ep/_sm90_push_fp8_baseline.py
  • tests/moe_ep/mega_oracle_compare.py
  • tests/moe_ep/run_tests.sh
  • tests/moe_ep/smoke_ft_ep.py
  • tests/moe_ep/test_deep_gemm_mega_kernel_vs_reference.py
  • tests/moe_ep/test_deprecated_aliases.py
  • tests/moe_ep/test_fused_quant_stage.py
  • tests/moe_ep/test_knob_cache.py
  • tests/moe_ep/test_layer_factory.py
  • tests/moe_ep/test_mega_cuda_graph.py
  • tests/moe_ep/test_mega_cuda_graph_multirank.py
  • tests/moe_ep/test_mega_layer_validation.py
  • tests/moe_ep/test_moe_ep_deep_gemm_mega_multirank.py
  • tests/moe_ep/test_moe_ep_deep_gemm_skew_determinism.py
  • tests/moe_ep/test_moe_ep_fault_tolerance_multirank.py
  • tests/moe_ep/test_moe_ep_mxfp8_cutedsl_mega_multirank.py
  • tests/moe_ep/test_moe_ep_nvfp4_cutedsl_mega_multirank.py
  • tests/moe_ep/test_moe_ep_sm120_mxfp8_cutedsl_mega_multirank.py
  • tests/moe_ep/test_moe_ep_sm90_pull_fp8_mega_multirank.py
  • tests/moe_ep/test_mxfp8_cutedsl_preprocess_vs_reference.py
  • tests/moe_ep/test_nvfp4_cutedsl_kernel_vs_reference.py
  • tests/moe_ep/test_sm90_pull_fp8_config.py
  • tests/moe_ep/test_sm90_pull_fp8_kernel_vs_reference.py
  • tests/moe_ep/test_sm90_push_fp8_backend.py
  • tests/moe_ep/test_sm90_push_fp8_backend_cpu.py
  • tests/moe_ep/test_sm90_push_fp8_orchestrator.py
  • tests/moe_ep/test_sm90_push_fp8_packaging.py
  • tests/moe_ep/test_weight_pack_union.py
  • tests/moe_ep/test_workspace_pool.py
💤 Files with no reviewable changes (1)
  • flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/src/moe_nvfp4_swapab/moe_persistent_scheduler.py
🚧 Files skipped from review as they are similar to previous changes (86)
  • flashinfer/moe_ep/backends/mega/kernel/sm100/fp8_fp4_bf16_deepgemm/init.py
  • flashinfer/moe_ep/backends/mega/kernel/sm100/init.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/common/init.py
  • flashinfer/moe_ep/backends/mega/kernel/sm100/nvfp4_nvfp4_bf16_cutedsl/init.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/src/iket_compat.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_mxfp8_glu/init.py
  • flashinfer/moe_ep/backends/mega/kernel/sm100/fp8_fp4_bf16_deepgemm/staging.py
  • flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/shim/comm.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_mxfp8_glu/runner_common.py
  • flashinfer/moe_ep/backends/mega/kernel/sm100/nvfp4_nvfp4_bf16_cutedsl/staging.py
  • flashinfer/moe_ep/kernel_src/sm120/init.py
  • .pre-commit-config.yaml
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_sm120_mxfp8_swapab/init.py
  • tests/moe_ep/mega_oracle_compare.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_nvfp4_swapab/run_functional_tests.sh
  • flashinfer/moe_ep/backends/mega/kernel/sm90/fp8_fp8_bf16_pull_cutedsl/init.py
  • flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/SKILL.md
  • flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/TUNING.md
  • flashinfer/moe_ep/backends/mega/kernel/sm100/fp8_fp4_bf16_deepgemm/config.py
  • flashinfer/moe_ep/backends/mega/kernel/sm100/mxfp8_mxfp8_bf16_cutedsl/init.py
  • flashinfer/moe_ep/backends/mega/kernel/sm100/mxfp8_mxfp8_bf16_cutedsl/staging.py
  • flashinfer/moe_ep/backends/mega/kernel/sm100/mxfp8_mxfp8_bf16_cutedsl/tuner.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/src/sf_swizzle.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/shim/_paths.py
  • flashinfer/moe_ep/backends/mega/kernel/sm120/init.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_sm120_mxfp8_swapab/sm120_ptx_helpers.py
  • flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/shim/kernel_helpers.py
  • tests/moe_ep/test_weight_pack_union.py
  • flashinfer/moe_ep/core/runtime/init.py
  • flashinfer/moe_ep/core/kernel/registry.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/moe_nvfp4_swapab/runner_common.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/shim/kernel_helpers.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_sm120_mxfp8_swapab/runner_fc12.py
  • tests/moe_ep/test_mega_cuda_graph_multirank.py
  • flashinfer/moe_ep/backends/mega/kernel/sm100/fp8_fp4_bf16_deepgemm/weights.py
  • tests/moe_ep/test_deep_gemm_mega_kernel_vs_reference.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_nvfp4_swapab/init.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/src/grid_sync.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_sm120_mxfp8_swapab/topk_reduce.py
  • flashinfer/moe_ep/backends/mega/kernel/sm120/mxfp8_mxfp8_bf16_cutedsl/staging.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/src/flag_batch.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/SKILL.md
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/shim/_paths.py
  • tests/conftest.py
  • tests/moe_ep/test_mega_cuda_graph.py
  • flashinfer/moe_ep/core/runtime/bootstrap.py
  • flashinfer/moe_ep/backends/mega/kernel/sm120/mxfp8_mxfp8_bf16_cutedsl/init.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/src/cleanup_kernel.py
  • flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/shim/_paths.py
  • flashinfer/moe_ep/backends/mega/kernel/sm100/fp8_fp4_bf16_deepgemm/backend.py
  • flashinfer/moe_ep/backends/mega/kernel/sm100/nvfp4_nvfp4_bf16_cutedsl/weights.py
  • tests/moe_ep/test_layer_factory.py
  • flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/shim/hopper_fp8.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/TUNING.md
  • benchmarks/bench_moe_ep_sm90_mega.py
  • flashinfer/moe_ep/backends/mega/kernel/sm120/mxfp8_mxfp8_bf16_cutedsl/weights.py
  • flashinfer/moe_ep/backends/mega/kernel/sm100/nvfp4_nvfp4_bf16_cutedsl/config.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_nvfp4_swapab/run_mega_tests.sh
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/src/ptx_helpers.py
  • flashinfer/moe_ep/core/validation/common.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_sm120_mxfp8_swapab/custom_ext.py
  • flashinfer/moe_ep/backends/mega/kernel/sm100/mxfp8_mxfp8_bf16_cutedsl/config.py
  • tests/moe_ep/test_workspace_pool.py
  • flashinfer/moe_ep/backends/mega/kernel/sm100/mxfp8_mxfp8_bf16_cutedsl/weights.py
  • tests/moe_ep/test_moe_ep_deep_gemm_skew_determinism.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/src/reference.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_nvfp4_swapab/custom_ext.py
  • flashinfer/moe_ep/backends/mega/kernel/sm120/mxfp8_mxfp8_bf16_cutedsl/backend.py
  • flashinfer/moe_ep/backends/mega/kernel/sm90/fp8_fp8_bf16_pull_cutedsl/staging.py
  • tests/moe_ep/test_nvfp4_cutedsl_kernel_vs_reference.py
  • tests/moe_ep/test_moe_ep_deep_gemm_mega_multirank.py
  • flashinfer/moe_ep/backends/mega/kernel/sm90/fp8_fp8_bf16_pull_cutedsl/backend.py
  • flashinfer/moe_ep/backends/mega/kernel/sm90/init.py
  • flashinfer/moe_ep/backends/mega/kernel/sm90/fp8_fp8_bf16_pull_cutedsl/weights.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_nvfp4_swapab/dynamic_mainloop.py
  • tests/moe_ep/test_mega_layer_validation.py
  • tests/moe_ep/test_moe_ep_sm90_pull_fp8_mega_multirank.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_mxfp8_glu/custom_ext.py
  • flashinfer/moe_ep/backends/mega/kernel/sm100/mxfp8_mxfp8_bf16_cutedsl/backend.py
  • tests/moe_ep/test_moe_ep_mxfp8_cutedsl_mega_multirank.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/shim/comm.py
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_nvfp4_swapab/fc1_fc2_fuse_sched.py
  • docs/design_docs/moe_ep_architecture.md
  • tests/moe_ep/run_tests.sh
  • flashinfer/moe_ep/backends/mega/kernel/sm100/nvfp4_nvfp4_bf16_cutedsl/backend.py
  • tests/moe_ep/test_sm90_pull_fp8_kernel_vs_reference.py

📝 Walkthrough

Walkthrough

The PR restructures the MegaMoE backend layout with architecture- and datatype-specific naming (for example sm100_fp8_fp4_bf16_deepgemm, sm90_fp8_fp8_bf16_pull_cutedsl). It adds SM90 pull-style FP8 and SM120 swap-AB MXFP8 CuTeDSL Mega backends with vendored kernel sources, updates the kernel registry with deprecated aliases, updates runtime/validation/tuning infrastructure, and updates documentation, benchmarks, and tests.

Changes

MegaMoE multi-architecture backend restructuring

Layer / File(s) Summary
Shared registry, runtime, validation, tuning, and SM100 backend renaming
flashinfer/moe_ep/__init__.py, flashinfer/moe_ep/backends/mega/kernel/*, flashinfer/moe_ep/core/*
Renames SM100 DeepGEMM/NVFP4/MXFP8 CuTeDSL configuration classes and kernel names to architecture-specific identifiers. Adds deprecated aliases with deprecation warnings in the kernel registry. Adds SM90/SM120 runtime requirement helpers and architecture validators. Refactors offline tuning into shared sweep helpers in tuning.py.
SM100 vendored CuTeDSL MegaMoE kernel source updates
flashinfer/moe_ep/kernel_src/cutedsl_megamoe/...
Updates the vendored SM100 kernel source tree, documentation (SKILL.md, TUNING.md, VENDOR.md), shim modules, quantization and reference utilities, and functional test scripts.
SM120 swap-AB MXFP8 Mega backend and vendored kernel source
flashinfer/moe_ep/backends/mega/kernel/sm120/..., flashinfer/moe_ep/kernel_src/sm120/...
Adds the SM120 backend wiring and the complete vendored SM120 swap-AB CuTeDSL Mega kernel source, including MMA, epilogue, scheduler, token-communication, runner, and test scripts.
SM90 pull-style FP8 and push-CUDA Mega backends and vendored kernel source
flashinfer/moe_ep/backends/mega/kernel/sm90/..., flashinfer/moe_ep/kernel_src/sm90/...
Adds the SM90 pull-style FP8 CuTeDSL backend and the SM90 push-style CUDA FP8 backend, together with the vendored SM90 pull-style kernel source tree.
SM90 benchmark, documentation updates, and tooling config
benchmarks/bench_moe_ep_sm90_mega.py, docs/design_docs/*, .pre-commit-config.yaml, pyproject.toml
Adds the SM90 mega-MoE token-sweep benchmark script. Updates architecture-taxonomy documentation and runbook guidance. Updates pre-commit and mypy/Ruff exclusion paths.
Tests for MegaMoE backends and CLI
flashinfer/moe_ep/tune.py, tests/conftest.py, tests/moe_ep/*
Updates the tune.py CLI to dispatch to backend-local tuners. Updates conftest.py markers and GPU-collection logic. Adds shared oracle comparison helpers. Updates run_tests.sh and test modules for SM90, SM120, and renamed SM100 backends.

Estimated code review effort: 5 (Critical) | ~180 minutes

Mergeability Score: 🟠 High · up to 34444

The new SM120 backend can silently produce incorrect results or fail with illegal memory access and distributed deadlocks in supported or configurable paths. Descriptor construction, routing-buffer sizing, shared state, compiled-workspace lifetime, and collective failure handling still have concrete unresolved risks, so the PR is not ready to merge until these are fixed or explicitly accepted by owners.

Sequence Diagram(s)

Not applicable: this PR is a large-scale rename, restructuring, and vendored-source addition across many files without a single coherent new user-facing control flow suitable for a concise sequence diagram.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 31.49% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely identifies the primary change: adding the SM120 MXFP8 swap-AB CuTeDSL MegaMoE kernel.
Description check ✅ Passed The description explains the implementation, constraints, upstream gaps, usage, testing, and performance status; it is detailed and relevant despite omitting template headings.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ 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: 4

Note

Due to the large number of review comments, Critical severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tests/moe_ep/test_deep_gemm_mega_kernel_vs_reference.py (1)

226-242: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Skip instead of erroring when the test runs outside torchrun.

The self-bootstrap path was removed, so the test now depends on the torchrun-provided rendezvous environment. Under plain pytest, WORLD_SIZE is unset, line 226 defaults it to 1, and the guard at line 227 passes. dist.init_process_group(backend="nccl") then runs without MASTER_ADDR / MASTER_PORT and raises, so the test errors rather than skips. run_tests.sh excludes this file from run_unit, but a direct pytest tests/moe_ep/ invocation still collects it.

Gate on the presence of WORLD_SIZE, matching the launcher requirement stated in the module docstring.

🛠️ Proposed fix
-    world_size = int(os.environ.get("WORLD_SIZE", "1"))
+    if "WORLD_SIZE" not in os.environ:
+        pytest.skip("requires torchrun launch (WORLD_SIZE unset)")
+    world_size = int(os.environ["WORLD_SIZE"])
     if world_size != 1:
         pytest.skip("single-rank oracle test; run with --nproc_per_node=1")
🤖 Prompt for 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.

In `@tests/moe_ep/test_deep_gemm_mega_kernel_vs_reference.py` around lines 226 -
242, Update the test’s launcher guard before dist.init_process_group to skip
when WORLD_SIZE is absent, rather than defaulting the missing environment
variable to 1. Preserve the existing single-rank skip for configured world sizes
other than 1, and keep torchrun-launched execution unchanged.
🟠 Major comments (34)
.pre-commit-config.yaml-21-21 (1)

21-21: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Correct and complete the vendored-source exclusions.

The configured SM100 path is not the documented SM100 vendor tree. The exclusions also omit the SM120 vendored src/ tree. Hooks, Ruff, and mypy will process some verbatim upstream files and can block kernel-drop re-syncs.

  • .pre-commit-config.yaml#L21-L21: exclude flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/, flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/src/, and flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/.
  • pyproject.toml#L110-L111: use those same three paths in the mypy exclusion list.
  • pyproject.toml#L125-L126: use those same three paths in the Ruff exclusion list.

Confidence: high. As per coding guidelines, kernel source changes must remain re-syncable without formatting or lint churn.

🤖 Prompt for 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.

In @.pre-commit-config.yaml at line 21, Update .pre-commit-config.yaml:21,
pyproject.toml:110-111, and pyproject.toml:125-126 so the pre-commit, mypy, and
Ruff exclusions consistently include
flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/,
flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/src/, and
flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/.

Source: Coding guidelines

docs/design_docs/moe_ep_runbook.md-210-423 (1)

210-423: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Remove the duplicate Benchmarking section.

This added section is followed by another ## Benchmarking section at Line 426. Keep one canonical section. Merge the SM90 additions into it so benchmark commands, version pins, and measured-result claims have one source of truth.

Confidence: high. As per coding guidelines, keep documentation synchronized with code changes.

🤖 Prompt for 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.

In `@docs/design_docs/moe_ep_runbook.md` around lines 210 - 423, Remove the
duplicate `## Benchmarking` section and retain one canonical benchmarking
section. Merge any SM90-specific additions, commands, version pins, and measured
results from the later section into the retained section, resolving conflicts so
each instruction and claim has a single authoritative version.

Source: Coding guidelines

flashinfer/moe_ep/kernel_src/cutedsl_megamoe/VENDOR.md-9-12 (1)

9-12: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Record the upstream snapshot provenance before merge.

VENDOR.md still leaves the repository URL, vendored commit, and sync date as TODOs. Without these values, reviewers cannot reproduce the src/ drop or distinguish upstream content from local edits.

Confidence: high.

🤖 Prompt for 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.

In `@flashinfer/moe_ep/kernel_src/cutedsl_megamoe/VENDOR.md` around lines 9 - 12,
Update the provenance entries in VENDOR.md: replace the repository URL TODO with
the canonical upstream URL, record the exact upstream commit SHA for the current
src/ drop, and set Last synced to the date that snapshot was imported. Preserve
the existing authors/contacts reference and document only the actual vendored
snapshot metadata.
flashinfer/moe_ep/backends/mega/kernel/sm100/nvfp4_nvfp4_bf16_cutedsl/backend.py-349-361 (1)

349-361: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Clear the thunk cache during workspace teardown.

Lines 305-306 store thunk and workspace.output_activation in _thunk_state. The thunk also retains the workspace launch inputs. This hook removes the staged-token memo but retains those tensors after the workspace pool releases the workspace.

Clear _thunk_state when its workspace key matches id(workspace).

Proposed fix
 def _forget_workspace_state(self, workspace) -> None:
+    if (
+        self._thunk_state is not None
+        and self._thunk_state[0][0] == id(workspace)
+    ):
+        self._thunk_state = None
+
     # The fused-stage memos key on topk_idx.data_ptr(); the symmetric

Confidence: High. Based on learnings, every tensor data_ptr() used as part of a cache key must participate in eviction or invalidation.

🤖 Prompt for 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.

In
`@flashinfer/moe_ep/backends/mega/kernel/sm100/nvfp4_nvfp4_bf16_cutedsl/backend.py`
around lines 349 - 361, Update _forget_workspace_state to remove the
_thunk_state entry associated with the workspace being torn down, using
id(workspace) as the key. Preserve the existing staged-token eviction and only
clear the thunk state when its stored workspace key matches the current
workspace.

Source: Learnings

tests/moe_ep/test_moe_ep_sm120_mxfp8_cutedsl_mega_multirank.py-652-676 (1)

652-676: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Quantitize the SM120 FC1 weight with hidden rows first.

_fc1_weight_from_w13 returns the interleaved (2I, hidden) tensor, but _quantize_mxfp8_weight_k_major treats its inputs as N, K with K trailing. Pass fc1_interleaved[expert].transpose(0, 1) before quantizing, like the SM100 oracle.

🤖 Prompt for 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.

In `@tests/moe_ep/test_moe_ep_sm120_mxfp8_cutedsl_mega_multirank.py` around lines
652 - 676, Update the FC1 quantization in the expert loop to pass
fc1_interleaved[expert].transpose(0, 1) into _quantize_mxfp8_weight_k_major,
ensuring the hidden dimension is treated as K-trailing. Keep the subsequent
transpose and scale-factor handling unchanged.
flashinfer/moe_ep/backends/mega/kernel/sm120/mxfp8_mxfp8_bf16_cutedsl/staging.py-80-155 (1)

80-155: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Validate pre-staged routing metadata before staging.

When quantize_input=False, this path validates only routing shapes. It accepts invalid expert IDs and incompatible routing dtypes. The backend then copies topk_ids into the shim's torch.int64 workspace and topk_weights into its typed workspace.

Validate topk_ids.dtype, topk_weights.dtype, device placement, and each live expert ID before the copy. Reuse the common routing checks where possible. Invalid IDs can select the wrong expert or cause an invalid kernel access.

Confidence: High. The SM120 shim allocates topk_idx as torch.int64 and consumes it as kernel routing metadata.

🤖 Prompt for 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.

In
`@flashinfer/moe_ep/backends/mega/kernel/sm120/mxfp8_mxfp8_bf16_cutedsl/staging.py`
around lines 80 - 155, Extend validate_sm120_mxfp8_forward_inputs for the
quantize_input=False path to validate routing metadata before staging: enforce
the expected device and dtypes for topk_ids and topk_weights, and reject every
live expert ID outside the configured expert range. Reuse
validate_mega_forward_inputs or its routing-validation helpers where compatible,
while preserving the existing shape and pre-staged MXFP8 checks.
flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_nvfp4_swapab/run_mega_tests.sh-127-127 (1)

127-127: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Do not run M01 with the known-broken N=128 default.

M01_single_balanced_topk2 sets MEGA_NO_DIST=1 but does not set --mma_tiler_mnk. The SM120 default uses N=128. VENDOR.md documents incorrect world-size-one output with N=128.

Select a validated N=64 tiler for M01, or disable this case until the upstream kernel fixes the single-rank path. Otherwise, this functional test can report a kernel result that is known to be numerically wrong.

Confidence: High.

🤖 Prompt for 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.

In
`@flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_nvfp4_swapab/run_mega_tests.sh`
at line 127, Update the M01_single_balanced_topk2 test entry to pass a validated
N=64 --mma_tiler_mnk configuration, or remove/disable the case until the
upstream single-rank kernel is fixed; do not leave it using the SM120 N=128
default.
flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/shim/mxfp8.py-290-311 (1)

290-311: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Knob application does not respect gate_up_clamp precedence in either entry point. Both sites accept every dataclass field as a knob, but neither keeps gate_up_clamp consistent with the value the rest of the frontend actually reads. MegaMoESm120Mxfp8Frontend stores the clamp twice, in self._config.gate_up_clamp and in self._gate_up_clamp, and _mega_compile_key and the kernel constructor read only the latter.

  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/shim/mxfp8.py#L290-L311: after line 310 assigns new_config, also assign self._gate_up_clamp = new_config.gate_up_clamp, and change the early-return comparison on line 306 to compare against self.config rather than self._config.
  • flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/shim/mxfp8.py#L1047-L1056: add overrides.pop("gate_up_clamp", None) and overrides.pop("token_back_mode", None) next to the existing in_kernel_fc2_reduce pop, so all three explicit parameters of get_symm_buffer_for_sm120_mxfp8_mega_moe win over the knob dict as the comment on lines 1053-1054 states.
🤖 Prompt for 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.

In `@flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/shim/mxfp8.py`
around lines 290 - 311, Update
flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/shim/mxfp8.py lines
290-311 in MegaMoESm120Mxfp8Frontend.apply_knobs to compare the new
configuration with self.config for the no-op check, then synchronize
self._gate_up_clamp with new_config.gate_up_clamp after assignment. Also update
lines 1047-1056 in get_symm_buffer_for_sm120_mxfp8_mega_moe to remove
gate_up_clamp and token_back_mode from overrides alongside in_kernel_fc2_reduce,
ensuring all explicit parameters take precedence over knobs.
flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/shim/mxfp8.py-496-505 (1)

496-505: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

A failed compile leaves a freed workspace reachable through the cache.

Line 504 calls _release_workspace(), which frees self._mega.shared_workspace and self._mega.combine_root. It does not clear self._mega or self._mega_key. Lines 639-640 set the new state only after cute.compile succeeds.

If cute.compile at line 611, sym_zeros at line 572, or compile_topk_reduce at line 629 raises, self._mega still references the old _CompiledMega whose symmetric buffers are already freed, and self._mega_key still holds the old key. A retry with the same config then matches line 500 and returns that entry. The launch runs against freed symmetric-heap storage.

set_gate_up_clamp and apply_knobs avoid this because they call _invalidate_compile_cache() right after _release_workspace(). Apply the same ordering here.

🛡️ Proposed fix to invalidate before releasing
         ensure_not_capturing("cute.compile + symmetric-heap allocation")
         self._release_workspace()
+        # Drop the cache entry before any step below can raise: the released
+        # workspace must never stay reachable through _mega / _mega_key.
+        self._invalidate_compile_cache()
         self._assert_mirrored_constants()
🤖 Prompt for 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.

In `@flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/shim/mxfp8.py`
around lines 496 - 505, In _ensure_mega_compiled, invalidate the compiled cache
immediately before calling _release_workspace(), matching the ordering used by
set_gate_up_clamp and apply_knobs. Ensure both self._mega and self._mega_key are
cleared before any potentially failing allocation or compilation step, while
preserving the existing cache-return path for valid matching entries.
flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_mxfp8_glu/epilogue_mxfp8.py-762-773 (1)

762-773: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

The rmem_sf if-chain silently drops scales beyond subtile 3.

rmem_sf is allocated with 4 entries and the chain handles subtile_idx 0..3. self._subtile_cnt is cta_tile_n // 2 // EpilogueTileN, so a larger cta_tile_n produces more subtiles. Those extra qpvscale values are then discarded without any error, and _stg_sf_fc1 writes stale scale factors.

Derive the buffer length and the loop bound from self._subtile_cnt, as _write_sf_fc2_buffer already does for the FC2 side.

♻️ Proposed fix
-            if subtile_idx == 0:
-                rmem_sf[0] = qpvscale
-            elif subtile_idx == 1:
-                rmem_sf[1] = qpvscale
-            elif subtile_idx == 2:
-                rmem_sf[2] = qpvscale
-            elif subtile_idx == 3:
-                rmem_sf[3] = qpvscale
+            for j in cutlass.range_constexpr(self._subtile_cnt):
+                if subtile_idx == cutlass.Int32(j):
+                    rmem_sf[j] = qpvscale

The matching allocation at line 578 must use cute.make_layout(self._subtile_cnt), and _stg_sf_fc1 must store self._subtile_cnt entries instead of a fixed 4.

🤖 Prompt for 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.

In
`@flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_mxfp8_glu/epilogue_mxfp8.py`
around lines 762 - 773, Update the FC1 scale-factor handling around rmem_sf
allocation and _stg_sf_fc1: derive the layout length and storage loop bound from
self._subtile_cnt, using cute.make_layout(self._subtile_cnt) and writing every
qpvscale entry through that count instead of a fixed four-entry if-chain.
Preserve the existing per-subtile scale generation and FC2 sizing pattern in
_write_sf_fc2_buffer.
flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_sm120_mxfp8_swapab/mega_runner.py-1400-1417 (1)

1400-1417: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

The CUDA-event path calls all_gather without checking that torch.distributed is initialized.

Every other collective in this file is guarded (see lines 887-891, 1266-1269, 2101-2104, and the world_size == 1 branch at 1759). This one is not. With MEGA_NO_DIST=1 and --use_cuda_events, torch.distributed.all_gather raises because no process group exists.

🐛 Proposed fix
-            gathered = [torch.empty_like(local_us) for _ in range(self.world_size)]
-            torch.distributed.all_gather(gathered, local_us)
+            if (
+                torch.distributed.is_available()
+                and torch.distributed.is_initialized()
+            ):
+                gathered = [
+                    torch.empty_like(local_us) for _ in range(self.world_size)
+                ]
+                torch.distributed.all_gather(gathered, local_us)
+            else:
+                gathered = [local_us]
             if self.rank == 0:
🤖 Prompt for 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.

In
`@flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_sm120_mxfp8_swapab/mega_runner.py`
around lines 1400 - 1417, Guard the CUDA-event aggregation in the shown timing
path before calling torch.distributed.all_gather, using the same
distributed-initialization and single-rank handling established by the other
collectives in this file. When distributed execution is unavailable, compute
critical_us from local_us directly; otherwise preserve the existing gathered
amax calculation.
flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_mxfp8_glu/epilogue_mxfp8.py-206-209 (1)

206-209: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Line 209 discards the _overlapping_accum guard.

Lines 206-208 compute _overlapping_accum from allow_overlap_acc and from the shape check self._cta_tile_n == EpiWarpCount * EpilogueTileN * 2. Line 209 then forces it to True unconditionally. Every downstream decision that depends on the flag (_num_acc_pipeline_stages, _num_accumulator_tmem_cols, the odd/even subtile walk, the TMEM stage stride in kernel_mxfp8_glu_fc12.py) assumes the guarded shape relation holds. A configuration that fails the check now silently takes the overlap path with mismatched TMEM column arithmetic.

If overlap is always required for this kernel, replace the computation with an explicit validation error. If it is a debug override, gate it behind a named flag.

🐛 Proposed fix
-        self._overlapping_accum = allow_overlap_acc and (
-            self._cta_tile_n == EpiWarpCount * EpilogueTileN * 2
-        )
-        self._overlapping_accum = True
+        if self._cta_tile_n != EpiWarpCount * EpilogueTileN * 2:
+            raise ValueError(
+                "GluMxfp8Epilogue requires cta_tile_n == "
+                f"{EpiWarpCount * EpilogueTileN * 2}; got {self._cta_tile_n}."
+            )
+        self._overlapping_accum = True
🤖 Prompt for 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.

In
`@flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_mxfp8_glu/epilogue_mxfp8.py`
around lines 206 - 209, Remove the unconditional `self._overlapping_accum =
True` assignment so the guard computed from `allow_overlap_acc` and the
`_cta_tile_n` shape check remains authoritative. If overlap must always be
enabled, replace the override with explicit validation that rejects
configurations failing the shape relation; otherwise expose any debug override
through a named flag.
flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_sm120_mxfp8_swapab/moe_persistent_scheduler.py-1205-1212 (1)

1205-1212: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Derive the static scheduler params shape from the params object.

When static_expert_shape is bound, MoEStaticSchedulerParams.__extract_mlir_values__ emits no MLIR values. MoEStaticPersistentTileScheduler.__new_from_mlir_values__ still slices values[idx : idx + 3], which deserializes the wrong fields and advances idx into offs.

🐛 Proposed fix
-        new_params = new_from_mlir_values(self.params, values[idx : idx + 3])
-        idx += 3
+        params_len = len(extract_mlir_values(self.params))
+        new_params = new_from_mlir_values(
+            self.params, values[idx : idx + params_len]
+        )
+        idx += params_len
🤖 Prompt for 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.

In
`@flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_sm120_mxfp8_swapab/moe_persistent_scheduler.py`
around lines 1205 - 1212, Update
MoEStaticPersistentTileScheduler.__new_from_mlir_values__ to derive the
serialized parameter count from self.params instead of hardcoding three values.
When self.params has static_expert_shape bound and emits no MLIR values, consume
zero entries and leave idx positioned at the start of self.offs; preserve normal
deserialization for dynamic parameters.
flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_sm120_mxfp8_swapab/runner_fc12_common.py-1268-1281 (1)

1268-1281: 🚀 Performance & Scalability | 🟠 Major | ⚡ Quick win

The correctness path always runs the torch profiler.

Line 1269 inverts the condition: the profiler wraps the launch whenever run_target_kernel_only is False, which is the default correctness path. Line 1278 then prints the full key_averages table on every run. Profiling adds significant launch overhead and floods the harness output that run_mega_tests.sh captures.

Gate the profiler on an explicit switch. MiscDesc already carries verbose.

🐛 Proposed fix
-        if not self.misc.run_target_kernel_only:
+        if self.misc.verbose:
             with torch.profiler.profile(
🤖 Prompt for 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.

In
`@flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_sm120_mxfp8_swapab/runner_fc12_common.py`
around lines 1268 - 1281, Update the launch logic around compiled_kernel so
torch.profiler.profile and its key_averages table run only when MiscDesc.verbose
is enabled. Keep the existing unprofiled launch and synchronization behavior for
the default correctness path and run_target_kernel_only mode.
flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_sm120_mxfp8_swapab/token_comm.py-62-75 (1)

62-75: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

The constructor silently overwrites a caller-supplied combine_format.

Lines 64-72 assign kwargs["combine_format"] unconditionally. If a caller passes combine_format through **kwargs, this discards it without any error. The base TokenInPullTokenBackPush accepts that keyword, so the call site looks valid and the substitution is invisible.

Line 73 has the same problem for token_back_by_dispatch: it derives the value from fc2_output_dtype and overwrites any explicit setting.

Reject the conflicting keywords instead of dropping them.

🐛 Proposed fix
         local_rank = kwargs.pop("local_rank")
         fc2_output_dtype = kwargs.pop("fc2_output_dtype", None)
+        for _reserved in ("combine_format", "token_back_by_dispatch"):
+            if _reserved in kwargs:
+                raise ValueError(
+                    f"{_reserved} is derived from fc2_output_dtype on the SM120 "
+                    f"SYSMEM path; do not pass it explicitly."
+                )
         kwargs["combine_format"] = CombineFormat(
🤖 Prompt for 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.

In
`@flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_sm120_mxfp8_swapab/token_comm.py`
around lines 62 - 75, Update the constructor around the `combine_format` and
`token_back_by_dispatch` assignments to detect whether either keyword was
already supplied in `kwargs`; raise an error for caller-provided values instead
of overwriting them, then derive and assign the defaults only when absent before
calling `TokenInPullTokenBackPush.__init__`.
flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_sm120_mxfp8_swapab/kernel_fc12.py-279-282 (1)

279-282: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Validate the K tile against the hardcoded four inner MMA steps.

_validate_mma_tiler_and_cluster_shape accepts any k % 32 == 0. Both compute loops then hardcode the inner K walk to four steps: for k_inner_mma in cutlass.range_constexpr(0, 4) at Line 1883 and Line 3880, against the make_swapab_m64n8k128_tiled_mma atom. Four steps of the K32 atom consume exactly 128 K elements per staged tile.

If a caller passes mma_tiler_mnk[2] = 256 (the ImplDesc default in runner_fc12_common.py is (128, 128, 256)), the TMA stages a K256 tile but the MMA loop only accumulates the first 128 K elements. The result is silently wrong, with no error. _setup_attributes only asserts divisibility by the instruction K, so it does not catch this either. fc1_tiles_per_fc2_k_tile at Line 3039 also assumes this relation.

Reject any K other than 128, or drive the inner loop from mma_tiler_mnk[2] // 32.

🐛 Proposed guard
         if k % 32 != 0:
             raise ValueError(
                 f"SM120 MXFP8 K ({k}) must be a multiple of the m16n8k32 K atom."
             )
+        if k != 128:
+            raise NotImplementedError(
+                f"SM120 MXFP8 swap-AB hardcodes 4 inner K32 MMA steps per staged "
+                f"tile, so mma_tiler K must be 128; got {k}."
+            )
🤖 Prompt for 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.

In
`@flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_sm120_mxfp8_swapab/kernel_fc12.py`
around lines 279 - 282, Update _validate_mma_tiler_and_cluster_shape so the K
tile matches the four hardcoded m16n8k32 MMA steps used by both compute loops
and fc1_tiles_per_fc2_k_tile: reject any mma_tiler_mnk[2] value other than 128,
or replace those fixed inner-loop bounds with mma_tiler_mnk[2] // 32 and update
dependent staging logic consistently.
flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_nvfp4_swapab/megamoe_kernel.py-909-938 (1)

909-938: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

name() duplicates the base cache key by hand.

This method restates every field of Sm100SwapABSwigluFp4Fc12Kernel.name() (kernel_fc12.py lines 193-211) and appends the MegaMoE fields. The docstring already records that the shared part must be kept in sync manually.

name() is the compiled-kernel cache key. If a future change adds a codegen-affecting field to the base name() and this copy is not updated, two functionally different kernels collide on one cache entry and the wrong binary is reused.

Have the base expose the shared segment once and have this method append to it.

♻️ Proposed structure

In kernel_fc12.py:

+    def _name_common_suffix(self) -> str:
+        m, n, k = self.mma_tiler_mnk
+        cm, cn = self.cluster_shape_mn
+        exp = "x".join(map(str, self.static_expert_shape)) if self.static_expert_shape else "dyn"
+        epiflag = "x".join(map(str, self.epi_flag_batch)) if self.epi_flag_batch else "none"
+        cta = "2_cta" if self.use_2cta_instrs else "1_cta"
+        fc2store = "fc2store_stg" if self.non_ubulk_fc2_store else "fc2store_ublk"
+        inkred = "inkernel_redg" if self.in_kernel_fc2_reduce else "no_inkernel_redg"
+        apply_topk = "apply_topk_fc1_pre_quant" if self.apply_topk_in_fc1 else "apply_topk_after_fc2"
+        return (
+            f"_mmatiler_{m}x{n}x{k}_cluster_{cm}x{cn}_{cta}_sched_{self.load_balance_mode}"
+            f"_expert_shape_{exp}_grouphint_{self.group_hint}"
+            f"_padding_{self.token_padding_block}x{self.sf_padding_block}"
+            f"_{fc2store}_{inkred}_{apply_topk}"
+            f"_fc2out{self.fc2_output_dtype.__name__}_sfvec{self.sf_vec_size}"
+            f"_acc{self.acc_dtype.__name__}_clamp{self.gate_up_clamp}_epiflag{epiflag}"
+        )
+
     def name(self) -> str:
-        ...
+        return "moe_fc12_fuse_nvfp4" + self._name_common_suffix()

Then in this file build "megamoe_nvfp4" + self._name_common_suffix() + <megamoe fields>.

🤖 Prompt for 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.

In
`@flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_nvfp4_swapab/megamoe_kernel.py`
around lines 909 - 938, Refactor the cache-key construction so the base kernel
exposes the shared name segment through a reusable method such as
_name_common_suffix(), and update the MegaMoE name() method to build
"megamoe_nvfp4" from that shared suffix before appending its MegaMoE-specific
fields. Remove the duplicated base-field formatting from name() while preserving
the existing key format and excluding local_rank as before.
flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_nvfp4_swapab/epilogue_refactor.py-1414-1451 (1)

1414-1451: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Use self.warp_idx for the per-warp TMEM slice index.

_subtile_local_tmem_tensor passes a TMEM subtile view that is already offset by each warp’s _warp_lane_offset, but this local 32-row split removes that warp-only stride. Selecting slice 0 makes epi warps 1-3 load warp 0's accumulator rows for the first raw load, so the non-preload fc1 path produces wrong outputs for non-zero epilogue warps. Use self.warp_idx here to keep the sliced view per-warp.

🤖 Prompt for 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.

In
`@flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_nvfp4_swapab/epilogue_refactor.py`
around lines 1414 - 1451, Update the per-warp TMEM slice selection in the
epilogue load path to use self.warp_idx instead of the hardcoded 0 when indexing
tmem_subtile_tensor_per_warp. Preserve the existing local 32-row split and copy
operations so each epilogue warp loads its own accumulator rows.
flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_nvfp4_swapab/kernel_fc12.py-1338-1343 (1)

1338-1343: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Use the scheduler’s 2-CTA position for is_leader_cta.

Under is_swap_ab, launch grid shape becomes (cluster_m, 1) and the 2-CTA pairs run along cta_id_in_cluster[0] == bidy % cluster_shape_mn[0]; bidx is fixed at 0, so the current derivation makes both CTAs in each pair leaders. Source the V pair index from block_in_cluster_coord_vmnk[0] instead.

🤖 Prompt for 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.

In
`@flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_nvfp4_swapab/kernel_fc12.py`
around lines 1338 - 1343, Update is_leader_cta in the kernel’s CTA-index setup
to derive the V pair index from block_in_cluster_coord_vmnk[0], using the
scheduler’s 2-CTA position rather than bidx or mma_tile_coord_v. Preserve the
existing leader comparison against the tiled-MMA thread-ID extent and leave
cta_rank_in_cluster unchanged.
flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_nvfp4_swapab/moe_utils.py-49-50 (1)

49-50: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Use 128 bytes for TensormapDescBytes and remove the duplicate assignment.

This file defines the TMA descriptor slot stride and allocation multiplier, including TensormapWorkspace.get_ptr and TensormapWorkspace.size_bytes. A CUtensorMap descriptor is 128 bytes; using 64 bytes makes descriptor slots underallocate and can write into the next executor’s slot. Keep TensormapDescBytes = 128 once.

🤖 Prompt for 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.

In
`@flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_nvfp4_swapab/moe_utils.py`
around lines 49 - 50, Update the module-level TensormapDescBytes definition to a
single assignment of 128, removing the duplicate 64-byte assignment. Ensure
TensormapWorkspace.get_ptr and TensormapWorkspace.size_bytes continue using this
constant for descriptor stride and allocation.

Source: Linters/SAST tools

flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/shim/hopper_fp8.py-457-479 (1)

457-479: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Pin the weight tensors used in the launch-key check.

MegaMoEHopperFp8Frontend.run() hits the cached path when the data_ptr tuple matches, and _CompiledMega stores launch_kwargs and launch_output but not the FC weights/scales they were built from. If a caller drops a tensor and CUDA reuses the same address, _validate_inputs is skipped and _build_mega_runtime_kwargs() will run on the replaced source. Include the weight tensor identities/objects in the cache entry or enforce a caller contract that keeps these tensors alive for the session lifetime.

🤖 Prompt for 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.

In
`@flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/shim/hopper_fp8.py`
around lines 457 - 479, The cache key built by _launch_cache_key must retain the
FC weight and scale tensor objects, not only their data_ptr values, so cached
launches cannot reuse an address for replacement tensors. Include the relevant
weight tensors in the cached entry or otherwise pin them for the compiled
session, and ensure _validate_inputs remains effective when the original tensors
are no longer alive.

Source: Learnings

flashinfer/moe_ep/backends/mega/kernel/sm90/fp8_fp8_bf16_pull_cutedsl/staging.py-67-73 (1)

67-73: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Record the staged token count before the zero-token early return.

The early return at Lines 68-69 skips _note_staged_tokens at Line 122. Two consequences follow:

  • On a fresh workspace, compute(output=None) calls staged_tokens(), gets None, and raises ValueError.
  • After an earlier stage of N > 0 tokens, the attribute keeps the stale N. A later zero-token stage leaves that stale value, so compute(output=None) runs over N rows of stale routing data.

The pre-staged branch in backend.py always calls _note_staged_tokens, so the two staging paths currently disagree.

🔧 Proposed fix
     num_tokens, hidden = hidden_states.shape
     if num_tokens == 0:
+        _note_staged_tokens(topk_idx_out, 0)
         return

Also applies to: 116-122

🤖 Prompt for 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.

In
`@flashinfer/moe_ep/backends/mega/kernel/sm90/fp8_fp8_bf16_pull_cutedsl/staging.py`
around lines 67 - 73, Update the staging function around the num_tokens
zero-token guard to call _note_staged_tokens with the current num_tokens before
returning, ensuring zero-token stages record 0 instead of leaving staged_tokens
unset or stale. Preserve the existing validation and non-empty staging flow, and
keep the behavior consistent with the pre-staged backend path.
flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/src/bootstrap.py-444-461 (1)

444-461: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

The CPU-staged all_gather shim drops async_op semantics.

_cpu_staged_all_gather accepts async_op but ignores it on the CUDA path and always returns None. A caller that passes async_op=True receives None instead of a work handle, so a following .wait() raises AttributeError. The shim replaces dist.all_gather process-wide, so any other code in the same process is affected once MEGA_SINGLE_GPU_GLOO=1 is set.

Reject the unsupported mode explicitly instead of returning a value that violates the API contract.

🔧 Proposed fix
         def _cpu_staged_all_gather(tensor_list, tensor, group=None, async_op=False):
             if not tensor.is_cuda:
                 return _orig_all_gather(
                     tensor_list, tensor, group=group, async_op=async_op
                 )
+            if async_op:
+                raise NotImplementedError(
+                    "MEGA_SINGLE_GPU_GLOO CPU-staged all_gather does not "
+                    "support async_op=True for CUDA tensors."
+                )
             cpu_out = [
                 torch.empty_like(t, device="cpu") for t in tensor_list
             ]
             _orig_all_gather(cpu_out, tensor.cpu(), group=group)
-            for dst, src in zip(tensor_list, cpu_out):
+            for dst, src in zip(tensor_list, cpu_out, strict=True):
                 dst.copy_(src)
             return None
🤖 Prompt for 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.

In
`@flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/src/bootstrap.py`
around lines 444 - 461, Update _cpu_staged_all_gather to explicitly reject
async_op=True, raising an appropriate unsupported-operation error before
entering the CUDA staging path; preserve the existing synchronous behavior and
return value for async_op=False, including the non-CUDA delegation.

Source: Linters/SAST tools

flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/src/moe_nvfp4_swapab/runner_fc12_common.py-205-234 (1)

205-234: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Use the kind-aware data dtype in the TMA alignment checks.

ProblemDesc.__post_init__ supports nvfp4, mxfp8_e4m3, mxfp8_e5m2, fp8_e4m3, and fp8_e5m2, but the four _check_tma_leading_dim_align calls use Nvfp4DataDtype. For FP8 kinds, leading_dim_bytes measures FP8 data as 1 byte/element, while Nvfp4DataDtype measures it as 0.5 byte/element, so valid FP8 layouts can fail and the error names the wrong dtype. Select the kind data dtype once with kind_data_dtype(self.kind) and pass it to those checks.

🤖 Prompt for 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.

In
`@flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/src/moe_nvfp4_swapab/runner_fc12_common.py`
around lines 205 - 234, Use kind_data_dtype(self.kind) in the surrounding
initialization logic to select the data dtype once, then pass that value to the
four TMA alignment checks for activation, fc1_weight, fc2_weight, and fc1_output
in the runner flow. Replace their hardcoded Nvfp4DataDtype arguments while
preserving the existing self.fc2_output_dtype argument for fc2_output.
flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/src/moe_nvfp4_swapab/moe_persistent_scheduler.py-1205-1212 (1)

1205-1212: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Keep params deserialization aligned with the serialized value count.

MoEStaticSchedulerParams.__extract_mlir_values__ emits zero values when only Python int fields are used in expert_shape. MoEStaticPersistentTileScheduler.__new_from_mlir_values__ still slices values[idx : idx + 3] and advances idx += 3, so every subsequent field is deserialized from the wrong offset. Use the emitted params value length, as MoEDynamicPersistentTileScheduler does.

🔧 Proposed fix
         idx = 0
 
-        new_params = new_from_mlir_values(self.params, values[idx : idx + 3])
-        idx += 3
+        params_len = len(extract_mlir_values(self.params))
+        new_params = new_from_mlir_values(self.params, values[idx : idx + params_len])
+        idx += params_len
🤖 Prompt for 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.

In
`@flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/src/moe_nvfp4_swapab/moe_persistent_scheduler.py`
around lines 1205 - 1212, Update
MoEStaticPersistentTileScheduler.__new_from_mlir_values__ to determine the
params slice length from MoEStaticSchedulerParams.__extract_mlir_values__ (or
the corresponding emitted params values) instead of assuming three values.
Advance idx by that same computed length so new_offs and all subsequent fields
remain aligned, including when expert_shape contains only Python ints.
flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/src/src/token_comm.py-653-664 (1)

653-664: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Use the fixed per-rank capacity when deriving the advertise buffer stride.

src_token_topk_idx is allocated as (num_experts_per_rank, world_size, max_tokens_per_rank * num_topk), but dispatch_warp_body passes input_token_buffer.shape[0] into dispatch_prep; this creates MAX_SLOT_C = num_tokens * num_topk. Under a per-rank capacity contract, this must be the runtime per-rank token count, not the local buffer length. Add an assertion or pass an explicit constant for the stride used at line 678.

🤖 Prompt for 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.

In
`@flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/src/src/token_comm.py`
around lines 653 - 664, Update dispatch_warp_body and dispatch_prep so the
advertise-buffer stride uses the fixed runtime per-rank token capacity required
by src_token_topk_idx, rather than input_token_buffer.shape[0]. Ensure
MAX_SLOT_C in the token_comm.py path is derived from that capacity and add an
assertion validating the buffer shape when appropriate.
flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/src/common/host_utils.py-170-173 (1)

170-173: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Detect NaN values as mismatches.

At Line 173, diff > threshold is false when diff is NaN. A NaN kernel result can therefore print a successful validation result against a finite reference value. Use torch.isclose(..., equal_nan=False) and invert its result, or explicitly include non-finite values in mismatch_mask.

Confidence: High.

Proposed fix
-    diff = _torch.abs(gpu_data.float() - ref_data.float())
-    threshold = atol + rtol * _torch.abs(ref_data.float())
-    mismatch_mask = diff > threshold
+    mismatch_mask = ~_torch.isclose(
+        gpu_data.float(), ref_data.float(), atol=atol, rtol=rtol, equal_nan=False
+    )
🤖 Prompt for 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.

In
`@flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/src/common/host_utils.py`
around lines 170 - 173, Update the mismatch calculation in the validation logic
around `mismatch_mask` to classify NaN results as mismatches, rather than
relying solely on `diff > threshold`. Use `_torch.isclose` with
`equal_nan=False` and invert it, or explicitly combine the existing comparison
with a non-finite-value check while preserving the atol/rtol thresholds.
flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/src/moe_nvfp4_swapab/mega_runner.py-2644-2664 (1)

2644-2664: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

The NotImplementedError handler reports success and hides real failures.

return_code stays 0 on every path, and os._exit(return_code) runs unconditionally. Any NotImplementedError raised anywhere inside tester.run() is caught, printed on rank 0 only, and the process exits with status 0.

The comment says the handler exists "until the MegaMoE kernel side is wired", but this PR wires the kernel. The handler now also swallows genuine failures. validate raises NotImplementedError at lines 1504-1508 for the transformers + in-kernel-reduce combination, and that failure would be reported as a pass. Non-rank-0 processes print nothing at all.

🐛 Proposed fix
     return_code = 0
     try:
         tester.run()
     except NotImplementedError as exc:
-        # Expected until the MegaMoE kernel side is wired; the host
-        # orchestration above is the part being smoke-tested for now.
-        if rank == 0:
-            print(f"[mega_runner] kernel launch skipped: {exc}")
+        print(f"[rank {rank}] [mega_runner] unsupported configuration: {exc}")
+        return_code = 1
🤖 Prompt for 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.

In
`@flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/src/moe_nvfp4_swapab/mega_runner.py`
around lines 2644 - 2664, Update the tester.run() error handling and return_code
flow so NotImplementedError is no longer silently treated as success now that
the kernel is wired. Preserve intentional handling for the unsupported
transformers plus in-kernel-reduce validation case by reporting the failure
appropriately, propagate a nonzero exit status for genuine failures, and ensure
all ranks participate consistently before os._exit(return_code).
flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/src/moe_nvfp4_swapab/mega_reference.py-2559-2597 (1)

2559-2597: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Include per-operand layout in the compiled-kernel cache key.

_to_cute_tensor() marks CuTe tensors with the input’s leading_dim before compiling, but self._compiled only uses dtype. Identical dtypes from different calls, such as fc1 and fc2 in reference_expert_fc12(), share one compiled kernel; if their 3D operand layouts differ, the second call reuses a cache entry with the wrong mark_layout_dynamic(leading_dim=...) shape. Add per-operand shape/stride/leading-dimension data to the cache key.

🤖 Prompt for 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.

In
`@flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/src/moe_nvfp4_swapab/mega_reference.py`
around lines 2559 - 2597, Update the _compiled cache key in the surrounding
execution method to include each operand’s layout metadata, not just dtype:
capture per-operand shape, stride, and leading-dimension information for a_cute,
b_cute, sfa_cute, sfb_cute, and c_cute. Ensure calls with different 3D layouts
compile and cache separate kernels while identical layouts continue reusing the
correct compiled entry.
flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/src/moe_hopper_fp8/epilogue_fp8_swapab.py-885-931 (1)

885-931: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Disable or rebuild the in-kernel FC2 REDG path.

fc2_in_kernel_topk_reduce reaches this epilogue without a swap-AB guard, and the swap-AB hidden mapping strides by lane_group (hidden0/hidden1 plus +8). The packing shuffles lanes +0/+4/+8/+12, so those lanes own h, h+4, h+8, h+12 rather than four adjacent 2-byte bf16 cells for one 8-byte REDG. This write path can use misaligned REDG targets or write wrong columns.

🤖 Prompt for 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.

In
`@flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/src/moe_hopper_fp8/epilogue_fp8_swapab.py`
around lines 885 - 931, Disable the in-kernel FC2 top-k reduction path in the
swap-AB configuration, or rebuild its lane mapping so the shuffle lanes and
hidden indices target four adjacent bf16 cells for each REDG segment. Update the
branch guarded by _fc2_in_kernel_topk_reduce and preserve aligned destinations
and correct columns before calling red_add_relaxed_sys_v2_bf16x2.
flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/src/moe_hopper_fp8/kernel_fp8_glu_fc12.py-2265-2284 (1)

2265-2284: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Use the full stage transaction size for tx_count.

tx_count is the expected transaction bytes for one stage barrier. The shared AB pipeline has two TMA producers, and num_tma_load_bytes already covers the A bytes, B bytes, and activation-scale bytes for one stage. Passing num_tma_load_bytes // 2 makes the full mbarrier complete before the TMA-B load finishes, so WGMMA consumers can read uninitialized SMEM. Set tx_count=self.num_tma_load_bytes.

🤖 Prompt for 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.

In
`@flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/src/moe_hopper_fp8/kernel_fp8_glu_fc12.py`
around lines 2265 - 2284, Update the AB pipeline construction in the kernel
initialization to pass the full stage transaction size as tx_count.
Specifically, change the PipelineTmaAsync.create call to use
self.num_tma_load_bytes rather than halving it, while leaving the producer and
consumer group configuration unchanged.
flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/src/src/bootstrap.py-27-31 (1)

27-31: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Defer nvshmem.core import until device bootstrap.

flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/__init__.py imports get_symm_buffer_for_hopper_fp8_mega_moe, which transitively imports shim/comm.py and then src/bootstrap.py. That makes flashinfer.moe_ep.kernel_src.sm90.pull_style_cutedsl_megakernel fail at import time in environments without nvshmem4py. Move nvshmem.core into the function path where sym-buffer allocation/bootstrap runs, or make src/bootstrap.py raise/defer a usable conditional error only when dist.is_initialized().

🤖 Prompt for 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.

In
`@flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/src/src/bootstrap.py`
around lines 27 - 31, Remove the module-level nvshmem.core import from
src/bootstrap.py and import it only inside the device bootstrap or
symmetric-buffer allocation function that requires it. Keep package imports
usable without nvshmem4py, while preserving a clear conditional error when that
runtime path is invoked without the dependency.
flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/src/moe_nvfp4_swapab/custom_ext.py-565-566 (1)

565-566: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

_cluster_m is global class state and can be overwritten between kernels.

Line 566 mutates the class attribute GluMxFp8WorkTileInfo._cluster_m. Every GluMxFp8WorkTileInfo.from_rmem call reads that class attribute at Line 253 to derive fc1_counter_index. If two GluMxFp8Fc12SchedExtension instances with different cluster_m exist in one process (for example during a tuning sweep or a mixed SM90/SM100 run), the last constructed extension wins, and the earlier kernel derives a wrong FC1 counter slot. __new_from_mlir_values__ at Lines 568-579 restores result.cluster_m but never restores the class attribute, so the hazard also survives MLIR round-trips.

Pass cluster_m explicitly into from_rmem instead, or make the work-tile class per-extension.

🐛 Sketch of an explicit-parameter fix
     `@classmethod`
-    def from_rmem(cls, rmem: cute.Tensor) -> "GluMxFp8WorkTileInfo":
+    def from_rmem(cls, rmem: cute.Tensor, cluster_m: int = 1) -> "GluMxFp8WorkTileInfo":
         return cls(
             ...
-            fc1_counter_index=rmem[1] // cutlass.Int32(cls._cluster_m),
+            fc1_counter_index=rmem[1] // cutlass.Int32(cluster_m),
         )

Each from_rmem call site then supplies the owning extension's self.cluster_m.

🤖 Prompt for 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.

In
`@flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/src/moe_nvfp4_swapab/custom_ext.py`
around lines 565 - 566, Remove the shared `GluMxFp8WorkTileInfo._cluster_m`
mutation and make `cluster_m` an explicit input to
`GluMxFp8WorkTileInfo.from_rmem`. Update every `from_rmem` call in
`GluMxFp8Fc12SchedExtension` to pass the owning extension’s `self.cluster_m`,
while preserving `result.cluster_m` handling in `__new_from_mlir_values__`.
flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/src/moe_hopper_fp8/mega_runner.py-52-56 (1)

52-56: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Add or move the missing tester.host_utils imports.

flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/src/moe_hopper_fp8/mega_runner.py imports reduce_add_deterministic_check_dim_size_limit and reduce_add_ordering_match from tester.host_utils, but there is no tester package in the vendored SM90 file set. Add those helpers alongside the existing shared test utilities or point the import at the package that defines them. Without this, mega_runner fails during module load and validate() cannot run.

🤖 Prompt for 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.

In
`@flashinfer/moe_ep/kernel_src/sm90/pull_style_cutedsl_megakernel/src/moe_hopper_fp8/mega_runner.py`
around lines 52 - 56, Update the imports used by mega_runner so
reduce_add_deterministic_check_dim_size_limit and reduce_add_ordering_match
resolve from an available shared utility package rather than the nonexistent
tester package. Preserve validate() behavior and ensure the module loads
successfully in the vendored SM90 file set.

Comment on lines +101 to +112
if sf_vec_size in self.VALID_AB_DTYPE_SF_SIZE:
valid_ab = self.VALID_AB_DTYPE_SF_SIZE[sf_vec_size]
if ab_dtype not in valid_ab:
raise ValueError(
f"ab_dtype={ab_dtype.__name__} is not valid for "
f"sf_vec_size={sf_vec_size}. "
f"Expected one of: {[t.__name__ for t in valid_ab_tuple]}."
)
else:
raise NotImplementedError(
f"sf_vec_size must be {Mxfp8BlockSize} (MXFP8)"
)

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.

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

valid_ab_tuple is undefined; the validation path raises NameError.

The local variable is named valid_ab at line 102. Line 107 references valid_ab_tuple. When a caller passes an unsupported ab_dtype, Python raises NameError while building the message instead of the intended ValueError. The diagnostic is lost.

🐛 Proposed fix
             if ab_dtype not in valid_ab:
                 raise ValueError(
                     f"ab_dtype={ab_dtype.__name__} is not valid for "
                     f"sf_vec_size={sf_vec_size}. "
-                    f"Expected one of: {[t.__name__ for t in valid_ab_tuple]}."
+                    f"Expected one of: {[t.__name__ for t in valid_ab]}."
                 )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if sf_vec_size in self.VALID_AB_DTYPE_SF_SIZE:
valid_ab = self.VALID_AB_DTYPE_SF_SIZE[sf_vec_size]
if ab_dtype not in valid_ab:
raise ValueError(
f"ab_dtype={ab_dtype.__name__} is not valid for "
f"sf_vec_size={sf_vec_size}. "
f"Expected one of: {[t.__name__ for t in valid_ab_tuple]}."
)
else:
raise NotImplementedError(
f"sf_vec_size must be {Mxfp8BlockSize} (MXFP8)"
)
if sf_vec_size in self.VALID_AB_DTYPE_SF_SIZE:
valid_ab = self.VALID_AB_DTYPE_SF_SIZE[sf_vec_size]
if ab_dtype not in valid_ab:
raise ValueError(
f"ab_dtype={ab_dtype.__name__} is not valid for "
f"sf_vec_size={sf_vec_size}. "
f"Expected one of: {[t.__name__ for t in valid_ab]}."
)
else:
raise NotImplementedError(
f"sf_vec_size must be {Mxfp8BlockSize} (MXFP8)"
)
🧰 Tools
🪛 Ruff (0.16.1)

[error] 107-107: Undefined name valid_ab_tuple

(F821)

🤖 Prompt for 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.

In
`@flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_mxfp8_glu/kernel_mxfp8_glu_fc12.py`
around lines 101 - 112, Update the validation error message in the sf_vec_size
branch to reference the existing valid_ab collection instead of the undefined
valid_ab_tuple, while preserving the intended ValueError for unsupported
ab_dtype values.

Source: Linters/SAST tools

Comment on lines +464 to +475
@cute.jit
def _amax_lane(self, v: cutlass.Float32) -> cutlass.Float32:
if cutlass.const_expr(self.sf_vec_size == 32):
return cute.arch.warp_redux_sync(v, "fmax", abs=True)
first_half = (self.lane_idx % cutlass.Int32(32)) < cutlass.Int32(16)
vsel = cutlass.Float32(0.0)
if first_half:
vsel = v
amax = cute.arch.warp_redux_sync(vsel, "fmax", abs=True)
if not first_half:
amax = cute.arch.warp_redux_sync(v, "fmax", abs=True)
return amax

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.

🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Inspect cute.arch.warp_redux_sync signature and its default member mask.
set -euo pipefail

CUTLASS_DIR="$(python -c 'import cutlass, pathlib; print(pathlib.Path(cutlass.__file__).parent)' 2>/dev/null || true)"
if [ -z "${CUTLASS_DIR:-}" ]; then echo "cutlass not importable in sandbox"; exit 0; fi

rg -nP -C10 'def\s+warp_redux_sync' "$CUTLASS_DIR" --glob '*.py'
rg -nP -C3 'redux\.sync' "$CUTLASS_DIR" --glob '*.py' | head -40

Repository: flashinfer-ai/flashinfer

Length of output: 196


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate target file =="
fd -a 'epilogue_refactor.py' . || true

echo "== relevant source context =="
if [ -f flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_nvfp4_swapab/epilogue_refactor.py ]; then
  sed -n '440,490p' flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_nvfp4_swapab/epilogue_refactor.py | cat -n
fi

echo "== cute.arch.warp_redux_sync call sites =="
rg -n 'warp_redux_sync|redux\.sync' . --glob '*.py' | head -200

echo "== imports and sf_vec_size context =="
sed -n '1,80p' flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_nvfp4_swapab/epilogue_refactor.py | cat -n
rg -n 'sf_vec_size|lane_idx' flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_nvfp4_swapab/epilogue_refactor.py | head -80

Repository: flashinfer-ai/flashinfer

Length of output: 16871


🌐 Web query:

CUTE warp_redux_sync default member mask redux.sync full member mask

💡 Result:

In the context of the NVIDIA CuTe (CUTLASS Template) library, the warp_redux_sync function and the underlying PTX redux.sync instruction utilize a membership mask to define which threads in a warp participate in a collective reduction operation [1][2]. Warp Membership Mask The membership mask is a 32-bit integer where each bit corresponds to a specific thread (lane) in a warp [3]. When executing warp-level primitives, this mask determines which threads are synchronized and participate in the operation [3]. Default and Full Masks - Full Member Mask: In most NVIDIA CUDA and CuTe contexts, the full member mask is defined as 0xFFFFFFFF, which represents all 32 threads in a warp [1][3][4]. - Default Mask: The CuTe warp_redux_sync API explicitly uses this full mask (0xFFFFFFFF) as the default value for its mask_and_clamp parameter [1]. Usage Notes - PTX Specification: The underlying PTX instruction redux.sync.<op>.<type> dst, src, membermask expects the src value followed by the membermask [2][5]. Developers should be cautious of alignment issues; historical discrepancies between intrinsic definitions and PTX documentation have occasionally led to confusion regarding argument order [6][5]. - Best Practices: While 0xFFFFFFFF is the standard default, you should analyze program logic to ensure only threads intended to participate are included in the mask [3]. Using an incorrect mask—especially failing to include all threads that reach the primitive—can lead to program hangs or undefined behavior [3]. It is important to note that redux.sync operations are architecture-specific (typically requiring SM 8.0 or higher) and function by synchronizing all participating threads before performing the reduction [2][7][8].

Citations:


Keep _amax_lane reductions on uniform warp control flow.

cute.arch.warp_redux_sync has a full-warp member mask by default, but the second reduction is reached only by the 16 lanes in first_half == False. That violates redux.sync’s full member-mask contract and can leave the warp hanging.

Compute both half-warp amax candidates with masked values, then select the lane’s result afterward.

🤖 Prompt for 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.

In
`@flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_nvfp4_swapab/epilogue_refactor.py`
around lines 464 - 475, Update _amax_lane to keep every warp_redux_sync call on
uniform warp control flow: compute both half-warp candidates using masked
values, perform the reductions unconditionally for all lanes, then select the
appropriate result based on first_half. Preserve the existing full-warp path for
sf_vec_size == 32.

Comment on lines +66 to +72
in_aligned_iter = cute.make_ptr(
in_tile.element_type,
in_tile.iterator.toint(),
AddressSpace.gmem,
assumed_align=16,
)
in_tile = cute.make_tensor(in_aligned_iter, in_tile.layout)

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.

🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

The kernel asserts 16-byte alignment that the validator never checks on the base pointer.

Lines 66-71 and 115-120 rebuild the tile iterators with assumed_align=16 and then issue a 128-bit CopyUniversalOp. _validate_tensors checks only the strides at lines 167-172. It never checks combine_output.data_ptr() or reduced_output.data_ptr().

_infer_assumed_align at lines 187-192 confirms that the base pointer can be less than 16-byte aligned. A non-owning slice of a larger buffer reaches this path with an 8-byte aligned base. Every stride check still passes, and the 128-bit copy then reads or writes a misaligned address, which faults at runtime.

Add a base-pointer check to _validate_tensors.

🛡️ Proposed fix
     if reduced_output.stride(0) % BF16_HIDDEN_PER_THREAD != 0:
         raise ValueError("reduced_output rows must preserve 16-byte alignment.")
+    for _name, _t in (("combine_output", combine_output), ("reduced_output", reduced_output)):
+        if int(_t.data_ptr()) % 16 != 0:
+            raise ValueError(
+                f"{_name} base pointer must be 16-byte aligned for the "
+                f"128-bit vector copy; got {int(_t.data_ptr()) % 16} byte offset."
+            )

Also applies to: 115-121, 167-172

🤖 Prompt for 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.

In
`@flashinfer/moe_ep/kernel_src/sm120/swapab_cutedsl_megakernel/src/moe_sm120_mxfp8_swapab/topk_reduce.py`
around lines 66 - 72, Update _validate_tensors to validate that
combine_output.data_ptr() and reduced_output.data_ptr() are 16-byte aligned, in
addition to the existing stride checks. Reject misaligned base pointers before
the tile iterators use assumed_align=16 for the 128-bit copies.

@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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
flashinfer/moe_ep/kernel_src/cutedsl_megamoe/VENDOR.md (1)

9-12: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Record the immutable upstream baseline.

Line 10 through Line 12 leave the repository URL, base commit, and sync date unresolved. The partial update at Line 29 cannot be audited or reproduced without this baseline. Record the exact upstream URL, full base SHA, and sync date before merge.

🤖 Prompt for 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.

In `@flashinfer/moe_ep/kernel_src/cutedsl_megamoe/VENDOR.md` around lines 9 - 12,
Update VENDOR.md to replace the TODO placeholders with the exact immutable
upstream repository URL, full source baseline commit SHA, and date when the
current drop was synced, preserving the existing repository, Vendored commit,
and Last synced fields so the partial update can be audited and reproduced.
🤖 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.

Outside diff comments:
In `@flashinfer/moe_ep/kernel_src/cutedsl_megamoe/VENDOR.md`:
- Around line 9-12: Update VENDOR.md to replace the TODO placeholders with the
exact immutable upstream repository URL, full source baseline commit SHA, and
date when the current drop was synced, preserving the existing repository,
Vendored commit, and Last synced fields so the partial update can be audited and
reproduced.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 8fe69aaf-04a6-4839-b1b7-87748290e6b6

📥 Commits

Reviewing files that changed from the base of the PR and between 9c2befb and c3210e3.

📒 Files selected for processing (6)
  • .pre-commit-config.yaml
  • docs/design_docs/moe_ep_runbook.md
  • flashinfer/moe_ep/kernel_src/README.md
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/VENDOR.md
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/common/host_utils.py
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/src/inputs_process.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • .pre-commit-config.yaml
  • docs/design_docs/moe_ep_runbook.md

@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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
flashinfer/moe_ep/kernel_src/cutedsl_megamoe/VENDOR.md (1)

9-12: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Pin the current upstream snapshot.

Repo, Vendored commit, and Last synced remain TODO. Lines 19-20 require a verbatim drop and a clean upstream diff, but these placeholders prevent reproducible auditing of src/. Record the canonical repository URL, exact upstream SHA, and sync date before merge.

🤖 Prompt for 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.

In `@flashinfer/moe_ep/kernel_src/cutedsl_megamoe/VENDOR.md` around lines 9 - 12,
Replace the TODO placeholders in VENDOR.md with the canonical upstream
repository URL, the exact commit SHA corresponding to the vendored src/
snapshot, and the date of that synchronization. Keep the existing attribution
and verbatim-drop requirements unchanged.
🧹 Nitpick comments (1)
flashinfer/moe_ep/kernel_src/cutedsl_megamoe/VENDOR.md (1)

29-47: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Make the standalone inputs_process harness compatible with the mixed snapshot.

Production fused staging imports DataPreprocess and does not load the mismatched host_utils symbol. The test suite references the harness but does not execute it. Vendor the matching host_utils API, or add a CI check that detects the missing mxfp8_quantize_per_block_32_row symbol when the harness runs.

🤖 Prompt for 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.

In `@flashinfer/moe_ep/kernel_src/cutedsl_megamoe/VENDOR.md` around lines 29 - 47,
Update the standalone inputs_process harness to work with the mixed snapshot by
providing the expected mxfp8_quantize_per_block_32_row API in the recorded-drop
host_utils, or by adding a CI check that explicitly detects and reports its
absence when the harness executes. Keep production DataPreprocess imports and
unrelated nvfp4, shim, and kernel paths unchanged.
🤖 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.

Outside diff comments:
In `@flashinfer/moe_ep/kernel_src/cutedsl_megamoe/VENDOR.md`:
- Around line 9-12: Replace the TODO placeholders in VENDOR.md with the
canonical upstream repository URL, the exact commit SHA corresponding to the
vendored src/ snapshot, and the date of that synchronization. Keep the existing
attribution and verbatim-drop requirements unchanged.

---

Nitpick comments:
In `@flashinfer/moe_ep/kernel_src/cutedsl_megamoe/VENDOR.md`:
- Around line 29-47: Update the standalone inputs_process harness to work with
the mixed snapshot by providing the expected mxfp8_quantize_per_block_32_row API
in the recorded-drop host_utils, or by adding a CI check that explicitly detects
and reports its absence when the harness executes. Keep production
DataPreprocess imports and unrelated nvfp4, shim, and kernel paths unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 4d7a0758-5827-4d28-b0a8-5adddb3bd8c3

📥 Commits

Reviewing files that changed from the base of the PR and between c3210e3 and 56209bc.

📒 Files selected for processing (2)
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/VENDOR.md
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/common/host_utils.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • flashinfer/moe_ep/kernel_src/cutedsl_megamoe/src/common/host_utils.py

@coderabbitai

coderabbitai Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@flashinfer-bot

Copy link
Copy Markdown
Collaborator

GitLab MR !1267 has been updated with latest changes, and the CI pipeline #65772681 is currently running. I'll report back once the pipeline job completes.

@Anerudhan
Anerudhan enabled auto-merge (squash) September 2, 2026 05:37
@flashinfer-bot

Copy link
Copy Markdown
Collaborator

[SUCCESS] Pipeline #65772681: 16/16 executed test jobs passed

aleozlx pushed a commit that referenced this pull request Sep 2, 2026
…on main) (#4903)

## 📌 Description


`tests/moe/test_unified_moe_activation_matrix.py::test_documented_activation_matrix_matches_runner_registry`
is failing on `main`, which blocks CI for **every open PR**:

```
AssertionError: docs/design_docs/flashinfer_moe_api.md is stale;
run: python scripts/generate_moe_activation_matrix.py --write
```

This is a **semantic merge conflict**, not a defect in any single PR.
#4805 added the generator, its check test, and a matrix block rendered
from `_BACKEND_RUNNERS` as it stood on that PR's base. Two changes
landed on `main` in between, and neither could have known to re-render
the block:

| Change | Effect on the matrix |
|---|---|
| #4793 (`f7d4b167`) | renamed `CuteDslRunner.backend_key`
`cute_dsl_nvfp4` → `cute_dsl` and added `QuantVariant.MXFP4` to its
supported variants |
| #4646 (`0cbace05`) | registered `CuTileBf16Runner` /
`CuTileNvfp4Runner` in `_BACKEND_RUNNERS` |

Each PR was green on its own base; the merged tree is what is stale.
Because the check compares the committed block against the live
registry, it has been red for everyone since #4805 merged.

## 🔍 Change

Only the generated block changes — this commit is the mechanical output
of the documented regeneration command:

```
python scripts/generate_moe_activation_matrix.py --write
```

- adds `cutile_bf16` (`BF16`) and `cutile_nvfp4` (`NVFP4`), both
`SwiGLU`, `ReLU2`
- replaces the two `cute_dsl_nvfp4` rows with three `cute_dsl` rows
(`MXFP4`, `NVFP4`, `W4A16`)

No source, test, or prose changes.

## 🧪 Testing

The authoritative check is
`test_documented_activation_matrix_matches_runner_registry`, which runs
in this PR's own CI.

## 🔗 Related

Surfaced while triaging CI on #4387, whose H100 job ran the full suite
with 221,273 passing and this as the sole failure.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Documentation**
* Updated the MoE activation matrix table to document MXFP4, NVFP4, and
W4A16 support across additional activation functions.
* Added documented BF16 and NVFP4 configuration entries for CuTile
implementations.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Md Anik and others added 17 commits September 2, 2026 10:15
Verbatim snapshot of the four kernel packages (common/, src/,
moe_sm120_mxfp8_swapab/, moe_mxfp8_glu/) from the sm120_swapab_wt fork
worktree at d19d30a (branch run/sm120-mxfp8-perf), incl. two uncommitted
worktree edits recorded in VENDOR.md. No shim yet — src/ only.

AI-assisted.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adapter layer over the verbatim drop, mirroring the sm90 fork-tree
conventions: _paths sibling-tree guard, per-tree comm.py (plus
zero_local_counter_regions -- this drop's kernel does not tail-clean its
local counters), all-lazy kernel_helpers (constants pull cutlass at
import), and the Sm120 MXFP8 frontend with combine_output + topk-reduce
second stage, per-expert all-ones epilogue args, K-major weight views,
and mirrored-ABI-constant guard. Also vendors moe_nvfp4_swapab (import
dependency of the mxfp8 torch reference).

AI-assisted.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Registers the SM120 swap-AB MXFP8 kernel behind the standard
MegaKernelBackend contract: Sm120_Mxfp8_Mxfp8_Bf16_Cutedsl_MegaMoeConfig
(native token_back_mode enum, knob dict only -- no autotune yet),
K-major + interleave-8 weight preprocessing, torch-composed staging
(no fused DataPreprocess shim in this tree), validate_mega_arch_sm120
(sm_120/sm_121 exact family), and the sm120 runtime-requirements alias.
Exported from flashinfer.moe_ep; runbook tree list updated.

AI-assisted.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Mirrors the sm100 mxfp8 multirank file for the sm120 swap-AB backend:
layer-vs-direct-shim parity (staged / prestaged / ikr / large-token
dispatch token-back), the all-gather torch-oracle anchor (the sm120
reference pins gate_up_interleave=8 + apply_topk_in_fc1=True itself),
sm120-local _plain_mxfp8_from_bf16, and registry/preprocess checks.
The term-magnitude band helper moves to an arch-free shared module
(tests/moe_ep/mega_oracle_compare.py) so both suites import one
definition without dragging in each other's importorskip. Adds the
arch_sm120 marker (exact sm_12x family) and tightens arch_blackwell to
the sm_10x family so sm100-tree tests stop collecting on sm_11x/12x
hosts where their kernels cannot compile. run_tests.sh gains
mega_sm120 (own torchrun process; trees are process-exclusive).

AI-assisted.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Every sm_120/121 node on the cluster has one GPU, and the SM120 kernel
drop's own bootstrap runs N ranks per GPU (GB10 / DGX Spark). Mirror
that in the FI runtime: fold LOCAL_RANK onto the physical GPUs
(identity when there are enough), and under MEGA_SINGLE_GPU_GLOO=1
(the drop's env) init the process group as gloo with a CPU-side
NVSHMEM UID broadcast (NCCL cannot host two ranks on one device).
tests/conftest.py: an explicit torchrun WORLD_SIZE >= N overrides the
physical-GPU-count skip for gpu_N markers.

AI-assisted.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The drop's own mega_runner crashes with cudaErrorIllegalAddress under
--in_kernel_fc2_reduce (verified on RTX PRO 6000, 4 ranks / 1 GPU,
DSL 4.6.1) and the flag is absent from the kernel team's test scripts.
Reject it in the FI backend, skip the ikr tests with the documented
reason, and record the gap in VENDOR.md; the shim keeps the plumbing
for a fixed drop.

AI-assisted.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
cluster_m > 1 fails cute.compile ('expects num_multicast to be 1 for
non multicast G2S copies') -- reproduced with the drop's own
mega_runner; its test scripts always use 1,1,1. Shim config rejects
anything else; large-token test profile drops the cluster knob.

AI-assisted.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Under the rank-sharing gloo process group, all_gather of CUDA tensors
silently corrupts (gloo has no CUDA all_gather; the kernel drop's own
bootstrap monkey-patches identical CPU staging) -- the oracle was
comparing the kernel against a reference built from garbage operands.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two more upstream gaps pinned by A/B against the drop's own runner:
(1) gate_up_clamp is dead plumbing (kernel_fc12 stores it, never reads
it; output bit-identical with/without clamp -- invisible to the drop's
±0.5-sparse test data). Backend rejects a set clamp; tests go
clampless. (2) world_size=1 (MEGA_NO_DIST) numerics are silently wrong
for mma_tiler N=128 (5-20% cells, reproduced upstream at their own
standard geometry); the same tile is bit-exact at world_size=4.
Both recorded in VENDOR.md.

AI-assisted.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
pre-commit run -a caught that the sm120 vendored drop was never added to
the lint excludes — mypy/ruff/whitespace hooks were rewriting ~50 files
under kernel_src/sm120/swapab_cutedsl_megakernel/src/ (verbatim tree, must
stay byte-identical to upstream per kernel_src/README.md). Added the drop
to the three exclude points (.pre-commit-config.yaml global exclude,
pyproject [tool.mypy] exclude, [tool.ruff] extend-exclude) and reverted
the hook damage.

Legit findings in OUR files, fixed:
- shim/mxfp8.py: the symm-buffer factory annotated token_back_mode as str
  while MegaMoESm120Mxfp8Config wants the Literal — annotated with the
  same Literal (mypy arg-type).
- ruff-format pass over shim/, sm120+sm100+sm90 backend wrappers, and the
  moe_ep tests (line wraps from the longer taxonomy names; same set the
  base branch reformatted in e9f791a).

AI-assisted (Claude Code).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e check

The error path referenced an undefined valid_ab_tuple, masking the
intended ValueError with a NameError; re-aligns with the reference
copy in kernel_src/cutedsl_megamoe (which uses valid_ab).

Addresses CodeRabbit review on PR flashinfer-ai#4387.
AI-assisted.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…28 numerics)

Dense-data microbenchmarks (moe_ep_benchmark, deepseek_v3 geometry) show the
sm120 drop's ws1 N=128 numerics gap extends to world_size=2: rel-L2 vs the
bf16 dense reference degrades from the ~6.35% MXFP8 band to 10-28% once
tokens fill past an N=64 tile, with run-to-run magnitude variation
(race-like). A/B on RTX 6000D: ws2 tokens/rank=64 N=64 -> 6.365%,
N=128 -> 10.266%. ws4 N=128 stays in band (6.32-6.34%).

Backend now defaults mma_tiler_mnk=(64, 64, 128) when ep_world_size <= 2;
an explicit mma_tiler_mnk knob still overrides. VENDOR.md updated.

AI-assisted (Claude Code).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Dense-data validation shows the N=128 corruption also hits world_size=4
(8-25% rel-L2 across 8..4096 tokens/rank vs the ~6.35% MXFP8 band; ws4
tokens/rank=64 with N=64 returns 6.356%). The drop's ws4 'bit-exact'
check used 1%-sparse test data, which cannot see it. Pin
mma_tiler_mnk=(64,64,128) unconditionally (explicit knob still overrides);
~23% large-batch throughput cost vs the broken N=128.

AI-assisted (Claude Code).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Upstream flashinfer-ai#4348 asserts _resolve_local_device returns the raw LOCAL_RANK;
the unconditional local_rank % device_count fold broke that test on
1-GPU CI (5 % 1 == 0). Fold only under the sm_12x rank-sharing flow
(MEGA_SINGLE_GPU_GLOO=1), where it is required, and add a unit test for
the gated fold.

AI-assisted.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The test-sharding runner collects the whole primary test scope in one
pytest process. tests/moe_ep/test_moe_ep_sm120_mxfp8_cutedsl_mega_multirank.py
imports the vendored SM120 swapab_cutedsl_megakernel shim at module scope,
whose _paths guard raises RuntimeError (not ImportError, so pytest.importorskip
does not catch it) when the SM100 cutedsl_megamoe tree already owns the
top-level `common` module in that process.

That aborts collection for the entire scope, which is why unit_test_b300 and
JIT Unittest (H100) fail with
"kernel module 'common' is already imported from .../cutedsl_megamoe/src/common"
before a single test runs.

SM90 already had a collection isolation partition for exactly this reason; the
three vendored trees are mutually exclusive with one another, so give SM120 its
own partition rather than folding it into the SM90 group. Execution is already
per-source-file subprocesses, so only collection needed the split.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@Anerudhan Anerudhan added run-ci and removed run-ci labels Sep 2, 2026
@Anerudhan
Anerudhan merged commit f7d8be0 into flashinfer-ai:main Sep 2, 2026
24 of 25 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants