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 /// This layer's slice of the LEDGERED row-wise BF16-weight slab
84 /// (`BufferSizes::ssm_rowwise_w_bf16`), or 0 before the first prefill
85 /// through the matching arm carves and fills it. See `rowwise_bf16.rs`
86 /// for the #917 receipt that moved these bytes out of a by-pointer cache
87 /// of `gpu.alloc`s and into the arena.
88 ///
89 /// Per LAYER rather than per weight pointer, because that is what the
90 /// lifetime is: the slab is the arena's, and the arena outlives every
91 /// prefill this layer runs.
92 qkvz_rowwise_bf16: std::sync::atomic::AtomicU64,
93 out_proj_rowwise_bf16: std::sync::atomic::AtomicU64,
94 /// Tier-1c keep-packed ternary Q2_0 fused in_proj_qkvz (`ATLAS_GGUF_NATIVE_Q2`).
95 /// [Q|K|V|Z] rows byte-concatenated from packed `in_proj_qkv` (V-region
96 /// row-permuted) + `in_proj_z` (row-permuted) at load, so the 2-bit weight is
97 /// HF-correct. `out_proj` stays NVFP4 (column reorder not packed-permutable here).
98 qkvz_q2: Option<crate::weight_map::PackedQ2Weight>,
99 /// Q2_0 kernels for the packed qkvz: `gemv` = `q2_0_gemv_vec` decode; `dequant`
100 /// = load-time packed→BF16 for the transient-dequant prefill fallback;
101 /// `mmq_{nc,wc}` = Tier-2 keep-packed tensor-core MMQ prefill (`KernelHandle(0)`
102 /// → fallback); `q4k_quant_act` = shared q8_1 activation quantizer.
103 q2_0_gemv_k: KernelHandle,
104 dequant_q2_0_gn_k: KernelHandle,
105 q2_0_mmq_nc_k: KernelHandle,
106 q2_0_mmq_wc_k: KernelHandle,
107 q4k_quant_act_k: KernelHandle,
108 /// When true, QKVZ projection output is already sequential [Q|K|V|Z].
109 /// Skips the deinterleave kernel (used by Qwen3.5 where QKV+Z are
110 /// concatenated at load time rather than interleaved per-group).
111 sequential_qkvz: bool,
112 /// Streaming multiprocessor count, read from the driver ONCE at
113 /// construction (`GpuBackend::sm_count`). `ms_proj_gemm` needs to know how
114 /// wide the machine is to decide whether halving the CTA rows is a saving
115 /// or an under-fill; a compiled-in constant would be wrong on every part
116 /// that is not the one it was tuned on.
117 sm_count: u32,
118 // Kernels — decode path (single-token GEMV)
119 rms_norm_residual_k: KernelHandle,
120 gated_rms_norm_k: KernelHandle,
121 gated_rms_norm_f32_k: KernelHandle,
122 /// `gated_rms_norm_f32_input_strided` — the SAME per-(sequence, head) math
123 /// as `gated_rms_norm_f32_k`, with `blockIdx.y` walking the sequences, so
124 /// a batched decode step spends ONE launch per layer instead of one per
125 /// row. 0 when absent (notably on a `gdn_norm_sigmoid` model, which has no
126 /// strided sigmoid twin), which keeps the per-seq loop. #927: the H100
127 /// batch-16 trace showed the per-seq loop at 768 launches / 1.61 ms.
128 gated_rms_norm_f32_strided_k: KernelHandle,
129 dense_gemv_k: KernelHandle,
130 /// K=2 verify: batched (M=2) BF16 GDN in_proj_qkvz — one weight pass for
131 /// both verify tokens instead of two M=1 `dense_gemv` reads.
132 dense_gemv_batch2_k: KernelHandle,
133 w4a16_gemv_k: KernelHandle,
134 /// Single-warp `w4a16_gemv_sw`. `KernelHandle(0)` on miss → base GEMV.
135 w4a16_gemv_sw_k: KernelHandle,
136 w8a16_gemv_k: KernelHandle,
137 w4a16_gemv_qkvz_k: KernelHandle,
138 deinterleave_k: KernelHandle,
139 conv1d_k: KernelHandle,
140 conv1d_l2norm_k: KernelHandle,
141 conv1d_l2norm_f32_k: KernelHandle,
142 /// `conv1d_l2norm_f32_k` with explicit input/output row strides, letting
143 /// the concurrent-decode path batch all N sequences into one launch.
144 /// `KernelHandle(0)` on kernel sets that predate it — the multi-seq path
145 /// then falls back to the per-sequence conv loop.
146 conv1d_l2norm_f32_strided_k: KernelHandle,
147 gdn_k: KernelHandle,
148 gdn_f32_k: KernelHandle,
149 gdn_f32_norm_k: KernelHandle,
150 gdn_f32_conv_norm_k: KernelHandle,
151 gdn_f32_strided_k: KernelHandle,
152 gdn_f32_strided_norm_k: KernelHandle,
153 /// Half-width register retention (k_dim==v_dim==128): retains the first 64 H
154 /// columns so the update re-reads only the rest (2R+1W -> 1.5R+1W).
155 gdn_f32_strided_norm_half_k: KernelHandle,
156 /// SRAM-staged full retention (k_dim==v_dim==128): the columns the register
157 /// file cannot hold are staged in shared memory on the first pass instead of
158 /// being re-read from H (1.5R+1W -> 1.0R+1W). Bit-identical to
159 /// `gdn_f32_strided_norm_half_k` but measured throughput-NEUTRAL, so it is
160 /// OPT-IN via `gdn_smem_stage_enabled()` (`ATLAS_GDN_SMEM_STAGE`).
161 gdn_f32_strided_norm_smem_k: KernelHandle,
162 /// FP16 h-state twin of `gdn_f32_strided_norm_half_k` (`ATLAS_SSM_H_FP16`).
163 /// Additive: it never replaces the FP32 kernel, it is selected instead of
164 /// it when the sequence's `SsmLayerState::h_is_f16` is set.
165 gdn_f16_strided_norm_half_k: KernelHandle,
166 /// FP16 h-state twin of `gdn_f32_norm_k` — the per-sequence arm the batched
167 /// dispatch falls back to at n == 1 and whenever pool slots fragment out of
168 /// slice order. Without it the FP16 pool would be read as FP32 on exactly
169 /// those steps.
170 gdn_f16_norm_k: KernelHandle,
171 ba_gates_k: KernelHandle,
172 residual_add_k: KernelHandle,
173 l2_norm_k: KernelHandle,
174 residual_add_rms_norm_k: KernelHandle,
175 /// Dual-output (bf16 + f32) MoE-input norm for ATLAS_FP32_ROUTING. Zero if absent.
176 residual_add_rms_norm_gatef32_k: KernelHandle,
177 gated_rms_norm_prefill_k: KernelHandle,
178 // Kernels — batched verification path (multi-token GEMM)
179 w4a16_gemm_k: KernelHandle,
180 w4a16_gemm_t_k: KernelHandle, // Transposed B layout [K/2, N] — K_STEP_T=32
181 w4a16_gemm_t_k64_k: KernelHandle, // K64 variant: K_STEP_T=64, halves outer loop
182 /// K64 with a 64-wide N tile: same math, 2x the CTAs. `KernelHandle(0)`
183 /// when absent or killed by `ATLAS_NO_K64_N64`.
184 w4a16_gemm_t_k64_n64_k: KernelHandle,
185 w4a16_gemm_t_m128_k: KernelHandle, // M128 variant: 2 M-chunks per CTA, halves B re-reads
186 w4a16_gemm_t_m128_v2_k: KernelHandle, // M128 8-warp pipelined (fast at small M; the FFN's kernel)
187 w4a16_gemv_batch2_k: KernelHandle,
188 dense_gemm_k: KernelHandle,
189 dense_gemm_pipelined_k: KernelHandle,
190 gdn_prefill_k: KernelHandle,
191 gdn_prefill_split_k: KernelHandle,
192 gdn_prefill_split4_k: KernelHandle,
193 gdn_prefill_persistent_k: KernelHandle,
194 gdn_prefill_persistent_wy4_k: KernelHandle,
195 /// Register-resident token-sequential warm-replay recurrence (H in regs, >=2
196 /// CTA/SM, no barriers). Token-equal to WY4 (cosine 1.0), ~2.9x faster.
197 /// DEFAULT-ON since 2026-07-25 (serve-validated: full MLPerf-edge e2e, wall
198 /// −7.25%, BFCL identical); kill switch `ATLAS_NO_GDN_REGRESIDENT=1`.
199 gdn_prefill_regresident_k: KernelHandle,
200 /// FLA multi-kernel chunked prefill (baked default for 128-dim GDN): recompute_wu →
201 /// chunk_delta_h_ksplit (k-split occupancy) → chunk_fwd_o. 1.75x vs wy4 @16k,
202 /// token-equal (cos=1.0 vs scalar). Three handles; all must be non-null.
203 gdn_prefill_fla_recompute_wu_k: KernelHandle,
204 /// Hopper twins of the two SCALAR REMNANTS of the FLA prefill (#928):
205 /// `gdn_recompute_wu_hopper.cu`'s blocked triangular solve on tensor cores
206 /// and `gdn_fwd_o_hopper.cu`'s masked `tril(kq).uc` square. They live only
207 /// under `kernels/hopper`, so `try_kernel` gives 0 everywhere else and the
208 /// launcher then runs the unchanged parents. Selected by the family lever
209 /// `[defaults] gdn_prefill_tc` (`ATLAS_GDN_PREFILL_TC` overriding), which
210 /// Hopper ships ON since round 13; `ATLAS_NO_GDN_PREFILL_TC_REMNANTS=1` pins them
211 /// off while keeping the tensor-core state spine, which is the A/B that
212 /// separates the three kernels. The nsys receipt that motivates them is in
213 /// `GDN-PREFILL-ATTRIBUTION.md`: 5.5% and 4.0% of a 1193-token H100
214 /// prefill, both with their big matmuls already on `mma.sync` and their
215 /// remainder — a triangular product on 128 of 512 threads, and two forward
216 /// substitutions worth 79-85% of their kernel — still scalar.
217 gdn_prefill_fla_recompute_wu_hopper_k: KernelHandle,
218 gdn_prefill_fla_chunk_fwd_o_hopper_k: KernelHandle,
219 gdn_prefill_fla_chunk_delta_h_k: KernelHandle,
220 /// Tensor-core / DV-block-split variant of the FLA chunk_delta_h spine
221 /// (`gated_delta_rule_chunk_delta_h_tc_vblock`). Loaded by default but not
222 /// yet wired into the prefill dispatch — the cos-gate validates it in
223 /// isolation first. `allow(dead_code)` until the launch site reads it.
224 #[allow(dead_code)]
225 gdn_prefill_fla_chunk_delta_h_tc_vblock_k: KernelHandle,
226 /// TENSOR-CORE chunked-prefill state spine
227 /// (`gated_delta_rule_chunk_tc::gated_delta_rule_chunk_delta_h_tcfuse`),
228 /// behind `[defaults] gdn_prefill_tc` — ON for `kernels/hopper` since round
229 /// 13, OFF elsewhere, with `ATLAS_GDN_PREFILL_TC` overriding either way.
230 /// Both per-chunk
231 /// products run on `mma.sync.m16n8k16` with bf16 operands and an f32
232 /// accumulator that IS the recurrent state; `h` stays f32 in memory. The
233 /// nsys receipt that motivates it is in `GDN-PREFILL-ATTRIBUTION.md`
234 /// (#928): the shipped scalar spine is 26.6%/32.3% of the 1193/4593-token
235 /// H100 prefill at 3.7 TFLOP/s, i.e. latency-bound at 4.5% warp residency.
236 /// `try_kernel` => 0 on images without it, and the launcher additionally
237 /// refuses any head/chunk that differs from the compile-time tile.
238 gdn_prefill_fla_chunk_delta_h_tcfuse_k: KernelHandle,
239 /// Warp-dense fused GDN state spine (`gated_delta_rule_chunk_delta_h_vtile`).
240 /// 512 threads = 16 warps/CTA against ksplit's 8, with the SAME grid (one CTA
241 /// per head) so `W`/`K` global loads are not duplicated — an ncu profile put
242 /// ksplit at L2 60.6% / L1 56.2%, i.e. memory-pipeline bound, which is why the
243 /// DV-split variants (which duplicate those loads) lost. Fusing the two
244 /// per-chunk passes deletes ksplit's `duc[CHUNK]` register array, and that is
245 /// what pays for the extra warps: 118 registers, no spills. Measured 2.15-2.18x
246 /// vs ksplit at 2048/8192/16384 with cos=1.0000 (`gdn_chunk_shapetest`).
247 gdn_prefill_fla_chunk_delta_h_fused_k: KernelHandle,
248 /// TMA (`cp.async.bulk.tensor`) build of the state spine, behind
249 /// `ATLAS_GDN_TMA=1`. `try_kernel` => 0 on images that lack it, and the
250 /// launcher additionally refuses varlen and any head narrower than the
251 /// compile-time tile — the descriptors encode that tile, and a mismatched
252 /// shape loads the wrong columns without erroring.
253 gdn_prefill_fla_chunk_delta_h_tma_k: KernelHandle,
254 gdn_prefill_fla_chunk_fwd_o_k: KernelHandle,
255 /// WY32 chunked prefill: processes 32 tokens per WY iteration with H in
256 /// shared memory. ~30x faster than per-token for 14k+ sequences.
257 gdn_prefill_wy32_k: KernelHandle,
258 // ── Q12 Phase 2b: same-chunk-len batched GDN prefill kernels ──
259 // Each takes `float* const* h_state_ptrs` plus stacked QKV/gate/beta/output.
260 // Used by `Qwen3SsmLayer::prefill_batched` when N≥2 streams have matching
261 // chunk_len. Null on targets that don't carry the corresponding kernel.
262 gdn_prefill_wy32_batched_k: KernelHandle,
263 gdn_prefill_persistent_batched_k: KernelHandle,
264 gdn_prefill_persistent_wy4_batched_k: KernelHandle,
265 gdn_prefill_split4_batched_k: KernelHandle,
266 compute_gdn_gates_k: KernelHandle,
267 ba_gates_prefill_k: KernelHandle,
268 /// Hopper twin of `ba_gates_prefill_k`
269 /// (`ssm_ba_gates_hopper::dense_gemm_ba_gates_prefill_hopper`, #928): one
270 /// CTA per token instead of `ceil(N/4)`, bit-identical output. Null on
271 /// every target but hopper, and declined below the token-count floor —
272 /// `ops::ba_gates_pick` owns both rules.
273 ba_gates_prefill_hopper_k: KernelHandle,
274 // Kernels — prefill (multi-token sequential)
275 conv1d_prefill_k: KernelHandle,
276 /// Token-parallel prefill conv1d (`causal_conv1d_update_prefill_tp`).
277 conv1d_prefill_tp_k: KernelHandle,
278 // Kernels — fused chunk2 path (2-token verification)
279 gdn_chunk2_k: KernelHandle,
280 conv1d_chunk2_k: KernelHandle,
281 // Kernels — fused chunk3 path (3-token verification)
282 gdn_chunk3_k: KernelHandle,
283 w4a16_gemv_batch3_k: KernelHandle,
284 // NVFP4 batched decode GEMV (multi-seq concurrency + chain verify):
285 // the narrow batch{4,5,6,7,8} family plus batch16 (M<=16) — siblings of
286 // w8a16_gemv_batch4/16 for the FP4 QKVZ + out_proj, so FP4 decode
287 // amortizes the weight read at C=4..16 like FP8.
288 w4a16_batchm: W4a16BatchmTiers,
289 w4a16_gemv_batch16_k: KernelHandle,
290 // Kernels — WY-chunkwise path (2-pass verification)
291 gdn_wy2_k: KernelHandle,
292 /// Register-resident wy2 twin (K=2 verify, the C=32 hot shape): Pass 2
293 /// is served from the Pass 1 H read retained in registers
294 /// (`__launch_bounds__(128,1)`, 128 floats/thread — the regresident
295 /// prefill pattern), cutting the kernel's HBM state traffic from 2R+2W
296 /// to 1R+2W. Byte-identical accumulation order to `gdn_wy2_k`
297 /// (bitwise-asserted by gdn_wy_verify_microtest's parity leg).
298 /// KernelHandle(0) when not linked (e.g. strix module sets). Selection +
299 /// kd/vd==128 guard + width gate (n >= wy_resident_min_width(); the
300 /// 1-block/SM kernel loses at narrow launches) live in `wy2_kernel`
301 /// (trait_decode_batched_conv_gdn);
302 /// kill switch ATLAS_NO_GDN_WY2_RESIDENT (PRESENCE — `=0` is NOT off).
303 gdn_wy2_resident_k: KernelHandle,
304 gdn_wy3_k: KernelHandle,
305 /// Register-resident wy3 twin (K=3 verify — the 16:2 ladder rung's 3
306 /// rows/seq shape, plus the 24:2/32:2 rungs of the 96-row envelope):
307 /// Pass 2 served from the Pass 1 H read retained in registers, cutting
308 /// HBM state traffic from 2R+3W to 1R+3W. Byte-identical accumulation
309 /// order to `gdn_wy3_k` (bitwise-asserted by gdn_wy_verify_microtest's
310 /// wy3 parity leg). KernelHandle(0) when not linked. Selection +
311 /// kd/vd==128 guard + width gate (n >= wy_resident_min_width()) live in
312 /// `wy3_kernel` (trait_decode_batched_conv_gdn);
313 /// kill switch ATLAS_NO_GDN_WY3_RESIDENT (PRESENCE — `=0` is NOT off).
314 gdn_wy3_resident_k: KernelHandle,
315 gdn_wy4_k: KernelHandle,
316 /// FP16 h-state twins of the five WY verify kernels above
317 /// (`ATLAS_SSM_H_FP16` stage 2). Same launch contracts, same float
318 /// expressions and accumulation orders as their FP32 parents — the h-state
319 /// and its rollback intermediates are simply `__half` in memory, with the
320 /// state rounded once per token boundary so a rollback checkpoint holds
321 /// exactly the bits the forward chain carried.
322 ///
323 /// Stage 1 narrowed only the NON-speculative decode scan, so `--speculative`
324 /// and the flag were mutually exclusive (preflight refused). These close
325 /// that: with speculation on, the WY kernels are the only GDN h-state
326 /// readers/writers in the step, so the rungs whose best config is spec-ON
327 /// could not use FP16 at all.
328 ///
329 /// KernelHandle(0) when not linked. The selectors (`wy2_kernel`,
330 /// `wy3_kernel`, and the K=4 sites) gate on `.0 != 0` and fall back to the
331 /// FP32 parent — which is why preflight must independently refuse the flag
332 /// when a reachable K has no twin, since that fallback would read an FP16
333 /// pool through an FP32 kernel and produce fluent garbage.
334 gdn_wy2_f16_k: KernelHandle,
335 gdn_wy2_resident_f16_k: KernelHandle,
336 gdn_wy3_f16_k: KernelHandle,
337 gdn_wy3_resident_f16_k: KernelHandle,
338 gdn_wy4_f16_k: KernelHandle,
339 /// Stage-3 f16-SIZED pool (`--ssm-h-dtype f16-pool`): the two h-state
340 /// width converters (`ssm_h_dtype.cu`). PREFILL uses them as a matched
341 /// pair around its FP32 kernels — widen the narrow slot into the
342 /// sequence's FP32 staging blob, run, narrow back — so unlike the
343 /// decode-side one-shot conversion these launch once per SSM layer per
344 /// prefill pass and are self-cancelling. A 0 handle is a hard error at
345 /// the first prefill, never an FP32 fallback: an FP32 kernel writing a
346 /// 2-byte-sized slot is an OOB write into the neighbouring slot.
347 ssm_h_f16_to_f32_k: KernelHandle,
348 ssm_h_f32_to_f16_k: KernelHandle,
349 /// STAGE 1 fused K=2 MTP-verify epilogue: conv1d+L2norm ×2 and
350 /// gated-RMS-norm ×2 each folded into a single launch. Dispatched only
351 /// when the `ATLAS_GDN_FUSED_VERIFY` env flag is set (default OFF); the
352 /// per-token path runs unchanged otherwise. Bit-identical (cos == 1.0).
353 gdn_verify_fused_conv_k2_k: KernelHandle,
354 gdn_verify_fused_norm_k2_k: KernelHandle,
355 /// Fused generic-K verify conv1d+L2norm (one launch for all K positions,
356 /// rollback snapshots written inline). Used by the K=17 DFlash verify arm;
357 /// default ON when present, kill-switch `ATLAS_GDN_FUSED_CONV17=0`.
358 /// NULL handle on targets lacking the .cu → per-token loop unchanged.
359 gdn_verify_fused_conv_kn_k: KernelHandle,
360 /// Batched twin (gridDim.y = n_seq) — batched spec decode. 0 when absent.
361 gdn_verify_fused_conv_kn_batched_k: KernelHandle,
362 /// Exact-verify `_snap` twins (issue #435 route (a)): the fused-norm
363 /// decode kernels with an inline per-token h-state rollback snapshot, and
364 /// the FP32-output fused verify conv. All OPTIONAL (model-shadow staged,
365 /// currently qwen3.6-27b/nvfp4 only): a 0 handle makes the exact arm fall
366 /// back to the parent kernel + `copy_d2d_async` snapshots — the same
367 /// bits, more launches.
368 gdn_f32_norm_snap_k: KernelHandle,
369 gdn_f32_strided_norm_snap_k: KernelHandle,
370 gdn_verify_fused_conv_kn_f32_k: KernelHandle,
371 /// WY-Chunkwise K=17 GDN verify (DFlash γ+1). Only present in
372 /// qwen3.6-35b-a3b's PTX module set; NULL handle for other targets,
373 /// in which case decode_batched(K=17) falls through to the sequential
374 /// per-token path.
375 gdn_wy17_k: KernelHandle,
376 /// WY-Chunkwise K∈{5..16} GDN verify (every chain-verify width between
377 /// the dedicated wy4 and the DFlash wy17; K=9..16 added 2026-08-29 for
378 /// the γ>8 window class, which previously fell to the sequential
379 /// per-token loop — the measured γ10 tax). One K-templated source
380 /// (`gated_delta_rule_wyn.cu`, gb10 common) instantiates wy5..wy16 with
381 /// the same pool-layout intermediates contract as wy17. Index = K-5;
382 /// NULL handles on targets lacking the module → sequential fallback.
383 /// Kill-switch: `ATLAS_GDN_WYN=0` (default ON).
384 gdn_wyn_k: [KernelHandle; 12],
385 /// FP16 h-state twins of the wyN family (K=5..16), stage 2 of
386 /// `ATLAS_SSM_H_FP16` — added 2026-08-29 (#812: the FP16 pool is the
387 /// lever that lets MTP serve wide batch; DFlash was refused it for
388 /// want of these twins). Same index contract (K-5); zero handles on
389 /// targets lacking the module. Under the f16 pool a missing twin is a
390 /// HARD ERROR at dispatch (never a silent FP32 fallback over FP16
391 /// state). provenance-id: 526f6e616c6420522e205374657369616b
392 gdn_wyn_f16_k: [KernelHandle; 12],
393 // State allocation sizes (pre-computed from config)
394 h_state_bytes: usize,
395 conv_state_bytes: usize,
396 // Pre-dequanted FP8 weights for zero-overhead prefill GEMMs
397 qkvz_fp8: Option<DevicePtr>,
398 out_proj_fp8: Option<DevicePtr>,
399 fp8_gemm_k: KernelHandle,
400 fp8_gemm_t_m128_k: KernelHandle, // M128: halves B re-reads for out_proj at ISL > 128
401 // Block-scaled W8A16 prefill kernels (preferred over single-scale
402 // fp8_gemm_n128 when block-scaled FP8 weights are available — matches
403 // vLLM's per-128-block scale precision instead of single-scale).
404 w8a16_gemm_k: KernelHandle,
405 // Pipelined (cp.async) rewrite of w8a16_gemm: bit-identical, ~4.6× faster.
406 // KernelHandle(0) when not linked into the image. Gated ON only when
407 // ATLAS_W8A16_PIPELINED=1 (default OFF — production dispatch unchanged).
408 w8a16_gemm_pipelined_k: KernelHandle,
409 // M<=4 weight-streaming block-scaled FP8 GEMV. Replaces the M-padded
410 // w8a16_gemm_pipelined for n<=4 batched decode (qkvz + out_proj): pipelined
411 // pads M=4 to a 128-row MMA tile (32× compute over-provision, issue-bound);
412 // this streams the weight once with 4 FP32 accumulators. Bit-identical per
413 // row to w8a16_gemv. KernelHandle(0) when not linked.
414 w8a16_gemv_batch4_k: KernelHandle,
415 // M<=16 sibling of batch4 for high-concurrency decode (n=5..16): same
416 // weight-streaming GEMV, avoids the M-padded MMA at C=8/16.
417 w8a16_gemv_batch16_k: KernelHandle,
418 w8a16_gemm_t_k: KernelHandle,
419 // W8A8 + FP32 epilogue (vLLM-equivalent) prefill kernels.
420 // `per_token_group_quant_fp8` produces FP8 activations + per-token-per-128
421 // FP32 scale; `fp8_gemm_t_blockscaled` consumes both with FP8 MMA and
422 // applies a_scale × b_scale in the FP32 epilogue. Gated behind
423 // `ATLAS_FP8_W8A8=1` for staged rollout.
424 per_token_group_quant_fp8_k: ops::Fp8ActQuant,
425 fp8_gemm_t_blockscaled_k: KernelHandle,
426 /// `fp8_act_scale_to_kmajor` — rewrites the quantizer's `[M, K/128]`
427 /// VEC128 activation scales into the `[K/128, ceil16(M)]` layout cuBLASLt
428 /// documents. 0 when the module is absent, which makes the cuBLASLt QKVZ
429 /// arm decline (see `prefill_w8a8.rs`); the in-tree kernel reads the
430 /// quantizer's own order and needs no adapter.
431 fp8_act_scale_kmajor_k: KernelHandle,
432}
433
434// Kernel-selection helpers moved to `kernel_select.rs` (≤500 LoC split).
435
436// ── Sub-files (split for ≤500 LoC) ────────────────────────────────────────
437mod debug;
438mod decode_w8a8_proj;
439pub mod gdn_flags;
440mod init;
441mod init_fp8;
442mod init_q2;
443mod kernel_select;
444mod lora;
445mod prefill_out_w8a8;
446mod prefill_w8a8;
447mod rowwise_bf16;
448mod ssm_forward;
449pub(crate) mod ssm_h_fp16;
450mod trait_decode;
451mod trait_decode_batched;
452mod trait_decode_batched_conv_gdn;
453mod trait_decode_batched_conv_gdn_exact;
454mod trait_decode_batched_conv_gdn_multi;
455mod trait_decode_batched_conv_gdn_multi_exact;
456mod trait_decode_batched_conv_gdn_wyn;
457mod trait_decode_hc;
458mod trait_decode_multi_seq;
459mod trait_layer;
460mod trait_prefill;
461mod trait_prefill_block;
462mod trait_prefill_gdn;
463mod trait_prefill_hc;
464mod trait_prefill_helper;
465mod trait_prefill_phase1;
466mod trait_prefill_phase3;
467mod trait_prefill_proj;
468mod trait_prefill_recur;
469
470pub use gdn_flags::{
471 GdnFlags, MAX_F16_TWIN_DFLASH_GAMMA, MAX_F16_TWIN_K, default_dflash_gamma,
472 gdn_fused_norm_enabled, ssm_batched_recurrent_enabled, ssm_h_dtype_bits,
473 ssm_h_f16_pool_enabled, ssm_h_fp16_enabled, verify_exact_enabled,
474};
475
476// ── TransformerLayer impl (delegates to per-file inherent _inner methods) ──
477
478#[cfg(test)]
479#[path = "prefill_alloc_tests.rs"]
480mod prefill_alloc_tests;
481#[cfg(test)]
482#[path = "rowwise_alloc_tests.rs"]
483mod rowwise_alloc_tests;
484#[cfg(test)]
485mod tests;
486
487#[path = "hc.rs"]
488mod hc;