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