liangsu9988 commited on
Commit
513d68d
·
verified ·
1 Parent(s): f3eeba1

Uploaded using `kernel-builder`.

Browse files
Files changed (32) hide show
  1. build/torch211-cxx11-cu128-x86_64-linux/__init__.py +11 -3
  2. build/torch211-cxx11-cu128-x86_64-linux/{_minimaxai_msa_blackwell_cuda_58018d1.abi3.so → _minimaxai_msa_blackwell_cuda_25b0067.abi3.so} +2 -2
  3. build/torch211-cxx11-cu128-x86_64-linux/_native.py +195 -1
  4. build/torch211-cxx11-cu128-x86_64-linux/_ops.py +3 -3
  5. build/torch211-cxx11-cu128-x86_64-linux/api_status.py +4 -3
  6. build/torch211-cxx11-cu128-x86_64-linux/decode/topk_sparse.py +20 -0
  7. build/torch211-cxx11-cu128-x86_64-linux/interface.py +38 -3
  8. build/torch211-cxx11-cu128-x86_64-linux/metadata.json +8 -8
  9. build/torch211-cxx11-cu130-x86_64-linux/__init__.py +11 -3
  10. build/torch211-cxx11-cu130-x86_64-linux/{_minimaxai_msa_blackwell_cuda_58018d1.abi3.so → _minimaxai_msa_blackwell_cuda_25b0067.abi3.so} +2 -2
  11. build/torch211-cxx11-cu130-x86_64-linux/_native.py +195 -1
  12. build/torch211-cxx11-cu130-x86_64-linux/_ops.py +3 -3
  13. build/torch211-cxx11-cu130-x86_64-linux/api_status.py +4 -3
  14. build/torch211-cxx11-cu130-x86_64-linux/decode/topk_sparse.py +20 -0
  15. build/torch211-cxx11-cu130-x86_64-linux/interface.py +38 -3
  16. build/torch211-cxx11-cu130-x86_64-linux/metadata.json +8 -8
  17. build/torch212-cxx11-cu130-x86_64-linux/__init__.py +11 -3
  18. build/torch212-cxx11-cu130-x86_64-linux/{_minimaxai_msa_blackwell_cuda_58018d1.abi3.so → _minimaxai_msa_blackwell_cuda_25b0067.abi3.so} +2 -2
  19. build/torch212-cxx11-cu130-x86_64-linux/_native.py +195 -1
  20. build/torch212-cxx11-cu130-x86_64-linux/_ops.py +3 -3
  21. build/torch212-cxx11-cu130-x86_64-linux/api_status.py +4 -3
  22. build/torch212-cxx11-cu130-x86_64-linux/decode/topk_sparse.py +20 -0
  23. build/torch212-cxx11-cu130-x86_64-linux/interface.py +38 -3
  24. build/torch212-cxx11-cu130-x86_64-linux/metadata.json +8 -8
  25. build/torch212-cxx11-cu132-x86_64-linux/__init__.py +11 -3
  26. build/torch212-cxx11-cu132-x86_64-linux/{_minimaxai_msa_blackwell_cuda_58018d1.abi3.so → _minimaxai_msa_blackwell_cuda_25b0067.abi3.so} +2 -2
  27. build/torch212-cxx11-cu132-x86_64-linux/_native.py +195 -1
  28. build/torch212-cxx11-cu132-x86_64-linux/_ops.py +3 -3
  29. build/torch212-cxx11-cu132-x86_64-linux/api_status.py +4 -3
  30. build/torch212-cxx11-cu132-x86_64-linux/decode/topk_sparse.py +20 -0
  31. build/torch212-cxx11-cu132-x86_64-linux/interface.py +38 -3
  32. build/torch212-cxx11-cu132-x86_64-linux/metadata.json +8 -8
build/torch211-cxx11-cu128-x86_64-linux/__init__.py CHANGED
@@ -7,9 +7,12 @@ MiniMax-M3 decode-sparse attention path used by FlashRT's MiniMax Spark runtime.
7
 
8
  Implementation status:
9
  * native CUDA helper: score -> top-k sparse block ids;
10
- * Triton CUDA attention kernels: Blackwell-validated decode and prefill paths;
 
 
 
11
  * MiniMaxAI/msa compatibility wrappers for CSR prefill, decode, NVFP4 helpers,
12
- and FP4 block-score fallback.
13
 
14
  The upstream MiniMaxAI/msa package is SM100-only; this package is the Blackwell
15
  extension path. The public API is Tensor-oriented and independent from
@@ -48,7 +51,11 @@ from .interface import (
48
  sparse_atten_nvfp4_kv_func,
49
  sparse_decode_atten_func,
50
  )
51
- from ._native import has_native_ops, native_topk_from_scores
 
 
 
 
52
  from .naive.flash_with_topk_idx import naive_flash_decode_with_topk_idx
53
  from .naive.topk_sparse import naive_flash_decode_with_gqa_share_sparse
