main
cpp 1,171 lines 49.4 KB
Raw
1 #include "ops.h"
2 #include "cuda_utils.h"
3 #include "core/registration.h"
4
5 #include <torch/csrc/stable/library.h>
6
7 // Register ops with STABLE_TORCH_LIBRARY for libtorch stable ABI compatibility.
8 // Note: We register under namespace "_C" so ops are accessible as
9 // torch.ops._C.<op_name> for compatibility with existing code.
10 STABLE_TORCH_LIBRARY_FRAGMENT(_C, ops) {
11 // Compute per-token-group FP8 quantized tensor and scaling factor.
12 // The dummy arguments are here so we can correctly fuse with RMSNorm.
13 ops.def(
14 "per_token_group_fp8_quant(Tensor input, Tensor! output_q, Tensor! "
15 "output_s, "
16 "int group_size, float eps, float fp8_min, float fp8_max, bool "
17 "scale_ue8m0, bool dummy_is_scale_transposed, bool dummy_is_tma_aligned "
18 ") -> ()");
19 // Compute per-token-group 8-bit quantized tensor and UE8M0-packed,
20 // TMA-aligned scales for DeepGEMM.
21 ops.def(
22 "per_token_group_fp8_quant_packed(Tensor input, Tensor! output_q, "
23 "Tensor! output_s_packed, int group_size, float eps, float fp8_min, "
24 "float fp8_max) -> ()");
25 // Compute per-token-group INT8 quantized tensor and scaling factor.
26 ops.def(
27 "per_token_group_quant_int8(Tensor input, Tensor! output_q, Tensor! "
28 "output_s, int group_size, float eps, float int8_min, float int8_max) -> "
29 "()");
30 ops.def("get_cuda_view_from_cpu_tensor(Tensor cpu_tensor) -> Tensor");
31
32 #ifndef USE_ROCM
33
34 // Note about marlin kernel 'workspace' arguments:
35 // Technically these should be mutable since they are modified by the kernel.
36 // But since they are set back to zero once the kernel is finished we can
37 // hand wave and say that they have no net effect.
38 //
39 // The reason to mark 'workspace' as immutable is so that they don't interfere
40 // with using ScalarType arguments in the ops. If they are marked as mutable,
41 // pytorch throws an assert in
42 // 'torch._higher_order_ops._register_effectful_op' that prevents these
43 // kernels from being torch.compile'd.
44 // See the following document for more info on custom types and ops that use
45 // custom types:
46 // https://docs.google.com/document/d/18fBMPuOJ0fY5ZQ6YyrHUppw9FA332CpNtgB6SOIgyuA
47
48 // Machete (Dense) Optimized Mixed Precision GEMM for Hopper.
49 ops.def(
50 "machete_supported_schedules("
51 " ScalarType a_type,"
52 " int b_type,"
53 " ScalarType? maybe_group_scales_type,"
54 " ScalarType? maybe_group_zeros_type,"
55 " ScalarType? maybe_channel_scales_type,"
56 " ScalarType? maybe_token_scales_type,"
57 " ScalarType? maybe_out_type"
58 ") -> str[]");
59 ops.def(
60 "machete_mm("
61 " Tensor A,"
62 " Tensor B,"
63 " int b_type,"
64 " ScalarType? out_type,"
65 " Tensor? group_scales,"
66 " Tensor? group_zeros,"
67 " int? group_size,"
68 " Tensor? channel_scales,"
69 " Tensor? token_scales,"
70 " str? schedule"
71 ") -> Tensor");
72 ops.def(
73 "machete_prepack_B("
74 " Tensor B,"
75 " ScalarType a_type,"
76 " int b_type,"
77 " ScalarType? group_scales_type"
78 ") -> Tensor");
79 // conditionally compiled so impl registration is in source file
80
81 // Marlin GEMM
82 ops.def(
83 "marlin_gemm(Tensor a, Tensor? c_or_none, Tensor b_q_weight, "
84 "Tensor? b_bias_or_none,Tensor b_scales, "
85 "Tensor? a_scales, Tensor? global_scale, Tensor? b_zeros_or_none, "
86 "Tensor workspace, int b_type_id, "
87 "SymInt size_m, SymInt size_n, SymInt size_k, "
88 "bool use_atomic_add, bool use_fp32_reduce, bool is_zp_float) -> Tensor");
89 // conditionally compiled so impl registrations are in source file
90
91 // gptq_marlin repack from GPTQ.
92 ops.def(
93 "gptq_marlin_repack(Tensor b_q_weight, "
94 "SymInt size_k, SymInt size_n, int num_bits, bool is_a_8bit) -> Tensor");
95 // conditionally compiled so impl registrations are in source file
96
97 // awq_marlin repack from AWQ.
98 ops.def(
99 "awq_marlin_repack(Tensor b_q_weight, SymInt size_k, "
100 "SymInt size_n, int num_bits, bool is_a_8bit) -> Tensor");
101 // conditionally compiled so impl registrations are in source file
102
103 // preprocess W-int4A-fp8 weight for marlin kernel
104 ops.def(
105 "marlin_int4_fp8_preprocess(Tensor qweight, "
106 "Tensor? qzeros_or_none, bool inplace) -> Tensor");
107 // conditionally compiled so impl registrations are in source file
108 #endif
109
110 #ifndef USE_ROCM
111 // CUTLASS w8a8 GEMM, supporting symmetric per-tensor or per-row/column
112 // quantization, as well as bias
113 ops.def(
114 "cutlass_scaled_mm(Tensor! out, Tensor a,"
115 " Tensor b, Tensor a_scales,"
116 " Tensor b_scales, Tensor? bias) -> ()");
117
118 // CUTLASS w8a8 GEMM, supporting asymmetric per-tensor or per-row/column
119 // quantization.
120 ops.def(
121 "cutlass_scaled_mm_azp(Tensor! out, Tensor a,"
122 " Tensor b, Tensor a_scales,"
123 " Tensor b_scales, Tensor azp_adj,"
124 " Tensor? azp, Tensor? bias) -> ()");
125
126 // Check if cutlass scaled_mm is supported for CUDA devices of the given
127 // capability
128 ops.def("cutlass_scaled_mm_supports_fp8(int cuda_device_capability) -> bool");
129
130 // Check if cutlass grouped gemm is supported for CUDA devices of the given
131 // capability
132 ops.def("cutlass_group_gemm_supported(int cuda_device_capability) -> bool");
133
134 // CUTLASS w8a8 grouped GEMM
135 ops.def(
136 "cutlass_moe_mm(Tensor! out_tensors, Tensor a_tensors, Tensor b_tensors, "
137 " Tensor a_scales, Tensor b_scales, Tensor expert_offsets, "
138 " Tensor problem_sizes, Tensor a_strides, "
139 " Tensor b_strides, Tensor c_strides, bool per_act_token, "
140 " bool per_out_ch) -> ()");
141
142 // A function that computes data required to run fused MoE with w8a8 grouped
143 // GEMM. It takes topk_ids as an input, and computes expert_offsets
144 // (token start indices of each expert). In addition to this, it computes
145 // problem sizes for each expert's multiplication used by the two mms called
146 // from fused MoE operation, and arrays with permutations required to shuffle
147 // and de-shuffle the input/output of the fused operation.
148 ops.def(
149 "get_cutlass_moe_mm_data(Tensor topk_ids, Tensor! expert_offsets, "
150 " Tensor! problem_sizes1, Tensor! problem_sizes2, "
151 " Tensor! input_permutation, "
152 " Tensor! output_permutation, int num_experts, "
153 " int n, int k, Tensor? blockscale_offsets, "
154 " bool is_gated) -> ()");
155
156 // compute per-expert problem sizes from expert_first_token_offset
157 // produced by vLLM's moe_permute kernel
158 ops.def(
159 "get_cutlass_moe_mm_problem_sizes_from_expert_offsets("
160 " Tensor expert_first_token_offset, "
161 " Tensor! problem_sizes1, "
162 " Tensor! problem_sizes2, "
163 " int n, int k, bool swap_ab) -> ()");
164
165 // A function that computes data required to run fused MoE with w8a8 grouped
166 // GEMM in batched expert format. It takes expert_num_tokens
167 // as an input, and computes expert_offsets (token start indices of each
168 // expert). In addition to this, it computes problem sizes for each expert's
169 // multiplication used by the two mms called from fused MoE operation.
170 ops.def(
171 "get_cutlass_batched_moe_mm_data(Tensor! expert_offsets, "
172 " Tensor! problem_sizes1, "
173 " Tensor! problem_sizes2, "
174 " Tensor expert_num_tokens, "
175 " int num_local_experts, int padded_m, "
176 " int n, int k) -> ()");
177
178 // Check if cutlass scaled_mm supports block quantization (used by DeepSeekV3)
179 ops.def(
180 "cutlass_scaled_mm_supports_block_fp8(int cuda_device_capability) -> "
181 "bool");
182
183 // CUTLASS nvfp4 block scaled GEMM
184 ops.def(
185 "cutlass_scaled_fp4_mm(Tensor! out, Tensor a, Tensor b,"
186 " Tensor block_scale_a, Tensor block_scale_b,"
187 " Tensor alpha) -> ()");
188
189 // cutlass nvfp4 block scaled group GEMM
190 ops.def(
191 "cutlass_fp4_group_mm(Tensor! out, Tensor a, Tensor b,"
192 " Tensor a_blockscale, Tensor b_blockscales, Tensor alphas,"
193 " Tensor problem_sizes, Tensor expert_offsets, Tensor sf_offsets) -> ()");
194
195 // cutlass mxfp4 block scaled group GEMM (MXFP4 x MXFP4 MoE)
196 ops.def(
197 "cutlass_mxfp4_group_mm(Tensor! out, Tensor a, Tensor b,"
198 " Tensor a_blockscale, Tensor b_blockscales,"
199 " Tensor problem_sizes, Tensor expert_offsets, Tensor sf_offsets) -> ()");
200
201 // Compute NVFP4 block quantized tensor.
202 ops.def(
203 "scaled_fp4_quant(Tensor input,"
204 " Tensor input_scale, bool "
205 "is_sf_swizzled_layout) -> (Tensor, Tensor)");
206
207 // Out variant
208 // TODO: Add out_variant tag once PyTorch supports it (added in 2.11)
209 // This registration is now migrated to stable ABI
210 // at::Tag::out_variant is not available in the stable ABI (enum_tag.h is not
211 // yet in torch/headeronly), the tag should be applied from Python
212 // via torch.library.Library.define(..., tags=(torch.Tag.out_variant,))
213 // with the .impl remaining in C++.
214 // See pytorch/pytorch#176117.
215 ops.def(
216 "scaled_fp4_quant.out(Tensor input,"
217 " Tensor input_scale, bool "
218 "is_sf_swizzled_layout, *, Tensor(a!) output, Tensor(b!) output_scale) "
219 "-> ()");
220
221 // Compute NVFP4 experts quantization.
222 ops.def(
223 "scaled_fp4_experts_quant(Tensor! output, Tensor! output_scale,"
224 "Tensor input, Tensor input_global_scale, Tensor input_offset_by_experts,"
225 "Tensor output_scale_offset_by_experts) -> ()");
226
227 // Fused SiLU+Mul+NVFP4 experts quantization.
228 ops.def(
229 "silu_and_mul_scaled_fp4_experts_quant(Tensor! output, Tensor! "
230 "output_scale,"
231 "Tensor input, Tensor input_global_scale, Tensor input_offset_by_experts,"
232 "Tensor output_scale_offset_by_experts) -> ()");
233
234 // Compute MXFP4 experts quantization (32-element blocks, E8M0 SFs).
235 ops.def(
236 "mxfp4_experts_quant(Tensor! output, Tensor! output_scale,"
237 "Tensor input, Tensor input_offset_by_experts,"
238 "Tensor output_scale_offset_by_experts, int n_experts) -> ()");
239
240 // Fused SiLU+Mul+MXFP4 experts quantization.
241 ops.def(
242 "silu_and_mul_mxfp4_experts_quant(Tensor! output, Tensor! "
243 "output_scale,"
244 "Tensor input, Tensor input_offset_by_experts,"
245 "Tensor output_scale_offset_by_experts, int n_experts) -> ()");
246
247 // Fused SiLU+Mul+NVFP4 quantization.
248 ops.def(
249 "silu_and_mul_nvfp4_quant(Tensor! result, Tensor! result_block_scale, "
250 "Tensor input, Tensor input_global_scale) -> ()");
251
252 // Check if cutlass_scaled_mm_fp4 is supported for CUDA devices
253 // of the given capability
254 ops.def("cutlass_scaled_mm_supports_fp4(int cuda_device_capability) -> bool");
255
256 // CUTLASS w4a8 GEMM
257 ops.def(
258 "cutlass_w4a8_mm("
259 " Tensor A,"
260 " Tensor B,"
261 " Tensor group_scales,"
262 " int group_size,"
263 " Tensor channel_scales,"
264 " Tensor token_scales,"
265 " ScalarType? out_type,"
266 " str? maybe_schedule"
267 ") -> Tensor");
268
269 // pack scales
270 ops.def("cutlass_pack_scale_fp8(Tensor scales) -> Tensor");
271
272 // encode and reorder weight matrix
273 ops.def("cutlass_encode_and_reorder_int4b(Tensor B) -> Tensor");
274
275 // CUTLASS w4a8 grouped GEMM
276 ops.def(
277 "cutlass_w4a8_moe_mm("
278 " Tensor! out_tensors,"
279 " Tensor a_tensors,"
280 " Tensor b_tensors,"
281 " Tensor a_scales,"
282 " Tensor b_scales,"
283 " Tensor b_group_scales,"
284 " int b_group_size,"
285 " Tensor expert_offsets,"
286 " Tensor problem_sizes,"
287 " Tensor a_strides,"
288 " Tensor b_strides,"
289 " Tensor c_strides,"
290 " Tensor group_scale_strides,"
291 " str? maybe_schedule"
292 ") -> ()");
293
294 ops.def(
295 "cutlass_encode_and_reorder_int4b_grouped(Tensor b_tensors) -> (Tensor, "
296 "Tensor)");
297
298 // SM100 CUTLASS MLA decode
299 // conditionally compiled so impl registrations are in source file
300 ops.def(
301 "sm100_cutlass_mla_decode(Tensor! out, Tensor! lse, Tensor q_nope,"
302 " Tensor q_pe, Tensor kv_c_and_k_pe_cache,"
303 " Tensor seq_lens, Tensor page_table,"
304 " Tensor workspace, float scale,"
305 " int num_kv_splits) -> ()");
306
307 ops.def(
308 "sm100_cutlass_mla_get_workspace_size(int max_seq_len, int num_batches,"
309 " int sm_count, int num_kv_splits) "
310 "-> int");
311 // Quantized GEMM for AWQ.
312 ops.def(
313 "awq_gemm(Tensor _in_feats, Tensor _kernel, Tensor _scaling_factors, "
314 "Tensor _zeros, SymInt split_k_iters) -> Tensor");
315
316 // Dequantization for AWQ.
317 ops.def(
318 "awq_dequantize(Tensor _kernel, Tensor _scaling_factors, "
319 "Tensor _zeros, SymInt split_k_iters, int thx, int thy) -> Tensor");
320
321 // DeepSeek V3 fused A GEMM (SM 9.0+, bf16 only, 1-16 tokens).
322 // conditionally compiled so impl registration is in source file
323 ops.def(
324 "dsv3_fused_a_gemm(Tensor! output, Tensor mat_a, Tensor mat_b, "
325 "bool enable_pdl=False) -> ()");
326
327 // BF16/FP32 x FP32 -> FP32 router GEMM for H=3072, E=256, M<=32 (SM90+).
328 // conditionally compiled so impl registration is in source file
329 ops.def("fp32_router_gemm(Tensor! output, Tensor mat_a, Tensor mat_b) -> ()");
330 #endif
331
332 // Merge attn states
333 // Implements section 2.2 of https://www.arxiv.org/pdf/2501.01005
334 // can be used to combine partial attention results (in the split-KV case)
335 ops.def(
336 "merge_attn_states("
337 " Tensor! output,"
338 " Tensor!? output_lse,"
339 " Tensor prefix_output,"
340 " Tensor prefix_lse,"
341 " Tensor suffix_output,"
342 " Tensor suffix_lse,"
343 " int!? prefill_tokens_with_context,"
344 " Tensor? output_scale=None) -> ()");
345
346 // Hadamard transforms
347 // conditionally compiled so impl registration is in source file
348 ops.def("hadacore_transform(Tensor! x, bool inplace) -> Tensor");
349
350 // Apply Root Mean Square (RMS) Normalization to the input tensor.
351 ops.def(
352 "rms_norm(Tensor! result, Tensor input, Tensor? weight, float epsilon) "
353 "-> "
354 "()");
355
356 // In-place fused Add and RMS Normalization.
357 ops.def(
358 "fused_add_rms_norm(Tensor! input, Tensor! residual, Tensor? weight, "
359 "float epsilon) -> ()");
360
361 // Layernorm-quant
362 // Apply Root Mean Square (RMS) Normalization to the input tensor.
363 ops.def(
364 "rms_norm_static_fp8_quant(Tensor! result, Tensor input, Tensor weight, "
365 "Tensor scale, float epsilon) -> "
366 "()");
367
368 // In-place fused Add and RMS Normalization.
369 ops.def(
370 "fused_add_rms_norm_static_fp8_quant(Tensor! result, Tensor input, "
371 "Tensor! residual, Tensor weight, "
372 "Tensor scale, float epsilon) -> ()");
373
374 // Fused Layernorm + Quant kernels
375 ops.def(
376 "rms_norm_dynamic_per_token_quant(Tensor! result, Tensor input, "
377 "Tensor weight, Tensor! scale, float epsilon, "
378 "Tensor? scale_ub, Tensor!? residual) -> ()");
379
380 // Fused Layernorm + Block quant kernels
381 ops.def(
382 "rms_norm_per_block_quant(Tensor! result, Tensor input, "
383 "Tensor weight, Tensor! scale, float epsilon, "
384 "Tensor? scale_ub, Tensor!? residual, int group_size, "
385 "bool is_scale_transposed) -> ()");
386
387 // Fused SiLU+Mul + per-block quantization
388 ops.def(
389 "silu_and_mul_per_block_quant("
390 "Tensor! out, "
391 "Tensor input, "
392 "Tensor! scales, "
393 "int group_size, "
394 "Tensor? scale_ub=None, "
395 "bool is_scale_transposed=False) -> ()");
396
397 // Rotary embedding
398 // Apply GPT-NeoX or GPT-J style rotary embedding to query and key.
399 ops.def(
400 "rotary_embedding(Tensor positions, Tensor! query,"
401 " Tensor!? key, int head_size,"
402 " Tensor cos_sin_cache, bool is_neox, int "
403 "rope_dim_offset=0, bool inverse=False) -> ()");
404
405 // Function for fused QK Norm and RoPE
406 ops.def(
407 "fused_qk_norm_rope(Tensor! qkv, int num_heads_q, "
408 "int num_heads_k, int num_heads_v, int head_dim, float eps, "
409 "Tensor q_weight, Tensor k_weight, Tensor cos_sin_cache, "
410 "bool is_neox, Tensor position_ids, "
411 "int forced_token_heads_per_warp=-1) -> ()");
412
413 // q_head_padded is the padded Q head count of the returned tensor, or 0 to
414 // do the KV insert alone and return an empty tensor. The Q knobs are
415 // independent: apply_q_norm and apply_q_rope each drop that step for Q
416 // alone (KV is always rotated), and is_q_interleaved reads and writes Q in
417 // FlashMLA's mega-attention chunk-interleaved layout, which moves the
418 // padding heads to the tail of every head-dim chunk.
419 ops.def(
420 "fused_deepseek_v4_kv_rope_insert("
421 "Tensor kv, Tensor! k_cache, Tensor slot_mapping, Tensor position_ids, "
422 "Tensor cos_sin_cache, int cache_block_size, Tensor? fp8_scale=None, "
423 "bool kv_mxfp8=False) -> "
424 "()");
425 ops.def(
426 "fused_deepseek_v4_qnorm_rope_kv_rope_quant_insert("
427 "Tensor q_in, Tensor kv, Tensor! k_cache, "
428 "Tensor slot_mapping, Tensor position_ids, Tensor cos_sin_cache, "
429 "int q_head_padded, float eps, int cache_block_size, "
430 "bool apply_q_norm=True, bool kv_mxfp8=False, bool apply_q_rope=True, "
431 "bool is_q_interleaved=False) -> Tensor");
432
433 // FlashInfer V4 full-cache variants: write Q in place (bf16) or to a separate
434 // FP8 tensor, and KV into a contiguous 512-wide token-strided cache.
435 ops.def(
436 "fused_deepseek_v4_qnorm_rope_kv_rope_full_cache_bf16_insert("
437 "Tensor! q, Tensor kv, Tensor! k_cache, Tensor slot_mapping, "
438 "Tensor position_ids, Tensor cos_sin_cache, float eps, "
439 "int cache_block_size, bool apply_q_norm=True) -> ()");
440 ops.def(
441 "fused_deepseek_v4_qnorm_rope_kv_rope_full_cache_fp8_insert("
442 "Tensor q, Tensor kv, Tensor! q_fp8, Tensor! k_cache, "
443 "Tensor slot_mapping, Tensor position_ids, Tensor cos_sin_cache, "
444 "Tensor fp8_scale, Tensor q_fp8_scale_inv, float eps, "
445 "int cache_block_size, bool apply_q_norm=True) -> ()");
446
447 // Kimi-K3 MLA epilogues: optional RoPE followed by concat/cache insertion.
448 ops.def(
449 "fused_kimi_k3_mla_key_concat_kv_cache_insert("
450 "Tensor! q, Tensor k_nope, Tensor k_pe, Tensor kv_c_normed, "
451 "Tensor! k_out, Tensor! k_cache, Tensor slot_mapping, "
452 "int cache_block_size, Tensor? position_ids=None, "
453 "Tensor? cos_sin_cache=None) -> ()");
454 ops.def(
455 "fused_kimi_k3_mla_key_concat_ds_mla_insert("
456 "Tensor! q, Tensor k_nope, Tensor k_pe, Tensor kv_c_normed, "
457 "Tensor! k_out, Tensor! k_cache, Tensor slot_mapping, "
458 "int cache_block_size, Tensor? position_ids=None, "
459 "Tensor? cos_sin_cache=None) -> ()");
460 ops.def(
461 "fused_kimi_k3_mla_kv_concat(Tensor k_nope, Tensor k_pe, Tensor! k_out) "
462 "-> ()");
463 ops.def(
464 "fused_kimi_k3_mla_kv_concat_quant_fp8("
465 "Tensor k_nope, Tensor k_pe, Tensor v, Tensor! k_fp8, Tensor! v_fp8) "
466 "-> ()");
467 ops.def(
468 "fused_kimi_k3_mla_qkv_quant_kv_cache_fp8_insert("
469 "Tensor q, Tensor k_nope, Tensor k_pe, Tensor kv_c_normed, Tensor v, "
470 "Tensor! q_fp8, Tensor! k_fp8, Tensor! v_fp8, Tensor! k_cache, "
471 "Tensor slot_mapping, Tensor q_scale_inv, Tensor k_scale_inv, "
472 "Tensor v_scale_inv, Tensor cache_scale_inv, int cache_block_size, "
473 "Tensor? position_ids=None, Tensor? cos_sin_cache=None) -> ()");
474
475 // Kimi-K3 MLA decode epilogue: concat mqa_q = [ql_nope | q_pe] and insert the
476 // latent [kv_c_normed | k_pe] into the paged cache (bf16 / fp8 / fp8_ds_mla).
477 ops.def(
478 "fused_kimi_k3_mla_decode_q_concat_kv_cache_insert("
479 "Tensor ql_nope, Tensor q_pe, Tensor kv_c_normed, Tensor k_pe, "
480 "Tensor! mqa_q, Tensor! k_cache, Tensor slot_mapping, "
481 "int cache_block_size, Tensor? position_ids=None, "
482 "Tensor? cos_sin_cache=None) -> ()");
483 ops.def(
484 "fused_kimi_k3_mla_decode_q_concat_kv_cache_fp8_insert("
485 "Tensor ql_nope, Tensor q_pe, Tensor kv_c_normed, Tensor k_pe, "
486 "Tensor! mqa_q, Tensor! k_cache, Tensor slot_mapping, "
487 "Tensor q_scale_inv, Tensor cache_scale_inv, int cache_block_size, "
488 "Tensor? position_ids=None, Tensor? cos_sin_cache=None) -> ()");
489 ops.def(
490 "fused_kimi_k3_mla_decode_q_concat_ds_mla_insert("
491 "Tensor ql_nope, Tensor q_pe, Tensor kv_c_normed, Tensor k_pe, "
492 "Tensor! mqa_q, Tensor! k_cache, Tensor slot_mapping, "
493 "int cache_block_size, Tensor? position_ids=None, "
494 "Tensor? cos_sin_cache=None) -> ()");
495
496 #ifndef USE_ROCM
497 ops.def(
498 "minimax_allreduce_rms_qk("
499 "Tensor qkv, Tensor norm_weight_q, Tensor norm_weight_k, "
500 "Tensor workspace, int q_size, int kv_size, int rank, int nranks, "
501 "float eps) -> (Tensor, Tensor)");
502 #endif
503
504 // Horizontally-fused MiniMax-M3 QK-norm + partial NeoX RoPE + KV-insert.
505 ops.def(
506 "fused_minimax_m3_qknorm_rope_kv_insert("
507 "Tensor! qkv, Tensor q_norm_weight, Tensor k_norm_weight, "
508 "Tensor cos_sin_cache, Tensor positions, int num_heads, "
509 "int num_kv_heads, int rotary_dim, float eps, "
510 "Tensor? index_q_norm_weight, Tensor? index_k_norm_weight, "
511 "int num_index_heads, "
512 "Tensor? slot_mapping, Tensor? index_slot_mapping, "
513 "Tensor!? kv_cache, Tensor!? index_cache, "
514 "int block_size, Tensor!? q_out, Tensor!? index_q_out, "
515 "str kv_cache_dtype, bool skip_index_branch=False, "
516 "Tensor!? q_fp8_out=None, float q_fp8_scale=1.0, "
517 "Tensor? kv_k_scale=None, Tensor? kv_v_scale=None) -> ()");
518
519 #ifdef VLLM_ENABLE_FUSED_KDA_DECODE
520 ops.def(
521 "fused_kda_decode("
522 "Tensor x, Tensor weight, Tensor? bias, Tensor! conv_state, "
523 "Tensor raw_g, Tensor raw_beta, Tensor A_log, Tensor dt_bias, "
524 "Tensor state_indices, Tensor! state, Tensor! out, "
525 "float? lower_bound=None, Tensor? output_gate=None, "
526 "Tensor? norm_weight=None, float norm_eps=1e-5) -> ()");
527 #endif
528
529 #ifdef VLLM_ENABLE_FUSED_GDN_DECODE
530 ops.def(
531 "fused_gdn_decode_post_conv_mtp("
532 "Tensor mixed_qkv, Tensor a, Tensor b, Tensor A_log, Tensor dt_bias, "
533 "Tensor state_indices, Tensor cu_seqlens, Tensor num_accepted_tokens, "
534 "Tensor! state, Tensor output_gate, Tensor norm_weight, Tensor! out, "
535 "float scale, float norm_eps=1e-5, "
536 "str output_gate_activation='silu') -> ()");
537 #endif
538
539 #ifdef VLLM_ENABLE_FUSED_KDA_CHUNK
540 ops.def(
541 "fused_kda_prologue("
542 "Tensor q, Tensor k, Tensor v, Tensor raw_g, Tensor raw_beta, "
543 "Tensor A_log, Tensor dt_bias, Tensor! qg, Tensor! w, Tensor! u, "
544 "Tensor! kg_t, Tensor! aqk, Tensor! decay, Tensor cu_seqlens, "
545 "Tensor chunk_indices, Tensor? conv_weight, Tensor(e!)? conv_state, "
546 "Tensor? conv_state_indices, Tensor? conv_has_initial_state, "
547 "float scale, float lower_bound) -> ()");
548 ops.def(
549 "fused_kda_chunk("
550 "Tensor qg, Tensor w, Tensor u, Tensor kg_t, Tensor aqk, Tensor decay, "
551 "Tensor? initial_state, Tensor(a!)? final_state, Tensor! out, "
552 "Tensor cu_seqlens, Tensor chunk_offsets, float scale, "
553 "Tensor(b!)? group_state, int groups, "
554 "Tensor(c!)? checkpoint_state=None, Tensor? checkpoint_offsets=None, "
555 "Tensor? checkpoint_state_indices=None, Tensor(d!)? state_cache=None, "
556 "Tensor? state_indices=None, Tensor? has_initial_state=None) -> ()");
557 #endif
558
559 #ifdef VLLM_ENABLE_KIMI_K3_ATTN_RES
560 ops.def(
561 "kimi_k3_attn_res("
562 "Tensor! prefix, Tensor? delta, Tensor! blocks, Tensor norm_weight, "
563 "Tensor qk_weight, Tensor? output_norm_weight, Tensor! output, "
564 "int num_blocks, "
565 "int block_write_idx, float eps, "
566 "float output_norm_eps) -> ()");
567 #endif
568
569 // Apply repetition penalties to logits in-place.
570 ops.def(
571 "apply_repetition_penalties_(Tensor! logits, Tensor prompt_mask, "
572 "Tensor output_mask, Tensor repetition_penalties) -> ()");
573
574 // Optimized top-k per row operations.
575 ops.def(
576 "top_k_per_row_prefill(Tensor logits, Tensor rowStarts, Tensor rowEnds, "
577 "Tensor! indices, int numRows, int stride0, "
578 "int stride1, int topK) -> ()");
579
580 ops.def(
581 "top_k_per_row_decode(Tensor logits, int next_n, "
582 "Tensor seq_lens, Tensor! indices, "
583 "int numRows, int stride0, int stride1, int topK) -> ()");
584
585 ops.def(
586 "persistent_topk(Tensor logits, Tensor lengths, Tensor! output, "
587 "Tensor workspace, int k, int max_seq_len) -> ()");
588
589 #ifdef VLLM_ENABLE_COOPERATIVE_TOPK
590 ops.def(
591 "cooperative_topk(Tensor logits, Tensor lengths, Tensor! output, "
592 "Tensor workspace, int k, int max_seq_len) -> ()");
593 #endif
594
595 // Activation ops
596 ops.def(
597 "persistent_masked_m_silu_mul_quant(Tensor input, Tensor counts, Tensor! "
598 "y_q, Tensor! y_s, bool use_ue8m0) -> ()");
599 ops.def("weak_ref_tensor(Tensor input) -> Tensor");
600
601 // Activation function used in SwiGLU.
602 ops.def("silu_and_mul(Tensor! result, Tensor input) -> ()");
603
604 ops.def("mul_and_silu(Tensor! out, Tensor input) -> ()");
605
606 // SwiGLU activation with input clamping.
607 // alpha scales the sigmoid (gate * sigmoid(alpha * gate)); beta is added to
608 // the up half (up + beta). Defaults alpha=1.0, beta=0.0 give silu(gate)*up.
609 ops.def(
610 "silu_and_mul_with_clamp(Tensor! result, Tensor input, float limit, "
611 "float alpha=1.0, float beta=0.0) -> ()");
612
613 // SwiGLU activation with FP8 quantization.
614 ops.def(
615 "silu_and_mul_quant(Tensor! result, Tensor input, Tensor scale) -> ()");
616
617 // Activation function used in GeGLU with `none` approximation.
618 ops.def("gelu_and_mul(Tensor! out, Tensor input) -> ()");
619
620 // Activation function used in GeGLU with `tanh` approximation.
621 ops.def("gelu_tanh_and_mul(Tensor! out, Tensor input) -> ()");
622
623 // FATReLU implementation.
624 ops.def("fatrelu_and_mul(Tensor! out, Tensor input, float threshold) -> ()");
625
626 ops.def(
627 "swigluoai_and_mul(Tensor! out, Tensor input, float alpha=1.702, float "
628 "limit=7.0) "
629 "-> ()");
630
631 // SituGLU implementation used in Kimi models.
632 ops.def(
633 "situ_and_mul(Tensor! out, Tensor input, float beta=1.0, float "
634 "linear_beta=-1.0) -> ()");
635 // Fused SituGLU activation + dynamic FP8 quantization for the Humming w2 path
636 // (writes the fp8 down input and its float32 scale). group_size=0 ->
637 // per-token scale [.., 1]; group_size=128 -> k-major block-FP8 scale [..,
638 // d/128].
639 ops.def(
640 "situ_and_mul_quant(Tensor! out, Tensor! scale, Tensor input, "
641 "float beta=1.0, float linear_beta=-1.0, int group_size=0, "
642 "Tensor? num_valid_tokens=None, int topk=1) -> ()");
643 ops.def(
644 "masked_situ_and_mul(Tensor! out, Tensor input, Tensor "
645 "expert_num_tokens, float beta=1.0, float linear_beta=-1.0) -> ()");
646 ops.def(
647 "masked_moe_activation(Tensor! out, Tensor input, Tensor "
648 "valid_token_counts, str activation, float clamp_limit=0.0, float "
649 "alpha=1.0, float beta=0.0, float situ_beta=1.0, float "
650 "situ_linear_beta=-1.0) -> ()");
651
652 // GELU implementation used in GPT-2.
653 ops.def("gelu_new(Tensor! out, Tensor input) -> ()");
654
655 // Approximate GELU implementation.
656 ops.def("gelu_fast(Tensor! out, Tensor input) -> ()");
657
658 // Quick GELU implementation.
659 ops.def("gelu_quick(Tensor! out, Tensor input) -> ()");
660
661 // relu(x)^2 activation from https://arxiv.org/abs/2109.08668v2
662 ops.def("relu_squared(Tensor! out, Tensor input) -> ()");
663
664 // Compute int8 quantized tensor for given scaling factor.
665 ops.def(
666 "static_scaled_int8_quant(Tensor! result, Tensor input, Tensor scale,"
667 "Tensor? azp) -> ()");
668
669 // Compute int8 quantized tensor and scaling factor
670 ops.def(
671 "dynamic_scaled_int8_quant(Tensor! result, Tensor input, Tensor! scale, "
672 "Tensor!? azp) -> ()");
673
674 // Compute FP8 quantized tensor for given scaling factor.
675 // Supports per-tensor, per-channel, per-token, and arbitrary 2D group
676 // scaling. Optional group_m/group_n specify the group shape explicitly;
677 // required for 1D scales to disambiguate per-channel vs per-token.
678 ops.def(
679 "static_scaled_fp8_quant(Tensor! result, Tensor input, Tensor scale, "
680 "int[]? group_shape=None) -> ()");
681
682 // Compute dynamic-per-tensor FP8 quantized tensor and scaling factor.
683 ops.def(
684 "dynamic_scaled_fp8_quant(Tensor! result, Tensor input, Tensor! scale) "
685 "-> "
686 "()");
687
688 // Compute dynamic-per-token FP8 quantized tensor and scaling factor.
689 ops.def(
690 "dynamic_per_token_scaled_fp8_quant(Tensor! result, Tensor input, "
691 "Tensor! scale, Tensor? scale_ub) -> "
692 "()");
693
694 // Quantized GEMM for GPTQ.
695 // Note: even though the C++ inferred schema is correct for this op, it seems
696 // to prevent the meta function registry.
697 ops.def(
698 "gptq_gemm(Tensor a, Tensor b_q_weight, Tensor b_gptq_qzeros, "
699 "Tensor b_gptq_scales, bool use_exllama, bool "
700 "use_v2_format, int bit) "
701 "-> Tensor");
702
703 // Post processing for GPTQ.
704 ops.def("gptq_shuffle(Tensor! q_weight, int bit) -> ()");
705
706 // Mamba selective scan kernel
707 ops.def(
708 "selective_scan_fwd(Tensor! u, Tensor! delta,"
709 "Tensor! A, Tensor! B, Tensor! C,"
710 "Tensor? D_, Tensor!? z_, Tensor? delta_bias_,"
711 "bool delta_softplus,"
712 "Tensor? query_start_loc,"
713 "Tensor? cache_indices,"
714 "Tensor? has_initial_state,"
715 "Tensor! ssm_states,"
716 "int null_block_id,"
717 "int block_size,"
718 "Tensor? block_idx_first_scheduled_token,"
719 "Tensor? block_idx_last_scheduled_token,"
720 "Tensor? initial_state_idx,"
721 "Tensor? cu_chunk_seqlen,"
722 "Tensor? last_chunk_indices) -> ()");
723
724 // LongCat n-gram embedding index kernel. All tensor args are marked mutable
725 // to match the (non-const) stable-Tensor& C++ signature; only ne_token_table
726 // and n_gram_ids are actually written in place.
727 // Fused vocab-parallel embedding: gather the rows this rank owns and write
728 // zeros for the rest, so the following all-reduce reconstructs the full
729 // embedding.
730 ops.def(
731 "vocab_parallel_embedding(Tensor! out, Tensor input_ids, Tensor weight, "
732 "int org_vocab_start_index, int org_vocab_end_index, "
733 "int num_org_vocab_padding, int added_vocab_start_index, "
734 "int added_vocab_end_index) -> ()");
735 ops.def(
736 "ngram_compute_n_gram_ids(int ne_n, int ne_k, Tensor(a!) ne_weights, "
737 "Tensor(b!) ne_mods, Tensor(c!) exclusive_ne_embedder_size_sums, "
738 "Tensor(d!) exclusive_req_len_sums, Tensor(e!) ne_token_table, "
739 "Tensor(f!) row_indices, Tensor(g!) column_starts, "
740 "Tensor(h!) n_gram_ids) -> ()");
741 }
742
743 STABLE_TORCH_LIBRARY_IMPL(_C, CUDA, ops) {
744 // LongCat n-gram embedding index kernel.
745 ops.impl("ngram_compute_n_gram_ids", TORCH_BOX(&ngram_compute_n_gram_ids));
746 ops.impl("vocab_parallel_embedding", TORCH_BOX(&vocab_parallel_embedding));
747
748 // Per-token group quantization
749 ops.impl("per_token_group_fp8_quant", TORCH_BOX(&per_token_group_quant_fp8));
750 ops.impl("per_token_group_fp8_quant_packed",
751 TORCH_BOX(&per_token_group_quant_8bit_packed));
752 ops.impl("per_token_group_quant_int8",
753 TORCH_BOX(&per_token_group_quant_int8));
754
755 #ifndef USE_ROCM
756 // CUTLASS scaled_mm ops
757 ops.impl("cutlass_scaled_mm", TORCH_BOX(&cutlass_scaled_mm));
758 ops.impl("cutlass_scaled_mm_azp", TORCH_BOX(&cutlass_scaled_mm_azp));
759 ops.impl("cutlass_moe_mm", TORCH_BOX(&cutlass_moe_mm));
760 ops.impl("get_cutlass_moe_mm_data", TORCH_BOX(&get_cutlass_moe_mm_data));
761 ops.impl("get_cutlass_moe_mm_problem_sizes_from_expert_offsets",
762 TORCH_BOX(&get_cutlass_moe_mm_problem_sizes_from_expert_offsets));
763 ops.impl("get_cutlass_batched_moe_mm_data",
764 TORCH_BOX(&get_cutlass_batched_moe_mm_data));
765
766 // FP4/NVFP4 ops
767 ops.impl("cutlass_scaled_fp4_mm", TORCH_BOX(&cutlass_scaled_fp4_mm));
768 ops.impl("scaled_fp4_quant", TORCH_BOX(&scaled_fp4_quant_func));
769 ops.impl("scaled_fp4_quant.out", TORCH_BOX(&scaled_fp4_quant_out));
770 ops.impl("scaled_fp4_experts_quant", TORCH_BOX(&scaled_fp4_experts_quant));
771 ops.impl("silu_and_mul_scaled_fp4_experts_quant",
772 TORCH_BOX(&silu_and_mul_scaled_fp4_experts_quant));
773 ops.impl("silu_and_mul_nvfp4_quant", TORCH_BOX(&silu_and_mul_nvfp4_quant));
774 // mxfp4_experts_quant: registered in mxfp4_experts_quant.cu (SM100 only).
775 // W4A8 ops: registered in w4a8_mm_entry.cu / w4a8_grouped_mm_entry.cu.
776
777 // AWQ ops
778 ops.impl("awq_gemm", TORCH_BOX(&awq_gemm));
779 ops.impl("awq_dequantize", TORCH_BOX(&awq_dequantize));
780
781 // DSV3 fused A GEMM: conditionally compiled so impl registration is in
782 // source file (dsv3_fused_a_gemm.cu)
783 #endif
784
785 ops.impl("merge_attn_states", TORCH_BOX(&merge_attn_states));
786
787 // Layernorm kernels (shared CUDA/ROCm)
788 ops.impl("rms_norm", TORCH_BOX(&rms_norm));
789 ops.impl("fused_add_rms_norm", TORCH_BOX(&fused_add_rms_norm));
790
791 // Layernorm-quant kernels (shared CUDA/ROCm)
792 ops.impl("rms_norm_static_fp8_quant", TORCH_BOX(&rms_norm_static_fp8_quant));
793 ops.impl("fused_add_rms_norm_static_fp8_quant",
794 TORCH_BOX(&fused_add_rms_norm_static_fp8_quant));
795
796 // Fused layernorm + dynamic per-token quant kernels (shared CUDA/ROCm)
797 ops.impl("rms_norm_dynamic_per_token_quant",
798 TORCH_BOX(&rms_norm_dynamic_per_token_quant));
799 ops.impl("rms_norm_per_block_quant", TORCH_BOX(&rms_norm_per_block_quant));
800 ops.impl("silu_and_mul_per_block_quant",
801 TORCH_BOX(&silu_and_mul_per_block_quant));
802
803 // Positional encoding kernels (shared CUDA/ROCm)
804 ops.impl("rotary_embedding", TORCH_BOX(&rotary_embedding));
805 ops.impl("fused_qk_norm_rope", TORCH_BOX(&fused_qk_norm_rope));
806 ops.impl("fused_deepseek_v4_kv_rope_insert",
807 TORCH_BOX(&fused_deepseek_v4_kv_rope_insert));
808 ops.impl("fused_deepseek_v4_qnorm_rope_kv_rope_quant_insert",
809 TORCH_BOX(&fused_deepseek_v4_qnorm_rope_kv_rope_quant_insert));
810 ops.impl(
811 "fused_deepseek_v4_qnorm_rope_kv_rope_full_cache_bf16_insert",
812 TORCH_BOX(&fused_deepseek_v4_qnorm_rope_kv_rope_full_cache_bf16_insert));
813 ops.impl(
814 "fused_deepseek_v4_qnorm_rope_kv_rope_full_cache_fp8_insert",
815 TORCH_BOX(&fused_deepseek_v4_qnorm_rope_kv_rope_full_cache_fp8_insert));
816 ops.impl("fused_kimi_k3_mla_key_concat_kv_cache_insert",
817 TORCH_BOX(&fused_kimi_k3_mla_key_concat_kv_cache_insert));
818 ops.impl("fused_kimi_k3_mla_key_concat_ds_mla_insert",
819 TORCH_BOX(&fused_kimi_k3_mla_key_concat_ds_mla_insert));
820 ops.impl("fused_kimi_k3_mla_kv_concat",
821 TORCH_BOX(&fused_kimi_k3_mla_kv_concat));
822 ops.impl("fused_kimi_k3_mla_kv_concat_quant_fp8",
823 TORCH_BOX(&fused_kimi_k3_mla_kv_concat_quant_fp8));
824 ops.impl("fused_kimi_k3_mla_qkv_quant_kv_cache_fp8_insert",
825 TORCH_BOX(&fused_kimi_k3_mla_qkv_quant_kv_cache_fp8_insert));
826 ops.impl("fused_kimi_k3_mla_decode_q_concat_kv_cache_insert",
827 TORCH_BOX(&fused_kimi_k3_mla_decode_q_concat_kv_cache_insert));
828 ops.impl("fused_kimi_k3_mla_decode_q_concat_kv_cache_fp8_insert",
829 TORCH_BOX(&fused_kimi_k3_mla_decode_q_concat_kv_cache_fp8_insert));
830 ops.impl("fused_kimi_k3_mla_decode_q_concat_ds_mla_insert",
831 TORCH_BOX(&fused_kimi_k3_mla_decode_q_concat_ds_mla_insert));
832 #ifndef USE_ROCM
833 ops.impl("minimax_allreduce_rms_qk", TORCH_BOX(&minimax_allreduce_rms_qk));
834 #endif
835 ops.impl("fused_minimax_m3_qknorm_rope_kv_insert",
836 TORCH_BOX(&fused_minimax_m3_qknorm_rope_kv_insert));
837 #ifdef VLLM_ENABLE_FUSED_KDA_DECODE
838 ops.impl("fused_kda_decode", TORCH_BOX(&fused_kda_decode));
839 #endif
840
841 #ifdef VLLM_ENABLE_FUSED_GDN_DECODE
842 ops.impl("fused_gdn_decode_post_conv_mtp",
843 TORCH_BOX(&fused_gdn_decode_post_conv_mtp));
844 #endif
845
846 #ifdef VLLM_ENABLE_FUSED_KDA_CHUNK
847 ops.impl("fused_kda_prologue", TORCH_BOX(&fused_kda_prologue));
848 ops.impl("fused_kda_chunk", TORCH_BOX(&fused_kda_chunk));
849 #endif
850
851 #ifdef VLLM_ENABLE_KIMI_K3_ATTN_RES
852 ops.impl("kimi_k3_attn_res", TORCH_BOX(&kimi_k3_attn_res));
853 #endif
854
855 // Sampler kernels (shared CUDA/ROCm)
856 ops.impl("apply_repetition_penalties_",
857 TORCH_BOX(&apply_repetition_penalties_));
858 ops.impl("top_k_per_row_prefill", TORCH_BOX(&top_k_per_row_prefill));
859 ops.impl("top_k_per_row_decode", TORCH_BOX(&top_k_per_row_decode));
860 ops.impl("persistent_topk", TORCH_BOX(&persistent_topk));
861 #ifdef VLLM_ENABLE_COOPERATIVE_TOPK
862 ops.impl("cooperative_topk", TORCH_BOX(&cooperative_topk));
863 #endif
864
865 // Activation kernels (shared CUDA/ROCm)
866 ops.impl("persistent_masked_m_silu_mul_quant",
867 TORCH_BOX(&persistent_masked_m_silu_mul_quant));
868 ops.impl("weak_ref_tensor", TORCH_BOX(&weak_ref_tensor));
869 ops.impl("silu_and_mul_quant", TORCH_BOX(&silu_and_mul_quant));
870 ops.impl("silu_and_mul", TORCH_BOX(&silu_and_mul));
871 ops.impl("mul_and_silu", TORCH_BOX(&mul_and_silu));
872 ops.impl("gelu_and_mul", TORCH_BOX(&gelu_and_mul));
873 ops.impl("gelu_tanh_and_mul", TORCH_BOX(&gelu_tanh_and_mul));
874 ops.impl("fatrelu_and_mul", TORCH_BOX(&fatrelu_and_mul));
875 ops.impl("swigluoai_and_mul", TORCH_BOX(&swigluoai_and_mul));
876 ops.impl("situ_and_mul", TORCH_BOX(&situ_and_mul));
877 ops.impl("situ_and_mul_quant", TORCH_BOX(&situ_and_mul_quant));
878 ops.impl("masked_situ_and_mul", TORCH_BOX(&masked_situ_and_mul));
879 ops.impl("masked_moe_activation", TORCH_BOX(&masked_moe_activation));
880 ops.impl("gelu_new", TORCH_BOX(&gelu_new));
881 ops.impl("gelu_fast", TORCH_BOX(&gelu_fast));
882 ops.impl("gelu_quick", TORCH_BOX(&gelu_quick));
883 ops.impl("relu_squared", TORCH_BOX(&relu_squared));
884 ops.impl("silu_and_mul_with_clamp", TORCH_BOX(&silu_and_mul_clamp));
885
886 // INT8 quantization kernels
887 ops.impl("static_scaled_int8_quant", TORCH_BOX(&static_scaled_int8_quant));
888 ops.impl("dynamic_scaled_int8_quant", TORCH_BOX(&dynamic_scaled_int8_quant));
889
890 // FP8 quantization kernels
891 ops.impl("static_scaled_fp8_quant", TORCH_BOX(&static_scaled_fp8_quant));
892 ops.impl("dynamic_scaled_fp8_quant", TORCH_BOX(&dynamic_scaled_fp8_quant));
893 ops.impl("dynamic_per_token_scaled_fp8_quant",
894 TORCH_BOX(&dynamic_per_token_scaled_fp8_quant));
895
896 // GPTQ kernels
897 ops.impl("gptq_gemm", TORCH_BOX(&gptq_gemm));
898 ops.impl("gptq_shuffle", TORCH_BOX(&gptq_shuffle));
899
900 // Mamba kernels
901 ops.impl("selective_scan_fwd", TORCH_BOX(&selective_scan_fwd));
902 }
903
904 STABLE_TORCH_LIBRARY_IMPL(_C, CPU, ops) {
905 ops.impl("get_cuda_view_from_cpu_tensor",
906 TORCH_BOX(&get_cuda_view_from_cpu_tensor));
907 }
908
909 STABLE_TORCH_LIBRARY_FRAGMENT(_C_cuda_utils, cuda_utils) {
910 cuda_utils.def("get_device_attribute(int attribute, int device_id) -> int");
911 cuda_utils.def(
912 "get_max_shared_memory_per_block_device_attribute(int device_id) -> int");
913 }
914
915 STABLE_TORCH_LIBRARY_IMPL(_C_cuda_utils, CompositeExplicitAutograd,
916 cuda_utils) {
917 cuda_utils.impl("get_device_attribute", TORCH_BOX(&get_device_attribute));
918 cuda_utils.impl("get_max_shared_memory_per_block_device_attribute",
919 TORCH_BOX(&get_max_shared_memory_per_block_device_attribute));
920 }
921
922 // These capability-check functions take only primitive args (no tensors), so
923 // there is no device to dispatch on. CompositeExplicitAutograd makes them
924 // available for all backends. This is the stable ABI equivalent of calling
925 // ops.impl("op_name", &func) without a dispatch key in the non-stable API.
926 STABLE_TORCH_LIBRARY_IMPL(_C, CompositeExplicitAutograd, ops) {
927 #ifndef USE_ROCM
928 ops.impl("cutlass_scaled_mm_supports_fp8",
929 TORCH_BOX(&cutlass_scaled_mm_supports_fp8));
930 ops.impl("cutlass_group_gemm_supported",
931 TORCH_BOX(&cutlass_group_gemm_supported));
932 ops.impl("cutlass_scaled_mm_supports_block_fp8",
933 TORCH_BOX(&cutlass_scaled_mm_supports_block_fp8));
934 ops.impl("cutlass_scaled_mm_supports_fp4",
935 TORCH_BOX(&cutlass_scaled_mm_supports_fp4));
936 #endif
937 }
938
939 // Cache ops
940 STABLE_TORCH_LIBRARY_FRAGMENT(_C_cache_ops, ops) {
941 // Swap in (out) the cache blocks from src to dst.
942 ops.def(
943 "swap_blocks(Tensor src, Tensor! dst,"
944 " int block_size_in_bytes, Tensor block_mapping) -> ()");
945
946 // Batch swap: submit all block copies in a single driver call.
947 ops.def(
948 "swap_blocks_batch(Tensor src_ptrs, Tensor dst_ptrs,"
949 " Tensor sizes,"
950 " bool is_src_access_order_any=False) -> ()");
951
952 // Reshape the key and value tensors and cache them.
953 ops.def(
954 "reshape_and_cache(Tensor key, Tensor value,"
955 " Tensor! key_cache, Tensor! value_cache,"
956 " Tensor slot_mapping,"
957 " str kv_cache_dtype,"
958 " Tensor k_scale, Tensor v_scale) -> ()");
959
960 // Reshape the key and value tensors and cache them.
961 ops.def(
962 "reshape_and_cache_flash(Tensor key, Tensor value,"
963 " Tensor! key_cache,"
964 " Tensor! value_cache,"
965 " Tensor slot_mapping,"
966 " str kv_cache_dtype,"
967 " Tensor k_scale, Tensor v_scale) -> ()");
968
969 // Concat kv_c and k_pe and cache them.
970 ops.def(
971 "concat_and_cache_mla(Tensor kv_c, Tensor k_pe,"
972 " Tensor! kv_cache,"
973 " Tensor slot_mapping,"
974 " str kv_cache_dtype,"
975 " Tensor scale) -> ()");
976
977 // Grouped concat_and_cache_mla across all layers. Each layer's cache base
978 // pointer and optional plain-FP8 scale are read from device tensors.
979 ops.def(
980 "concat_and_cache_mla_grouped(Tensor kv_c, Tensor k_pe,"
981 " Tensor kv_cache_ptrs,"
982 " Tensor slot_mapping,"
983 " int block_size, int block_stride,"
984 " int entry_stride,"
985 " Tensor? kv_scales=None,"
986 " str kv_cache_dtype='auto') -> ()");
987
988 #ifndef USE_ROCM
989 ops.def(
990 "hisparse_resolve_residency(Tensor host_cache,"
991 " Tensor! hot_cache,"
992 " Tensor hot_block_table,"
993 " Tensor global_indices,"
994 " Tensor! hot_indices,"
995 " Tensor! device_global_indices,"
996 " Tensor! lru_slots,"
997 " Tensor? request_state_indices,"
998 " int region_stride,"
999 " int max_union_rows,"
1000 " Tensor(a!)? miss_mask=None,"
1001 " Tensor(b!)? stats=None,"
1002 " Tensor(c!)? attention_indices=None,"
1003 " int attention_block_stride=0,"
1004 " Tensor? request_ids=None,"
1005 " Tensor? source_block_table=None,"
1006 " int source_block_size=0,"
1007 " Tensor(d!)? resolved_global_indices=None,"
1008 " Tensor(e!)? valid_counts=None,"
1009 " Tensor(f!)? swap_host_physical_rows=None,"
1010 " Tensor(g!)? swap_device_physical_rows=None,"
1011 " Tensor(h!)? swap_counts=None,"
1012 " Tensor? resident_block_table=None,"
1013 " int resident_block_size=0,"
1014 " int resident_null_block=0) -> ()");
1015
1016 ops.def(
1017 "hisparse_invalidate_written_slots(Tensor! device_global_indices,"
1018 " Tensor request_state_indices,"
1019 " Tensor req_id_per_token,"
1020 " Tensor written_slots) -> ()");
1021
1022 ops.def(
1023 "hisparse_gather_plan(Tensor host_cache,"
1024 " Tensor! hot_cache,"
1025 " Tensor global_indices,"
1026 " Tensor hot_indices,"
1027 " Tensor miss_mask,"
1028 " Tensor? request_state_indices,"
1029 " Tensor(a!)? attention_indices=None,"
1030 " int attention_block_stride=0) -> ()");
1031
1032 ops.def(
1033 "hisparse_gather_compact(Tensor host_cache,"
1034 " Tensor! hot_cache,"
1035 " Tensor miss_global_indices,"
1036 " Tensor miss_hot_indices,"
1037 " Tensor miss_counts) -> ()");
1038
1039 #endif // !USE_ROCM
1040
1041 // Rotate Q and K, then write to kv cache for MLA
1042 ops.def(
1043 "concat_and_cache_mla_rope_fused("
1044 " Tensor positions,"
1045 " Tensor! q_pe,"
1046 " Tensor! k_pe,"
1047 " Tensor kv_c,"
1048 " Tensor cos_sin_cache,"
1049 " bool is_neox,"
1050 " Tensor slot_mapping,"
1051 " Tensor! kv_cache,"
1052 " str kv_cache_dtype,"
1053 " Tensor kv_cache_scale) -> ()");
1054
1055 // Convert the key and value cache to fp8 data type.
1056 ops.def(
1057 "convert_fp8(Tensor! dst_cache, Tensor src_cache, float scale, "
1058 "str kv_cache_dtype) -> ()");
1059
1060 // Gather cache blocks from src_cache to dst, dequantizing from
1061 // src_cache's dtype to dst's dtype if necessary.
1062 ops.def(
1063 "gather_and_maybe_dequant_cache(Tensor src_cache, Tensor! dst, "
1064 " Tensor block_table, Tensor cu_seq_lens, "
1065 " Tensor token_to_seq, "
1066 " int num_tokens, "
1067 " str kv_cache_dtype, "
1068 " Tensor scale, Tensor? seq_starts) -> ()");
1069
1070 ops.def(
1071 "cp_gather_cache(Tensor src_cache, Tensor! dst, Tensor block_table, "
1072 "Tensor cu_seq_lens, int batch_size, Tensor? seq_starts) -> ()");
1073
1074 ops.def(
1075 "cp_gather_and_upconvert_fp8_kv_cache(Tensor src_cache, Tensor! dst, "
1076 "Tensor block_table, Tensor workspace_starts, int batch_size, Tensor? "
1077 "seq_starts, Tensor? host_cache=None, Tensor? host_row_ids=None, Tensor? "
1078 "device_row_ids=None) -> ()");
1079
1080 ops.def(
1081 "cp_gather_and_upconvert_nvfp4_kv_cache(Tensor src_cache, Tensor! dst, "
1082 "Tensor block_table, Tensor workspace_starts, int batch_size) -> ()");
1083
1084 ops.def(
1085 "indexer_k_quant_and_cache(Tensor k, Tensor! kv_cache, Tensor "
1086 "slot_mapping, "
1087 "int quant_block_size, str kv_cache_dtype) -> ()");
1088
1089 ops.def("concat_mla_q(Tensor ql_nope, Tensor q_pe, Tensor! q_out) -> ()");
1090
1091 ops.def(
1092 "cp_gather_indexer_k_quant_cache(Tensor kv_cache, Tensor! dst_k, Tensor! "
1093 "dst_scale, Tensor block_table, Tensor cu_seq_lens) -> ()");
1094 }
1095
1096 STABLE_TORCH_LIBRARY_FRAGMENT(_C_custom_ar, custom_ar) {
1097 custom_ar.def(
1098 "init_custom_ar(int[] ipc_tensors, Tensor rank_data, "
1099 "int rank, bool fully_connected) -> int");
1100 custom_ar.def(
1101 "all_reduce(int fa, Tensor inp, Tensor! out, int reg_buffer, "
1102 "int reg_buffer_sz_bytes) -> ()");
1103 custom_ar.def("dispose(int fa) -> ()");
1104 custom_ar.def("meta_size() -> int");
1105 custom_ar.def("register_buffer(int fa, int[] ipc_tensors) -> ()");
1106 custom_ar.def("get_graph_buffer_ipc_meta(int fa) -> (int[], int[])");
1107 custom_ar.def(
1108 "register_graph_buffers(int fa, int[][] handles, int[][] offsets) -> ()");
1109 custom_ar.def("allocate_shared_buffer_and_handle(int size) -> (int, Tensor)");
1110 custom_ar.def("open_mem_handle(Tensor mem_handle) -> int");
1111 custom_ar.def("free_shared_buffer(int ptr) -> ()");
1112 }
1113
1114 STABLE_TORCH_LIBRARY_IMPL(_C_custom_ar, CUDA, custom_ar) {
1115 custom_ar.impl("init_custom_ar", TORCH_BOX(&init_custom_ar));
1116 custom_ar.impl("all_reduce", TORCH_BOX(&all_reduce));
1117 }
1118
1119 STABLE_TORCH_LIBRARY_IMPL(_C_custom_ar, CPU, custom_ar) {
1120 custom_ar.impl("open_mem_handle", TORCH_BOX(&open_mem_handle));
1121 }
1122
1123 STABLE_TORCH_LIBRARY_IMPL(_C_custom_ar, CompositeExplicitAutograd, custom_ar) {
1124 custom_ar.impl("dispose", TORCH_BOX(&dispose));
1125 custom_ar.impl("meta_size", TORCH_BOX(&meta_size));
1126 custom_ar.impl("register_buffer", TORCH_BOX(&register_buffer));
1127 custom_ar.impl("get_graph_buffer_ipc_meta",
1128 TORCH_BOX(&get_graph_buffer_ipc_meta));
1129 custom_ar.impl("register_graph_buffers", TORCH_BOX(&register_graph_buffers));
1130 custom_ar.impl("allocate_shared_buffer_and_handle",
1131 TORCH_BOX(&allocate_shared_buffer_and_handle));
1132 custom_ar.impl("free_shared_buffer", TORCH_BOX(&free_shared_buffer));
1133 }
1134
1135 STABLE_TORCH_LIBRARY_IMPL(_C_cache_ops, CPU, ops) {
1136 ops.impl("swap_blocks_batch", TORCH_BOX(&swap_blocks_batch));
1137 }
1138
1139 STABLE_TORCH_LIBRARY_IMPL(_C_cache_ops, CUDA, ops) {
1140 ops.impl("swap_blocks", TORCH_BOX(&swap_blocks));
1141 ops.impl("reshape_and_cache", TORCH_BOX(&reshape_and_cache));
1142 ops.impl("reshape_and_cache_flash", TORCH_BOX(&reshape_and_cache_flash));
1143 ops.impl("concat_and_cache_mla", TORCH_BOX(&concat_and_cache_mla));
1144 ops.impl("concat_and_cache_mla_grouped",
1145 TORCH_BOX(&concat_and_cache_mla_grouped));
1146
1147 #ifndef USE_ROCM
1148 ops.impl("hisparse_resolve_residency",
1149 TORCH_BOX(&hisparse_resolve_residency));
1150 ops.impl("hisparse_invalidate_written_slots",
1151 TORCH_BOX(&hisparse_invalidate_written_slots));
1152 ops.impl("hisparse_gather_plan", TORCH_BOX(&hisparse_gather_plan));
1153 ops.impl("hisparse_gather_compact", TORCH_BOX(&hisparse_gather_compact));
1154 #endif // !USE_ROCM
1155 ops.impl("concat_and_cache_mla_rope_fused",
1156 TORCH_BOX(&concat_and_cache_mla_rope_fused));
1157 ops.impl("convert_fp8", TORCH_BOX(&convert_fp8));
1158 ops.impl("gather_and_maybe_dequant_cache",
1159 TORCH_BOX(&gather_and_maybe_dequant_cache));
1160 ops.impl("cp_gather_cache", TORCH_BOX(&cp_gather_cache));
1161 ops.impl("cp_gather_and_upconvert_fp8_kv_cache",
1162 TORCH_BOX(&cp_gather_and_upconvert_fp8_kv_cache));
1163 ops.impl("cp_gather_and_upconvert_nvfp4_kv_cache",
1164 TORCH_BOX(&cp_gather_and_upconvert_nvfp4_kv_cache));
1165 ops.impl("indexer_k_quant_and_cache", TORCH_BOX(&indexer_k_quant_and_cache));
1166 ops.impl("concat_mla_q", TORCH_BOX(&concat_mla_q));
1167 ops.impl("cp_gather_indexer_k_quant_cache",
1168 TORCH_BOX(&cp_gather_indexer_k_quant_cache));
1169 }
1170
1171 REGISTER_EXTENSION(_C_stable_libtorch)