spark_model/layers/qwen3_ssm/
init.rs

1// SPDX-License-Identifier: AGPL-3.0-only
2
3//! Qwen3SsmLayer constructors + setters.
4
5use super::*;
6
7impl Qwen3SsmLayer {
8    pub fn new(
9        input_norm: DenseWeight,
10        ssm: SsmWeights,
11        post_attn_norm: DenseWeight,
12        ffn: FfnComponent,
13        qkvz_nvfp4: Option<QuantizedWeight>,
14        config: &atlas_core::config::ModelConfig,
15        gpu: &dyn GpuBackend,
16    ) -> Result<Self> {
17        let nv = config.linear_num_value_heads;
18        let vd = config.linear_value_head_dim;
19        let nk = config.linear_num_key_heads;
20        let kd = config.linear_key_head_dim;
21        let d_conv = config.linear_conv_kernel_dim;
22
23        // conv_dim = Q_flat + K_flat + V_flat = 2*key_dim + value_dim = 8192
24        let conv_dim = nk * kd * 2 + nv * vd;
25
26        // Resolved BEFORE the struct literal because two fields need it: the
27        // tensor-core spine's handle IS the bit that decides which spine the
28        // prefill launches, so the scalar spine's route line has to read it,
29        // and a field initializer cannot read a sibling field.
30        let gdn_tc_spine = gdn_prefill_tc_kernel(gpu);
31
32        Ok(Self {
33            // mHC is attached later by the loader, and only for models that
34            // carry a hc_mult-wide residual highway. The handles are gated on
35            // the same condition `ArchProbes` uses, so a plain GDN model
36            // never issues the lookup.
37            hc: None,
38            ple: None,
39            hc_pre_k: hc_kernel(config, gpu, "hc_pre"),
40            hc_post_k: hc_kernel(config, gpu, "hc_post"),
41            hc_expand_k: hc_kernel(config, gpu, "hc_expand"),
42            input_norm,
43            ssm,
44            post_attn_norm,
45            ffn,
46            lora_out_proj: None,
47            qkvz_nvfp4,
48            qkvz_nvfp4_t: None,
49            out_proj_nvfp4_t: None,
50            out_proj_dense: None,
51            qkvz_fp8w: None,
52            out_proj_fp8w: None,
53            qkvz_fp8w_rowwise: None,
54            out_proj_fp8w_rowwise: None,
55            qkvz_rowwise_bf16: std::sync::atomic::AtomicU64::new(0),
56            out_proj_rowwise_bf16: std::sync::atomic::AtomicU64::new(0),
57            qkvz_q2: None,
58            q2_0_gemv_k: super::super::try_kernel(gpu, "q2_0_gemv_vec", "q2_0_gemv_vec"),
59            dequant_q2_0_gn_k: super::super::try_kernel(
60                gpu,
61                "dequant_gguf_bf16",
62                "dequant_q2_0_gn_to_bf16",
63            ),
64            // The keep-packed MMQ family ships only in targets that serve
65            // GGUF Q2 checkpoints; probing here would fail the boot audit on
66            // every other GDN target. `set_packed_q2_qkvz` resolves them —
67            // the only path that installs weights their dispatch sites check.
68            q2_0_mmq_nc_k: KernelHandle(0),
69            q2_0_mmq_wc_k: KernelHandle(0),
70            q4k_quant_act_k: KernelHandle(0),
71            sequential_qkvz: false,
72            // Resolved ONCE here from the driver, then carried on the layer:
73            // the projection dispatch asks "does this grid still fill the
74            // machine?" and that question has no portable answer.
75            sm_count: gpu.sm_count()?,
76            rms_norm_residual_k: gpu.kernel("norm", "rms_norm_residual")?,
77            // `output_gate_type: "sigmoid"` (qwen4_exp) swaps the gated-norm
78            // handles for the sigmoid twins ONCE, here, so no forward call
79            // site branches on it. Every other model keeps the SiLU originals.
80            gated_rms_norm_k: if config.gdn_norm_sigmoid {
81                gpu.kernel("gated_norm_sigmoid", "gated_rms_norm_sigmoid")?
82            } else {
83                gpu.kernel("norm", "gated_rms_norm")?
84            },
85            gated_rms_norm_f32_k: if config.gdn_norm_sigmoid {
86                super::super::try_kernel(
87                    gpu,
88                    "gated_norm_sigmoid",
89                    "gated_rms_norm_f32_input_sigmoid",
90                )
91            } else {
92                super::super::try_kernel(gpu, "norm", "gated_rms_norm_f32_input")
93            },
94            // Only the SiLU (non-sigmoid) family has a strided twin today; a
95            // `gdn_norm_sigmoid` model gets KernelHandle(0) and keeps the
96            // per-sequence loop, which is correct, just launch-heavy.
97            gated_rms_norm_f32_strided_k: if config.gdn_norm_sigmoid {
98                KernelHandle(0)
99            } else {
100                super::super::try_kernel(gpu, "norm", "gated_rms_norm_f32_input_strided")
101            },
102            dense_gemv_k: gpu.kernel("gemv", "dense_gemv_bf16")?,
103            dense_gemv_batch2_k: gpu.kernel("dense_gemv_bf16_batch2", "dense_gemv_bf16_batch2")?,
104            w4a16_gemv_k: gpu.kernel("w4a16_gemv", "w4a16_gemv")?,
105            w4a16_gemv_sw_k: super::super::try_kernel(gpu, "w4a16_gemv", "w4a16_gemv_sw"),
106            w8a16_gemv_k: gpu.kernel("w8a16_gemv", "w8a16_gemv")?,
107            w4a16_gemv_qkvz_k: gpu.kernel("w4a16_gemv", "w4a16_gemv_qkvz")?,
108            deinterleave_k: gpu.kernel("ssm_preprocess", "deinterleave_qkvz")?,
109            conv1d_k: gpu.kernel("causal_conv1d", "causal_conv1d_update")?,
110            conv1d_l2norm_k: gpu.kernel("causal_conv1d", "causal_conv1d_update_l2norm")?,
111            // FP32 conv1d output prevents BF16 truncation in the recurrent
112            // path from compounding past ~8k tokens. The Metal backend
113            // (kernels/metal/common/causal_conv1d_update_l2norm.metal) only
114            // ships the BF16 variant; on those targets we fall back to the
115            // BF16 kernel via the `.0 != 0` gate at the use site
116            // (ssm_forward.rs). Warn instead of error: missing-on-Metal is
117            // expected, and a startup `error!` would page on benign cases.
118            // Strided twin of `conv1d_l2norm_f32_k` for the batched multi-seq
119            // decode path. Optional: absent on older kernel sets, where the
120            // multi-seq conv stays a per-sequence loop.
121            conv1d_l2norm_f32_strided_k: super::super::try_kernel(
122                gpu,
123                "causal_conv1d",
124                "causal_conv1d_update_l2norm_f32_strided",
125            ),
126            conv1d_l2norm_f32_k: {
127                let h = super::super::try_kernel(
128                    gpu,
129                    "causal_conv1d",
130                    "causal_conv1d_update_l2norm_f32",
131                );
132                if h.0 == 0 {
133                    tracing::warn!(
134                        "FP32 conv1d kernel not loaded; SSM uses BF16 conv \
135                         output. Expect long-context coherence drift past ~8k \
136                         tokens on this backend."
137                    );
138                }
139                h
140            },
141            gdn_k: gpu.kernel("gated_delta_rule", "gated_delta_rule_decode")?,
142            gdn_f32_k: super::super::try_kernel(
143                gpu,
144                "gated_delta_rule",
145                "gated_delta_rule_decode_f32",
146            ),
147            gdn_f32_norm_k: super::super::try_kernel(
148                gpu,
149                "gated_delta_rule",
150                "gated_delta_rule_decode_f32_norm",
151            ),
152            gdn_f32_conv_norm_k: super::super::try_kernel(
153                gpu,
154                "gated_delta_rule",
155                "gated_delta_rule_decode_f32_conv_norm",
156            ),
157            gdn_f32_strided_k: super::super::try_kernel(
158                gpu,
159                "gated_delta_rule",
160                "gated_delta_rule_decode_f32_strided",
161            ),
162            gdn_f32_strided_norm_k: super::super::try_kernel(
163                gpu,
164                "gated_delta_rule",
165                "gated_delta_rule_decode_f32_strided_norm",
166            ),
167            gdn_f32_strided_norm_half_k: super::super::try_kernel(
168                gpu,
169                "gated_delta_rule",
170                "gated_delta_rule_decode_f32_strided_norm_half",
171            ),
172            gdn_f32_strided_norm_smem_k: super::super::try_kernel(
173                gpu,
174                "gated_delta_rule",
175                "gated_delta_rule_decode_f32_strided_norm_smem",
176            ),
177            gdn_f16_strided_norm_half_k: super::super::try_kernel(
178                gpu,
179                "gated_delta_rule",
180                "gated_delta_rule_decode_f16_strided_norm_half",
181            ),
182            gdn_f16_norm_k: super::super::try_kernel(
183                gpu,
184                "gated_delta_rule",
185                "gated_delta_rule_decode_f16_norm",
186            ),
187            ssm_h_f16_to_f32_k: super::super::try_kernel(
188                gpu,
189                "ssm_h_dtype",
190                "ssm_h_state_f16_to_f32",
191            ),
192            ssm_h_f32_to_f16_k: super::super::try_kernel(
193                gpu,
194                "ssm_h_dtype",
195                "ssm_h_state_f32_to_f16",
196            ),
197            ba_gates_k: gpu.kernel("ssm_preprocess", "dense_gemv_ba_gates")?,
198            residual_add_k: gpu.kernel("residual_add", "bf16_residual_add")?,
199            l2_norm_k: gpu.kernel("norm", "l2_norm_bf16")?,
200            residual_add_rms_norm_k: gpu.kernel("norm", "residual_add_rms_norm")?,
201            residual_add_rms_norm_gatef32_k: crate::layers::try_kernel(
202                gpu,
203                "norm",
204                "residual_add_rms_norm_gatef32",
205            ),
206            gated_rms_norm_prefill_k: if config.gdn_norm_sigmoid {
207                gpu.kernel("gated_norm_sigmoid", "gated_rms_norm_prefill_sigmoid")?
208            } else {
209                gpu.kernel("norm", "gated_rms_norm_prefill")?
210            },
211            w4a16_gemm_k: gpu.kernel("w4a16", "w4a16_gemm")?,
212            w4a16_gemm_t_k: crate::layers::tgemm_kernel(gpu),
213            w4a16_gemm_t_k64_k: crate::layers::k64_kernel(gpu)?,
214            w4a16_gemm_t_k64_n64_k: crate::layers::k64_n64_kernel(gpu),
215            w4a16_gemm_t_m128_k: gpu.kernel("w4a16", "w4a16_gemm_t_m128")?,
216            // 8-warp pipelined M128 (try_kernel: 0 when absent → falls back to m128/n128).
217            w4a16_gemm_t_m128_v2_k: super::super::w4a16_v2_kernel(gpu),
218            w4a16_gemv_batch2_k: gpu.kernel("w4a16_gemv", "w4a16_gemv_batch2")?,
219            dense_gemm_k: gpu.kernel("gemm", "dense_gemm_bf16")?,
220            // try_kernel: 0-handle if absent (gated at dispatch); the pipelined
221            // BF16 GEMM lives in the same `gemm` module as dense_gemm_bf16.
222            dense_gemm_pipelined_k: super::super::try_kernel(
223                gpu,
224                "gemm",
225                "dense_gemm_bf16_pipelined",
226            ),
227            gdn_prefill_k: gpu.kernel("gated_delta_rule", "gated_delta_rule_prefill")?,
228            gdn_prefill_split_k: gpu
229                .kernel("gated_delta_rule", "gated_delta_rule_prefill_split")?,
230            gdn_prefill_split4_k: gpu
231                .kernel("gated_delta_rule", "gated_delta_rule_prefill_split4")?,
232            gdn_prefill_persistent_k: super::super::try_kernel(
233                gpu,
234                "gated_delta_rule_persistent",
235                "gated_delta_rule_prefill_persistent",
236            ),
237            gdn_prefill_persistent_wy4_k: super::super::try_kernel(
238                gpu,
239                "gated_delta_rule_persistent",
240                "gated_delta_rule_prefill_persistent_wy4",
241            ),
242            gdn_prefill_regresident_k: super::super::try_kernel(
243                gpu,
244                "gated_delta_rule_regresident",
245                "gated_delta_rule_prefill_regresident",
246            ),
247            gdn_prefill_fla_recompute_wu_k: super::super::try_kernel(
248                gpu,
249                "gated_delta_rule_fla",
250                "gated_delta_rule_recompute_wu",
251            ),
252            gdn_prefill_fla_recompute_wu_hopper_k: init_kernels::prefill_wu_hopper_k(gpu),
253            gdn_prefill_fla_chunk_fwd_o_hopper_k: init_kernels::prefill_fwd_o_hopper_k(gpu),
254            gdn_prefill_fla_chunk_delta_h_k: super::super::try_kernel(
255                gpu,
256                "gated_delta_rule_fla",
257                "gated_delta_rule_chunk_delta_h_ksplit",
258            ),
259            gdn_prefill_fla_chunk_delta_h_tc_vblock_k: super::super::try_kernel(
260                gpu,
261                "gated_delta_rule_fla",
262                "gated_delta_rule_chunk_delta_h_tc_vblock",
263            ),
264            gdn_prefill_fla_chunk_delta_h_tcfuse_k: gdn_tc_spine,
265            // ONE handle for the scalar fused GDN state spine, and the route
266            // line naming whichever spine the prefill will launch — see
267            // `init_kernels::fused_spine_kernel` for both.
268            gdn_prefill_fla_chunk_delta_h_fused_k: fused_spine_kernel(gpu, gdn_tc_spine),
269            gdn_prefill_fla_chunk_delta_h_tma_k: super::super::try_kernel(
270                gpu,
271                "gated_delta_rule_fla",
272                "gated_delta_rule_chunk_delta_h_tma",
273            ),
274            gdn_prefill_fla_chunk_fwd_o_k: super::super::try_kernel(
275                gpu,
276                "gated_delta_rule_fla",
277                "gated_delta_rule_chunk_fwd_o",
278            ),
279            gdn_prefill_wy32_k: super::super::try_kernel(
280                gpu,
281                "gated_delta_rule_wy64_prefill",
282                "gated_delta_rule_prefill_wy64",
283            ),
284            // ── Q12 Phase 2b: batched GDN kernel handles ──
285            gdn_prefill_wy32_batched_k: super::super::try_kernel(
286                gpu,
287                "gated_delta_rule_wy64_prefill",
288                "gated_delta_rule_prefill_wy64_batched",
289            ),
290            gdn_prefill_persistent_batched_k: super::super::try_kernel(
291                gpu,
292                "gated_delta_rule_persistent",
293                "gated_delta_rule_prefill_persistent_batched",
294            ),
295            gdn_prefill_persistent_wy4_batched_k: super::super::try_kernel(
296                gpu,
297                "gated_delta_rule_persistent",
298                "gated_delta_rule_prefill_persistent_wy4_batched",
299            ),
300            gdn_prefill_split4_batched_k: super::super::try_kernel(
301                gpu,
302                "gated_delta_rule",
303                "gated_delta_rule_prefill_split4_batched",
304            ),
305            compute_gdn_gates_k: gpu.kernel("ssm_preprocess", "compute_gdn_gates")?,
306            ba_gates_prefill_k: gpu.kernel("ssm_preprocess", "dense_gemm_ba_gates_prefill")?,
307            ba_gates_prefill_hopper_k: init_kernels::ba_gates_hopper_k(gpu),
308            conv1d_prefill_k: gpu.kernel("causal_conv1d", "causal_conv1d_update_prefill")?,
309            conv1d_prefill_tp_k: super::super::try_kernel(
310                gpu,
311                "causal_conv1d",
312                "causal_conv1d_update_prefill_tp",
313            ),
314            gdn_chunk2_k: gpu.kernel("gated_delta_rule", "gated_delta_rule_chunk2")?,
315            conv1d_chunk2_k: gpu.kernel("causal_conv1d", "causal_conv1d_update_chunk2")?,
316            gdn_chunk3_k: gpu.kernel("gated_delta_rule", "gated_delta_rule_chunk3")?,
317            w4a16_gemv_batch3_k: gpu.kernel("w4a16_gemv", "w4a16_gemv_batch3")?,
318            gdn_wy2_k: gpu.kernel("gated_delta_rule_wy", "gated_delta_rule_wy2")?,
319            // Register-resident wy2 twin (own gb10-common module so non-gb10
320            // targets simply resolve 0 and keep the base wy2 — try_kernel
321            // misses are a silent handle 0, so `wy2_kernel` logs the
322            // resolution outcome once at first K=2 dispatch).
323            gdn_wy2_resident_k: super::super::try_kernel(
324                gpu,
325                "gated_delta_rule_wy2_resident",
326                "gated_delta_rule_wy2_resident",
327            ),
328            gdn_wy3_k: gpu.kernel("gated_delta_rule_wy3", "gated_delta_rule_wy3")?,
329            // Register-resident wy3 twin (same pattern as wy2's above:
330            // try_kernel so non-gb10 targets resolve 0 and keep base wy3;
331            // `wy3_kernel` logs the resolution outcome at first K=3 dispatch).
332            gdn_wy3_resident_k: super::super::try_kernel(
333                gpu,
334                "gated_delta_rule_wy3_resident",
335                "gated_delta_rule_wy3_resident",
336            ),
337            gdn_wy4_k: gpu.kernel("gated_delta_rule_wy4", "gated_delta_rule_wy4")?,
338            // ── ATLAS_SSM_H_FP16 stage 2: FP16 h-state twins of the MTP
339            // verify WY kernels. try_kernel for the same reason as the
340            // resident twins above — a miss is a silent handle 0, and the
341            // selectors gate on `.0 != 0` before ever picking one. Without
342            // these the flag and `--speculative` are mutually exclusive,
343            // because every WY kernel above writes the state as FP32 and an
344            // FP32 kernel over an FP16 pool produces fluent garbage, not an
345            // error. Preflight refuses the combination unless the K values the
346            // configured draft count can reach all have a twin here.
347            gdn_wy2_f16_k: super::super::try_kernel(
348                gpu,
349                "gated_delta_rule_wy_f16",
350                "gated_delta_rule_wy2_f16",
351            ),
352            gdn_wy2_resident_f16_k: super::super::try_kernel(
353                gpu,
354                "gated_delta_rule_wy2_resident_f16",
355                "gated_delta_rule_wy2_resident_f16",
356            ),
357            gdn_wy3_f16_k: super::super::try_kernel(
358                gpu,
359                "gated_delta_rule_wy3_f16",
360                "gated_delta_rule_wy3_f16",
361            ),
362            gdn_wy3_resident_f16_k: super::super::try_kernel(
363                gpu,
364                "gated_delta_rule_wy3_resident_f16",
365                "gated_delta_rule_wy3_resident_f16",
366            ),
367            gdn_wy4_f16_k: super::super::try_kernel(
368                gpu,
369                "gated_delta_rule_wy4_f16",
370                "gated_delta_rule_wy4_f16",
371            ),
372            // STAGE 1 fused K=2 verify epilogue. Only present in the gb10
373            // common PTX module set; NULL on targets lacking the .cu, in which
374            // case the num_tokens==2 arm keeps the per-token path even when
375            // ATLAS_GDN_FUSED_VERIFY is set.
376            gdn_verify_fused_conv_k2_k: super::super::try_kernel(
377                gpu,
378                "gdn_verify_fused_k2",
379                "gdn_verify_fused_conv_k2",
380            ),
381            gdn_verify_fused_norm_k2_k: super::super::try_kernel(
382                gpu,
383                "gdn_verify_fused_k2",
384                "gdn_verify_fused_norm_k2",
385            ),
386            // Generic-K fused verify conv (K=17 DFlash arm). gb10 common
387            // module; NULL on targets lacking the .cu, in which case the
388            // K=17 arm keeps its per-token conv loop.
389            gdn_verify_fused_conv_kn_k: super::super::try_kernel(
390                gpu,
391                "gdn_verify_fused_conv_kn",
392                "gdn_verify_fused_conv_kn",
393            ),
394            // Batched twin (gridDim.y = n_seq) for batched speculative decoding.
395            gdn_verify_fused_conv_kn_batched_k: super::super::try_kernel(
396                gpu,
397                "gdn_verify_fused_conv_kn",
398                "gdn_verify_fused_conv_kn_batched",
399            ),
400            // Exact-verify `_snap` twins (#435): model-shadow staged
401            // (qwen3.6-27b/nvfp4), 0 elsewhere — the exact arm then uses the
402            // parent kernel + copy_d2d snapshots (same bits, more launches).
403            // Every other GDN target declares these three lookups in its
404            // MODEL.toml [expected_absent] (#438) — the boot gate fails closed.
405            gdn_f32_norm_snap_k: super::super::try_kernel(
406                gpu,
407                "gated_delta_rule_snap",
408                "gated_delta_rule_decode_f32_norm_snap",
409            ),
410            gdn_f32_strided_norm_snap_k: super::super::try_kernel(
411                gpu,
412                "gated_delta_rule_snap",
413                "gated_delta_rule_decode_f32_strided_norm_snap",
414            ),
415            gdn_verify_fused_conv_kn_f32_k: super::super::try_kernel(
416                gpu,
417                "gdn_verify_fused_conv_kn_f32",
418                "gdn_verify_fused_conv_kn_f32",
419            ),
420            // wy17 ships only in qwen3.6-35b-a3b's and qwen3.6-27b's PTX sets;
421            // NULL elsewhere (declared [expected_absent] in those MODEL.tomls).
422            // decode_batched(K=17) checks for non-NULL before dispatching the fused path.
423            gdn_wy17_k: super::super::try_kernel(
424                gpu,
425                "gated_delta_rule_wy17",
426                "gated_delta_rule_wy17",
427            ),
428            gdn_wyn_k: init_kernels::wyn_kernels(gpu),
429            gdn_wyn_f16_k: init_kernels::wyn_f16_kernels(gpu),
430            h_state_bytes: nv * vd * kd * 4, // FP32 [nv, kd, vd] transposed for coalescing
431            conv_state_bytes: conv_dim * d_conv * 4, // FP32 [conv_dim, d_conv]
432            qkvz_fp8: None,
433            out_proj_fp8: None,
434            fp8_gemm_k: gpu.kernel("w4a16", "fp8_gemm_t")?,
435            fp8_gemm_t_m128_k: gpu.kernel("w4a16", "fp8_gemm_t_m128")?,
436            w8a16_gemm_k: super::super::try_kernel(gpu, "w8a16_gemm", "w8a16_gemm"),
437            w8a16_gemm_pipelined_k: super::super::try_kernel(
438                gpu,
439                "w8a16_gemm_pipelined",
440                "w8a16_gemm_pipelined",
441            ),
442            w8a16_gemv_batch4_k: super::super::try_kernel(
443                gpu,
444                "w8a16_gemv_batch4",
445                "w8a16_gemv_batch4",
446            ),
447            w8a16_gemv_batch16_k: super::super::try_kernel(
448                gpu,
449                "w8a16_gemv_batch4",
450                "w8a16_gemv_batch16",
451            ),
452            // NVFP4 batched decode GEMV (all entries live in the w4a16_gemv module).
453            w4a16_batchm: crate::layers::w4a16_gemv_tiers::W4a16BatchmTiers::resolve(gpu),
454            w4a16_gemv_batch16_k: super::super::try_kernel(gpu, "w4a16_gemv", "w4a16_gemv_batch16"),
455            w8a16_gemm_t_k: super::super::try_kernel(gpu, "w8a16_gemm_t", "w8a16_gemm_t"),
456            per_token_group_quant_fp8_k: ops::Fp8ActQuant::resolve(gpu),
457            fp8_gemm_t_blockscaled_k: super::super::try_kernel(
458                gpu,
459                "fp8_gemm_t_blockscaled",
460                "fp8_gemm_t_blockscaled",
461            ),
462            fp8_act_scale_kmajor_k: super::super::try_kernel(
463                gpu,
464                "fp8_scale_transpose",
465                "fp8_act_scale_to_kmajor",
466            ),
467        })
468    }
469
470    // `new_sequential` moved to `init_sequential.rs` (≤500 LoC split).
471}
472
473#[path = "init_kernels.rs"]
474mod init_kernels;
475use init_kernels::{fused_spine_kernel, gdn_prefill_tc_kernel, hc_kernel};
476
477#[path = "init_sequential.rs"]
478mod init_sequential;