The kq.* namespace has two tiers. The core codec ops - quantize, dequantize,
quantized_matmul, gather_qmm - are the general K-quant surface, documented in the
README and integration.md; everything a downstream project needs to
store and multiply K-quant weights is there. On top of them sits a set of fused and
architecture-specific kernels: decode/prefill fusions that collapse several ops into one dispatch,
and a cluster of sparse-attention kernels for the DeepSeek/GLM lightning-indexer attention. This page
catalogs that second tier.
Kernels are named for what they compute, not the model that first needed them. A fusion motivated by
one architecture (a norm layout, an activation, an attention shape) is written as a general kernel and
reused wherever the shape recurs; the entries below note the motivating regime. The one exception is
the dsa_* group, which implements a specific attention mechanism (DeepSeek-V4-Flash / GLM) end to
end and is scoped to it.
Each op's Python docstring carries the full argument contract, shape constraints, and dtype rules
(help(kq.<name>)); the one-liners here are a map, not a spec.
General K-quant matmul paths beyond the core quantized_matmul / gather_qmm, for the shapes those
two leave on the table (single-row decode, expert-sorted prefill, fused bias/mix).
quantized_matmul_qmv_bias-x @ dequant(w) + biaswith the bias add fused into the matvec. Decode-only (single row);q8_0for now, other codecs fall through to matmul-then-add.gather_qmv_kq- gathered matvec for an expert stack, one activation row per expert slot: the MoE down projection at decode. Takes an optional per-expert bias for the fp4 wire codecs (mxfp4/nvfp4, gpt-oss experts).gather_qmv_mix_kq/gather_qmv_mix_ns_kq- the down projection with the routing mix folded in - every slot accumulated in f32 weighted by its score, and (in themixvariant) a shared expert as the last slot - replacing a gather plus a weighted sum plus the shared-expert add. Shaped for DeepSeek-V3/V4-style shared-expert MoE.gather_qmv_bias- gathered matvec with a fused expert bias on MLX's packed mxfp4 layout (the counterpart to the K-quant gathers above for that codec).gather_qmm_seg+expert_tile_map- expert-sorted MoE prefill as one GEMM per expert segment instead of per-row gathers.expert_tile_mapbuilds the 64-row tile map on the GPU from the sorted routing indices (no host sync);gather_qmm_segwalks it. Gated byKQ_SWITCH_GEMM_MIN_ROWS(see README).
On NAX GPUs, quantized_matmul transpose (decode-orientation) shapes route by row count M: the
mat-vec paths up to a per-codec crossover (M 6-9), a BM=32 double-buffered NAX tile through M 32,
the BM=64 tile above that with a double-buffered _db variant on the M 33-64 band at large N, and
a BM=128 tile from M 193 when ceil(M/64) is even. Every floor is a measured per-codec policy
(kq_smallbm_policy in src/kquant_matmul.cpp).
Tuning levers (defaults are right for normal use):
KQ_NAX_SMALL_BM- small-M routing.0restores the old routing (mat-vec paths below M 13 and no BM=32 tile),2forces BM=32 for policy-excluded codecs, unset or1follows the per-codec policy.KQ_NAX_BM128- BM=128 band.0off,1forces the floor to M 193 for every codec,2drops the floor entirely (any even ceil(M/64), probing the M65-128 wash band), unset follows the per-codec entry floors (193/449/961 tiers, measured on M5 Max bybenchmarks/bench_qmm_bm128_ab.py; re-run it before trusting them on new silicon).KQ_NAX_DB64- double-buffered M 33-64 band.0off,1drops the N floor, unset follows the per-codec N floors. Only the five policy-enabled codecs (q6_k, q8_0, q4_1, q5_1, q5_0) carry_dbinstantiations, so1is bounded by availability; probing another codec needs its instantiation restored and a metallib rebuild.KQ_FORCE_QMM_MIN_M- probe lever: routes transpose shapes with M at or above the value straight to the NAX qmm, bypassing the mat-vec route claims, for crossover measurement below M 13. Unset (off) by default.KQ_NAX_SWIZZLE-1enables the row-tile traversal swizzle (folds row-tiles into grid.x for SLC reuse of the weight band). Falsified on M5 Max, where the M>64 band is per-threadgroup-bound rather than DRAM-bound; kept as a probe for future silicon. Default off.KQ_MV_EXT_NR-2selects the two-rows-per-threadmv_extvariant (q6_k, M 5-12), which halves activation cache traffic but measured no faster than the shipped kernels. Kept as a probe for future silicon. Default1(shipped behavior).KQ_QMM_SPLITK_NAX- split-K on the NAX BM=32 tile;0disables the route, a value at or above1forces it and sets the target slice count. Unset takes the per-codec entry M inkq_splitk_nax_min_m, measured on M5 Max. Every codec with NAX kernels, M <= 32; read live per call, so both arms can share one process.KQ_QMM_SPLITK- the same lever for the plain small-M qmm, used when NAX is absent or disabled. Entry points come from a per-device table. K-quants, legacy quants and the IQ codecs, M <= 32.KQ_MV_EXT_SB/KQ_MV_EXT_NX/KQ_MV_EXT_HD-mv_extactivation-traffic experiments: shuffle-broadcast (1), wide nxpsg (16/32), half-precision chunk dots (1). q6_k M 4-12 only.HDmeasured +4-5% at M 8; the rest flat to negative on M5 Max. Kept as probes. Default off.
Fused gate/up expert matvecs with the GLU epilogue applied in the same dispatch, so each activation load feeds both projections.
moe_glu_gather_kq- fused MoE GLU gather for K-quant expert stacks:act(gate) * upin one decode-shaped dispatch. Bias-free for most codecs; the fp4 wire codecs (mxfp4/nvfp4) also take per-expert gate/up biases with theswiglu_clampactivation (gpt-oss experts).moe_glu_gather_shexp_kq- the same with the block's shared expert folded in as an extra slot.moe_glu_gather- the MLX packed-mxfp4 counterpart.moe_router_topk- the router in one dispatch: f32 scoring (softmax, orsqrtsoftplusfor DeepSeek-V4), top-k with a min-index tie-break, optional bias-ranked selection, optional renormalization, and an optional per-expert scale.
The GLU activation is selected per model: plain SwiGLU/GELU, the clamped silu_limit
(silu(min(g, limit)) * clip(u, -limit, limit)) that DeepSeek-V4's LimitedSwiGLU needs, or
swiglu_clamp (gpt-oss clamped SwiGLU: biases added, sigmoid slope alpha, and a (u + 1) linear
term; requires the expert biases and is instantiated for mxfp4/nvfp4 only).
Scaled-dot-product variants for shapes stock MLX's fused allowlist excludes, plus the sparse mechanism below.
sdpa_vector- vector SDPA for large head dims (256, 512) - e.g. DeepSeek MLA - which MLX's fused vector path does not cover.sdpa_decode_gqa- decode/verify GQA tuned for long KV caches: the key axis splits into coarse chunks streamed through threadgroup-staged K/V tiles shared by the GQA group, so device memory reads the KV once per chunk. Optionalstarts(int32[B]) restricts row b to keys[starts[b], kL)for left-padded batches, skipping fully padded-out chunks. Optional affine q8 K/V operands (scales and biases, bits 8, group 64) dequantize on the tile stage.return_lse=Trueadds per-row log-sum-exp.sdpa_decode_gqa_cascade- shared-prefix batched decode: every row attends one common prefix plus its own private suffix. The prefix is walked once for all rows on the matrix-unit tile, private suffixes run per row, one merge pass folds both; 1.6-4.2x over per-row calls at 14k-32k prefixes. qL 1-8 (verify width, end-aligned causal); takesstartsand the q8 operands on either region.sdpa_decode_gqa_paged- sparse page-gather decode: attends only the K/V pages listed per (batch, kv-head), so cost tracks the selected keys rather than the cache length. The page unit is the staged tile height (32 rows at head dim 64/128, 16 at 256, 8 at 512); takesstarts.sdpa_fa_verify- speculative-verify attention on the matrix units for a GQA-folded query tile. Head dims 64 through 512;return_lseas above.
The DeepSeek-V4-Flash / GLM lightning-indexer attention: a lightweight indexer scores every pooled
(compressed) KV row against the query, a top-k select picks the rows to attend to, and sparse
attention runs the local sliding window plus those gathered rows in one pass. Ported, with
modifications, from omlx's glm_moe_dsa custom kernels (see the
acknowledgement). All six accept qL >= 1, so decode, MTP verify
(qL = 2), and prefill share them.
dsa_indexer_scores- indexer relevance scores over a prefill query tile (steel GEMM):out[b,0,m,n] = sum_h relu(q[b,h,m] . k[b,0,n]) * w[h,m].dsa_indexer_score_decode- the same for decode-width (qL <= 4) queries without materializing the per-head[H, P]scores.dsa_topk_indices- per-row top-k arg-select over the 16-bit scores (2-pass radix select). The selected index set matches a full sort; the order within a row does not.dsa_sparse_attention- the sliding local window plus the indexer-selected gathered rows plus per-head attention sinks, in one flash-softmax dispatch (f32 accumulation).dsa_kv_qat/dsa_indexer_qat- the fused quantization-aware round-trips DeepSeek-V4 does on its main-attention KV (per-64-block FP8-E4M3FN) and indexer activations (128-wide Hadamard then per-32-block FP4-E2M1), each bit-identical to the equivalent MLX graph.dsa_kv_qat(..., f16_round=False)drops the trailing fp16 round for the compressor emit path, whose pooled rows are quantized but never stored in the f16 KV cache.
Tuning levers (defaults are right for normal use):
KQ_DSA_BK- key-tile width fordsa_sparse_attention,128or256. Default:128for top-k lists up to 128 entries,256for denser ones.KQ_DSA_SPLIT-1/0forces the split-KV decode route on/off. Default: auto, on for the small-grid decode/verify shapes where a single threadgroup would leave the GPU idle.
add_rmsnorm- fused post-norm residual(residual + rms_norm(h, weight)) * scale, all in f32.rmsnorm2_add- two independent RMS norms plus an add in one dispatch.rmsnorm_multi3- three RMS norms of one tensor sharing its mean-square reduction (the QK-norm plus a third head-norm shape).
codecs- the list of supported codec names.metallib_loads/metallib_dir- whether the bundled metallib opened on the device, and where it lives.nax_available/nax_gather_enabled- whether the GPU exposes NAX tensor units, and whether the sorted-gather NAX GEMM leaf is reachable for a codec.cpu_neon_available- whether the arm64 NEON int8 GEMV path is compiled in.
The zero-copy arena buffers and shared-event stream primitives (arena_alloc, event_signal /
event_wait, shared_event_*, zero_copy_view_count, verify_zero_copy_views, load_gguf) support
a producer/consumer decode loop and are a separate subsystem; see
docs/feeder/DESIGN.md.
route_shed- routed-expert slot remap plus residency shed for streamed MoE decode: expert ids map to arena slots through a resident-slot table, non-resident experts are shed with their gate mass renormalized onto the kept ones, and the misses come back (ids and scores) for between-token prestaging. No host sync.