spark_model/layers/qwen3_ssm/
mod.rs

1// SPDX-License-Identifier: AGPL-3.0-only
2
3//! Qwen3-Next SSM (Gated Delta Net) layer implementing TransformerLayer.
4//!
5//! Corrected pipeline matching the HuggingFace reference implementation:
6//!   1. QKVZ projection (interleaved output)
7//!   2. Deinterleave QKVZ → sequential [Q | K | V | Z]
8//!   3. BA projection (interleaved output)
9//!   4. Compute GDN gates: gate = exp(-A * softplus(alpha + dt_bias)), beta = sigmoid(b)
10//!   5. Conv1d update on [Q | K | V] concatenated (d_inner=8192)
11//!   6. Split conv output → Q', K', V'
12//!   7. GDN decode (Q', K', V', gate, beta) — kernel handles GQA internally
13//!   8. Gated RMS norm (GDN output, Z gate)
14//!   9. Output projection [value_dim → hidden_size]
15//!  10. MoE FFN
16
17use anyhow::Result;
18use spark_runtime::gpu::{DevicePtr, GpuBackend, KernelHandle};
19use spark_runtime::kv_cache::PagedKvCache;
20
21use crate::layer::{ForwardContext, GdnPrefillBuffers, LayerState, SsmLayerState};
22use crate::layers::FfnComponent;
23use crate::layers::ops;
24use crate::layers::w4a16_gemv_tiers::W4a16BatchmTiers;
25use crate::weight_map::{DenseWeight, Fp8Weight, QuantizedWeight, SsmWeights};
26
27/// Qwen3-Next SSM/GDN layer (36 of 48 layers).
28///
29/// Supports two QKVZ projection modes:
30/// - **Interleaved** (80B): `w4a16_gemv_qkvz` or GEMV + `deinterleave_qkvz`
31/// - **Sequential** (3.5-35B): plain GEMV → `[Q|K|V|Z]` already in order
32#[allow(dead_code)]
33pub struct Qwen3SsmLayer {
34    /// mHC weights when the model carries a `hc_mult`-wide highway; see `hc`.
35    pub(crate) hc: Option<crate::layers::qwen3_attention::HcWeights>,
36    /// PLE n-gram injection. `Some` on exactly ONE model layer (layer 1 on
37    /// this checkpoint); it runs at the TOP of the mHC forward, before this
38    /// layer's own hyper-connection, matching the reference's
39    /// `hidden_states = hidden_states + self.ple(...)`.
40    pub(crate) ple: Option<crate::layers::ple::PleLayer>,
41    /// mHC kernel handles. Resolved only when `config.hc_mult > 0`, so a
42    /// plain GDN model issues no lookup and leaves no row in the startup
43    /// audit. See `qwen3_attention::init_arch_gates`.
44    pub(super) hc_pre_k: KernelHandle,
45    pub(super) hc_post_k: KernelHandle,
46    /// Seeds the highway on MODEL layer 0 — which on a 3:1 GDN:attention
47    /// interleave is a GDN layer, so this side owns the expand that the
48    /// attention side used to do.
49    pub(super) hc_expand_k: KernelHandle,
50    input_norm: DenseWeight,
51    ssm: SsmWeights,
52    post_attn_norm: DenseWeight,
53    ffn: FfnComponent,
54    /// GDN `out_proj` LoRA delta for this layer, with the kernels to apply it.
55    /// `None` on every base serve, which keeps the base path byte-identical.
56    lora_out_proj: Option<(
57        crate::layers::ops::lora_delta::LoraPair,
58        crate::layers::ops::lora_delta::LoraKernels,
59    )>,
60    // NVFP4-quantized QKVZ weight (quarters bandwidth vs BF16)
61    qkvz_nvfp4: Option<QuantizedWeight>,
62    // Transposed [K/2, N] copy for coalesced w4a16_gemm reads (prefill)
63    qkvz_nvfp4_t: Option<QuantizedWeight>,
64    // Transposed out_proj for prefill GEMM
65    out_proj_nvfp4_t: Option<QuantizedWeight>,
66    // BF16 out_proj for models where SSM weights are not pre-quantized
67    pub out_proj_dense: Option<DenseWeight>,
68    // FP8 E4M3 checkpoint weights for native FP8 serving (w8a16_gemv LUT kernel)
69    qkvz_fp8w: Option<Fp8Weight>,
70    out_proj_fp8w: Option<Fp8Weight>,
71    /// PER-ROW FP8 (`Fp8PerRow`) for PREFILL ONLY, from mixed-precision
72    /// compressed-tensors checkpoints (`ATLAS_FP8_ROWWISE=1`).
73    ///
74    /// Separate fields rather than reusing `qkvz_fp8w`/`out_proj_fp8w`, and
75    /// that separation is the safety property: those two are read by
76    /// `w8a16_gemv` in `ssm_forward.rs` and `trait_decode_batched.rs`, which
77    /// index the scale as a `[N/128, K/128]` block grid. A per-row buffer is
78    /// SMALLER than that index space, so it would not fault — it would return
79    /// plausible garbage. Only the row-wise cuBLASLt prefill arm reads these;
80    /// decode keeps the NVFP4 copy.
81    qkvz_fp8w_rowwise: Option<Fp8Weight>,
82    out_proj_fp8w_rowwise: Option<Fp8Weight>,
83    /// Tier-1c keep-packed ternary Q2_0 fused in_proj_qkvz (`ATLAS_GGUF_NATIVE_Q2`).
84    /// [Q|K|V|Z] rows byte-concatenated from packed `in_proj_qkv` (V-region
85    /// row-permuted) + `in_proj_z` (row-permuted) at load, so the 2-bit weight is
86    /// HF-correct. `out_proj` stays NVFP4 (column reorder not packed-permutable here).
87    qkvz_q2: Option<crate::weight_map::PackedQ2Weight>,
88    /// Q2_0 kernels for the packed qkvz: `gemv` = `q2_0_gemv_vec` decode; `dequant`
89    /// = load-time packed→BF16 for the transient-dequant prefill fallback;
90    /// `mmq_{nc,wc}` = Tier-2 keep-packed tensor-core MMQ prefill (`KernelHandle(0)`
91    /// → fallback); `q4k_quant_act` = shared q8_1 activation quantizer.
92    q2_0_gemv_k: KernelHandle,
93    dequant_q2_0_gn_k: KernelHandle,
94    q2_0_mmq_nc_k: KernelHandle,
95    q2_0_mmq_wc_k: KernelHandle,
96    q4k_quant_act_k: KernelHandle,
97    /// When true, QKVZ projection output is already sequential [Q|K|V|Z].
98    /// Skips the deinterleave kernel (used by Qwen3.5 where QKV+Z are
99    /// concatenated at load time rather than interleaved per-group).
100    sequential_qkvz: bool,
101    /// Streaming multiprocessor count, read from the driver ONCE at
102    /// construction (`GpuBackend::sm_count`). `ms_proj_gemm` needs to know how
103    /// wide the machine is to decide whether halving the CTA rows is a saving
104    /// or an under-fill; a compiled-in constant would be wrong on every part
105    /// that is not the one it was tuned on.
106    sm_count: u32,
107    // Kernels — decode path (single-token GEMV)
108    rms_norm_residual_k: KernelHandle,
109    gated_rms_norm_k: KernelHandle,
110    gated_rms_norm_f32_k: KernelHandle,
111    dense_gemv_k: KernelHandle,
112    /// K=2 verify: batched (M=2) BF16 GDN in_proj_qkvz — one weight pass for
113    /// both verify tokens instead of two M=1 `dense_gemv` reads.
114    dense_gemv_batch2_k: KernelHandle,
115    w4a16_gemv_k: KernelHandle,
116    /// Single-warp `w4a16_gemv_sw`. `KernelHandle(0)` on miss → base GEMV.
117    w4a16_gemv_sw_k: KernelHandle,
118    w8a16_gemv_k: KernelHandle,
119    w4a16_gemv_qkvz_k: KernelHandle,
120    deinterleave_k: KernelHandle,
121    conv1d_k: KernelHandle,
122    conv1d_l2norm_k: KernelHandle,
123    conv1d_l2norm_f32_k: KernelHandle,
124    /// `conv1d_l2norm_f32_k` with explicit input/output row strides, letting
125    /// the concurrent-decode path batch all N sequences into one launch.
126    /// `KernelHandle(0)` on kernel sets that predate it — the multi-seq path
127    /// then falls back to the per-sequence conv loop.
128    conv1d_l2norm_f32_strided_k: KernelHandle,
129    gdn_k: KernelHandle,
130    gdn_f32_k: KernelHandle,
131    gdn_f32_norm_k: KernelHandle,
132    gdn_f32_conv_norm_k: KernelHandle,
133    gdn_f32_strided_k: KernelHandle,
134    gdn_f32_strided_norm_k: KernelHandle,
135    /// Half-width register retention (k_dim==v_dim==128): retains the first 64 H
136    /// columns so the update re-reads only the rest (2R+1W -> 1.5R+1W).
137    gdn_f32_strided_norm_half_k: KernelHandle,
138    /// SRAM-staged full retention (k_dim==v_dim==128): the columns the register
139    /// file cannot hold are staged in shared memory on the first pass instead of
140    /// being re-read from H (1.5R+1W -> 1.0R+1W). Bit-identical to
141    /// `gdn_f32_strided_norm_half_k` but measured throughput-NEUTRAL, so it is
142    /// OPT-IN via `gdn_smem_stage_enabled()` (`ATLAS_GDN_SMEM_STAGE`).
143    gdn_f32_strided_norm_smem_k: KernelHandle,
144    /// FP16 h-state twin of `gdn_f32_strided_norm_half_k` (`ATLAS_SSM_H_FP16`).
145    /// Additive: it never replaces the FP32 kernel, it is selected instead of
146    /// it when the sequence's `SsmLayerState::h_is_f16` is set.
147    gdn_f16_strided_norm_half_k: KernelHandle,
148    /// FP16 h-state twin of `gdn_f32_norm_k` — the per-sequence arm the batched
149    /// dispatch falls back to at n == 1 and whenever pool slots fragment out of
150    /// slice order. Without it the FP16 pool would be read as FP32 on exactly
151    /// those steps.
152    gdn_f16_norm_k: KernelHandle,
153    ba_gates_k: KernelHandle,
154    residual_add_k: KernelHandle,
155    l2_norm_k: KernelHandle,
156    residual_add_rms_norm_k: KernelHandle,
157    /// Dual-output (bf16 + f32) MoE-input norm for ATLAS_FP32_ROUTING. Zero if absent.
158    residual_add_rms_norm_gatef32_k: KernelHandle,
159    gated_rms_norm_prefill_k: KernelHandle,
160    // Kernels — batched verification path (multi-token GEMM)
161    w4a16_gemm_k: KernelHandle,
162    w4a16_gemm_t_k: KernelHandle, // Transposed B layout [K/2, N] — K_STEP_T=32
163    w4a16_gemm_t_k64_k: KernelHandle, // K64 variant: K_STEP_T=64, halves outer loop
164    /// K64 with a 64-wide N tile: same math, 2x the CTAs. `KernelHandle(0)`
165    /// when absent or killed by `ATLAS_NO_K64_N64`.
166    w4a16_gemm_t_k64_n64_k: KernelHandle,
167    w4a16_gemm_t_m128_k: KernelHandle, // M128 variant: 2 M-chunks per CTA, halves B re-reads
168    w4a16_gemm_t_m128_v2_k: KernelHandle, // M128 8-warp pipelined (fast at small M; the FFN's kernel)
169    w4a16_gemv_batch2_k: KernelHandle,
170    dense_gemm_k: KernelHandle,
171    dense_gemm_pipelined_k: KernelHandle,
172    gdn_prefill_k: KernelHandle,
173    gdn_prefill_split_k: KernelHandle,
174    gdn_prefill_split4_k: KernelHandle,
175    gdn_prefill_persistent_k: KernelHandle,
176    gdn_prefill_persistent_wy4_k: KernelHandle,
177    /// Register-resident token-sequential warm-replay recurrence (H in regs, >=2
178    /// CTA/SM, no barriers). Token-equal to WY4 (cosine 1.0), ~2.9x faster.
179    /// DEFAULT-ON since 2026-07-25 (serve-validated: full MLPerf-edge e2e, wall
180    /// −7.25%, BFCL identical); kill switch `ATLAS_NO_GDN_REGRESIDENT=1`.
181    gdn_prefill_regresident_k: KernelHandle,
182    /// FLA multi-kernel chunked prefill (baked default for 128-dim GDN): recompute_wu →
183    /// chunk_delta_h_ksplit (k-split occupancy) → chunk_fwd_o. 1.75x vs wy4 @16k,
184    /// token-equal (cos=1.0 vs scalar). Three handles; all must be non-null.
185    gdn_prefill_fla_recompute_wu_k: KernelHandle,
186    gdn_prefill_fla_chunk_delta_h_k: KernelHandle,
187    /// Tensor-core / DV-block-split variant of the FLA chunk_delta_h spine
188    /// (`gated_delta_rule_chunk_delta_h_tc_vblock`). Loaded by default but not
189    /// yet wired into the prefill dispatch — the cos-gate validates it in
190    /// isolation first. `allow(dead_code)` until the launch site reads it.
191    #[allow(dead_code)]
192    gdn_prefill_fla_chunk_delta_h_tc_vblock_k: KernelHandle,
193    /// Warp-dense fused GDN state spine (`gated_delta_rule_chunk_delta_h_vtile`).
194    /// 512 threads = 16 warps/CTA against ksplit's 8, with the SAME grid (one CTA
195    /// per head) so `W`/`K` global loads are not duplicated — an ncu profile put
196    /// ksplit at L2 60.6% / L1 56.2%, i.e. memory-pipeline bound, which is why the
197    /// DV-split variants (which duplicate those loads) lost. Fusing the two
198    /// per-chunk passes deletes ksplit's `duc[CHUNK]` register array, and that is
199    /// what pays for the extra warps: 118 registers, no spills. Measured 2.15-2.18x
200    /// vs ksplit at 2048/8192/16384 with cos=1.0000 (`gdn_chunk_shapetest`).
201    gdn_prefill_fla_chunk_delta_h_fused_k: KernelHandle,
202    /// TMA (`cp.async.bulk.tensor`) build of the state spine, behind
203    /// `ATLAS_GDN_TMA=1`. `try_kernel` => 0 on images that lack it, and the
204    /// launcher additionally refuses varlen and any head narrower than the
205    /// compile-time tile — the descriptors encode that tile, and a mismatched
206    /// shape loads the wrong columns without erroring.
207    gdn_prefill_fla_chunk_delta_h_tma_k: KernelHandle,
208    gdn_prefill_fla_chunk_fwd_o_k: KernelHandle,
209    /// WY32 chunked prefill: processes 32 tokens per WY iteration with H in
210    /// shared memory. ~30x faster than per-token for 14k+ sequences.
211    gdn_prefill_wy32_k: KernelHandle,
212    // ── Q12 Phase 2b: same-chunk-len batched GDN prefill kernels ──
213    // Each takes `float* const* h_state_ptrs` plus stacked QKV/gate/beta/output.
214    // Used by `Qwen3SsmLayer::prefill_batched` when N≥2 streams have matching
215    // chunk_len. Null on targets that don't carry the corresponding kernel.
216    gdn_prefill_wy32_batched_k: KernelHandle,
217    gdn_prefill_persistent_batched_k: KernelHandle,
218    gdn_prefill_persistent_wy4_batched_k: KernelHandle,
219    gdn_prefill_split4_batched_k: KernelHandle,
220    compute_gdn_gates_k: KernelHandle,
221    ba_gates_prefill_k: KernelHandle,
222    // Kernels — prefill (multi-token sequential)
223    conv1d_prefill_k: KernelHandle,
224    /// Token-parallel prefill conv1d (`causal_conv1d_update_prefill_tp`).
225    conv1d_prefill_tp_k: KernelHandle,
226    // Kernels — fused chunk2 path (2-token verification)
227    gdn_chunk2_k: KernelHandle,
228    conv1d_chunk2_k: KernelHandle,
229    // Kernels — fused chunk3 path (3-token verification)
230    gdn_chunk3_k: KernelHandle,
231    w4a16_gemv_batch3_k: KernelHandle,
232    // NVFP4 batched decode GEMV (multi-seq concurrency + chain verify):
233    // the narrow batch{4,5,6,7,8} family plus batch16 (M<=16) — siblings of
234    // w8a16_gemv_batch4/16 for the FP4 QKVZ + out_proj, so FP4 decode
235    // amortizes the weight read at C=4..16 like FP8.
236    w4a16_batchm: W4a16BatchmTiers,
237    w4a16_gemv_batch16_k: KernelHandle,
238    // Kernels — WY-chunkwise path (2-pass verification)
239    gdn_wy2_k: KernelHandle,
240    /// Register-resident wy2 twin (K=2 verify, the C=32 hot shape): Pass 2
241    /// is served from the Pass 1 H read retained in registers
242    /// (`__launch_bounds__(128,1)`, 128 floats/thread — the regresident
243    /// prefill pattern), cutting the kernel's HBM state traffic from 2R+2W
244    /// to 1R+2W. Byte-identical accumulation order to `gdn_wy2_k`
245    /// (bitwise-asserted by gdn_wy_verify_microtest's parity leg).
246    /// KernelHandle(0) when not linked (e.g. strix module sets). Selection +
247    /// kd/vd==128 guard + width gate (n >= wy_resident_min_width(); the
248    /// 1-block/SM kernel loses at narrow launches) live in `wy2_kernel`
249    /// (trait_decode_batched_conv_gdn);
250    /// kill switch ATLAS_NO_GDN_WY2_RESIDENT (PRESENCE — `=0` is NOT off).
251    gdn_wy2_resident_k: KernelHandle,
252    gdn_wy3_k: KernelHandle,
253    /// Register-resident wy3 twin (K=3 verify — the 16:2 ladder rung's 3
254    /// rows/seq shape, plus the 24:2/32:2 rungs of the 96-row envelope):
255    /// Pass 2 served from the Pass 1 H read retained in registers, cutting
256    /// HBM state traffic from 2R+3W to 1R+3W. Byte-identical accumulation
257    /// order to `gdn_wy3_k` (bitwise-asserted by gdn_wy_verify_microtest's
258    /// wy3 parity leg). KernelHandle(0) when not linked. Selection +
259    /// kd/vd==128 guard + width gate (n >= wy_resident_min_width()) live in
260    /// `wy3_kernel` (trait_decode_batched_conv_gdn);
261    /// kill switch ATLAS_NO_GDN_WY3_RESIDENT (PRESENCE — `=0` is NOT off).
262    gdn_wy3_resident_k: KernelHandle,
263    gdn_wy4_k: KernelHandle,
264    /// FP16 h-state twins of the five WY verify kernels above
265    /// (`ATLAS_SSM_H_FP16` stage 2). Same launch contracts, same float
266    /// expressions and accumulation orders as their FP32 parents — the h-state
267    /// and its rollback intermediates are simply `__half` in memory, with the
268    /// state rounded once per token boundary so a rollback checkpoint holds
269    /// exactly the bits the forward chain carried.
270    ///
271    /// Stage 1 narrowed only the NON-speculative decode scan, so `--speculative`
272    /// and the flag were mutually exclusive (preflight refused). These close
273    /// that: with speculation on, the WY kernels are the only GDN h-state
274    /// readers/writers in the step, so the rungs whose best config is spec-ON
275    /// could not use FP16 at all.
276    ///
277    /// KernelHandle(0) when not linked. The selectors (`wy2_kernel`,
278    /// `wy3_kernel`, and the K=4 sites) gate on `.0 != 0` and fall back to the
279    /// FP32 parent — which is why preflight must independently refuse the flag
280    /// when a reachable K has no twin, since that fallback would read an FP16
281    /// pool through an FP32 kernel and produce fluent garbage.
282    gdn_wy2_f16_k: KernelHandle,
283    gdn_wy2_resident_f16_k: KernelHandle,
284    gdn_wy3_f16_k: KernelHandle,
285    gdn_wy3_resident_f16_k: KernelHandle,
286    gdn_wy4_f16_k: KernelHandle,
287    /// Stage-3 f16-SIZED pool (`--ssm-h-dtype f16-pool`): the two h-state
288    /// width converters (`ssm_h_dtype.cu`). PREFILL uses them as a matched
289    /// pair around its FP32 kernels — widen the narrow slot into the
290    /// sequence's FP32 staging blob, run, narrow back — so unlike the
291    /// decode-side one-shot conversion these launch once per SSM layer per
292    /// prefill pass and are self-cancelling. A 0 handle is a hard error at
293    /// the first prefill, never an FP32 fallback: an FP32 kernel writing a
294    /// 2-byte-sized slot is an OOB write into the neighbouring slot.
295    ssm_h_f16_to_f32_k: KernelHandle,
296    ssm_h_f32_to_f16_k: KernelHandle,
297    /// STAGE 1 fused K=2 MTP-verify epilogue: conv1d+L2norm ×2 and
298    /// gated-RMS-norm ×2 each folded into a single launch. Dispatched only
299    /// when the `ATLAS_GDN_FUSED_VERIFY` env flag is set (default OFF); the
300    /// per-token path runs unchanged otherwise. Bit-identical (cos == 1.0).
301    gdn_verify_fused_conv_k2_k: KernelHandle,
302    gdn_verify_fused_norm_k2_k: KernelHandle,
303    /// Fused generic-K verify conv1d+L2norm (one launch for all K positions,
304    /// rollback snapshots written inline). Used by the K=17 DFlash verify arm;
305    /// default ON when present, kill-switch `ATLAS_GDN_FUSED_CONV17=0`.
306    /// NULL handle on targets lacking the .cu → per-token loop unchanged.
307    gdn_verify_fused_conv_kn_k: KernelHandle,
308    /// Batched twin (gridDim.y = n_seq) — batched spec decode. 0 when absent.
309    gdn_verify_fused_conv_kn_batched_k: KernelHandle,
310    /// Exact-verify `_snap` twins (issue #435 route (a)): the fused-norm
311    /// decode kernels with an inline per-token h-state rollback snapshot, and
312    /// the FP32-output fused verify conv. All OPTIONAL (model-shadow staged,
313    /// currently qwen3.6-27b/nvfp4 only): a 0 handle makes the exact arm fall
314    /// back to the parent kernel + `copy_d2d_async` snapshots — the same
315    /// bits, more launches.
316    gdn_f32_norm_snap_k: KernelHandle,
317    gdn_f32_strided_norm_snap_k: KernelHandle,
318    gdn_verify_fused_conv_kn_f32_k: KernelHandle,
319    /// WY-Chunkwise K=17 GDN verify (DFlash γ+1). Only present in
320    /// qwen3.6-35b-a3b's PTX module set; NULL handle for other targets,
321    /// in which case decode_batched(K=17) falls through to the sequential
322    /// per-token path.
323    gdn_wy17_k: KernelHandle,
324    /// WY-Chunkwise K∈{5..16} GDN verify (every chain-verify width between
325    /// the dedicated wy4 and the DFlash wy17; K=9..16 added 2026-08-29 for
326    /// the γ>8 window class, which previously fell to the sequential
327    /// per-token loop — the measured γ10 tax). One K-templated source
328    /// (`gated_delta_rule_wyn.cu`, gb10 common) instantiates wy5..wy16 with
329    /// the same pool-layout intermediates contract as wy17. Index = K-5;
330    /// NULL handles on targets lacking the module → sequential fallback.
331    /// Kill-switch: `ATLAS_GDN_WYN=0` (default ON).
332    gdn_wyn_k: [KernelHandle; 12],
333    /// FP16 h-state twins of the wyN family (K=5..16), stage 2 of
334    /// `ATLAS_SSM_H_FP16` — added 2026-08-29 (#812: the FP16 pool is the
335    /// lever that lets MTP serve wide batch; DFlash was refused it for
336    /// want of these twins). Same index contract (K-5); zero handles on
337    /// targets lacking the module. Under the f16 pool a missing twin is a
338    /// HARD ERROR at dispatch (never a silent FP32 fallback over FP16
339    /// state). provenance-id: 526f6e616c6420522e205374657369616b
340    gdn_wyn_f16_k: [KernelHandle; 12],
341    // State allocation sizes (pre-computed from config)
342    h_state_bytes: usize,
343    conv_state_bytes: usize,
344    // Pre-dequanted FP8 weights for zero-overhead prefill GEMMs
345    qkvz_fp8: Option<DevicePtr>,
346    out_proj_fp8: Option<DevicePtr>,
347    fp8_gemm_k: KernelHandle,
348    fp8_gemm_t_m128_k: KernelHandle, // M128: halves B re-reads for out_proj at ISL > 128
349    // Block-scaled W8A16 prefill kernels (preferred over single-scale
350    // fp8_gemm_n128 when block-scaled FP8 weights are available — matches
351    // vLLM's per-128-block scale precision instead of single-scale).
352    w8a16_gemm_k: KernelHandle,
353    // Pipelined (cp.async) rewrite of w8a16_gemm: bit-identical, ~4.6× faster.
354    // KernelHandle(0) when not linked into the image. Gated ON only when
355    // ATLAS_W8A16_PIPELINED=1 (default OFF — production dispatch unchanged).
356    w8a16_gemm_pipelined_k: KernelHandle,
357    // M<=4 weight-streaming block-scaled FP8 GEMV. Replaces the M-padded
358    // w8a16_gemm_pipelined for n<=4 batched decode (qkvz + out_proj): pipelined
359    // pads M=4 to a 128-row MMA tile (32× compute over-provision, issue-bound);
360    // this streams the weight once with 4 FP32 accumulators. Bit-identical per
361    // row to w8a16_gemv. KernelHandle(0) when not linked.
362    w8a16_gemv_batch4_k: KernelHandle,
363    // M<=16 sibling of batch4 for high-concurrency decode (n=5..16): same
364    // weight-streaming GEMV, avoids the M-padded MMA at C=8/16.
365    w8a16_gemv_batch16_k: KernelHandle,
366    w8a16_gemm_t_k: KernelHandle,
367    // W8A8 + FP32 epilogue (vLLM-equivalent) prefill kernels.
368    // `per_token_group_quant_fp8` produces FP8 activations + per-token-per-128
369    // FP32 scale; `fp8_gemm_t_blockscaled` consumes both with FP8 MMA and
370    // applies a_scale × b_scale in the FP32 epilogue. Gated behind
371    // `ATLAS_FP8_W8A8=1` for staged rollout.
372    per_token_group_quant_fp8_k: KernelHandle,
373    fp8_gemm_t_blockscaled_k: KernelHandle,
374}
375
376// Kernel-selection helpers moved to `kernel_select.rs` (≤500 LoC split).
377
378// ── Sub-files (split for ≤500 LoC) ────────────────────────────────────────
379mod debug;
380pub mod gdn_flags;
381mod init;
382mod init_fp8;
383mod init_q2;
384mod kernel_select;
385mod lora;
386mod ssm_forward;
387pub(crate) mod ssm_h_fp16;
388mod trait_decode;
389mod trait_decode_batched;
390mod trait_decode_batched_conv_gdn;
391mod trait_decode_batched_conv_gdn_exact;
392mod trait_decode_batched_conv_gdn_multi;
393mod trait_decode_batched_conv_gdn_multi_exact;
394mod trait_decode_batched_conv_gdn_wyn;
395mod trait_decode_hc;
396mod trait_decode_multi_seq;
397mod trait_layer;
398mod trait_prefill;
399mod trait_prefill_block;
400mod trait_prefill_gdn;
401mod trait_prefill_hc;
402mod trait_prefill_helper;
403mod trait_prefill_phase1;
404mod trait_prefill_phase3;
405mod trait_prefill_proj;
406mod trait_prefill_recur;
407
408pub use gdn_flags::{
409    GdnFlags, MAX_F16_TWIN_DFLASH_GAMMA, MAX_F16_TWIN_K, default_dflash_gamma,
410    gdn_fused_norm_enabled, ssm_batched_recurrent_enabled, ssm_h_dtype_bits,
411    ssm_h_f16_pool_enabled, ssm_h_fp16_enabled, verify_exact_enabled,
412};
413
414// ── TransformerLayer impl (delegates to per-file inherent _inner methods) ──
415
416#[cfg(test)]
417mod tests;
418
419#[path = "hc.rs"]
420mod hc;