IMPORTANT: To view this page as Markdown, append `.md` to the URL (e.g. /get-started.md). For the complete documentation index, see llms.txt.
Skip to main content
For the complete documentation index, see llms.txt. Markdown versions of all pages are available by appending .md to any URL (e.g. /get-started.md).

Mojo module

mla_decode_sparse_qkv_fp8

Native FP8 sparse MLA decode kernel for SM100 (B200) -- unified gather.

Combines the OLD kernel's efficient contiguous KV gather (mla_decode_sparse_kv_fp8.mojo: INT64/SWIZZLE_NONE gather4, 16 gather4 instructions/tile at 2304 B/txn) with the native-FP8 compute core (tcgen05.mma.kind::f8f6f4, no dtype conversion). The two are decoupled by a re-swizzle staging warpgroup: KV gathers contiguously into a LINEAR FP8 SMEM buffer, then WG3 (repurposing the old kernel's convert-WG role, minus the dtype cast) permutes it FP8->FP8 into the SW64 byte layout the FP8 tcgen05 operand descriptor expects, into a SECOND SMEM buffer. QK^T and P*V still run natively in FP8 reading the SW64 buffer -- only the KV front-end changed; the compute core is byte-for-byte what MLA_SM100_Decode_Sparse_QKV_FP8 already validated.

Root cause this fixes (see .claude/agent-memory/mojo-kernel-engineer/ mla-decode-sm100-native-fp8-warpgroup-count.md): the native kernel's own K/Q operand layout mandates SWIZZLE_64B for tcgen05.mma.kind::f8f6f4, and a gather4 TMA under SW64 has box_width=64B, so a 576-byte row needs ceildiv(576,64)=9 column-groups x 16 four-row-chunks = 144 gather4 instructions/tile -- 9x the old kernel's 16 instructions/tile (SWIZZLE_NONE, single 576-byte box) for identical bytes. That per-tile hardware-instruction inflation, not pipeline depth or warp count, is what NCU's PC-sampled stall attribution pinned to the KV-gather producer path.

4 warpgroups (back from 3 -- the re-swizzle stage, like the old kernel's convert stage, needs its own resident warps; it is a pure FP8->FP8 layout permute, not a dtype conversion): WG0 (warps 0-3): Softmax (native_fp8=True) WG1 (warps 4-7): Correction WG2 (warps 8-11): Load (warp 8, INT64/SWIZZLE_NONE gather4) / MMA QK (warp 9) / MMA PV (warp 10) / idx_producer + Store (warp 11) -- unchanged roles from the 3-WG kernel. WG3 (warps 12-15): Re-swizzle: read the contiguously-gathered FP8 linearly, write FP8 (unchanged bytes, no cast) into the SW64 layout via a manual swizzled SMEM store (all 128 threads cooperate, mirroring convertFP8ToBF16's thread mapping but without the dtype cast or the BF16-overlay aliasing -- this uses a separate, non-overlaid destination buffer).

SMEM layout (FP8, N = num_kv_stages; expect N ~= 2 at the GLM-5.2 shape, since the linear + SW64 buffer pair costs the same total bytes/stage as the old kernel's own KV region): Q FP8: 64 x 576 x 1 = 36864 bytes (SWIZZLE_64B, persistent) KV linear-in: N x 64 x 576 x 1 bytes (SWIZZLE_NONE, gather dest) KV SW64-out: N x 64 x 576 x 1 bytes (SWIZZLE_64B, MMA operand) P stages: N x 64 x 64 x 1 bytes (SWIZZLE_64B, separate region) max/li: 128 x 4 x 3 = 1536 bytes barriers: (8N+11) fixed + output + idx_bars (2N) barriers ptr_tmem_addr: 4 bytes idx_smem: N x 64 x 4 bytes

Structs