54
  from .quantize import (
@@ -88,6 +95,7 @@ __all__ = [
88
  "flash_decode_with_gqa_share_sparse",
89
  "has_native_ops",
90
  "native_topk_from_scores",
 
91
  "naive_flash_decode_with_gqa_share_sparse",
92
  "naive_flash_decode_with_topk_idx",
93
  "get_cu_seqblocks",
 
7
 
8
  Implementation status:
9
  * native CUDA helper: score -> top-k sparse block ids;
10
+ * native CUDA tensor-core sparse decode for the MiniMax-M3 Blackwell shape;
11
+ * native CUDA FP4 block-score indexer;
12
+ * native CUDA helper: swizzled NVFP4 -> BF16 dequant for the W4A16 quality path;
13
+ * Blackwell-validated sparse prefill path;
14
  * MiniMaxAI/msa compatibility wrappers for CSR prefill, decode, NVFP4 helpers,
15
+ and FP4 block-score helpers.
16
 
17
  The upstream MiniMaxAI/msa package is SM100-only; this package is the Blackwell
18
  extension path. The public API is Tensor-oriented and independent from
 
51
  sparse_atten_nvfp4_kv_func,
52
  sparse_decode_atten_func,
53
  )
54
+ from ._native import (
55
+ has_native_ops,
56
+ native_nvfp4_dequant_swizzled_to_bf16,
57
+ native_topk_from_scores,
58
+ )
59
  from .naive.flash_with_topk_idx import naive_flash_decode_with_topk_idx
60
  from .naive.topk_sparse import naive_flash_decode_with_gqa_share_sparse
61
  from .quantize import (
 
95
  "flash_decode_with_gqa_share_sparse",
96
  "has_native_ops",
97
  "native_topk_from_scores",
98
+ "native_nvfp4_dequant_swizzled_to_bf16",
99
  "naive_flash_decode_with_gqa_share_sparse",
100
  "naive_flash_decode_with_topk_idx",
101
  "get_cu_seqblocks",
build/torch211-cxx11-cu128-x86_64-linux/{_minimaxai_msa_blackwell_cuda_58018d1.abi3.so → _minimaxai_msa_blackwell_cuda_25b0067.abi3.so} RENAMED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:bffdfdc7f5f7e61a7a828d7887f42ea2412a75e6a259d11699fc24cf0f69b2b5
3
- size 119536
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:528883873873d9a482cbe93eb0ea0ec5be7f0eac009dd8b103a0609841c032d5
3
+ size 446928
build/torch211-cxx11-cu128-x86_64-linux/_native.py CHANGED
@@ -62,4 +62,198 @@ def native_topk_from_scores(
62
  return out
63
 
64
 
65
- __all__ = ["has_native_ops", "native_topk_from_scores"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
  return out
63
 
64
 
65
+ if _HAS_NATIVE_OPS:
66
+
67
+ @torch.library.register_fake(
68
+ add_op_namespace_prefix("msa_decode_sparse_attn_mma_paged")
69
+ )
70
+ def _msa_decode_sparse_attn_mma_paged_fake(
71
+ q: torch.Tensor,
72
+ k_cache: torch.Tensor,
73
+ v_cache: torch.Tensor,
74
+ req_to_token: torch.Tensor,
75
+ seq_lens: torch.Tensor,
76
+ slot_ids: torch.Tensor,
77
+ topk_idx: torch.Tensor,
78
+ block_size: int,
79
+ sm_scale: float,
80
+ out: torch.Tensor,
81
+ ) -> None:
82
+ return None
83
+
84
+
85
+ def native_decode_mma_supported(
86
+ q: torch.Tensor,
87
+ k_cache: torch.Tensor,
88
+ *,
89
+ block_size: int,
90
+ ) -> bool:
91
+ """Whether the tensor-core decode kernel applies to these inputs.
92
+
93
+ The mma kernel is specialized for the M3 MSA shape: head_dim 128, GQA
94
+ group (Hq/Hkv) 16, bf16, and a block size that is a multiple of 64.
95
+ """
96
+
97
+ if not _HAS_NATIVE_OPS:
98
+ return False
99
+ if q.dtype is not torch.bfloat16 or k_cache.dtype is not torch.bfloat16:
100
+ return False
101
+ if q.dim() != 3 or k_cache.dim() != 3:
102
+ return False
103
+ head_dim = int(q.shape[-1])
104
+ num_q_heads = int(q.shape[1])
105
+ num_kv_heads = int(k_cache.shape[1])
106
+ if head_dim != 128 or num_kv_heads <= 0:
107
+ return False
108
+ if num_q_heads % num_kv_heads != 0 or num_q_heads // num_kv_heads != 16:
109
+ return False
110
+ if int(block_size) % 64 != 0:
111
+ return False
112
+ return True
113
+
114
+
115
+ def native_decode_sparse_attn_mma_paged(
116
+ q: torch.Tensor,
117
+ k_cache: torch.Tensor,
118
+ v_cache: torch.Tensor,
119
+ req_to_token: torch.Tensor,
120
+ seq_lens: torch.Tensor,
121
+ slot_ids: torch.Tensor,
122
+ block_size: int,
123
+ topk_idx: torch.Tensor,
124
+ sm_scale: float,
125
+ ) -> torch.Tensor:
126
+ """Paged tensor-core block-sparse GQA decode. Returns [B, Hq, D] bf16."""
127
+
128
+ if not _HAS_NATIVE_OPS:
129
+ raise RuntimeError("native MiniMax MSA ops are not available in source-tree mode")
130
+ out = torch.empty(
131
+ (int(q.shape[0]), int(q.shape[1]), int(q.shape[2])),
132
+ device=q.device,
133
+ dtype=q.dtype,
134
+ )
135
+ ops.msa_decode_sparse_attn_mma_paged(
136
+ q.contiguous(),
137
+ k_cache.contiguous(),
138
+ v_cache.contiguous(),
139
+ req_to_token.contiguous(),
140
+ seq_lens.contiguous(),
141
+ slot_ids.contiguous(),
142
+ topk_idx.contiguous(),
143
+ int(block_size),
144
+ float(sm_scale),
145
+ out,
146
+ )
147
+ return out
148
+
149
+
150
+ if _HAS_NATIVE_OPS:
151
+
152
+ @torch.library.register_fake(
153
+ add_op_namespace_prefix("msa_indexer_block_scores")
154
+ )
155
+ def _msa_indexer_block_scores_fake(
156
+ q: torch.Tensor,
157
+ k_pages: torch.Tensor,
158
+ batch_of_q: torch.Tensor,
159
+ cu_q: torch.Tensor,
160
+ cu_k: torch.Tensor,
161
+ cu_pages: torch.Tensor,
162
+ kv_indices: torch.Tensor,
163
+ causal: int,
164
+ scores: torch.Tensor,
165
+ ) -> None:
166
+ return None
167
+
168
+
169
+ def native_indexer_block_scores(
170
+ q: torch.Tensor,
171
+ k_pages: torch.Tensor,
172
+ batch_of_q: torch.Tensor,
173
+ cu_q: torch.Tensor,
174
+ cu_k: torch.Tensor,
175
+ cu_pages: torch.Tensor,
176
+ kv_indices: torch.Tensor,
177
+ *,
178
+ max_blocks: int,
179
+ causal: bool,
180
+ ) -> torch.Tensor:
181
+ """Block-max QK indexer scores. q/k_pages are bf16 (already dequantized).
182
+
183
+ Returns [Hq, max_blocks, total_q] f32 (-inf where no key is visible).
184
+ """
185
+
186
+ if not _HAS_NATIVE_OPS:
187
+ raise RuntimeError("native MiniMax MSA ops are not available in source-tree mode")
188
+ total_q = int(q.shape[0])
189
+ hq = int(q.shape[1])
190
+ scores = torch.full(
191
+ (hq, int(max_blocks), total_q),
192
+ float("-inf"),
193
+ dtype=torch.float32,
194
+ device=q.device,
195
+ )
196
+ ops.msa_indexer_block_scores(
197
+ q.contiguous(),
198
+ k_pages.contiguous(),
199
+ batch_of_q.contiguous(),
200
+ cu_q.contiguous(),
201
+ cu_k.contiguous(),
202
+ cu_pages.contiguous(),
203
+ kv_indices.contiguous(),
204
+ 1 if causal else 0,
205
+ scores,
206
+ )
207
+ return scores
208
+
209
+
210
+ if _HAS_NATIVE_OPS:
211
+
212
+ @torch.library.register_fake(
213
+ add_op_namespace_prefix("msa_nvfp4_dequant_swizzled_to_bf16")
214
+ )
215
+ def _msa_nvfp4_dequant_swizzled_to_bf16_fake(
216
+ packed: torch.Tensor,
217
+ scale_128x4: torch.Tensor,
218
+ global_scale: float,
219
+ out: torch.Tensor,
220
+ ) -> None:
221
+ return None
222
+
223
+
224
+ def native_nvfp4_dequant_swizzled_to_bf16(
225
+ packed: torch.Tensor,
226
+ scale_128x4: torch.Tensor,
227
+ global_scale: torch.Tensor | float,
228
+ ) -> torch.Tensor:
229
+ """Expand swizzled NVFP4 weights/KV to dense BF16 with the native CUDA path."""
230
+
231
+ if not _HAS_NATIVE_OPS:
232
+ raise RuntimeError("native MiniMax MSA ops are not available in source-tree mode")
233
+ if packed.dtype is not torch.uint8:
234
+ raise TypeError("packed must be torch.uint8")
235
+ if scale_128x4.dtype is not torch.uint8:
236
+ raise TypeError("scale_128x4 must be torch.uint8")
237
+ original_shape = tuple(int(v) for v in packed.shape[:-1]) + (int(packed.shape[-1]) * 2,)
238
+ out = torch.empty(original_shape, device=packed.device, dtype=torch.bfloat16)
239
+ if isinstance(global_scale, torch.Tensor):
240
+ global_scale_value = float(global_scale.reshape(-1)[0].item())
241
+ else:
242
+ global_scale_value = float(global_scale)
243
+ ops.msa_nvfp4_dequant_swizzled_to_bf16(
244
+ packed.contiguous(),
245
+ scale_128x4.contiguous(),
246
+ global_scale_value,
247
+ out,
248
+ )
249
+ return out
250
+
251
+
252
+ __all__ = [
253
+ "has_native_ops",
254
+ "native_topk_from_scores",
255
+ "native_decode_mma_supported",
256
+ "native_decode_sparse_attn_mma_paged",
257
+ "native_indexer_block_scores",
258
+ "native_nvfp4_dequant_swizzled_to_bf16",
259
+ ]
build/torch211-cxx11-cu128-x86_64-linux/_ops.py CHANGED
@@ -1,9 +1,9 @@
1
  import torch
2
- from . import _minimaxai_msa_blackwell_cuda_58018d1
3
- ops = torch.ops._minimaxai_msa_blackwell_cuda_58018d1
4
 
5
  def add_op_namespace_prefix(op_name: str):
6
  """
7
  Prefix op by namespace.
8
  """
9
- return f"_minimaxai_msa_blackwell_cuda_58018d1::{op_name}"
 
1
  import torch
2
+ from . import _minimaxai_msa_blackwell_cuda_25b0067
3
+ ops = torch.ops._minimaxai_msa_blackwell_cuda_25b0067
4
 
5
  def add_op_namespace_prefix(op_name: str):
6
  """
7
  Prefix op by namespace.
8
  """
9
+ return f"_minimaxai_msa_blackwell_cuda_25b0067::{op_name}"
build/torch211-cxx11-cu128-x86_64-linux/api_status.py CHANGED
@@ -22,6 +22,7 @@ V1_AVAILABLE_FUNCTIONS = (
22
  "nvfp4_global_scale_from_amax",
23
  "has_native_ops",
24
  "native_topk_from_scores",
 
25
  "flash_decode_with_topk_idx",
26
  "flash_decode_with_gqa_share_sparse",
27
  "naive_flash_decode_with_topk_idx",
@@ -55,7 +56,7 @@ _OFFICIAL_API_STATUS = {
55
  "sparse_atten_nvfp4_kv_func": {
56
  "status": "available",
57
  "target": "blackwell-prefill-nvfp4",
58
- "reason": "Official NVFP4 KV prefill API is available via NVFP4 dequantization followed by the Blackwell prefill wrapper.",
59
  },
60
  "sparse_decode_atten_func": {
61
  "status": "available",
@@ -70,12 +71,12 @@ _OFFICIAL_API_STATUS = {
70
  "fp4_indexer_block_scores": {
71
  "status": "available",
72
  "target": "blackwell-fp4-indexer",
73
- "reason": "Official FP4 block-score API is available as a correctness-first PyTorch fallback.",
74
  },
75
  "build_k2q_csr": {
76
  "status": "available",
77
  "target": "v1",
78
- "reason": "Torch CSR construction fallback is available for compatibility.",
79
  },
80
  "SparseK2qCsrBuilderSm100": {
81
  "status": "available",
 
22
  "nvfp4_global_scale_from_amax",
23
  "has_native_ops",
24
  "native_topk_from_scores",
25
+ "native_nvfp4_dequant_swizzled_to_bf16",
26
  "flash_decode_with_topk_idx",
27
  "flash_decode_with_gqa_share_sparse",
28
  "naive_flash_decode_with_topk_idx",
 
56
  "sparse_atten_nvfp4_kv_func": {
57
  "status": "available",
58
  "target": "blackwell-prefill-nvfp4",
59
+ "reason": "Official NVFP4 KV prefill API is available via native swizzled NVFP4 dequantization followed by the Blackwell prefill wrapper.",
60
  },
61
  "sparse_decode_atten_func": {
62
  "status": "available",
 
71
  "fp4_indexer_block_scores": {
72
  "status": "available",
73
  "target": "blackwell-fp4-indexer",
74
+ "reason": "Official FP4 block-score API uses the native Blackwell block-score kernel in built artifacts, with a reference fallback in source-tree mode.",
75
  },
76
  "build_k2q_csr": {
77
  "status": "available",
78
  "target": "v1",
79
+ "reason": "CSR construction helper is available for the official prefill API.",
80
  },
81
  "SparseK2qCsrBuilderSm100": {
82
  "status": "available",
build/torch211-cxx11-cu128-x86_64-linux/decode/topk_sparse.py CHANGED
@@ -8,6 +8,10 @@ import triton.language as tl
8
 
9
  from .._compat import is_hip # vendored: was `from sglang.srt.utils import is_hip`
10
 
 
 
 
 
11
  from ..common.utils import robust_allocator
12
 
13
  _is_hip = is_hip()
@@ -341,6 +345,22 @@ def flash_decode_with_gqa_share_sparse(
341
  # sm scale
342
  if sm_scale is None:
343
  sm_scale = head_dim**-0.5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
344
  # Pick NUM_TOPK_CHUNKS so total grid ≈ TARGET_GRID. Same constraints as
345
  # flash_decode_with_topk_idx: must be power of 2 (Triton arange) and must
346
  # only depend on shape constants (so grid is fixed within a cuda graph).
 
8
 
9
  from .._compat import is_hip # vendored: was `from sglang.srt.utils import is_hip`
10
 
11
+ from .._native import (
12
+ native_decode_mma_supported,
13
+ native_decode_sparse_attn_mma_paged,
14
+ )
15
  from ..common.utils import robust_allocator
16
 
17
  _is_hip = is_hip()
 
345
  # sm scale
346
  if sm_scale is None:
347
  sm_scale = head_dim**-0.5
348
+ # Fast path: native tensor-core decode for the M3 MSA shape. Falls through
349
+ # to the Triton kernel for other shapes, sink, or fp8 caches.
350
+ if sink is None and not is_fp8 and native_decode_mma_supported(
351
+ q, k_cache, block_size=block_size
352
+ ):
353
+ return native_decode_sparse_attn_mma_paged(
354
+ q,
355
+ k_cache,
356
+ v_cache,
357
+ req_to_token,
358
+ seq_lens,
359
+ slot_ids,
360
+ block_size,
361
+ topk_idx,
362
+ sm_scale,
363
+ )
364
  # Pick NUM_TOPK_CHUNKS so total grid ≈ TARGET_GRID. Same constraints as
365
  # flash_decode_with_topk_idx: must be power of 2 (Triton arange) and must
366
  # only depend on shape constants (so grid is fixed within a cuda graph).
build/torch211-cxx11-cu128-x86_64-linux/interface.py CHANGED
@@ -7,6 +7,11 @@ from typing import Optional
7
 
8
  import torch
9
 
 
 
 
 
 
10
  from .decode.topk_sparse import flash_decode_with_gqa_share_sparse
11
  from .prefill.topk_sparse import flash_prefill_with_gqa_share_sparse
12
  from .quantize import Nvfp4QuantizedTensor, dequantize_nvfp4_128x4_to_bf16
@@ -488,6 +493,12 @@ def _nvfp4_dequant_kv(
488
  ) -> torch.Tensor:
489
  if packed.dtype is not torch.uint8:
490
  return packed
 
 
 
 
 
 
491
  original_shape = tuple(int(v) for v in packed.shape[:-1]) + (int(packed.shape[-1]) * 2,)
492
  rows = 1
493
  for dim in original_shape[:-1]:
@@ -572,11 +583,12 @@ def fp4_indexer_block_scores(
572
  qo_offset: Optional[torch.Tensor] = None,
573
  scale_layout: str = "preordered_mma",
574
  ) -> torch.Tensor:
575
- """Correctness-first FP4 block-score API for Blackwell.
576
 
577
  Returns the official shape `[Hq, ceil(max_seqlen_k / 128), total_q]`.
578
- This fallback is intentionally simple and is used to keep the public API
579
- callable on Blackwell while optimized CUTE block scoring remains SM100-only.
 
580
  """
581
 
582
  del qo_offset
@@ -599,6 +611,29 @@ def fp4_indexer_block_scores(
599
 
600
  q = _apply_public_fp4_scale(_unpack_e2m1_fp4(q_fp4), q_scale)
601
  k = _apply_public_fp4_scale(_unpack_e2m1_fp4(k_fp4), k_scale)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
602
  gqa = hq // hkv
603
  batch = int(cu_seqlens_q.numel()) - 1
604
  cu_q = cu_seqlens_q.to("cpu", non_blocking=False).tolist()
 
7
 
8
  import torch
9
 
10
+ from ._native import (
11
+ has_native_ops,
12
+ native_indexer_block_scores,
13
+ native_nvfp4_dequant_swizzled_to_bf16,
14
+ )
15
  from .decode.topk_sparse import flash_decode_with_gqa_share_sparse
16
  from .prefill.topk_sparse import flash_prefill_with_gqa_share_sparse
17
  from .quantize import Nvfp4QuantizedTensor, dequantize_nvfp4_128x4_to_bf16
 
493
  ) -> torch.Tensor:
494
  if packed.dtype is not torch.uint8:
495
  return packed
496
+ if has_native_ops() and packed.is_cuda:
497
+ return native_nvfp4_dequant_swizzled_to_bf16(
498
+ packed,
499
+ scale_128x4,
500
+ global_scale,
501
+ )
502
  original_shape = tuple(int(v) for v in packed.shape[:-1]) + (int(packed.shape[-1]) * 2,)
503
  rows = 1
504
  for dim in original_shape[:-1]:
 
583
  qo_offset: Optional[torch.Tensor] = None,
584
  scale_layout: str = "preordered_mma",
585
  ) -> torch.Tensor:
586
+ """FP4 block-score API for Blackwell.
587
 
588
  Returns the official shape `[Hq, ceil(max_seqlen_k / 128), total_q]`.
589
+ Built artifacts route CUDA tensors through the native Blackwell block-score
590
+ kernel. Source-tree mode uses the reference loop below so the API remains
591
+ testable before the extension is built.
592
  """
593
 
594
  del qo_offset
 
611
 
612
  q = _apply_public_fp4_scale(_unpack_e2m1_fp4(q_fp4), q_scale)
613
  k = _apply_public_fp4_scale(_unpack_e2m1_fp4(k_fp4), k_scale)
614
+
615
+ # Native block-max QK kernel for the cubic scoring loop when available.
616
+ # Same dequant numerics as the reference (bf16 compute); falls back to the
617
+ # Python reference below in source-tree mode.
618
+ if has_native_ops() and q_fp4.is_cuda:
619
+ batch = int(cu_seqlens_q.numel()) - 1
620
+ q_lens = (cu_seqlens_q[1:] - cu_seqlens_q[:-1]).to(torch.int64)
621
+ batch_of_q = torch.repeat_interleave(
622
+ torch.arange(batch, device=q_fp4.device, dtype=torch.int32),
623
+ q_lens,
624
+ )
625
+ return native_indexer_block_scores(
626
+ q.to(torch.bfloat16),
627
+ k.to(torch.bfloat16),
628
+ batch_of_q,
629
+ cu_seqlens_q.to(torch.int32),
630
+ cu_seqlens_k.to(torch.int32),
631
+ cu_page_offsets.to(torch.int32),
632
+ kv_indices.to(torch.int32),
633
+ max_blocks=max_blocks,
634
+ causal=causal,
635
+ )
636
+
637
  gqa = hq // hkv
638
  batch = int(cu_seqlens_q.numel()) - 1
639
  cu_q = cu_seqlens_q.to("cpu", non_blocking=False).tolist()
build/torch211-cxx11-cu128-x86_64-linux/metadata.json CHANGED
@@ -1,6 +1,6 @@
1
  {
2
  "name": "minimaxai-msa-blackwell",
3
- "id": "_minimaxai_msa_blackwell_cuda_58018d1",
4
  "version": 1,
5
  "license": "Apache-2.0",
6
  "python-depends": [],
@@ -13,18 +13,18 @@
13
  "digest": {
14
  "algorithm": "sha256",
15
  "files": {
16
- "__init__.py": "bH4lC+HdMx2DgfiEWfvxhd7GvQBOt02ftSPAzKo1rE0=",
17
  "_compat.py": "5Wy4a96HVMD8omRNsGg8rQJ+0qCCeXiDANk0CuyyP0I=",
18
- "_minimaxai_msa_blackwell_cuda_58018d1.abi3.so": "v/39x/X35hp6go14h/QuokEqdeaiWdEWmfwkzw9psrU=",
19
- "_native.py": "mIDvfkcQVd3H9plDsodJelrIFD2XHiEQgk4uqiiRLLE=",
20
- "_ops.py": "kuQPE8cc2FNEl3lIMfjaj074xh5YntsWFa8cYC5CLIQ=",
21
- "api_status.py": "VhS7aJhSznFwcgIQAnzXQTTuLJ2WgtysWrhX7RTSXaM=",
22
  "common/__init__.py": "bG7Ffen4LvQtgnYPFEpFccsWs81t4zqqeqn9ZeirH6E=",
23
  "common/utils.py": "qtwh+wZoySlsWWALvWGVsmcIHKkdZUwePxUZ42tfWxc=",
24
  "decode/__init__.py": "bG7Ffen4LvQtgnYPFEpFccsWs81t4zqqeqn9ZeirH6E=",
25
  "decode/flash_with_topk_idx.py": "Pk70+HJ60IKuy4KJC6hPdMtD2BjwPfSMabFiIBODWiQ=",
26
- "decode/topk_sparse.py": "PLwQnOyiZT44pCXcZXzXdlZSixfBeanTZsfbpMOjlpQ=",
27
- "interface.py": "TKlKdIqTtzfmieaY5ci3GwhD1QZXqUAZcqfcfPmyeuM=",
28
  "minimaxai_msa_blackwell/__init__.py": "DFYPlrhXwYjEqCl/8n0SmWGZV8NFml5DPhMjKfv98GY=",
29
  "naive/__init__.py": "bG7Ffen4LvQtgnYPFEpFccsWs81t4zqqeqn9ZeirH6E=",
30
  "naive/flash_with_topk_idx.py": "K7WQsRdO9+H2sz7pZ6axnJwE1OmnF0egdKtftHuChig=",
 
1
  {
2
  "name": "minimaxai-msa-blackwell",
3
+ "id": "_minimaxai_msa_blackwell_cuda_25b0067",
4
  "version": 1,
5
  "license": "Apache-2.0",
6
  "python-depends": [],
 
13
  "digest": {
14
  "algorithm": "sha256",
15
  "files": {
16
+ "__init__.py": "oPB7xQhjHd9+aLVJkEmJkZOXOwMEarmCdj3SBbhH2bM=",
17
  "_compat.py": "5Wy4a96HVMD8omRNsGg8rQJ+0qCCeXiDANk0CuyyP0I=",
18
+ "_minimaxai_msa_blackwell_cuda_25b0067.abi3.so": "UoiDhzhz2aSCy+k+sOoOxb5/DqwAndixA6BgmEHAMtU=",
19
+ "_native.py": "wTh66DiIKxsJ5m8fkAXKSCBYD3CVFVx4PFxceQiwvPY=",
20
+ "_ops.py": "ikU3Lg+kgswKktYjNSq5f4DmgyTR8dnxV8lH3rmOWvk=",
21
+ "api_status.py": "7oZzIkb4fuwkAz3r4Q1slHbOfaP3jwVB647Ok223ATk=",
22
  "common/__init__.py": "bG7Ffen4LvQtgnYPFEpFccsWs81t4zqqeqn9ZeirH6E=",
23
  "common/utils.py": "qtwh+wZoySlsWWALvWGVsmcIHKkdZUwePxUZ42tfWxc=",
24
  "decode/__init__.py": "bG7Ffen4LvQtgnYPFEpFccsWs81t4zqqeqn9ZeirH6E=",
25
  "decode/flash_with_topk_idx.py": "Pk70+HJ60IKuy4KJC6hPdMtD2BjwPfSMabFiIBODWiQ=",
26
+ "decode/topk_sparse.py": "uINcV9SP5sAf9jYPsPvyQ9lon8sajZ8Qn/yJ+2LA8NU=",
27
+ "interface.py": "jfhBHGyunFF+OdFycJYyptNNIAngKrXY67buTXAN66M=",
28
  "minimaxai_msa_blackwell/__init__.py": "DFYPlrhXwYjEqCl/8n0SmWGZV8NFml5DPhMjKfv98GY=",
29
  "naive/__init__.py": "bG7Ffen4LvQtgnYPFEpFccsWs81t4zqqeqn9ZeirH6E=",
30
  "naive/flash_with_topk_idx.py": "K7WQsRdO9+H2sz7pZ6axnJwE1OmnF0egdKtftHuChig=",
build/torch211-cxx11-cu130-x86_64-linux/__init__.py CHANGED
@@ -7,9 +7,12 @@ MiniMax-M3 decode-sparse attention path used by FlashRT's MiniMax Spark runtime.
7
 
8
  Implementation status:
9
  * native CUDA helper: score -> top-k sparse block ids;
10
- * Triton CUDA attention kernels: Blackwell-validated decode and prefill paths;
 
 
 
11
  * MiniMaxAI/msa compatibility wrappers for CSR prefill, decode, NVFP4 helpers,
12
- and FP4 block-score fallback.
13
 
14
  The upstream MiniMaxAI/msa package is SM100-only; this package is the Blackwell
15
  extension path. The public API is Tensor-oriented and independent from
@@ -48,7 +51,11 @@ from .interface import (
48
  sparse_atten_nvfp4_kv_func,
49
  sparse_decode_atten_func,
50
  )
51
- from ._native import has_native_ops, native_topk_from_scores
 
 
 
 
52
  from .naive.flash_with_topk_idx import naive_flash_decode_with_topk_idx
53
  from .naive.topk_sparse import naive_flash_decode_with_gqa_share_sparse
54
  from .quantize import (
@@ -88,6 +95,7 @@ __all__ = [
88
  "flash_decode_with_gqa_share_sparse",
89
  "has_native_ops",
90
  "native_topk_from_scores",
 
91
  "naive_flash_decode_with_gqa_share_sparse",
92
  "naive_flash_decode_with_topk_idx",
93
  "get_cu_seqblocks",
 
7
 
8
  Implementation status:
9
  * native CUDA helper: score -> top-k sparse block ids;
10
+ * native CUDA tensor-core sparse decode for the MiniMax-M3 Blackwell shape;
11
+ * native CUDA FP4 block-score indexer;
12
+ * native CUDA helper: swizzled NVFP4 -> BF16 dequant for the W4A16 quality path;
13
+ * Blackwell-validated sparse prefill path;
14
  * MiniMaxAI/msa compatibility wrappers for CSR prefill, decode, NVFP4 helpers,
15
+ and FP4 block-score helpers.
16
 
17
  The upstream MiniMaxAI/msa package is SM100-only; this package is the Blackwell
18
  extension path. The public API is Tensor-oriented and independent from
 
51
  sparse_atten_nvfp4_kv_func,
52
  sparse_decode_atten_func,
53
  )
54
+ from ._native import (
55
+ has_native_ops,
56
+ native_nvfp4_dequant_swizzled_to_bf16,
57
+ native_topk_from_scores,
58
+ )
59
  from .naive.flash_with_topk_idx import naive_flash_decode_with_topk_idx
60
  from .naive.topk_sparse import naive_flash_decode_with_gqa_share_sparse
61
  from .quantize import (
 
95
  "flash_decode_with_gqa_share_sparse",
96
  "has_native_ops",
97
  "native_topk_from_scores",
98
+ "native_nvfp4_dequant_swizzled_to_bf16",
99
  "naive_flash_decode_with_gqa_share_sparse",
100
  "naive_flash_decode_with_topk_idx",
101
  "get_cu_seqblocks",
build/torch211-cxx11-cu130-x86_64-linux/{_minimaxai_msa_blackwell_cuda_58018d1.abi3.so → _minimaxai_msa_blackwell_cuda_25b0067.abi3.so} RENAMED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:495a67916122bc24e1c4e4b994c40e9e0b32118061be58af0f76b8f225eee617
3
- size 145216
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a053c1fd69c4df3f94e566a7c4d88ba943f8d5cece714ade52789f6819a961ac
3
+ size 729824
build/torch211-cxx11-cu130-x86_64-linux/_native.py CHANGED
@@ -62,4 +62,198 @@ def native_topk_from_scores(
62
  return out
63
 
64
 
65
- __all__ = ["has_native_ops", "native_topk_from_scores"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
  return out
63
 
64
 
65
+ if _HAS_NATIVE_OPS:
66
+
67
+ @torch.library.register_fake(
68
+ add_op_namespace_prefix("msa_decode_sparse_attn_mma_paged")
69
+ )
70
+ def _msa_decode_sparse_attn_mma_paged_fake(
71
+ q: torch.Tensor,
72
+ k_cache: torch.Tensor,
73
+ v_cache: torch.Tensor,
74
+ req_to_token: torch.Tensor,
75
+ seq_lens: torch.Tensor,
76
+ slot_ids: torch.Tensor,
77
+ topk_idx: torch.Tensor,
78
+ block_size: int,
79
+ sm_scale: float,
80
+ out: torch.Tensor,
81
+ ) -> None:
82
+ return None
83
+
84
+
85
+ def native_decode_mma_supported(
86
+ q: torch.Tensor,
87
+ k_cache: torch.Tensor,
88
+ *,
89
+ block_size: int,
90
+ ) -> bool:
91
+ """Whether the tensor-core decode kernel applies to these inputs.
92
+
93
+ The mma kernel is specialized for the M3 MSA shape: head_dim 128, GQA
94
+ group (Hq/Hkv) 16, bf16, and a block size that is a multiple of 64.
95
+ """
96
+
97
+ if not _HAS_NATIVE_OPS:
98
+ return False
99
+ if q.dtype is not torch.bfloat16 or k_cache.dtype is not torch.bfloat16:
100
+ return False
101
+ if q.dim() != 3 or k_cache.dim() != 3:
102
+ return False
103
+ head_dim = int(q.shape[-1])
104
+ num_q_heads = int(q.shape[1])
105
+ num_kv_heads = int(k_cache.shape[1])
106
+ if head_dim != 128 or num_kv_heads <= 0:
107
+ return False
108
+ if num_q_heads % num_kv_heads != 0 or num_q_heads // num_kv_heads != 16:
109
+ return False
110
+ if int(block_size) % 64 != 0:
111
+ return False
112
+ return True
113
+
114
+
115
+ def native_decode_sparse_attn_mma_paged(
116
+ q: torch.Tensor,
117
+ k_cache: torch.Tensor,
118
+ v_cache: torch.Tensor,
119
+ req_to_token: torch.Tensor,
120
+ seq_lens: torch.Tensor,
121
+ slot_ids: torch.Tensor,
122
+ block_size: int,
123
+ topk_idx: torch.Tensor,
124
+ sm_scale: float,
125
+ ) -> torch.Tensor:
126
+ """Paged tensor-core block-sparse GQA decode. Returns [B, Hq, D] bf16."""
127
+
128
+ if not _HAS_NATIVE_OPS:
129
+ raise RuntimeError("native MiniMax MSA ops are not available in source-tree mode")
130
+ out = torch.empty(
131
+ (int(q.shape[0]), int(q.shape[1]), int(q.shape[2])),
132
+ device=q.device,
133
+ dtype=q.dtype,
134
+ )
135
+ ops.msa_decode_sparse_attn_mma_paged(
136
+ q.contiguous(),
137
+ k_cache.contiguous(),
138
+ v_cache.contiguous(),
139
+ req_to_token.contiguous(),
140
+ seq_lens.contiguous(),
141
+ slot_ids.contiguous(),
142
+ topk_idx.contiguous(),
143
+ int(block_size),
144
+ float(sm_scale),
145
+ out,
146
+ )
147
+ return out
148
+
149
+
150
+ if _HAS_NATIVE_OPS:
151
+
152
+ @torch.library.register_fake(
153
+ add_op_namespace_prefix("msa_indexer_block_scores")
154
+ )
155
+ def _msa_indexer_block_scores_fake(
156
+ q: torch.Tensor,
157
+ k_pages: torch.Tensor,
158
+ batch_of_q: torch.Tensor,
159
+ cu_q: torch.Tensor,
160
+ cu_k: torch.Tensor,
161
+ cu_pages: torch.Tensor,
162
+ kv_indices: torch.Tensor,
163
+ causal: int,
164
+ scores: torch.Tensor,
165
+ ) -> None:
166
+ return None
167
+
168
+
169
+ def native_indexer_block_scores(
170
+ q: torch.Tensor,
171
+ k_pages: torch.Tensor,
172
+ batch_of_q: torch.Tensor,
173
+ cu_q: torch.Tensor,
174
+ cu_k: torch.Tensor,
175
+ cu_pages: torch.Tensor,
176
+ kv_indices: torch.Tensor,
177
+ *,
178
+ max_blocks: int,
179
+ causal: bool,
180
+ ) -> torch.Tensor:
181
+ """Block-max QK indexer scores. q/k_pages are bf16 (already dequantized).
182
+
183
+ Returns [Hq, max_blocks, total_q] f32 (-inf where no key is visible).
184
+ """
185
+
186
+ if not _HAS_NATIVE_OPS:
187
+ raise RuntimeError("native MiniMax MSA ops are not available in source-tree mode")
188
+ total_q = int(q.shape[0])
189
+ hq = int(q.shape[1])
190
+ scores = torch.full(
191
+ (hq, int(max_blocks), total_q),
192
+ float("-inf"),
193
+ dtype=torch.float32,
194
+ device=q.device,
195
+ )
196
+ ops.msa_indexer_block_scores(
197
+ q.contiguous(),
198
+ k_pages.contiguous(),
199
+ batch_of_q.contiguous(),
200
+ cu_q.contiguous(),
201
+ cu_k.contiguous(),
202
+ cu_pages.contiguous(),
203
+ kv_indices.contiguous(),
204
+ 1 if causal else 0,
205
+ scores,
206
+ )
207
+ return scores
208
+
209
+
210
+ if _HAS_NATIVE_OPS:
211
+
212
+ @torch.library.register_fake(
213
+ add_op_namespace_prefix("msa_nvfp4_dequant_swizzled_to_bf16")
214
+ )
215
+ def _msa_nvfp4_dequant_swizzled_to_bf16_fake(
216
+ packed: torch.Tensor,
217
+ scale_128x4: torch.Tensor,
218
+ global_scale: float,
219
+ out: torch.Tensor,
220
+ ) -> None:
221
+ return None
222
+
223
+
224
+ def native_nvfp4_dequant_swizzled_to_bf16(
225
+ packed: torch.Tensor,
226
+ scale_128x4: torch.Tensor,
227
+ global_scale: torch.Tensor | float,
228
+ ) -> torch.Tensor:
229
+ """Expand swizzled NVFP4 weights/KV to dense BF16 with the native CUDA path."""
230
+
231
+ if not _HAS_NATIVE_OPS:
232
+ raise RuntimeError("native MiniMax MSA ops are not available in source-tree mode")
233
+ if packed.dtype is not torch.uint8:
234
+ raise TypeError("packed must be torch.uint8")
235
+ if scale_128x4.dtype is not torch.uint8:
236
+ raise TypeError("scale_128x4 must be torch.uint8")
237
+ original_shape = tuple(int(v) for v in packed.shape[:-1]) + (int(packed.shape[-1]) * 2,)
238
+ out = torch.empty(original_shape, device=packed.device, dtype=torch.bfloat16)
239
+ if isinstance(global_scale, torch.Tensor):
240
+ global_scale_value = float(global_scale.reshape(-1)[0].item())
241
+ else:
242
+ global_scale_value = float(global_scale)
243
+ ops.msa_nvfp4_dequant_swizzled_to_bf16(
244
+ packed.contiguous(),
245
+ scale_128x4.contiguous(),
246
+ global_scale_value,
247
+ out,
248
+ )
249
+ return out
250
+
251
+
252
+ __all__ = [
253
+ "has_native_ops",
254
+ "native_topk_from_scores",
255
+ "native_decode_mma_supported",
256
+ "native_decode_sparse_attn_mma_paged",
257
+ "native_indexer_block_scores",
258
+ "native_nvfp4_dequant_swizzled_to_bf16",
259
+ ]
build/torch211-cxx11-cu130-x86_64-linux/_ops.py CHANGED
@@ -1,9 +1,9 @@
1
  import torch
2
- from . import _minimaxai_msa_blackwell_cuda_58018d1
3
- ops = torch.ops._minimaxai_msa_blackwell_cuda_58018d1
4
 
5
  def add_op_namespace_prefix(op_name: str):
6
  """
7
  Prefix op by namespace.
8
  """
9
- return f"_minimaxai_msa_blackwell_cuda_58018d1::{op_name}"
 
1
  import torch
2
+ from . import _minimaxai_msa_blackwell_cuda_25b0067
3
+ ops = torch.ops._minimaxai_msa_blackwell_cuda_25b0067
4
 
5
  def add_op_namespace_prefix(op_name: str):
6
  """
7
  Prefix op by namespace.
8
  """
9
+ return f"_minimaxai_msa_blackwell_cuda_25b0067::{op_name}"
build/torch211-cxx11-cu130-x86_64-linux/api_status.py CHANGED
@@ -22,6 +22,7 @@ V1_AVAILABLE_FUNCTIONS = (
22
  "nvfp4_global_scale_from_amax",
23
  "has_native_ops",
24
  "native_topk_from_scores",
 
25
  "flash_decode_with_topk_idx",
26
  "flash_decode_with_gqa_share_sparse",
27
  "naive_flash_decode_with_topk_idx",
@@ -55,7 +56,7 @@ _OFFICIAL_API_STATUS = {
55
  "sparse_atten_nvfp4_kv_func": {
56
  "status": "available",
57
  "target": "blackwell-prefill-nvfp4",
58
- "reason": "Official NVFP4 KV prefill API is available via NVFP4 dequantization followed by the Blackwell prefill wrapper.",
59
  },
60
  "sparse_decode_atten_func": {
61
  "status": "available",
@@ -70,12 +71,12 @@ _OFFICIAL_API_STATUS = {
70
  "fp4_indexer_block_scores": {
71
  "status": "available",
72
  "target": "blackwell-fp4-indexer",
73
- "reason": "Official FP4 block-score API is available as a correctness-first PyTorch fallback.",
74
  },
75
  "build_k2q_csr": {
76
  "status": "available",
77
  "target": "v1",
78
- "reason": "Torch CSR construction fallback is available for compatibility.",
79
  },
80
  "SparseK2qCsrBuilderSm100": {
81
  "status": "available",
 
22
  "nvfp4_global_scale_from_amax",
23
  "has_native_ops",
24
  "native_topk_from_scores",
25
+ "native_nvfp4_dequant_swizzled_to_bf16",
26
  "flash_decode_with_topk_idx",
27
  "flash_decode_with_gqa_share_sparse",
28
  "naive_flash_decode_with_topk_idx",
 
56
  "sparse_atten_nvfp4_kv_func": {
57
  "status": "available",
58
  "target": "blackwell-prefill-nvfp4",
59
+ "reason": "Official NVFP4 KV prefill API is available via native swizzled NVFP4 dequantization followed by the Blackwell prefill wrapper.",
60
  },
61
  "sparse_decode_atten_func": {
62
  "status": "available",
 
71
  "fp4_indexer_block_scores": {
72
  "status": "available",
73
  "target": "blackwell-fp4-indexer",
74
+ "reason": "Official FP4 block-score API uses the native Blackwell block-score kernel in built artifacts, with a reference fallback in source-tree mode.",
75
  },
76
  "build_k2q_csr": {
77
  "status": "available",
78
  "target": "v1",
79
+ "reason": "CSR construction helper is available for the official prefill API.",
80
  },
81
  "SparseK2qCsrBuilderSm100": {
82
  "status": "available",
build/torch211-cxx11-cu130-x86_64-linux/decode/topk_sparse.py CHANGED
@@ -8,6 +8,10 @@ import triton.language as tl
8
 
9
  from .._compat import is_hip # vendored: was `from sglang.srt.utils import is_hip`
10
 
 
 
 
 
11
  from ..common.utils import robust_allocator
12
 
13
  _is_hip = is_hip()
@@ -341,6 +345,22 @@ def flash_decode_with_gqa_share_sparse(
341
  # sm scale
342
  if sm_scale is None:
343
  sm_scale = head_dim**-0.5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
344
  # Pick NUM_TOPK_CHUNKS so total grid ≈ TARGET_GRID. Same constraints as
345
  # flash_decode_with_topk_idx: must be power of 2 (Triton arange) and must
346
  # only depend on shape constants (so grid is fixed within a cuda graph).
 
8
 
9
  from .._compat import is_hip # vendored: was `from sglang.srt.utils import is_hip`
10
 
11
+ from .._native import (
12
+ native_decode_mma_supported,
13
+ native_decode_sparse_attn_mma_paged,
14
+ )
15
  from ..common.utils import robust_allocator
16
 
17
  _is_hip = is_hip()
 
345
  # sm scale
346
  if sm_scale is None:
347
  sm_scale = head_dim**-0.5
348
+ # Fast path: native tensor-core decode for the M3 MSA shape. Falls through
349
+ # to the Triton kernel for other shapes, sink, or fp8 caches.
350
+ if sink is None and not is_fp8 and native_decode_mma_supported(
351
+ q, k_cache, block_size=block_size
352
+ ):
353
+ return native_decode_sparse_attn_mma_paged(
354
+ q,
355
+ k_cache,
356
+ v_cache,
357
+ req_to_token,
358
+ seq_lens,
359
+ slot_ids,
360
+ block_size,
361
+ topk_idx,
362
+ sm_scale,
363
+ )
364
  # Pick NUM_TOPK_CHUNKS so total grid ≈ TARGET_GRID. Same constraints as
365
  # flash_decode_with_topk_idx: must be power of 2 (Triton arange) and must
366
  # only depend on shape constants (so grid is fixed within a cuda graph).
build/torch211-cxx11-cu130-x86_64-linux/interface.py CHANGED
@@ -7,6 +7,11 @@ from typing import Optional
7
 
8
  import torch
9
 
 
 
 
 
 
10
  from .decode.topk_sparse import flash_decode_with_gqa_share_sparse
11
  from .prefill.topk_sparse import flash_prefill_with_gqa_share_sparse
12
  from .quantize import Nvfp4QuantizedTensor, dequantize_nvfp4_128x4_to_bf16
@@ -488,6 +493,12 @@ def _nvfp4_dequant_kv(
488
  ) -> torch.Tensor:
489
  if packed.dtype is not torch.uint8:
490
  return packed
 
 
 
 
 
 
491
  original_shape = tuple(int(v) for v in packed.shape[:-1]) + (int(packed.shape[-1]) * 2,)
492
  rows = 1
493
  for dim in original_shape[:-1]:
@@ -572,11 +583,12 @@ def fp4_indexer_block_scores(
572
  qo_offset: Optional[torch.Tensor] = None,
573
  scale_layout: str = "preordered_mma",
574
  ) -> torch.Tensor:
575
- """Correctness-first FP4 block-score API for Blackwell.
576
 
577
  Returns the official shape `[Hq, ceil(max_seqlen_k / 128), total_q]`.
578
- This fallback is intentionally simple and is used to keep the public API
579
- callable on Blackwell while optimized CUTE block scoring remains SM100-only.
 
580
  """
581
 
582
  del qo_offset
@@ -599,6 +611,29 @@ def fp4_indexer_block_scores(
599
 
600
  q = _apply_public_fp4_scale(_unpack_e2m1_fp4(q_fp4), q_scale)
601
  k = _apply_public_fp4_scale(_unpack_e2m1_fp4(k_fp4), k_scale)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
602
  gqa = hq // hkv
603
  batch = int(cu_seqlens_q.numel()) - 1
604
  cu_q = cu_seqlens_q.to("cpu", non_blocking=False).tolist()
 
7
 
8
  import torch
9
 
10
+ from ._native import (
11
+ has_native_ops,
12
+ native_indexer_block_scores,
13
+ native_nvfp4_dequant_swizzled_to_bf16,
14
+ )
15
  from .decode.topk_sparse import flash_decode_with_gqa_share_sparse
16
  from .prefill.topk_sparse import flash_prefill_with_gqa_share_sparse
17
  from .quantize import Nvfp4QuantizedTensor, dequantize_nvfp4_128x4_to_bf16
 
493
  ) -> torch.Tensor:
494
  if packed.dtype is not torch.uint8:
495
  return packed
496
+ if has_native_ops() and packed.is_cuda:
497
+ return native_nvfp4_dequant_swizzled_to_bf16(
498
+ packed,
499
+ scale_128x4,
500
+ global_scale,
501
+ )
502
  original_shape = tuple(int(v) for v in packed.shape[:-1]) + (int(packed.shape[-1]) * 2,)
503
  rows = 1
504
  for dim in original_shape[:-1]:
 
583
  qo_offset: Optional[torch.Tensor] = None,
584
  scale_layout: str = "preordered_mma",
585
  ) -> torch.Tensor:
586
+ """FP4 block-score API for Blackwell.
587
 
588
  Returns the official shape `[Hq, ceil(max_seqlen_k / 128), total_q]`.
589
+ Built artifacts route CUDA tensors through the native Blackwell block-score
590
+ kernel. Source-tree mode uses the reference loop below so the API remains
591
+ testable before the extension is built.
592
  """
593
 
594
  del qo_offset
 
611
 
612
  q = _apply_public_fp4_scale(_unpack_e2m1_fp4(q_fp4), q_scale)
613
  k = _apply_public_fp4_scale(_unpack_e2m1_fp4(k_fp4), k_scale)
614
+
615
+ # Native block-max QK kernel for the cubic scoring loop when available.
616
+ # Same dequant numerics as the reference (bf16 compute); falls back to the
617
+ # Python reference below in source-tree mode.
618
+ if has_native_ops() and q_fp4.is_cuda:
619
+ batch = int(cu_seqlens_q.numel()) - 1
620
+ q_lens = (cu_seqlens_q[1:] - cu_seqlens_q[:-1]).to(torch.int64)
621
+ batch_of_q = torch.repeat_interleave(
622
+ torch.arange(batch, device=q_fp4.device, dtype=torch.int32),
623
+ q_lens,
624
+ )
625
+ return native_indexer_block_scores(
626
+ q.to(torch.bfloat16),
627
+ k.to(torch.bfloat16),
628
+ batch_of_q,
629
+ cu_seqlens_q.to(torch.int32),
630
+ cu_seqlens_k.to(torch.int32),
631
+ cu_page_offsets.to(torch.int32),
632
+ kv_indices.to(torch.int32),
633
+ max_blocks=max_blocks,
634
+ causal=causal,
635
+ )
636
+
637
  gqa = hq // hkv
638
  batch = int(cu_seqlens_q.numel()) - 1
639
  cu_q = cu_seqlens_q.to("cpu", non_blocking=False).tolist()
build/torch211-cxx11-cu130-x86_64-linux/metadata.json CHANGED
@@ -1,6 +1,6 @@
1
  {
2
  "name": "minimaxai-msa-blackwell",
3
- "id": "_minimaxai_msa_blackwell_cuda_58018d1",
4
  "version": 1,
5
  "license": "Apache-2.0",
6
  "python-depends": [],
@@ -14,18 +14,18 @@
14
  "digest": {
15
  "algorithm": "sha256",
16
  "files": {
17
- "__init__.py": "bH4lC+HdMx2DgfiEWfvxhd7GvQBOt02ftSPAzKo1rE0=",
18
  "_compat.py": "5Wy4a96HVMD8omRNsGg8rQJ+0qCCeXiDANk0CuyyP0I=",
19
- "_minimaxai_msa_blackwell_cuda_58018d1.abi3.so": "SVpnkWEivCThxOS5lMQOngsyEYBhvlivD3a48iXu5hc=",
20
- "_native.py": "mIDvfkcQVd3H9plDsodJelrIFD2XHiEQgk4uqiiRLLE=",
21
- "_ops.py": "kuQPE8cc2FNEl3lIMfjaj074xh5YntsWFa8cYC5CLIQ=",
22
- "api_status.py": "VhS7aJhSznFwcgIQAnzXQTTuLJ2WgtysWrhX7RTSXaM=",
23
  "common/__init__.py": "bG7Ffen4LvQtgnYPFEpFccsWs81t4zqqeqn9ZeirH6E=",
24
  "common/utils.py": "qtwh+wZoySlsWWALvWGVsmcIHKkdZUwePxUZ42tfWxc=",
25
  "decode/__init__.py": "bG7Ffen4LvQtgnYPFEpFccsWs81t4zqqeqn9ZeirH6E=",
26
  "decode/flash_with_topk_idx.py": "Pk70+HJ60IKuy4KJC6hPdMtD2BjwPfSMabFiIBODWiQ=",
27
- "decode/topk_sparse.py": "PLwQnOyiZT44pCXcZXzXdlZSixfBeanTZsfbpMOjlpQ=",
28
- "interface.py": "TKlKdIqTtzfmieaY5ci3GwhD1QZXqUAZcqfcfPmyeuM=",
29
  "minimaxai_msa_blackwell/__init__.py": "DFYPlrhXwYjEqCl/8n0SmWGZV8NFml5DPhMjKfv98GY=",
30
  "naive/__init__.py": "bG7Ffen4LvQtgnYPFEpFccsWs81t4zqqeqn9ZeirH6E=",
31
  "naive/flash_with_topk_idx.py": "K7WQsRdO9+H2sz7pZ6axnJwE1OmnF0egdKtftHuChig=",
 
1
  {
2
  "name": "minimaxai-msa-blackwell",
3
+ "id": "_minimaxai_msa_blackwell_cuda_25b0067",
4
  "version": 1,
5
  "license": "Apache-2.0",
6
  "python-depends": [],
 
14
  "digest": {
15
  "algorithm": "sha256",
16
  "files": {
17
+ "__init__.py": "oPB7xQhjHd9+aLVJkEmJkZOXOwMEarmCdj3SBbhH2bM=",
18
  "_compat.py": "5Wy4a96HVMD8omRNsGg8rQJ+0qCCeXiDANk0CuyyP0I=",
19
+ "_minimaxai_msa_blackwell_cuda_25b0067.abi3.so": "oFPB/WnE3z+U5WanxNiLqUP41c7OcUreUnifaBmpYaw=",
20
+ "_native.py": "wTh66DiIKxsJ5m8fkAXKSCBYD3CVFVx4PFxceQiwvPY=",
21
+ "_ops.py": "ikU3Lg+kgswKktYjNSq5f4DmgyTR8dnxV8lH3rmOWvk=",
22
+ "api_status.py": "7oZzIkb4fuwkAz3r4Q1slHbOfaP3jwVB647Ok223ATk=",
23
  "common/__init__.py": "bG7Ffen4LvQtgnYPFEpFccsWs81t4zqqeqn9ZeirH6E=",
24
  "common/utils.py": "qtwh+wZoySlsWWALvWGVsmcIHKkdZUwePxUZ42tfWxc=",
25
  "decode/__init__.py": "bG7Ffen4LvQtgnYPFEpFccsWs81t4zqqeqn9ZeirH6E=",
26
  "decode/flash_with_topk_idx.py": "Pk70+HJ60IKuy4KJC6hPdMtD2BjwPfSMabFiIBODWiQ=",
27
+ "decode/topk_sparse.py": "uINcV9SP5sAf9jYPsPvyQ9lon8sajZ8Qn/yJ+2LA8NU=",
28
+ "interface.py": "jfhBHGyunFF+OdFycJYyptNNIAngKrXY67buTXAN66M=",
29
  "minimaxai_msa_blackwell/__init__.py": "DFYPlrhXwYjEqCl/8n0SmWGZV8NFml5DPhMjKfv98GY=",
30
  "naive/__init__.py": "bG7Ffen4LvQtgnYPFEpFccsWs81t4zqqeqn9ZeirH6E=",
31
  "naive/flash_with_topk_idx.py": "K7WQsRdO9+H2sz7pZ6axnJwE1OmnF0egdKtftHuChig=",
build/torch212-cxx11-cu130-x86_64-linux/__init__.py CHANGED
@@ -7,9 +7,12 @@ MiniMax-M3 decode-sparse attention path used by FlashRT's MiniMax Spark runtime.
7
 
8
  Implementation status:
9
  * native CUDA helper: score -> top-k sparse block ids;
10
- * Triton CUDA attention kernels: Blackwell-validated decode and prefill paths;
 
 
 
11
  * MiniMaxAI/msa compatibility wrappers for CSR prefill, decode, NVFP4 helpers,
12
- and FP4 block-score fallback.
13
 
14
  The upstream MiniMaxAI/msa package is SM100-only; this package is the Blackwell
15
  extension path. The public API is Tensor-oriented and independent from
@@ -48,7 +51,11 @@ from .interface import (
48
  sparse_atten_nvfp4_kv_func,
49
  sparse_decode_atten_func,
50
  )
51
- from ._native import has_native_ops, native_topk_from_scores
 
 
 
 
52
  from .naive.flash_with_topk_idx import naive_flash_decode_with_topk_idx
53
  from .naive.topk_sparse import naive_flash_decode_with_gqa_share_sparse
54
  from .quantize import (
@@ -88,6 +95,7 @@ __all__ = [
88
  "flash_decode_with_gqa_share_sparse",
89
  "has_native_ops",
90
  "native_topk_from_scores",
 
91
  "naive_flash_decode_with_gqa_share_sparse",
92
  "naive_flash_decode_with_topk_idx",
93
  "get_cu_seqblocks",
 
7
 
8
  Implementation status:
9
  * native CUDA helper: score -> top-k sparse block ids;
10
+ * native CUDA tensor-core sparse decode for the MiniMax-M3 Blackwell shape;
11
+ * native CUDA FP4 block-score indexer;
12
+ * native CUDA helper: swizzled NVFP4 -> BF16 dequant for the W4A16 quality path;
13
+ * Blackwell-validated sparse prefill path;
14
  * MiniMaxAI/msa compatibility wrappers for CSR prefill, decode, NVFP4 helpers,
15
+ and FP4 block-score helpers.
16
 
17
  The upstream MiniMaxAI/msa package is SM100-only; this package is the Blackwell
18
  extension path. The public API is Tensor-oriented and independent from
 
51
  sparse_atten_nvfp4_kv_func,
52
  sparse_decode_atten_func,
53
  )
54
+ from ._native import (
55
+ has_native_ops,
56
+ native_nvfp4_dequant_swizzled_to_bf16,
57
+ native_topk_from_scores,
58
+ )
59
  from .naive.flash_with_topk_idx import naive_flash_decode_with_topk_idx
60
  from .naive.topk_sparse import naive_flash_decode_with_gqa_share_sparse
61
  from .quantize import (
 
95
  "flash_decode_with_gqa_share_sparse",
96
  "has_native_ops",
97
  "native_topk_from_scores",
98
+ "native_nvfp4_dequant_swizzled_to_bf16",
99
  "naive_flash_decode_with_gqa_share_sparse",
100
  "naive_flash_decode_with_topk_idx",
101
  "get_cu_seqblocks",
build/torch212-cxx11-cu130-x86_64-linux/{_minimaxai_msa_blackwell_cuda_58018d1.abi3.so → _minimaxai_msa_blackwell_cuda_25b0067.abi3.so} RENAMED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:473074c02a1f88aa83de41429947330435156e125b9b4ac1a8b72fabfa49fd66
3
- size 151920
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2ea862050a19dcc4b0c7cbfd3b519112f1b4e054cfc182a14f92876b4ae5b9f7
3
+ size 735888
build/torch212-cxx11-cu130-x86_64-linux/_native.py CHANGED
@@ -62,4 +62,198 @@ def native_topk_from_scores(
62
  return out
63
 
64
 
65
- __all__ = ["has_native_ops", "native_topk_from_scores"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
  return out
63
 
64
 
65
+ if _HAS_NATIVE_OPS:
66
+
67
+ @torch.library.register_fake(
68
+ add_op_namespace_prefix("msa_decode_sparse_attn_mma_paged")
69
+ )
70
+ def _msa_decode_sparse_attn_mma_paged_fake(
71
+ q: torch.Tensor,
72
+ k_cache: torch.Tensor,
73
+ v_cache: torch.Tensor,
74
+ req_to_token: torch.Tensor,
75
+ seq_lens: torch.Tensor,
76
+ slot_ids: torch.Tensor,
77
+ topk_idx: torch.Tensor,
78
+ block_size: int,
79
+ sm_scale: float,
80
+ out: torch.Tensor,
81
+ ) -> None:
82
+ return None
83
+
84
+
85
+ def native_decode_mma_supported(
86
+ q: torch.Tensor,
87
+ k_cache: torch.Tensor,
88
+ *,
89
+ block_size: int,
90
+ ) -> bool:
91
+ """Whether the tensor-core decode kernel applies to these inputs.
92
+
93
+ The mma kernel is specialized for the M3 MSA shape: head_dim 128, GQA
94
+ group (Hq/Hkv) 16, bf16, and a block size that is a multiple of 64.
95
+ """
96
+
97
+ if not _HAS_NATIVE_OPS:
98
+ return False
99
+ if q.dtype is not torch.bfloat16 or k_cache.dtype is not torch.bfloat16:
100
+ return False
101
+ if q.dim() != 3 or k_cache.dim() != 3:
102
+ return False
103
+ head_dim = int(q.shape[-1])
104
+ num_q_heads = int(q.shape[1])
105
+ num_kv_heads = int(k_cache.shape[1])
106
+ if head_dim != 128 or num_kv_heads <= 0:
107
+ return False
108
+ if num_q_heads % num_kv_heads != 0 or num_q_heads // num_kv_heads != 16:
109
+ return False
110
+ if int(block_size) % 64 != 0:
111
+ return False
112
+ return True
113
+
114
+
115
+ def native_decode_sparse_attn_mma_paged(
116
+ q: torch.Tensor,
117
+ k_cache: torch.Tensor,
118
+ v_cache: torch.Tensor,
119
+ req_to_token: torch.Tensor,
120
+ seq_lens: torch.Tensor,
121
+ slot_ids: torch.Tensor,
122
+ block_size: int,
123
+ topk_idx: torch.Tensor,
124
+ sm_scale: float,
125
+ ) -> torch.Tensor:
126
+ """Paged tensor-core block-sparse GQA decode. Returns [B, Hq, D] bf16."""
127
+
128
+ if not _HAS_NATIVE_OPS:
129
+ raise RuntimeError("native MiniMax MSA ops are not available in source-tree mode")
130
+ out = torch.empty(
131
+ (int(q.shape[0]), int(q.shape[1]), int(q.shape[2])),
132
+ device=q.device,
133
+ dtype=q.dtype,
134
+ )
135
+ ops.msa_decode_sparse_attn_mma_paged(
136
+ q.contiguous(),
137
+ k_cache.contiguous(),
138
+ v_cache.contiguous(),
139
+ req_to_token.contiguous(),
140
+ seq_lens.contiguous(),
141
+ slot_ids.contiguous(),
142
+ topk_idx.contiguous(),
143
+ int(block_size),
144
+ float(sm_scale),
145
+ out,
146
+ )
147
+ return out
148
+
149
+
150
+ if _HAS_NATIVE_OPS:
151
+
152
+ @torch.library.register_fake(
153
+ add_op_namespace_prefix("msa_indexer_block_scores")
154
+ )
155
+ def _msa_indexer_block_scores_fake(
156
+ q: torch.Tensor,
157
+ k_pages: torch.Tensor,
158
+ batch_of_q: torch.Tensor,
159
+ cu_q: torch.Tensor,
160
+ cu_k: torch.Tensor,
161
+ cu_pages: torch.Tensor,
162
+ kv_indices: torch.Tensor,
163
+ causal: int,
164
+ scores: torch.Tensor,
165
+ ) -> None:
166
+ return None
167
+
168
+
169
+ def native_indexer_block_scores(
170
+ q: torch.Tensor,
171
+ k_pages: torch.Tensor,
172
+ batch_of_q: torch.Tensor,
173
+ cu_q: torch.Tensor,
174
+ cu_k: torch.Tensor,
175
+ cu_pages: torch.Tensor,
176
+ kv_indices: torch.Tensor,
177
+ *,
178
+ max_blocks: int,
179
+ causal: bool,
180
+ ) -> torch.Tensor:
181
+ """Block-max QK indexer scores. q/k_pages are bf16 (already dequantized).
182
+
183
+ Returns [Hq, max_blocks, total_q] f32 (-inf where no key is visible).
184
+ """
185
+
186
+ if not _HAS_NATIVE_OPS:
187
+ raise RuntimeError("native MiniMax MSA ops are not available in source-tree mode")
188
+ total_q = int(q.shape[0])
189
+ hq = int(q.shape[1])
190
+ scores = torch.full(
191
+ (hq, int(max_blocks), total_q),
192
+ float("-inf"),
193
+ dtype=torch.float32,
194
+ device=q.device,
195
+ )
196
+ ops.msa_indexer_block_scores(
197
+ q.contiguous(),
198
+ k_pages.contiguous(),
199
+ batch_of_q.contiguous(),
200
+ cu_q.contiguous(),
201
+ cu_k.contiguous(),
202
+ cu_pages.contiguous(),
203
+ kv_indices.contiguous(),
204
+ 1 if causal else 0,
205
+ scores,
206
+ )
207
+ return scores
208
+
209
+
210
+ if _HAS_NATIVE_OPS:
211
+
212
+ @torch.library.register_fake(
213
+ add_op_namespace_prefix("msa_nvfp4_dequant_swizzled_to_bf16")
214
+ )
215
+ def _msa_nvfp4_dequant_swizzled_to_bf16_fake(
216
+ packed: torch.Tensor,
217
+ scale_128x4: torch.Tensor,
218
+ global_scale: float,
219
+ out: torch.Tensor,
220
+ ) -> None:
221
+ return None
222
+
223
+
224
+ def native_nvfp4_dequant_swizzled_to_bf16(
225
+ packed: torch.Tensor,
226
+ scale_128x4: torch.Tensor,
227
+ global_scale: torch.Tensor | float,
228
+ ) -> torch.Tensor:
229
+ """Expand swizzled NVFP4 weights/KV to dense BF16 with the native CUDA path."""
230
+
231
+ if not _HAS_NATIVE_OPS:
232
+ raise RuntimeError("native MiniMax MSA ops are not available in source-tree mode")
233
+ if packed.dtype is not torch.uint8:
234
+ raise TypeError("packed must be torch.uint8")
235
+ if scale_128x4.dtype is not torch.uint8:
236
+ raise TypeError("scale_128x4 must be torch.uint8")
237
+ original_shape = tuple(int(v) for v in packed.shape[:-1]) + (int(packed.shape[-1]) * 2,)
238
+ out = torch.empty(original_shape, device=packed.device, dtype=torch.bfloat16)
239
+ if isinstance(global_scale, torch.Tensor):
240
+ global_scale_value = float(global_scale.reshape(-1)[0].item())
241
+ else:
242
+ global_scale_value = float(global_scale)
243
+ ops.msa_nvfp4_dequant_swizzled_to_bf16(
244
+ packed.contiguous(),
245
+ scale_128x4.contiguous(),
246
+ global_scale_value,
247
+ out,
248
+ )
249
+ return out
250
+
251
+
252
+ __all__ = [
253
+ "has_native_ops",
254
+ "native_topk_from_scores",
255
+ "native_decode_mma_supported",
256
+ "native_decode_sparse_attn_mma_paged",
257
+ "native_indexer_block_scores",
258
+ "native_nvfp4_dequant_swizzled_to_bf16",
259
+ ]
build/torch212-cxx11-cu130-x86_64-linux/_ops.py CHANGED
@@ -1,9 +1,9 @@
1
  import torch
2
- from . import _minimaxai_msa_blackwell_cuda_58018d1
3
- ops = torch.ops._minimaxai_msa_blackwell_cuda_58018d1
4
 
5
  def add_op_namespace_prefix(op_name: str):
6
  """
7
  Prefix op by namespace.
8
  """
9
- return f"_minimaxai_msa_blackwell_cuda_58018d1::{op_name}"
 
1
  import torch
2
+ from . import _minimaxai_msa_blackwell_cuda_25b0067
3
+ ops = torch.ops._minimaxai_msa_blackwell_cuda_25b0067
4
 
5
  def add_op_namespace_prefix(op_name: str):
6
  """
7
  Prefix op by namespace.
8
  """
9
+ return f"_minimaxai_msa_blackwell_cuda_25b0067::{op_name}"
build/torch212-cxx11-cu130-x86_64-linux/api_status.py CHANGED
@@ -22,6 +22,7 @@ V1_AVAILABLE_FUNCTIONS = (
22
  "nvfp4_global_scale_from_amax",
23
  "has_native_ops",
24
  "native_topk_from_scores",
 
25
  "flash_decode_with_topk_idx",
26
  "flash_decode_with_gqa_share_sparse",
27
  "naive_flash_decode_with_topk_idx",
@@ -55,7 +56,7 @@ _OFFICIAL_API_STATUS = {
55
  "sparse_atten_nvfp4_kv_func": {
56
  "status": "available",
57
  "target": "blackwell-prefill-nvfp4",
58
- "reason": "Official NVFP4 KV prefill API is available via NVFP4 dequantization followed by the Blackwell prefill wrapper.",
59
  },
60
  "sparse_decode_atten_func": {
61
  "status": "available",
@@ -70,12 +71,12 @@ _OFFICIAL_API_STATUS = {
70
  "fp4_indexer_block_scores": {
71
  "status": "available",
72
  "target": "blackwell-fp4-indexer",
73
- "reason": "Official FP4 block-score API is available as a correctness-first PyTorch fallback.",
74
  },
75
  "build_k2q_csr": {
76
  "status": "available",
77
  "target": "v1",
78
- "reason": "Torch CSR construction fallback is available for compatibility.",
79
  },
80
  "SparseK2qCsrBuilderSm100": {
81
  "status": "available",
 
22
  "nvfp4_global_scale_from_amax",
23
  "has_native_ops",
24
  "native_topk_from_scores",
25
+ "native_nvfp4_dequant_swizzled_to_bf16",
26
  "flash_decode_with_topk_idx",
27
  "flash_decode_with_gqa_share_sparse",
28
  "naive_flash_decode_with_topk_idx",
 
56
  "sparse_atten_nvfp4_kv_func": {
57
  "status": "available",
58
  "target": "blackwell-prefill-nvfp4",
59
+ "reason": "Official NVFP4 KV prefill API is available via native swizzled NVFP4 dequantization followed by the Blackwell prefill wrapper.",
60
  },
61
  "sparse_decode_atten_func": {
62
  "status": "available",
 
71
  "fp4_indexer_block_scores": {
72
  "status": "available",
73
  "target": "blackwell-fp4-indexer",
74
+ "reason": "Official FP4 block-score API uses the native Blackwell block-score kernel in built artifacts, with a reference fallback in source-tree mode.",
75
  },
76
  "build_k2q_csr": {
77
  "status": "available",
78
  "target": "v1",
79
+ "reason": "CSR construction helper is available for the official prefill API.",
80
  },
81
  "SparseK2qCsrBuilderSm100": {
82
  "status": "available",
build/torch212-cxx11-cu130-x86_64-linux/decode/topk_sparse.py CHANGED
@@ -8,6 +8,10 @@ import triton.language as tl
8
 
9
  from .._compat import is_hip # vendored: was `from sglang.srt.utils import is_hip`
10
 
 
 
 
 
11
  from ..common.utils import robust_allocator
12
 
13
  _is_hip = is_hip()
@@ -341,6 +345,22 @@ def flash_decode_with_gqa_share_sparse(
341
  # sm scale
342
  if sm_scale is None:
343
  sm_scale = head_dim**-0.5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
344
  # Pick NUM_TOPK_CHUNKS so total grid ≈ TARGET_GRID. Same constraints as
345
  # flash_decode_with_topk_idx: must be power of 2 (Triton arange) and must
346
  # only depend on shape constants (so grid is fixed within a cuda graph).
 
8
 
9
  from .._compat import is_hip # vendored: was `from sglang.srt.utils import is_hip`
10
 
11
+ from .._native import (
12
+ native_decode_mma_supported,
13
+ native_decode_sparse_attn_mma_paged,
14
+ )
15
  from ..common.utils import robust_allocator
16
 
17
  _is_hip = is_hip()
 
345
  # sm scale
346
  if sm_scale is None:
347
  sm_scale = head_dim**-0.5
348
+ # Fast path: native tensor-core decode for the M3 MSA shape. Falls through
349
+ # to the Triton kernel for other shapes, sink, or fp8 caches.
350
+ if sink is None and not is_fp8 and native_decode_mma_supported(
351
+ q, k_cache, block_size=block_size
352
+ ):
353
+ return native_decode_sparse_attn_mma_paged(
354
+ q,
355
+ k_cache,
356
+ v_cache,
357
+ req_to_token,
358
+ seq_lens,
359
+ slot_ids,
360
+ block_size,
361
+ topk_idx,
362
+ sm_scale,
363
+ )
364
  # Pick NUM_TOPK_CHUNKS so total grid ≈ TARGET_GRID. Same constraints as
365
  # flash_decode_with_topk_idx: must be power of 2 (Triton arange) and must
366
  # only depend on shape constants (so grid is fixed within a cuda graph).
build/torch212-cxx11-cu130-x86_64-linux/interface.py CHANGED
@@ -7,6 +7,11 @@ from typing import Optional
7
 
8
  import torch
9
 
 
 
 
 
 
10
  from .decode.topk_sparse import flash_decode_with_gqa_share_sparse
11
  from .prefill.topk_sparse import flash_prefill_with_gqa_share_sparse
12
  from .quantize import Nvfp4QuantizedTensor, dequantize_nvfp4_128x4_to_bf16
@@ -488,6 +493,12 @@ def _nvfp4_dequant_kv(
488
  ) -> torch.Tensor:
489
  if packed.dtype is not torch.uint8:
490
  return packed
 
 
 
 
 
 
491
  original_shape = tuple(int(v) for v in packed.shape[:-1]) + (int(packed.shape[-1]) * 2,)
492
  rows = 1
493
  for dim in original_shape[:-1]:
@@ -572,11 +583,12 @@ def fp4_indexer_block_scores(
572
  qo_offset: Optional[torch.Tensor] = None,
573
  scale_layout: str = "preordered_mma",
574
  ) -> torch.Tensor:
575
- """Correctness-first FP4 block-score API for Blackwell.
576
 
577
  Returns the official shape `[Hq, ceil(max_seqlen_k / 128), total_q]`.
578
- This fallback is intentionally simple and is used to keep the public API
579
- callable on Blackwell while optimized CUTE block scoring remains SM100-only.
 
580
  """
581
 
582
  del qo_offset
@@ -599,6 +611,29 @@ def fp4_indexer_block_scores(
599
 
600
  q = _apply_public_fp4_scale(_unpack_e2m1_fp4(q_fp4), q_scale)
601
  k = _apply_public_fp4_scale(_unpack_e2m1_fp4(k_fp4), k_scale)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
602
  gqa = hq // hkv
603
  batch = int(cu_seqlens_q.numel()) - 1
604
  cu_q = cu_seqlens_q.to("cpu", non_blocking=False).tolist()
 
7
 
8
  import torch
9
 
10
+ from ._native import (
11
+ has_native_ops,
12
+ native_indexer_block_scores,
13
+ native_nvfp4_dequant_swizzled_to_bf16,
14
+ )
15
  from .decode.topk_sparse import flash_decode_with_gqa_share_sparse
16
  from .prefill.topk_sparse import flash_prefill_with_gqa_share_sparse
17
  from .quantize import Nvfp4QuantizedTensor, dequantize_nvfp4_128x4_to_bf16
 
493
  ) -> torch.Tensor:
494
  if packed.dtype is not torch.uint8:
495
  return packed
496
+ if has_native_ops() and packed.is_cuda:
497
+ return native_nvfp4_dequant_swizzled_to_bf16(
498
+ packed,
499
+ scale_128x4,
500
+ global_scale,
501
+ )
502
  original_shape = tuple(int(v) for v in packed.shape[:-1]) + (int(packed.shape[-1]) * 2,)
503
  rows = 1
504
  for dim in original_shape[:-1]:
 
583
  qo_offset: Optional[torch.Tensor] = None,
584
  scale_layout: str = "preordered_mma",
585
  ) -> torch.Tensor:
586
+ """FP4 block-score API for Blackwell.
587
 
588
  Returns the official shape `[Hq, ceil(max_seqlen_k / 128), total_q]`.
589
+ Built artifacts route CUDA tensors through the native Blackwell block-score
590
+ kernel. Source-tree mode uses the reference loop below so the API remains
591
+ testable before the extension is built.
592
  """
593
 
594
  del qo_offset
 
611
 
612
  q = _apply_public_fp4_scale(_unpack_e2m1_fp4(q_fp4), q_scale)
613
  k = _apply_public_fp4_scale(_unpack_e2m1_fp4(k_fp4), k_scale)
614
+
615
+ # Native block-max QK kernel for the cubic scoring loop when available.
616
+ # Same dequant numerics as the reference (bf16 compute); falls back to the
617
+ # Python reference below in source-tree mode.
618
+ if has_native_ops() and q_fp4.is_cuda:
619
+ batch = int(cu_seqlens_q.numel()) - 1
620
+ q_lens = (cu_seqlens_q[1:] - cu_seqlens_q[:-1]).to(torch.int64)
621
+ batch_of_q = torch.repeat_interleave(
622
+ torch.arange(batch, device=q_fp4.device, dtype=torch.int32),
623
+ q_lens,
624
+ )
625
+ return native_indexer_block_scores(
626
+ q.to(torch.bfloat16),
627
+ k.to(torch.bfloat16),
628
+ batch_of_q,
629
+ cu_seqlens_q.to(torch.int32),
630
+ cu_seqlens_k.to(torch.int32),
631
+ cu_page_offsets.to(torch.int32),
632
+ kv_indices.to(torch.int32),
633
+ max_blocks=max_blocks,
634
+ causal=causal,
635
+ )
636
+
637
  gqa = hq // hkv
638
  batch = int(cu_seqlens_q.numel()) - 1
639
  cu_q = cu_seqlens_q.to("cpu", non_blocking=False).tolist()
build/torch212-cxx11-cu130-x86_64-linux/metadata.json CHANGED
@@ -1,6 +1,6 @@
1
  {
2
  "name": "minimaxai-msa-blackwell",
3
- "id": "_minimaxai_msa_blackwell_cuda_58018d1",
4
  "version": 1,
5
  "license": "Apache-2.0",
6
  "python-depends": [],
@@ -14,18 +14,18 @@
14
  "digest": {
15
  "algorithm": "sha256",
16
  "files": {
17
- "__init__.py": "bH4lC+HdMx2DgfiEWfvxhd7GvQBOt02ftSPAzKo1rE0=",
18
  "_compat.py": "5Wy4a96HVMD8omRNsGg8rQJ+0qCCeXiDANk0CuyyP0I=",
19
- "_minimaxai_msa_blackwell_cuda_58018d1.abi3.so": "RzB0wCofiKqD3kFCmUczBDUVbhJbm0rBqLcvq/pJ/WY=",
20
- "_native.py": "mIDvfkcQVd3H9plDsodJelrIFD2XHiEQgk4uqiiRLLE=",
21
- "_ops.py": "kuQPE8cc2FNEl3lIMfjaj074xh5YntsWFa8cYC5CLIQ=",
22
- "api_status.py": "VhS7aJhSznFwcgIQAnzXQTTuLJ2WgtysWrhX7RTSXaM=",
23
  "common/__init__.py": "bG7Ffen4LvQtgnYPFEpFccsWs81t4zqqeqn9ZeirH6E=",
24
  "common/utils.py": "qtwh+wZoySlsWWALvWGVsmcIHKkdZUwePxUZ42tfWxc=",
25
  "decode/__init__.py": "bG7Ffen4LvQtgnYPFEpFccsWs81t4zqqeqn9ZeirH6E=",
26
  "decode/flash_with_topk_idx.py": "Pk70+HJ60IKuy4KJC6hPdMtD2BjwPfSMabFiIBODWiQ=",
27
- "decode/topk_sparse.py": "PLwQnOyiZT44pCXcZXzXdlZSixfBeanTZsfbpMOjlpQ=",
28
- "interface.py": "TKlKdIqTtzfmieaY5ci3GwhD1QZXqUAZcqfcfPmyeuM=",
29
  "minimaxai_msa_blackwell/__init__.py": "DFYPlrhXwYjEqCl/8n0SmWGZV8NFml5DPhMjKfv98GY=",
30
  "naive/__init__.py": "bG7Ffen4LvQtgnYPFEpFccsWs81t4zqqeqn9ZeirH6E=",
31
  "naive/flash_with_topk_idx.py": "K7WQsRdO9+H2sz7pZ6axnJwE1OmnF0egdKtftHuChig=",
 
1
  {
2
  "name": "minimaxai-msa-blackwell",
3
+ "id": "_minimaxai_msa_blackwell_cuda_25b0067",
4
  "version": 1,
5
  "license": "Apache-2.0",
6
  "python-depends": [],
 
14
  "digest": {
15
  "algorithm": "sha256",
16
  "files": {
17
+ "__init__.py": "oPB7xQhjHd9+aLVJkEmJkZOXOwMEarmCdj3SBbhH2bM=",
18
  "_compat.py": "5Wy4a96HVMD8omRNsGg8rQJ+0qCCeXiDANk0CuyyP0I=",
19
+ "_minimaxai_msa_blackwell_cuda_25b0067.abi3.so": "LqhiBQoZ3MSwx8v9O1GREvG04FTPwYKhT5KHa0rlufc=",
20
+ "_native.py": "wTh66DiIKxsJ5m8fkAXKSCBYD3CVFVx4PFxceQiwvPY=",
21
+ "_ops.py": "ikU3Lg+kgswKktYjNSq5f4DmgyTR8dnxV8lH3rmOWvk=",
22
+ "api_status.py": "7oZzIkb4fuwkAz3r4Q1slHbOfaP3jwVB647Ok223ATk=",
23
  "common/__init__.py": "bG7Ffen4LvQtgnYPFEpFccsWs81t4zqqeqn9ZeirH6E=",
24
  "common/utils.py": "qtwh+wZoySlsWWALvWGVsmcIHKkdZUwePxUZ42tfWxc=",
25
  "decode/__init__.py": "bG7Ffen4LvQtgnYPFEpFccsWs81t4zqqeqn9ZeirH6E=",
26
  "decode/flash_with_topk_idx.py": "Pk70+HJ60IKuy4KJC6hPdMtD2BjwPfSMabFiIBODWiQ=",
27
+ "decode/topk_sparse.py": "uINcV9SP5sAf9jYPsPvyQ9lon8sajZ8Qn/yJ+2LA8NU=",
28
+ "interface.py": "jfhBHGyunFF+OdFycJYyptNNIAngKrXY67buTXAN66M=",
29
  "minimaxai_msa_blackwell/__init__.py": "DFYPlrhXwYjEqCl/8n0SmWGZV8NFml5DPhMjKfv98GY=",
30
  "naive/__init__.py": "bG7Ffen4LvQtgnYPFEpFccsWs81t4zqqeqn9ZeirH6E=",
31
  "naive/flash_with_topk_idx.py": "K7WQsRdO9+H2sz7pZ6axnJwE1OmnF0egdKtftHuChig=",
build/torch212-cxx11-cu132-x86_64-linux/__init__.py CHANGED
@@ -7,9 +7,12 @@ MiniMax-M3 decode-sparse attention path used by FlashRT's MiniMax Spark runtime.
7
 
8
  Implementation status:
9
  * native CUDA helper: score -> top-k sparse block ids;
10
- * Triton CUDA attention kernels: Blackwell-validated decode and prefill paths;
 
 
 
11
  * MiniMaxAI/msa compatibility wrappers for CSR prefill, decode, NVFP4 helpers,
12
- and FP4 block-score fallback.
13
 
14
  The upstream MiniMaxAI/msa package is SM100-only; this package is the Blackwell
15
  extension path. The public API is Tensor-oriented and independent from
@@ -48,7 +51,11 @@ from .interface import (
48
  sparse_atten_nvfp4_kv_func,
49
  sparse_decode_atten_func,
50
  )
51
- from ._native import has_native_ops, native_topk_from_scores
 
 
 
 
52
  from .naive.flash_with_topk_idx import naive_flash_decode_with_topk_idx
53
  from .naive.topk_sparse import naive_flash_decode_with_gqa_share_sparse
54
  from .quantize import (
@@ -88,6 +95,7 @@ __all__ = [
88
  "flash_decode_with_gqa_share_sparse",
89
  "has_native_ops",
90
  "native_topk_from_scores",
 
91
  "naive_flash_decode_with_gqa_share_sparse",
92
  "naive_flash_decode_with_topk_idx",
93
  "get_cu_seqblocks",
 
7
 
8
  Implementation status:
9
  * native CUDA helper: score -> top-k sparse block ids;
10
+ * native CUDA tensor-core sparse decode for the MiniMax-M3 Blackwell shape;
11
+ * native CUDA FP4 block-score indexer;
12
+ * native CUDA helper: swizzled NVFP4 -> BF16 dequant for the W4A16 quality path;
13
+ * Blackwell-validated sparse prefill path;
14
  * MiniMaxAI/msa compatibility wrappers for CSR prefill, decode, NVFP4 helpers,
15
+ and FP4 block-score helpers.
16
 
17
  The upstream MiniMaxAI/msa package is SM100-only; this package is the Blackwell
18
  extension path. The public API is Tensor-oriented and independent from
 
51
  sparse_atten_nvfp4_kv_func,
52
  sparse_decode_atten_func,
53
  )
54
+ from ._native import (
55
+ has_native_ops,
56
+ native_nvfp4_dequant_swizzled_to_bf16,
57
+ native_topk_from_scores,
58
+ )
59
  from .naive.flash_with_topk_idx import naive_flash_decode_with_topk_idx
60
  from .naive.topk_sparse import naive_flash_decode_with_gqa_share_sparse
61
  from .quantize import (
 
95
  "flash_decode_with_gqa_share_sparse",
96
  "has_native_ops",
97
  "native_topk_from_scores",
98
+ "native_nvfp4_dequant_swizzled_to_bf16",
99
  "naive_flash_decode_with_gqa_share_sparse",
100
  "naive_flash_decode_with_topk_idx",
101
  "get_cu_seqblocks",
build/torch212-cxx11-cu132-x86_64-linux/{_minimaxai_msa_blackwell_cuda_58018d1.abi3.so → _minimaxai_msa_blackwell_cuda_25b0067.abi3.so} RENAMED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:3c2f06a4139531e1dffcede1973b0c0605afa3b62f9818a87504ed794adc874d
3
- size 164208
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:4eb01c1a96c3e640474b3a52f2d38da4be2af0290c4b945c50f90e867d9e907f
3
+ size 744080
build/torch212-cxx11-cu132-x86_64-linux/_native.py CHANGED
@@ -62,4 +62,198 @@ def native_topk_from_scores(
62
  return out
63
 
64
 
65
- __all__ = ["has_native_ops", "native_topk_from_scores"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
  return out
63
 
64
 
65
+ if _HAS_NATIVE_OPS:
66
+
67
+ @torch.library.register_fake(
68
+ add_op_namespace_prefix("msa_decode_sparse_attn_mma_paged")
69
+ )
70
+ def _msa_decode_sparse_attn_mma_paged_fake(
71
+ q: torch.Tensor,
72
+ k_cache: torch.Tensor,
73
+ v_cache: torch.Tensor,
74
+ req_to_token: torch.Tensor,
75
+ seq_lens: torch.Tensor,
76
+ slot_ids: torch.Tensor,
77
+ topk_idx: torch.Tensor,
78
+ block_size: int,
79
+ sm_scale: float,
80
+ out: torch.Tensor,
81
+ ) -> None:
82
+ return None
83
+
84
+
85
+ def native_decode_mma_supported(
86
+ q: torch.Tensor,
87
+ k_cache: torch.Tensor,
88
+ *,
89
+ block_size: int,
90
+ ) -> bool:
91
+ """Whether the tensor-core decode kernel applies to these inputs.
92
+
93
+ The mma kernel is specialized for the M3 MSA shape: head_dim 128, GQA
94
+ group (Hq/Hkv) 16, bf16, and a block size that is a multiple of 64.
95
+ """
96
+
97
+ if not _HAS_NATIVE_OPS:
98
+ return False
99
+ if q.dtype is not torch.bfloat16 or k_cache.dtype is not torch.bfloat16:
100
+ return False
101
+ if q.dim() != 3 or k_cache.dim() != 3:
102
+ return False
103
+ head_dim = int(q.shape[-1])
104
+ num_q_heads = int(q.shape[1])
105
+ num_kv_heads = int(k_cache.shape[1])
106
+ if head_dim != 128 or num_kv_heads <= 0:
107
+ return False
108
+ if num_q_heads % num_kv_heads != 0 or num_q_heads // num_kv_heads != 16:
109
+ return False
110
+ if int(block_size) % 64 != 0:
111
+ return False
112
+ return True
113
+
114
+
115
+ def native_decode_sparse_attn_mma_paged(
116
+ q: torch.Tensor,
117
+ k_cache: torch.Tensor,
118
+ v_cache: torch.Tensor,
119
+ req_to_token: torch.Tensor,
120
+ seq_lens: torch.Tensor,
121
+ slot_ids: torch.Tensor,
122
+ block_size: int,
123
+ topk_idx: torch.Tensor,
124
+ sm_scale: float,
125
+ ) -> torch.Tensor:
126
+ """Paged tensor-core block-sparse GQA decode. Returns [B, Hq, D] bf16."""
127
+
128
+ if not _HAS_NATIVE_OPS:
129
+ raise RuntimeError("native MiniMax MSA ops are not available in source-tree mode")
130
+ out = torch.empty(
131
+ (int(q.shape[0]), int(q.shape[1]), int(q.shape[2])),
132
+ device=q.device,
133
+ dtype=q.dtype,
134
+ )
135
+ ops.msa_decode_sparse_attn_mma_paged(
136
+ q.contiguous(),
137
+ k_cache.contiguous(),
138
+ v_cache.contiguous(),
139
+ req_to_token.contiguous(),
140
+ seq_lens.contiguous(),
141
+ slot_ids.contiguous(),
142
+ topk_idx.contiguous(),
143
+ int(block_size),
144
+ float(sm_scale),
145
+ out,
146
+ )
147
+ return out
148
+
149
+
150
+ if _HAS_NATIVE_OPS:
151
+
152
+ @torch.library.register_fake(
153
+ add_op_namespace_prefix("msa_indexer_block_scores")
154
+ )
155
+ def _msa_indexer_block_scores_fake(
156
+ q: torch.Tensor,
157
+ k_pages: torch.Tensor,
158
+ batch_of_q: torch.Tensor,
159
+ cu_q: torch.Tensor,
160
+ cu_k: torch.Tensor,
161
+ cu_pages: torch.Tensor,
162
+ kv_indices: torch.Tensor,
163
+ causal: int,
164
+ scores: torch.Tensor,
165
+ ) -> None:
166
+ return None
167
+
168
+
169
+ def native_indexer_block_scores(
170
+ q: torch.Tensor,
171
+ k_pages: torch.Tensor,
172
+ batch_of_q: torch.Tensor,
173
+ cu_q: torch.Tensor,
174
+ cu_k: torch.Tensor,
175
+ cu_pages: torch.Tensor,
176
+ kv_indices: torch.Tensor,
177
+ *,
178
+ max_blocks: int,
179
+ causal: bool,
180
+ ) -> torch.Tensor:
181
+ """Block-max QK indexer scores. q/k_pages are bf16 (already dequantized).
182
+
183
+ Returns [Hq, max_blocks, total_q] f32 (-inf where no key is visible).
184
+ """
185
+
186
+ if not _HAS_NATIVE_OPS:
187
+ raise RuntimeError("native MiniMax MSA ops are not available in source-tree mode")
188
+ total_q = int(q.shape[0])
189
+ hq = int(q.shape[1])
190
+ scores = torch.full(
191
+ (hq, int(max_blocks), total_q),
192
+ float("-inf"),
193
+ dtype=torch.float32,
194
+ device=q.device,
195
+ )
196
+ ops.msa_indexer_block_scores(
197
+ q.contiguous(),
198
+ k_pages.contiguous(),
199
+ batch_of_q.contiguous(),
200
+ cu_q.contiguous(),
201
+ cu_k.contiguous(),
202
+ cu_pages.contiguous(),
203
+ kv_indices.contiguous(),
204
+ 1 if causal else 0,
205
+ scores,
206
+ )
207
+ return scores
208
+
209
+
210
+ if _HAS_NATIVE_OPS:
211
+
212
+ @torch.library.register_fake(
213
+ add_op_namespace_prefix("msa_nvfp4_dequant_swizzled_to_bf16")
214
+ )
215
+ def _msa_nvfp4_dequant_swizzled_to_bf16_fake(
216
+ packed: torch.Tensor,
217
+ scale_128x4: torch.Tensor,
218
+ global_scale: float,
219
+ out: torch.Tensor,
220
+ ) -> None:
221
+ return None
222
+
223
+
224
+ def native_nvfp4_dequant_swizzled_to_bf16(
225
+ packed: torch.Tensor,
226
+ scale_128x4: torch.Tensor,
227
+ global_scale: torch.Tensor | float,
228
+ ) -> torch.Tensor:
229
+ """Expand swizzled NVFP4 weights/KV to dense BF16 with the native CUDA path."""
230
+
231
+ if not _HAS_NATIVE_OPS:
232
+ raise RuntimeError("native MiniMax MSA ops are not available in source-tree mode")
233
+ if packed.dtype is not torch.uint8:
234
+ raise TypeError("packed must be torch.uint8")
235
+ if scale_128x4.dtype is not torch.uint8:
236
+ raise TypeError("scale_128x4 must be torch.uint8")
237
+ original_shape = tuple(int(v) for v in packed.shape[:-1]) + (int(packed.shape[-1]) * 2,)
238
+ out = torch.empty(original_shape, device=packed.device, dtype=torch.bfloat16)
239
+ if isinstance(global_scale, torch.Tensor):
240
+ global_scale_value = float(global_scale.reshape(-1)[0].item())
241
+ else:
242
+ global_scale_value = float(global_scale)
243
+ ops.msa_nvfp4_dequant_swizzled_to_bf16(
244
+ packed.contiguous(),
245
+ scale_128x4.contiguous(),
246
+ global_scale_value,
247
+ out,
248
+ )
249
+ return out
250
+
251
+
252
+ __all__ = [
253
+ "has_native_ops",
254
+ "native_topk_from_scores",
255
+ "native_decode_mma_supported",
256
+ "native_decode_sparse_attn_mma_paged",
257
+ "native_indexer_block_scores",
258
+ "native_nvfp4_dequant_swizzled_to_bf16",
259
+ ]
build/torch212-cxx11-cu132-x86_64-linux/_ops.py CHANGED
@@ -1,9 +1,9 @@
1
  import torch
2
- from . import _minimaxai_msa_blackwell_cuda_58018d1
3
- ops = torch.ops._minimaxai_msa_blackwell_cuda_58018d1
4
 
5
  def add_op_namespace_prefix(op_name: str):
6
  """
7
  Prefix op by namespace.
8
  """
9
- return f"_minimaxai_msa_blackwell_cuda_58018d1::{op_name}"
 
1
  import torch
2
+ from . import _minimaxai_msa_blackwell_cuda_25b0067
3
+ ops = torch.ops._minimaxai_msa_blackwell_cuda_25b0067
4
 
5
  def add_op_namespace_prefix(op_name: str):
6
  """
7
  Prefix op by namespace.
8
  """
9
+ return f"_minimaxai_msa_blackwell_cuda_25b0067::{op_name}"
build/torch212-cxx11-cu132-x86_64-linux/api_status.py CHANGED
@@ -22,6 +22,7 @@ V1_AVAILABLE_FUNCTIONS = (
22
  "nvfp4_global_scale_from_amax",
23
  "has_native_ops",
24
  "native_topk_from_scores",
 
25
  "flash_decode_with_topk_idx",
26
  "flash_decode_with_gqa_share_sparse",
27
  "naive_flash_decode_with_topk_idx",
@@ -55,7 +56,7 @@ _OFFICIAL_API_STATUS = {
55
  "sparse_atten_nvfp4_kv_func": {
56
  "status": "available",
57
  "target": "blackwell-prefill-nvfp4",
58
- "reason": "Official NVFP4 KV prefill API is available via NVFP4 dequantization followed by the Blackwell prefill wrapper.",
59
  },
60
  "sparse_decode_atten_func": {
61
  "status": "available",
@@ -70,12 +71,12 @@ _OFFICIAL_API_STATUS = {
70
  "fp4_indexer_block_scores": {
71
  "status": "available",
72
  "target": "blackwell-fp4-indexer",
73
- "reason": "Official FP4 block-score API is available as a correctness-first PyTorch fallback.",
74
  },
75
  "build_k2q_csr": {
76
  "status": "available",
77
  "target": "v1",
78
- "reason": "Torch CSR construction fallback is available for compatibility.",
79
  },
80
  "SparseK2qCsrBuilderSm100": {
81
  "status": "available",
 
22
  "nvfp4_global_scale_from_amax",
23
  "has_native_ops",
24
  "native_topk_from_scores",
25
+ "native_nvfp4_dequant_swizzled_to_bf16",
26
  "flash_decode_with_topk_idx",
27
  "flash_decode_with_gqa_share_sparse",
28
  "naive_flash_decode_with_topk_idx",
 
56
  "sparse_atten_nvfp4_kv_func": {
57
  "status": "available",
58
  "target": "blackwell-prefill-nvfp4",
59
+ "reason": "Official NVFP4 KV prefill API is available via native swizzled NVFP4 dequantization followed by the Blackwell prefill wrapper.",
60
  },
61
  "sparse_decode_atten_func": {
62
  "status": "available",
 
71
  "fp4_indexer_block_scores": {
72
  "status": "available",
73
  "target": "blackwell-fp4-indexer",
74
+ "reason": "Official FP4 block-score API uses the native Blackwell block-score kernel in built artifacts, with a reference fallback in source-tree mode.",
75
  },
76
  "build_k2q_csr": {
77
  "status": "available",
78
  "target": "v1",
79
+ "reason": "CSR construction helper is available for the official prefill API.",
80
  },
81
  "SparseK2qCsrBuilderSm100": {
82
  "status": "available",
build/torch212-cxx11-cu132-x86_64-linux/decode/topk_sparse.py CHANGED
@@ -8,6 +8,10 @@ import triton.language as tl
8
 
9
  from .._compat import is_hip # vendored: was `from sglang.srt.utils import is_hip`
10
 
 
 
 
 
11
  from ..common.utils import robust_allocator
12
 
13
  _is_hip = is_hip()
@@ -341,6 +345,22 @@ def flash_decode_with_gqa_share_sparse(
341
  # sm scale
342
  if sm_scale is None:
343
  sm_scale = head_dim**-0.5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
344
  # Pick NUM_TOPK_CHUNKS so total grid ≈ TARGET_GRID. Same constraints as
345
  # flash_decode_with_topk_idx: must be power of 2 (Triton arange) and must
346
  # only depend on shape constants (so grid is fixed within a cuda graph).
 
8
 
9
  from .._compat import is_hip # vendored: was `from sglang.srt.utils import is_hip`
10
 
11
+ from .._native import (
12
+ native_decode_mma_supported,
13
+ native_decode_sparse_attn_mma_paged,
14
+ )
15
  from ..common.utils import robust_allocator
16
 
17
  _is_hip = is_hip()
 
345
  # sm scale
346
  if sm_scale is None:
347
  sm_scale = head_dim**-0.5
348
+ # Fast path: native tensor-core decode for the M3 MSA shape. Falls through
349
+ # to the Triton kernel for other shapes, sink, or fp8 caches.
350
+ if sink is None and not is_fp8 and native_decode_mma_supported(
351
+ q, k_cache, block_size=block_size
352
+ ):
353
+ return native_decode_sparse_attn_mma_paged(
354
+ q,
355
+ k_cache,
356
+ v_cache,
357
+ req_to_token,
358
+ seq_lens,
359
+ slot_ids,
360
+ block_size,
361
+ topk_idx,
362
+ sm_scale,
363
+ )
364
  # Pick NUM_TOPK_CHUNKS so total grid ≈ TARGET_GRID. Same constraints as
365
  # flash_decode_with_topk_idx: must be power of 2 (Triton arange) and must
366
  # only depend on shape constants (so grid is fixed within a cuda graph).
build/torch212-cxx11-cu132-x86_64-linux/interface.py CHANGED
@@ -7,6 +7,11 @@ from typing import Optional
7
 
8
  import torch
9
 
 
 
 
 
 
10
  from .decode.topk_sparse import flash_decode_with_gqa_share_sparse
11
  from .prefill.topk_sparse import flash_prefill_with_gqa_share_sparse
12
  from .quantize import Nvfp4QuantizedTensor, dequantize_nvfp4_128x4_to_bf16
@@ -488,6 +493,12 @@ def _nvfp4_dequant_kv(
488
  ) -> torch.Tensor:
489
  if packed.dtype is not torch.uint8:
490
  return packed
 
 
 
 
 
 
491
  original_shape = tuple(int(v) for v in packed.shape[:-1]) + (int(packed.shape[-1]) * 2,)
492
  rows = 1
493
  for dim in original_shape[:-1]:
@@ -572,11 +583,12 @@ def fp4_indexer_block_scores(
572
  qo_offset: Optional[torch.Tensor] = None,
573
  scale_layout: str = "preordered_mma",
574
  ) -> torch.Tensor:
575
- """Correctness-first FP4 block-score API for Blackwell.
576
 
577
  Returns the official shape `[Hq, ceil(max_seqlen_k / 128), total_q]`.
578
- This fallback is intentionally simple and is used to keep the public API
579
- callable on Blackwell while optimized CUTE block scoring remains SM100-only.
 
580
  """
581
 
582
  del qo_offset
@@ -599,6 +611,29 @@ def fp4_indexer_block_scores(
599
 
600
  q = _apply_public_fp4_scale(_unpack_e2m1_fp4(q_fp4), q_scale)
601
  k = _apply_public_fp4_scale(_unpack_e2m1_fp4(k_fp4), k_scale)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
602
  gqa = hq // hkv
603
  batch = int(cu_seqlens_q.numel()) - 1
604
  cu_q = cu_seqlens_q.to("cpu", non_blocking=False).tolist()
 
7
 
8
  import torch
9
 
10
+ from ._native import (
11
+ has_native_ops,
12
+ native_indexer_block_scores,
13
+ native_nvfp4_dequant_swizzled_to_bf16,
14
+ )
15
  from .decode.topk_sparse import flash_decode_with_gqa_share_sparse
16
  from .prefill.topk_sparse import flash_prefill_with_gqa_share_sparse
17
  from .quantize import Nvfp4QuantizedTensor, dequantize_nvfp4_128x4_to_bf16
 
493
  ) -> torch.Tensor:
494
  if packed.dtype is not torch.uint8:
495
  return packed
496
+ if has_native_ops() and packed.is_cuda:
497
+ return native_nvfp4_dequant_swizzled_to_bf16(
498
+ packed,
499
+ scale_128x4,
500
+ global_scale,
501
+ )
502
  original_shape = tuple(int(v) for v in packed.shape[:-1]) + (int(packed.shape[-1]) * 2,)
503
  rows = 1
504
  for dim in original_shape[:-1]:
 
583
  qo_offset: Optional[torch.Tensor] = None,
584
  scale_layout: str = "preordered_mma",
585
  ) -> torch.Tensor:
586
+ """FP4 block-score API for Blackwell.
587
 
588
  Returns the official shape `[Hq, ceil(max_seqlen_k / 128), total_q]`.
589
+ Built artifacts route CUDA tensors through the native Blackwell block-score
590
+ kernel. Source-tree mode uses the reference loop below so the API remains
591
+ testable before the extension is built.
592
  """
593
 
594
  del qo_offset
 
611
 
612
  q = _apply_public_fp4_scale(_unpack_e2m1_fp4(q_fp4), q_scale)
613
  k = _apply_public_fp4_scale(_unpack_e2m1_fp4(k_fp4), k_scale)
614
+
615
+ # Native block-max QK kernel for the cubic scoring loop when available.
616
+ # Same dequant numerics as the reference (bf16 compute); falls back to the
617
+ # Python reference below in source-tree mode.
618
+ if has_native_ops() and q_fp4.is_cuda:
619
+ batch = int(cu_seqlens_q.numel()) - 1
620
+ q_lens = (cu_seqlens_q[1:] - cu_seqlens_q[:-1]).to(torch.int64)
621
+ batch_of_q = torch.repeat_interleave(
622
+ torch.arange(batch, device=q_fp4.device, dtype=torch.int32),
623
+ q_lens,
624
+ )
625
+ return native_indexer_block_scores(
626
+ q.to(torch.bfloat16),
627
+ k.to(torch.bfloat16),
628
+ batch_of_q,
629
+ cu_seqlens_q.to(torch.int32),
630
+ cu_seqlens_k.to(torch.int32),
631
+ cu_page_offsets.to(torch.int32),
632
+ kv_indices.to(torch.int32),
633
+ max_blocks=max_blocks,
634
+ causal=causal,
635
+ )
636
+
637
  gqa = hq // hkv
638
  batch = int(cu_seqlens_q.numel()) - 1
639
  cu_q = cu_seqlens_q.to("cpu", non_blocking=False).tolist()
build/torch212-cxx11-cu132-x86_64-linux/metadata.json CHANGED
@@ -1,6 +1,6 @@
1
  {
2
  "name": "minimaxai-msa-blackwell",
3
- "id": "_minimaxai_msa_blackwell_cuda_58018d1",
4
  "version": 1,
5
  "license": "Apache-2.0",
6
  "python-depends": [],
@@ -14,18 +14,18 @@
14
  "digest": {
15
  "algorithm": "sha256",
16
  "files": {
17
- "__init__.py": "bH4lC+HdMx2DgfiEWfvxhd7GvQBOt02ftSPAzKo1rE0=",
18
  "_compat.py": "5Wy4a96HVMD8omRNsGg8rQJ+0qCCeXiDANk0CuyyP0I=",
19
- "_minimaxai_msa_blackwell_cuda_58018d1.abi3.so": "PC8GpBOVMeHf/O3hlzsMBgWvo7YvmBiodQTteUrch00=",
20
- "_native.py": "mIDvfkcQVd3H9plDsodJelrIFD2XHiEQgk4uqiiRLLE=",
21
- "_ops.py": "kuQPE8cc2FNEl3lIMfjaj074xh5YntsWFa8cYC5CLIQ=",
22
- "api_status.py": "VhS7aJhSznFwcgIQAnzXQTTuLJ2WgtysWrhX7RTSXaM=",
23
  "common/__init__.py": "bG7Ffen4LvQtgnYPFEpFccsWs81t4zqqeqn9ZeirH6E=",
24
  "common/utils.py": "qtwh+wZoySlsWWALvWGVsmcIHKkdZUwePxUZ42tfWxc=",
25
  "decode/__init__.py": "bG7Ffen4LvQtgnYPFEpFccsWs81t4zqqeqn9ZeirH6E=",
26
  "decode/flash_with_topk_idx.py": "Pk70+HJ60IKuy4KJC6hPdMtD2BjwPfSMabFiIBODWiQ=",
27
- "decode/topk_sparse.py": "PLwQnOyiZT44pCXcZXzXdlZSixfBeanTZsfbpMOjlpQ=",
28
- "interface.py": "TKlKdIqTtzfmieaY5ci3GwhD1QZXqUAZcqfcfPmyeuM=",
29
  "minimaxai_msa_blackwell/__init__.py": "DFYPlrhXwYjEqCl/8n0SmWGZV8NFml5DPhMjKfv98GY=",
30
  "naive/__init__.py": "bG7Ffen4LvQtgnYPFEpFccsWs81t4zqqeqn9ZeirH6E=",
31
  "naive/flash_with_topk_idx.py": "K7WQsRdO9+H2sz7pZ6axnJwE1OmnF0egdKtftHuChig=",
 
1
  {
2
  "name": "minimaxai-msa-blackwell",
3
+ "id": "_minimaxai_msa_blackwell_cuda_25b0067",
4
  "version": 1,
5
  "license": "Apache-2.0",
6
  "python-depends": [],
 
14
  "digest": {
15
  "algorithm": "sha256",
16
  "files": {
17
+ "__init__.py": "oPB7xQhjHd9+aLVJkEmJkZOXOwMEarmCdj3SBbhH2bM=",
18
  "_compat.py": "5Wy4a96HVMD8omRNsGg8rQJ+0qCCeXiDANk0CuyyP0I=",
19
+ "_minimaxai_msa_blackwell_cuda_25b0067.abi3.so": "TrAcGpbD5kBHSzpS8tONpL4q8CkMS5RcUPkOhn2ekH8=",
20
+ "_native.py": "wTh66DiIKxsJ5m8fkAXKSCBYD3CVFVx4PFxceQiwvPY=",
21
+ "_ops.py": "ikU3Lg+kgswKktYjNSq5f4DmgyTR8dnxV8lH3rmOWvk=",
22
+ "api_status.py": "7oZzIkb4fuwkAz3r4Q1slHbOfaP3jwVB647Ok223ATk=",
23
  "common/__init__.py": "bG7Ffen4LvQtgnYPFEpFccsWs81t4zqqeqn9ZeirH6E=",
24
  "common/utils.py": "qtwh+wZoySlsWWALvWGVsmcIHKkdZUwePxUZ42tfWxc=",
25
  "decode/__init__.py": "bG7Ffen4LvQtgnYPFEpFccsWs81t4zqqeqn9ZeirH6E=",
26
  "decode/flash_with_topk_idx.py": "Pk70+HJ60IKuy4KJC6hPdMtD2BjwPfSMabFiIBODWiQ=",
27
+ "decode/topk_sparse.py": "uINcV9SP5sAf9jYPsPvyQ9lon8sajZ8Qn/yJ+2LA8NU=",
28
+ "interface.py": "jfhBHGyunFF+OdFycJYyptNNIAngKrXY67buTXAN66M=",
29
  "minimaxai_msa_blackwell/__init__.py": "DFYPlrhXwYjEqCl/8n0SmWGZV8NFml5DPhMjKfv98GY=",
30
  "naive/__init__.py": "bG7Ffen4LvQtgnYPFEpFccsWs81t4zqqeqn9ZeirH6E=",
31
  "naive/flash_with_topk_idx.py": "K7WQsRdO9+H2sz7pZ6axnJwE1OmnF0egdKtftHuChig=",