[Chore] Remove redundant `_pack_topk_ids_weights_kernel` in TrtLLM NvFP4 MoE (#46872)

Signed-off-by: jdebache <jdebache@nvidia.com>

Julien Debache committed Sep 1, 2026 at 21:30 UTC ab54f5bd832d27fbe3bccbfa45af5775473301c3
6 files changed +17 -60
vllm/model_executor/layers/fused_moe/experts/trtllm_bf16_moe.py
+2 -4
@@ -20,7 +20,6 @@ from vllm.model_executor.layers.fused_moe.topk_weight_and_reduce import (
20 )
21 from vllm.model_executor.layers.fused_moe.utils import (
22 fi_moe_largest_bucket,
23 - trtllm_moe_pack_topk_ids_weights,
23 )
24 from vllm.model_executor.layers.quantization.utils.flashinfer_utils import (
25 activation_to_flashinfer_int,
@@ -199,11 +198,10 @@ class TrtLlmBf16ExpertsModular(TrtLlmBf16ExpertsBase, mk.FusedMoEExpertsModular)
198 import flashinfer
199 from flashinfer.fused_moe import WeightLayout
200
202 - # Pack topk ids and weights into format expected by the TRTLLM kernel.
203 - packed_topk_ids = trtllm_moe_pack_topk_ids_weights(topk_ids, topk_weights)
201 + topk_ids = topk_ids.to(dtype=torch.int32)
202
203 result = flashinfer.fused_moe.trtllm_bf16_routed_moe(
206 - topk_ids=packed_topk_ids,
204 + topk_ids=(topk_ids, topk_weights),
205 hidden_states=hidden_states,
206 gemm1_weights=w1,
207 gemm2_weights=w2,
vllm/model_executor/layers/fused_moe/experts/trtllm_fp8_moe.py
+2 -4
@@ -17,7 +17,6 @@ from vllm.model_executor.layers.fused_moe.topk_weight_and_reduce import (
17 )
18 from vllm.model_executor.layers.fused_moe.utils import (
19 fi_moe_largest_bucket,
20 - trtllm_moe_pack_topk_ids_weights,
20 )
21 from vllm.model_executor.layers.quantization.utils.flashinfer_utils import (
22 activation_to_flashinfer_int,
@@ -273,8 +272,7 @@ class TrtLlmFp8ExpertsModular(TrtLlmFp8ExpertsBase, mk.FusedMoEExpertsModular):
272 import flashinfer
273 from flashinfer.fused_moe import Fp8QuantizationType, WeightLayout
274
276 - # Pack topk ids and weights into format expected by the kernel.
277 - packed_topk_ids = trtllm_moe_pack_topk_ids_weights(topk_ids, topk_weights)
275 + topk_ids = topk_ids.to(dtype=torch.int32)
276
277 if a1q_scale is None:
278 raise RuntimeError(
@@ -295,7 +293,7 @@ class TrtLlmFp8ExpertsModular(TrtLlmFp8ExpertsBase, mk.FusedMoEExpertsModular):
293 hidden_states_scale = prepare_deepseek_fp8_x_sf(hidden_states, a1q_scale)
294
295 flashinfer.fused_moe.trtllm_fp8_block_scale_routed_moe(
298 - topk_ids=packed_topk_ids,
296 + topk_ids=(topk_ids, topk_weights),
297 routing_bias=None,
298 hidden_states=hidden_states,
299 hidden_states_scale=hidden_states_scale,
vllm/model_executor/layers/fused_moe/experts/trtllm_lora_moe.py
+5 -12
@@ -38,9 +38,6 @@ from vllm.model_executor.layers.fused_moe.experts.lora_experts_mixin import (
38 from vllm.model_executor.layers.fused_moe.topk_weight_and_reduce import (
39 TopKWeightAndReduceNoOP,
40 )
41 -from vllm.model_executor.layers.fused_moe.utils import (
42 - trtllm_moe_pack_topk_ids_weights,
43 -)
41 from vllm.platforms import current_platform
42 from vllm.triton_utils import tl, triton
43 from vllm.utils.flashinfer import has_flashinfer_trtllm_fused_moe
@@ -206,7 +203,7 @@ class _TrtLlmLoRAExpertsBase(LoRAExpertsMixin, mk.FusedMoEExpertsModular):
203 hidden_states: torch.Tensor,
204 w1: torch.Tensor,
205 w2: torch.Tensor,
209 - packed_topk_ids: torch.Tensor,
206 + topk_ids_and_weights: tuple[torch.Tensor, torch.Tensor],
207 gemm1_lora_delta: torch.Tensor | None,
208 global_num_experts: int,
209 a1q_scale: torch.Tensor | None,
@@ -250,10 +247,6 @@ class _TrtLlmLoRAExpertsBase(LoRAExpertsMixin, mk.FusedMoEExpertsModular):
247 intermediate_size = self.intermediate_size_per_partition
248 K = output.size(1)
249
253 - # Routing is computed outside the MoE; pack it into the
254 - # (eid<<16)|w.bf16 format the routed API expects.
255 - packed_topk_ids = trtllm_moe_pack_topk_ids_weights(topk_ids, topk_weights)
256 -
250 # ---- Base-model fast path ----
251 # When no token in the batch selects a LoRA adapter, skip the LoRA machinery
252 # and run the plain base MoE with do_finalize=True, which writes the finalized
@@ -263,7 +256,7 @@ class _TrtLlmLoRAExpertsBase(LoRAExpertsMixin, mk.FusedMoEExpertsModular):
256 hidden_states=hidden_states,
257 w1=w1,
258 w2=w2,
266 - packed_topk_ids=packed_topk_ids,
259 + topk_ids_and_weights=(topk_ids, topk_weights),
260 gemm1_lora_delta=None, # without LoRA, no delta
261 global_num_experts=global_num_experts,
262 a1q_scale=a1q_scale,
@@ -337,7 +330,7 @@ class _TrtLlmLoRAExpertsBase(LoRAExpertsMixin, mk.FusedMoEExpertsModular):
330 hidden_states=hidden_states,
331 w1=w1,
332 w2=w2,
340 - packed_topk_ids=packed_topk_ids,
333 + topk_ids_and_weights=(topk_ids, topk_weights),
334 gemm1_lora_delta=gemm1_lora_delta,
335 global_num_experts=global_num_experts,
336 a1q_scale=a1q_scale,
@@ -518,7 +511,7 @@ class TrtLlmBf16LoRAExperts(_TrtLlmLoRAExpertsBase):
511 hidden_states: torch.Tensor,
512 w1: torch.Tensor,
513 w2: torch.Tensor,
521 - packed_topk_ids: torch.Tensor,
514 + topk_ids_and_weights: tuple[torch.Tensor, torch.Tensor],
515 gemm1_lora_delta: torch.Tensor | None,
516 global_num_experts: int,
517 a1q_scale: torch.Tensor | None,
@@ -533,7 +526,7 @@ class TrtLlmBf16LoRAExperts(_TrtLlmLoRAExpertsBase):
526 # the caller's buffer via output= so it finalizes in place -- no copy.
527 do_finalize = gemm1_lora_delta is None
528 ret = flashinfer.fused_moe.trtllm_bf16_routed_moe(
536 - topk_ids=packed_topk_ids,
529 + topk_ids=topk_ids_and_weights,
530 hidden_states=hidden_states,
531 gemm1_weights=w1,
532 gemm2_weights=w2,
vllm/model_executor/layers/fused_moe/experts/trtllm_mxfp4_moe.py
+3 -3
@@ -20,7 +20,6 @@ from vllm.model_executor.layers.fused_moe.topk_weight_and_reduce import (
20 )
21 from vllm.model_executor.layers.fused_moe.utils import (
22 fi_moe_largest_bucket,
23 - trtllm_moe_pack_topk_ids_weights,
23 )
24 from vllm.model_executor.layers.quantization.utils.flashinfer_utils import (
25 activation_to_flashinfer_int,
@@ -363,9 +362,8 @@ class TrtLlmMxfp4ExpertsModular(TrtLlmMxfp4ExpertsBase, mk.FusedMoEExpertsModula
362 ) -> None:
363 from flashinfer import trtllm_fp4_block_scale_routed_moe
364
366 - packed_tensor = trtllm_moe_pack_topk_ids_weights(topk_ids, topk_weights)
365 trtllm_fp4_block_scale_routed_moe(
368 - topk_ids=packed_tensor,
366 + topk_ids=(topk_ids, topk_weights),
367 routing_bias=None,
368 hidden_states=x_quant,
369 hidden_states_scale=x_scale,
@@ -417,6 +415,8 @@ class TrtLlmMxfp4ExpertsModular(TrtLlmMxfp4ExpertsBase, mk.FusedMoEExpertsModula
415 expert_tokens_meta: mk.ExpertTokensMetadata | None,
416 apply_router_weight_on_input: bool,
417 ):
418 + topk_ids = topk_ids.to(dtype=torch.int32)
419 +
420 topk = topk_ids.size(-1)
421 local_num_experts = w1.size(0)
422 local_expert_offset = self.moe_config.ep_rank * local_num_experts
vllm/model_executor/layers/fused_moe/experts/trtllm_nvfp4_moe.py
+5 -8
@@ -20,10 +20,7 @@ from vllm.model_executor.layers.fused_moe.moe_output import (
20 from vllm.model_executor.layers.fused_moe.topk_weight_and_reduce import (
21 TopKWeightAndReduceNoOP,
22 )
23 -from vllm.model_executor.layers.fused_moe.utils import (
24 - fi_moe_largest_bucket,
25 - trtllm_moe_pack_topk_ids_weights,
26 -)
23 +from vllm.model_executor.layers.fused_moe.utils import fi_moe_largest_bucket
24 from vllm.model_executor.layers.quantization.utils.flashinfer_utils import (
25 activation_to_flashinfer_int,
26 has_flashinfer_situ_activation,
@@ -369,14 +366,11 @@ class TrtLlmNvFp4ExpertsModular(TrtLlmNvFp4ExpertsBase, mk.FusedMoEExpertsModula
366 )
367 else:
368 block_scale, per_token_scale = a1q_scale, None
372 -
373 - # Pack topk ids and weights into format expected by the kernel.
374 - packed_tensor = trtllm_moe_pack_topk_ids_weights(topk_ids, topk_weights)
369 output1_scale_gate_scalar = self.quant_config.g1_alphas
370
371 # Invoke kernel.
372 flashinfer.fused_moe.trtllm_fp4_block_scale_routed_moe(
379 - topk_ids=packed_tensor,
373 + topk_ids=(topk_ids, topk_weights),
374 routing_bias=None,
375 hidden_states=hidden_states,
376 hidden_states_scale=block_scale.view(torch.float8_e4m3fn).reshape(
@@ -434,6 +428,9 @@ class TrtLlmNvFp4ExpertsModular(TrtLlmNvFp4ExpertsBase, mk.FusedMoEExpertsModula
428 # Per-token defers input quant to _invoke_kernel, so a1q_scale is None.
429 assert a1q_scale is not None or self.per_token_activation
430
431 + # DeepEP produces int64 indexes.
432 + topk_ids = topk_ids.to(dtype=torch.int32)
433 +
434 M = hidden_states.shape[0]
435 chunk_size = self._get_chunk_size()
436
vllm/model_executor/layers/fused_moe/utils.py
-29
@@ -503,35 +503,6 @@ def fi_moe_largest_bucket(moe_config: "FusedMoEConfig") -> int:
503 return max(moe_config.max_num_tokens * moe_config.dp_size, 8192)
504
505
506 -def trtllm_moe_pack_topk_ids_weights(
507 - topk_ids: torch.Tensor,
508 - topk_weights: torch.Tensor,
509 - block_size: int = 1024,
510 -) -> torch.Tensor:
511 - assert topk_ids.shape == topk_weights.shape
512 - assert topk_ids.is_contiguous() and topk_weights.is_contiguous()
513 -
514 - original_shape = topk_ids.shape
515 - ids_flat = topk_ids.reshape(-1)
516 - weights_flat = topk_weights.reshape(-1)
517 -
518 - n_elements = ids_flat.numel()
519 - output = torch.empty(n_elements, dtype=torch.int32, device=topk_ids.device)
520 -
521 - use_gdc = current_platform.is_cuda() and current_platform.has_device_capability(90)
522 - grid = (triton.cdiv(n_elements, block_size),)
523 - _pack_topk_ids_weights_kernel[grid](
524 - ids_flat,
525 - weights_flat,
526 - output,
527 - n_elements,
528 - BLOCK_SIZE=block_size,
529 - USE_GDC=use_gdc,
530 - launch_pdl=use_gdc,
531 - )
532 - return output.reshape(original_shape)
533 -
534 -
506 @torch.compile(dynamic=True, backend=current_platform.simple_compile_backend)
507 def _swiglu_limit_torch(
508 output: torch.Tensor,