Skip to main content

logicaffeine_compile/codegen_cuda/
qwen38.rs

1//! Qwen3.8-27B authored in LOGOS.
2//!
3//! The model is a **hybrid**: of its 64 layers, 48 are Gated DeltaNet (a fixed-size associative memory,
4//! rewritten per token) and 16 are gated attention (a growing KV cache). `full_attention_interval = 4` puts
5//! the attention layers at indices 3, 7, 11 … 63. That 3:1 ratio is why the model caches only a quarter of
6//! its depth, and it is what makes the checkpoint cheap to run relative to its parameter count.
7//!
8//! [`gen_qwen38_lg`] emits the whole forward as a `.lg` program — the artifact the claim "authored in LOGOS"
9//! rests on. Every line is ordinary LOGOS tensor sugar; nothing here is a compiler intrinsic. Following the
10//! Qwen3-30B precedent the `.lg` is the SINGLE-TOKEN forward (KV caches declared one row deep), and the
11//! generation harness is what grows the cache and replays the step.
12
13use crate::model::author::{self, Authored, RowState, TpAuthored};
14
15/// Everything the emitter needs, read from the checkpoint rather than assumed. Field names mirror the GGUF
16/// metadata keys so a mismatch is easy to spot.
17#[derive(Debug, Clone)]
18pub struct Qwen38Cfg {
19    pub d: usize,               // embedding_length            5120
20    pub layers: usize,          // model layers (block_count − nextn_predict_layers)  64
21    pub full_attn_every: usize, // full_attention_interval     4
22    pub dff: usize,             // feed_forward_length         17408
23    pub vocab: usize,           // 248320, untied
24    // gated attention
25    pub h: usize,        // attention.head_count        24
26    pub kv: usize,       // attention.head_count_kv     4
27    pub hd: usize,       // attention.key_length        256
28    pub rope_dim: usize, // rope.dimension_count        64  (PARTIAL: 64 of 256)
29    pub rope_theta: f64, // rope.freq_base              1e7
30    pub rms_eps: f64,    // 1e-6
31    // gated deltanet
32    pub gdn_k_heads: usize,  // ssm.group_count             16
33    pub gdn_v_heads: usize,  // ssm.time_step_rank          48
34    pub gdn_head_dim: usize, // ssm.state_size              128
35    pub conv_taps: usize,    // ssm.conv_kernel             4
36    pub ctx_len: usize,      // context_length              262144
37}
38
39impl Qwen38Cfg {
40    /// The real Qwen3.8-27B shape, as read from `Qwen3.8-27B-Q8_0.gguf` (see `benchmarks/results/qwen38_arch.json`).
41    pub fn real() -> Self {
42        Qwen38Cfg {
43            d: 5120,
44            layers: 64,
45            full_attn_every: 4,
46            dff: 17408,
47            vocab: 248320,
48            h: 24,
49            kv: 4,
50            hd: 256,
51            rope_dim: 64,
52            rope_theta: 1.0e7,
53            rms_eps: 1e-6,
54            gdn_k_heads: 16,
55            gdn_v_heads: 48,
56            gdn_head_dim: 128,
57            conv_taps: 4,
58            ctx_len: 262144,
59        }
60    }
61    /// A structurally faithful miniature — same op sequence, same hybrid schedule, tiny dimensions. Used to
62    /// exercise the whole authored program on every backend without 29 GB of weights.
63    pub fn tiny() -> Self {
64        Qwen38Cfg {
65            d: 8,
66            layers: 4,
67            full_attn_every: 4,
68            dff: 16,
69            vocab: 32,
70            h: 2,
71            kv: 1,
72            hd: 4,
73            rope_dim: 2,
74            rope_theta: 1.0e7,
75            rms_eps: 1e-6,
76            gdn_k_heads: 1,
77            gdn_v_heads: 2,
78            gdn_head_dim: 4,
79            conv_taps: 4,
80            ctx_len: 64,
81        }
82    }
83    /// [`Qwen38Cfg::tiny`] with the real model's HEAD PATTERN at a size that splits: 8 query heads over 2 KV heads and
84    /// 4/8 Gated-DeltaNet heads, so it admits 2 and 4 chips of tensor parallelism — at 4 each KV head is replicated on
85    /// two chips, as the real model's 4 KV heads are over its 8.
86    pub fn mini() -> Self {
87        Qwen38Cfg {
88            h: 8,
89            kv: 2,
90            gdn_k_heads: 4,
91            gdn_v_heads: 8,
92            ..Qwen38Cfg::tiny()
93        }
94    }
95    /// GDN q/k width — `k_heads · head_dim`.
96    pub fn gdn_qk(&self) -> usize {
97        self.gdn_k_heads * self.gdn_head_dim
98    }
99    /// GDN v/gate width — `v_heads · head_dim` (`ssm.inner_size`).
100    pub fn gdn_v(&self) -> usize {
101        self.gdn_v_heads * self.gdn_head_dim
102    }
103    /// Attention query width — `h · hd`.
104    pub fn aq(&self) -> usize {
105        self.h * self.hd
106    }
107    /// Attention K/V width — `kv · hd`.
108    pub fn akv(&self) -> usize {
109        self.kv * self.hd
110    }
111    /// Layer `l` is full attention when `(l+1) % full_attn_every == 0` — indices 3, 7, 11 … for interval 4.
112    /// The configuration of a checkpoint's own spec: a Qwen3.5/3.8 hybrid, its attention every `full_attn_every`-th
113    /// layer, every attention layer alike, every Gated-DeltaNet layer alike, every FFN a dense SwiGLU. Refused by name
114    /// for anything else — and refused unless the configuration writes the checkpoint's own program, the decode step
115    /// the author writes for `spec` (`model::program`), so no bundle lowered from it can be another model's.
116    pub fn from_spec(spec: &crate::model::spec::ModelSpec) -> Result<Qwen38Cfg, author::NotYet> {
117        use crate::model::spec::{Act, Ffn, Mixer, RopeScaling};
118        use author::NotYet;
119        if spec.arch != "qwen35" {
120            return Err(NotYet("a model other than a Qwen3.5/3.8 hybrid, which the spatial lowering is written for"));
121        }
122        let every = spec
123            .layers
124            .iter()
125            .position(|l| matches!(l.mixer, Mixer::Attention(_)))
126            .map(|l| l + 1)
127            .ok_or(NotYet("a hybrid with no attention layer"))?;
128        let attention = spec.layers.iter().find_map(|l| match &l.mixer {
129            Mixer::Attention(a) => Some(a.clone()),
130            _ => None,
131        });
132        let delta = spec.layers.iter().find_map(|l| match &l.mixer {
133            Mixer::GatedDelta(g) => Some(g.clone()),
134            _ => None,
135        });
136        let (Some(a), Some(g)) = (attention, delta) else {
137            return Err(NotYet("a hybrid without both attention and Gated-DeltaNet layers"));
138        };
139        let rope = a.rope.as_ref().ok_or(NotYet("attention without a rotation"))?;
140        if !rope.neox || rope.scaling != RopeScaling::None {
141            return Err(NotYet("a rotation other than an unscaled NEOX one"));
142        }
143        let dff = match &spec.layers[0].ffn {
144            Ffn::Dense { dff, act: Act::Silu } => *dff,
145            _ => return Err(NotYet("a feed-forward block other than a dense SwiGLU")),
146        };
147        for (l, layer) in spec.layers.iter().enumerate() {
148            let alike = match &layer.mixer {
149                Mixer::Attention(x) => (l + 1) % every == 0 && *x == a,
150                Mixer::GatedDelta(x) => (l + 1) % every != 0 && *x == g,
151                Mixer::Mla(_) => false,
152            };
153            if !alike || layer.ffn != (Ffn::Dense { dff, act: Act::Silu }) || layer.post_mixer_norm || layer.post_ffn_norm {
154                return Err(NotYet("a layer unlike the hybrid's pattern of alike attention and Gated-DeltaNet layers"));
155            }
156        }
157        let cfg = Qwen38Cfg {
158            d: spec.d,
159            layers: spec.layers.len(),
160            full_attn_every: every,
161            dff,
162            vocab: spec.vocab,
163            h: a.heads,
164            kv: a.kv_heads,
165            hd: a.head_dim,
166            rope_dim: rope.dims,
167            rope_theta: rope.theta,
168            rms_eps: spec.rms_eps,
169            gdn_k_heads: g.k_heads,
170            gdn_v_heads: g.v_heads,
171            gdn_head_dim: g.head_dim,
172            conv_taps: g.conv_taps,
173            ctx_len: spec.ctx_len,
174        };
175        let step = crate::model::program::Cut::Decode { ctx: 64 };
176        if crate::model::program::written(&cfg.spec(), step).1 != crate::model::program::written(spec, step).1 {
177            return Err(NotYet("a hybrid whose configuration would write a program other than the checkpoint's"));
178        }
179        Ok(cfg)
180    }
181
182    pub fn is_attn(&self, l: usize) -> bool {
183        (l + 1) % self.full_attn_every == 0
184    }
185    /// How many of the layers are attention (the rest are GDN).
186    pub fn attn_layers(&self) -> usize {
187        (0..self.layers).filter(|&l| self.is_attn(l)).count()
188    }
189
190    /// The model this configuration describes, as a `ModelSpec`: every `full_attn_every`-th layer gated attention
191    /// (partial NEOX rotation, QK-norm, a sigmoid output gate), the rest Gated DeltaNet, each with a dense SiLU FFN.
192    pub fn spec(&self) -> crate::model::spec::ModelSpec {
193        self.spec_of(self.layers)
194    }
195
196    /// The spec of this configuration reaching layer `l`: its layers, or as many more of its pattern as layer `l`
197    /// needs — the model a single-layer form of layer `l` is written from.
198    pub fn layer_spec(&self, l: usize) -> crate::model::spec::ModelSpec {
199        self.spec_of(self.layers.max(l + 1))
200    }
201
202    /// The spec of this configuration's first `layers` layers.
203    fn spec_of(&self, layers: usize) -> crate::model::spec::ModelSpec {
204        use crate::model::spec::{
205            Act, Attention, Ffn, GateActivation, GatedDelta, Layer, Mixer, ModelSpec, Rope, RopeScaling,
206        };
207        let attention = Attention {
208            heads: self.h,
209            kv_heads: self.kv,
210            head_dim: self.hd,
211            value_dim: self.hd,
212            rope: Some(Rope {
213                dims: self.rope_dim,
214                theta: self.rope_theta,
215                neox: true,
216                scaling: RopeScaling::None,
217                sections: None,
218            }),
219            qk_norm: true,
220            output_gate: true,
221            fused_qkv: false,
222            bias: false,
223            output_bias: false,
224            window: None,
225            sinks: false,
226            softcap: None,
227            scale: 1.0 / (self.hd as f64).sqrt(),
228            temperature: None,
229            qk_unit_norm: false,
230            qk_norm_whole: false,
231        };
232        let gdn = GatedDelta {
233            k_heads: self.gdn_k_heads,
234            v_heads: self.gdn_v_heads,
235            head_dim: self.gdn_head_dim,
236            conv_taps: self.conv_taps,
237            gate: GateActivation::Silu,
238        };
239        ModelSpec {
240            arch: "qwen35".to_string(),
241            d: self.d,
242            vocab: self.vocab,
243            ctx_len: self.ctx_len,
244            rms_eps: self.rms_eps,
245            embedding_scale: None,
246            tied_output: false,
247            final_logit_softcap: None,
248            layers: (0..layers)
249                .map(|l| Layer {
250                    mixer: if self.is_attn(l) {
251                        Mixer::Attention(attention.clone())
252                    } else {
253                        Mixer::GatedDelta(gdn.clone())
254                    },
255                    ffn: Ffn::Dense {
256                        dff: self.dff,
257                        act: Act::Silu,
258                    },
259                    post_mixer_norm: false,
260                    post_ffn_norm: false,
261                })
262                .collect(),
263            mtp_blocks: 0,
264            ffn_norm: "post_attention_norm",
265            hyper: None,
266            ple: None,
267            indexer: None,
268        }
269    }
270}
271
272/// The rotary cache for `rows` positions, `rope_dim / 2` pairs a row: row `p` (1-based) holds the cosines and the sines
273/// of `(p − 1)·θ^(−2i/rope_dim)` — the angles `gk_qk_norm_rope_part` turns 0-based position `p − 1` by, over the
274/// rotary width — each computed in f64 and rounded once.
275pub fn qwen38_rope_cache(cfg: &Qwen38Cfg, rows: usize) -> (Vec<f32>, Vec<f32>) {
276    let half = cfg.rope_dim / 2;
277    let angle =
278        |p: usize, i: usize| p as f64 * cfg.rope_theta.powf(-2.0 * i as f64 / cfg.rope_dim as f64);
279    let (mut cos, mut sin) = (
280        Vec::with_capacity(rows * half),
281        Vec::with_capacity(rows * half),
282    );
283    for p in 0..rows {
284        for i in 0..half {
285            let a = angle(p, i);
286            cos.push(a.cos() as f32);
287            sin.push(a.sin() as f32);
288        }
289    }
290    (cos, sin)
291}
292
293/// The authored forward ([`gen_qwen38_lg`]) with every declared tensor filled DETERMINISTICALLY right after
294/// its declaration (a hash of the element index salted by the tensor's name, in (-0.2, 0.2)) and the first
295/// and last logit shown — the self-contained program the demo corpus (`examples/rdu_demo/qwen38_tiny.lg`)
296/// and the tier-agreement locks run without a weight file. Fills follow declarations because the weights
297/// are declared per block, interleaved with the compute that reads them.
298pub fn gen_qwen38_filled_lg(cfg: &Qwen38Cfg, dir: &str) -> String {
299    let (authored, _f32w, _q8w) = gen_qwen38_lg(cfg, dir);
300    let mut src = String::new();
301    for line in authored.lines() {
302        src.push_str(line);
303        src.push('\n');
304        let Some(rest) = line.strip_prefix("Let ") else {
305            continue;
306        };
307        let Some((var, tail)) = rest.split_once(" be a ") else {
308            continue;
309        };
310        let Some(dims) = tail.strip_suffix(" tensor of Real.") else {
311            continue;
312        };
313        let (r, c) = dims.split_once(" by ").expect("R by C");
314        let n = r.parse::<usize>().expect("rows") * c.parse::<usize>().expect("cols");
315        let salt = var.bytes().map(|b| b as u64).sum::<u64>();
316        for i in 0..n {
317            let h = (i as u64)
318                .wrapping_mul(2654435761)
319                .wrapping_add(salt.wrapping_mul(40503));
320            let v = ((h % 97) as f64 / 97.0 - 0.5) * 0.4;
321            src.push_str(&format!("Set item {} of {var} to {v:?}.\n", i + 1));
322        }
323    }
324    src.push_str("Show round(item 1 of logits * 1000000).\n");
325    src.push_str(&format!(
326        "Show round(item {} of logits * 1000000).\n",
327        cfg.vocab
328    ));
329    src
330}
331
332// ── The Qwen3.8 programs ───────────────────────────────────────────────────────────────────────────────────────────
333//
334// Each form is the generic author's program for this configuration's spec (`model::author`, `Qwen38Cfg::spec`); the
335// names stay the model's entry points. `model_author_migration_lock` pins every one of them to the text they had
336// before the author took them over.
337
338/// The whole Qwen3.8 forward as a LOGOS program — the single token with no history — and its weight manifest.
339pub fn gen_qwen38_lg(cfg: &Qwen38Cfg, dir: &str) -> Authored {
340    author::forward(&cfg.spec(), dir)
341}
342
343/// One decode step: token `tok` at position `pos` (1-based) in, the next token out, the KV caches and the
344/// Gated-DeltaNet state carried. See [`author::decode_step`].
345pub fn gen_qwen38_decode_step_lg(cfg: &Qwen38Cfg, dir: &str, ctx: usize, tok: usize, pos: usize) -> Authored {
346    author::decode_step(&cfg.spec(), dir, ctx, tok, pos)
347}
348
349/// A prefill chunk of one sequence from position `pos0`. See [`author::prefill`].
350pub fn gen_qwen38_prefill_lg(cfg: &Qwen38Cfg, dir: &str, ctx: usize, toks: &[usize], pos0: usize) -> Authored {
351    author::prefill(&cfg.spec(), dir, ctx, toks, pos0)
352}
353
354/// B decode steps at once, each sequence with its own state. See [`author::decode_batch`].
355pub fn gen_qwen38_decode_batch_lg(cfg: &Qwen38Cfg, dir: &str, ctx: usize, seqs: &[(usize, usize)]) -> Authored {
356    author::decode_batch(&cfg.spec(), dir, ctx, seqs)
357}
358
359/// A batched decode step's embedding lookups alone.
360pub fn gen_qwen38_decode_batch_embed_lg(cfg: &Qwen38Cfg, dir: &str, toks: &[usize]) -> Authored {
361    author::decode_batch_embed(&cfg.spec(), dir, toks)
362}
363
364/// Layer `l` of a batched decode step alone.
365pub fn gen_qwen38_decode_batch_layer_lg(cfg: &Qwen38Cfg, l: usize, dir: &str, ctx: usize, poss: &[usize]) -> Authored {
366    author::stacked_layer(&cfg.layer_spec(l), l, dir, ctx, poss, RowState::PerSequence)
367}
368
369/// Layer `l` of a prefill chunk of `chunk` rows from `pos0` alone.
370pub fn gen_qwen38_prefill_layer_lg(cfg: &Qwen38Cfg, l: usize, dir: &str, ctx: usize, pos0: usize, chunk: usize) -> Authored {
371    let poss: Vec<usize> = (pos0..pos0 + chunk).collect();
372    author::stacked_layer(&cfg.layer_spec(l), l, dir, ctx, &poss, RowState::Shared)
373}
374
375/// A prefill chunk's head alone.
376pub fn gen_qwen38_prefill_head_lg(cfg: &Qwen38Cfg, dir: &str, chunk: usize) -> Authored {
377    author::prefill_head(&cfg.spec(), dir, chunk)
378}
379
380/// A batched decode step's head alone.
381pub fn gen_qwen38_decode_batch_head_lg(cfg: &Qwen38Cfg, dir: &str, bsz: usize) -> Authored {
382    author::decode_batch_head(&cfg.spec(), dir, bsz)
383}
384
385/// A decode step's embedding lookup alone.
386pub fn gen_qwen38_decode_embed_lg(cfg: &Qwen38Cfg, dir: &str, tok: usize) -> Authored {
387    author::decode_embed(&cfg.spec(), dir, tok)
388}
389
390/// A decode step's head alone: the final norm, the LM head and the arg-max.
391pub fn gen_qwen38_decode_head_lg(cfg: &Qwen38Cfg, dir: &str) -> Authored {
392    author::decode_head(&cfg.spec(), dir)
393}
394
395/// Layer `l` alone, as the forward writes it.
396pub fn gen_qwen38_layer_lg(cfg: &Qwen38Cfg, l: usize, dir: &str) -> Authored {
397    author::layer(&cfg.layer_spec(l), l, dir)
398}
399
400/// Layer `l` of a decode step alone, its attention reading a KV cache of `ctx` positions up to `pos`.
401pub fn gen_qwen38_decode_layer_lg(cfg: &Qwen38Cfg, l: usize, dir: &str, ctx: usize, pos: usize) -> Authored {
402    author::decode_layer(&cfg.layer_spec(l), l, dir, ctx, pos)
403}
404
405/// The final norm and LM head alone.
406pub fn gen_qwen38_head_lg(cfg: &Qwen38Cfg, dir: &str) -> Authored {
407    author::head(&cfg.spec(), dir)
408}
409
410/// The spec split over `tp` chips; `tp` must be a width the model admits (`spatial::fit::qwen38_admits_tp`).
411fn split(cfg: &Qwen38Cfg, tp: usize, form: Result<TpAuthored, author::NotYet>) -> TpAuthored {
412    form.unwrap_or_else(|e| panic!("Qwen3.8 does not split over {tp} chips ({cfg:?}): {e}"))
413}
414
415/// A whole decode step, tensor-parallel over `tp` chips. See [`author::tp_decode_step`].
416pub fn gen_qwen38_tp_decode_step_lg(cfg: &Qwen38Cfg, dir: &str, ctx: usize, tok: usize, pos: usize, tp: usize) -> TpAuthored {
417    split(cfg, tp, author::tp_decode_step(&cfg.spec(), dir, ctx, tok, pos, tp))
418}
419
420/// A batched decode step, tensor-parallel over `tp` chips. See [`author::tp_decode_batch`].
421pub fn gen_qwen38_decode_batch_tp_lg(cfg: &Qwen38Cfg, dir: &str, ctx: usize, seqs: &[(usize, usize)], tp: usize) -> TpAuthored {
422    split(cfg, tp, author::tp_decode_batch(&cfg.spec(), dir, ctx, seqs, tp))
423}
424
425/// Layer `l` of a batched tensor-parallel decode step alone.
426pub fn gen_qwen38_decode_batch_tp_layer_lg(cfg: &Qwen38Cfg, l: usize, dir: &str, ctx: usize, poss: &[usize], tp: usize) -> TpAuthored {
427    split(cfg, tp, author::tp_stacked_layer(&cfg.layer_spec(l), l, dir, ctx, poss, tp))
428}
429
430/// Layer `l` of a tensor-parallel decode step alone.
431pub fn gen_qwen38_tp_decode_layer_lg(cfg: &Qwen38Cfg, l: usize, dir: &str, ctx: usize, pos: usize, tp: usize) -> TpAuthored {
432    split(cfg, tp, author::tp_decode_layer(&cfg.layer_spec(l), l, dir, ctx, pos, tp))
433}
434
435/// Emit a self-contained CUDA program that generates from the real Qwen3.8-27B weights and reports throughput.
436///
437/// ## Where the speed comes from
438///
439/// A dense 27B at Q8_0 reads ~27 GB of weights per token, so batch-1 decode is bandwidth-bound and the GEMV
440/// is ~90% of the work. Three things follow, and the emitter is built around them:
441///
442///  1. **One GEMV per activation, not four.** `extract_qwen38` concatenates every projection that shares an
443///     activation into a single matrix (`qkvz`, `qgkv`, `gu`), so a GDN layer's q/k/v/z is ONE launch over
444///     16384 output rows with no branching, and the FFN's gate+up is one launch over 34816.
445///  2. **One CUDA graph for the whole token.** ~800 kernels per token at a few µs of launch overhead each is
446///     milliseconds against a ~24 ms budget. The decode step is captured once and replayed, with the sampled
447///     token and the position advanced ON DEVICE (`gk_argmax_adv`) so no replay needs a host round trip.
448///  3. **Fusion past what a per-operator graph can express.** The conv carries its silu, both GDN gates come
449///     from one launch, the recurrence touches its memory once (see `gdn.rs`), and the residual add, the next
450///     RMSNorm and the activation re-quantization are a single kernel.
451///
452/// `precise` swaps the split-K flash attention for the byte-exact multi-pass kernel — slower, but it does not
453/// reorder float additions, so it is the lane to check a token stream against llama.cpp with.
454/// `deq` selects how much of the decode keeps its activations in f32 instead of quantizing them to int8:
455/// 0 = none (dp4a everywhere), 1 = the LM head only, 2 = every Q8_0 GEMV.
456///
457/// At batch 1 this is nearly free. A GEMV reads a whole weight matrix and ONE activation vector, so the
458/// activation contributes no measurable traffic and quantizing it saves no bandwidth — it only lets the
459/// inner loop use `dp4a`. The dequantizing form costs ~3 float ops per weight instead of a quarter of a
460/// dp4a, which at 1400 GB/s works out to about 4 TFLOP/s against the A100's 19.5: still memory bound. What
461/// it buys is the removal of the activation quantization error entirely.
462pub fn emit_qwen38_generate(
463    cfg: &Qwen38Cfg,
464    wdir: &str,
465    prompt: &[usize],
466    n_gen: usize,
467    precise: bool,
468    deq: u8,
469) -> String {
470    let debug = std::env::var("LOGOS_Q38_DEBUG").is_ok();
471    let (d, dff, taps) = (cfg.d, cfg.dff, cfg.conv_taps);
472    let (qk, vw) = (cfg.gdn_qk(), cfg.gdn_v());
473    let (aq, akv) = (cfg.aq(), cfg.akv());
474    let (nk, nv, ghd) = (cfg.gdn_k_heads, cfg.gdn_v_heads, cfg.gdn_head_dim);
475    let convc = 2 * qk + vw; // channels the conv covers: q|k|v
476    let projw = 2 * qk + 2 * vw; // q|k|v|z
477    let attnw = 2 * aq + 2 * akv; // q|gate|k|v
478    let maxseq = prompt.len() + n_gen + 128;
479    let scale = 1.0f64 / (cfg.hd as f64).sqrt();
480    let prompt_c = prompt
481        .iter()
482        .map(|t| t.to_string())
483        .collect::<Vec<_>>()
484        .join(",");
485    let attn_split = 4usize;
486
487    // ── weight tables, per layer, loaded from the files the extractor wrote ──
488    let mut decls = String::new();
489    let mut loads = String::new();
490    let q8 = |decls: &mut String, loads: &mut String, var: &str, out: usize, inn: usize| {
491        let (qn, sn) = (out * inn, out * inn / 32);
492        decls.push_str(&format!(
493            "static signed char* {var}_q; static __half* {var}_s;\n"
494        ));
495        loads.push_str(&format!(
496            "  LDQ({var}, {qn}, {sn}, \"{wdir}/{var}.q\", \"{wdir}/{var}.s\");\n"
497        ));
498    };
499    let f32t = |decls: &mut String, loads: &mut String, var: &str, n: usize| {
500        decls.push_str(&format!("static float* {var}_f;\n"));
501        loads.push_str(&format!("  LDF({var}, {n}, \"{wdir}/{var}.f\");\n"));
502    };
503    q8(&mut decls, &mut loads, "emb", cfg.vocab, d);
504    q8(&mut decls, &mut loads, "Wout", cfg.vocab, d);
505    f32t(&mut decls, &mut loads, "on", d);
506    for l in 0..cfg.layers {
507        f32t(&mut decls, &mut loads, &format!("an{l}"), d);
508        f32t(&mut decls, &mut loads, &format!("fn{l}"), d);
509        if cfg.is_attn(l) {
510            q8(&mut decls, &mut loads, &format!("qgkv{l}"), attnw, d);
511            f32t(&mut decls, &mut loads, &format!("Qn{l}"), cfg.hd);
512            f32t(&mut decls, &mut loads, &format!("Kn{l}"), cfg.hd);
513            q8(&mut decls, &mut loads, &format!("Wo{l}"), d, aq);
514        } else {
515            q8(&mut decls, &mut loads, &format!("qkvz{l}"), projw, d);
516            f32t(&mut decls, &mut loads, &format!("ba{l}"), 2 * nv * d);
517            f32t(&mut decls, &mut loads, &format!("Wc{l}"), taps * convc);
518            f32t(&mut decls, &mut loads, &format!("Al{l}"), nv);
519            f32t(&mut decls, &mut loads, &format!("Dt{l}"), nv);
520            f32t(&mut decls, &mut loads, &format!("Gn{l}"), ghd);
521            q8(&mut decls, &mut loads, &format!("Wo{l}"), d, vw);
522        }
523        q8(&mut decls, &mut loads, &format!("gu{l}"), 2 * dff, d);
524        q8(&mut decls, &mut loads, &format!("Wd{l}"), d, dff);
525    }
526
527    // ── per-layer state: KV caches for the 16 attention layers, memories + conv rings for the 48 GDN ones ──
528    let mut state_decl = String::new();
529    let mut state_alloc = String::new();
530    for l in 0..cfg.layers {
531        if cfg.is_attn(l) {
532            state_decl.push_str(&format!("static float *kc{l}, *vc{l};\n"));
533            state_alloc.push_str(&format!(
534                "  cudaMalloc(&kc{l},(size_t){maxseq}*{akv}*4); cudaMalloc(&vc{l},(size_t){maxseq}*{akv}*4);\n"
535            ));
536        } else {
537            state_decl.push_str(&format!("static float *st{l}, *cs{l};\n"));
538            state_alloc.push_str(&format!(
539                "  cudaMalloc(&st{l},(size_t){vw}*{ghd}*4); cudaMemset(st{l},0,(size_t){vw}*{ghd}*4);\n\
540                 \x20 cudaMalloc(&cs{l},(size_t){taps}*{convc}*4); cudaMemset(cs{l},0,(size_t){taps}*{convc}*4);\n"
541            ));
542        }
543    }
544
545    // ── the decode step: one token through 64 layers, emitted as straight-line launches on stream `s` ──
546    let fast_attn = if precise {
547        format!("gk_attn<<<{h},256,(size_t){maxseq}*4,s>>>(attnb,pbuf,kc{{L}},vc{{L}},d_pos,{h},{kv},{hd},SCALEV);", h = cfg.h, kv = cfg.kv, hd = cfg.hd)
548    } else {
549        format!("gk_attn_part<<<{h}*{p},256,0,s>>>(pbuf,kc{{L}},vc{{L}},d_pos,{h},{kv},{hd},SCALEV,{p},acc_part,m_part,d_part); \
550                 gk_attn_comb<<<{h},128,0,s>>>(attnb,{h},{hd},{p},acc_part,m_part,d_part);", h = cfg.h, kv = cfg.kv, hd = cfg.hd, p = attn_split)
551    };
552    // deq==2 keeps EVERY activation in f32. Each Q8 GEMV is paired with the f32 buffer its int8 operand was
553    // quantized from, so the pairing is mechanical: whatever kernel produced `aqE/asE` also produced `x_f32`,
554    // `attnb` is what `gk_quant_act` read, `gnbuf` is what the gate norm wrote, `x2n` is the post-attention
555    // norm, and the SwiGLU hadamard lands in `hfbuf`. The quantization steps they replace disappear.
556    let all_deq = deq == 2;
557    // deq==3 is the two-pass int8 lane: every activation carries a second int8 word, so the GEMV stays on
558    // dp4a while the activation it reads is 254x closer to the f32 value the norm actually produced.
559    let hl = deq == 3;
560    // Two output rows per warp. Off by default until a chip has been measured with it.
561    let wide = std::env::var("LOGOS_Q38_WIDE").is_ok();
562    // Unroll two K-blocks per iteration. Bit-identical, so it is a pure scheduling choice.
563    let unroll = std::env::var("LOGOS_Q38_U2").is_ok();
564    let unroll4 = std::env::var("LOGOS_Q38_U4").is_ok();
565    // Split-K, applied ONLY to projections narrow enough to leave the machine idle. The wide matrices
566    // (qkvz N=16384, gu N=34816, the LM head N=248320) already saturate and gain nothing from splitting.
567    let splitk: usize = std::env::var("LOGOS_Q38_SPLITK")
568        .ok()
569        .and_then(|s| s.parse().ok())
570        .unwrap_or(0);
571    let nval = move |n: &str| -> usize {
572        if n == "E" {
573            d
574        } else {
575            n.parse().unwrap_or(usize::MAX)
576        }
577    };
578    let narrow = move |n: &str| splitk > 1 && nval(n) <= 8192;
579    let gemv = |y: &str, w: &str, aq: &str, f32src: &str, k: &str, n: &str| -> String {
580        if all_deq {
581            format!("gk_gemv_deq_h<<<Gw({n}),256,0,s>>>({y},{w}_q,{w}_s,{f32src},{k},{n});")
582        } else if hl {
583            // `aq` names the "<hi>,<scale>" pair; the low word is the hi buffer's name with an `l` suffix.
584            let (h, sc) = aq.split_once(',').expect("activation pair");
585            if narrow(n) {
586                format!("gk_gemv_hl_sk<<<dim3(Gw({n}),{splitk}),256,0,s>>>(skbuf,{w}_q,{w}_s,{h},{h}l,{sc},{k},{n},{splitk});\n\
587                 \x20 gk_sk_combine<<<Gs({n}),256,0,s>>>({y},skbuf,{n},{splitk});")
588            } else if wide {
589                format!("gk_gemv_hl2<<<Gw2({n}),256,0,s>>>({y},{w}_q,{w}_s,{h},{h}l,{sc},{k},{n});")
590            } else if unroll4 {
591                format!("gk_gemv_hlu4<<<Gw({n}),256,0,s>>>({y},{w}_q,{w}_s,{h},{h}l,{sc},{k},{n});")
592            } else if unroll {
593                format!("gk_gemv_hlu<<<Gw({n}),256,0,s>>>({y},{w}_q,{w}_s,{h},{h}l,{sc},{k},{n});")
594            } else {
595                format!("gk_gemv_hl<<<Gw({n}),256,0,s>>>({y},{w}_q,{w}_s,{h},{h}l,{sc},{k},{n});")
596            }
597        } else if wide {
598            format!("gk_gemv_h2<<<Gw2({n}),256,0,s>>>({y},{w}_q,{w}_s,{aq},{k},{n});")
599        } else if unroll {
600            format!("gk_gemv_hu<<<Gw({n}),256,0,s>>>({y},{w}_q,{w}_s,{aq},{k},{n});")
601        } else {
602            format!("gk_gemv_h<<<Gw({n}),256,0,s>>>({y},{w}_q,{w}_s,{aq},{k},{n});")
603        }
604    };
605    let mut step = String::new();
606    for l in 0..cfg.layers {
607        // Layer 0 is entered straight from the embedding; every other layer is entered from the previous
608        // layer's residual, and the entry norm absorbs that add rather than paying a launch for it.
609        let entry = if hl {
610            // Every entry norm emits the f32 side output too: the two-word split is computed from it, and
611            // the GDN body already wanted it for the tiny f32-weight gate projection.
612            if l == 0 {
613                format!("gk_rmsnorm_q8f_hl<<<1,256,0,s>>>(x,aqE,aqEl,asE,x_f32,an{l}_f,E,EPSV);")
614            } else {
615                format!("gk_add_rmsnorm_q8f_hl<<<1,256,0,s>>>(x,tmp,aqE,aqEl,asE,x_f32,an{l}_f,E,EPSV);")
616            }
617        } else if cfg.is_attn(l) && all_deq {
618            if l == 0 {
619                format!("gk_rmsnorm_q8f<<<1,256,0,s>>>(x,aqE,asE,x_f32,an{l}_f,E,EPSV);")
620            } else {
621                format!("gk_add_rmsnorm_q8f<<<1,256,0,s>>>(x,tmp,aqE,asE,x_f32,an{l}_f,E,EPSV);")
622            }
623        } else if cfg.is_attn(l) {
624            if l == 0 {
625                format!("gk_rmsnorm_q8<<<1,256,0,s>>>(x,aqE,asE,an{l}_f,E,EPSV);")
626            } else {
627                format!("gk_add_rmsnorm_q8a<<<1,256,0,s>>>(x,tmp,aqE,asE,an{l}_f,E,EPSV);")
628            }
629        } else if l == 0 {
630            format!("gk_rmsnorm_q8f<<<1,256,0,s>>>(x,aqE,asE,x_f32,an{l}_f,E,EPSV);")
631        } else {
632            format!("gk_add_rmsnorm_q8f<<<1,256,0,s>>>(x,tmp,aqE,asE,x_f32,an{l}_f,E,EPSV);")
633        };
634        if cfg.is_attn(l) {
635            step.push_str(&format!(
636                "  {entry}\n\
637                 \x20 {g_qgkv}\n\
638                 \x20 gk_kv_store<<<Gs({akv}*2),256,0,s>>>(kc{l},vc{l},d_pos,{akv},pbuf+{two_aq});\n\
639                 \x20 gk_qk_norm_rope_part<<<{h},128,0,s>>>(pbuf,d_zero,0,Qn{l}_f,{h},{hd},{rot},ROPEV,EPSV);\n\
640                 \x20 gk_qk_norm_rope_part<<<{kv},128,0,s>>>(kc{l},d_pos,{akv},Kn{l}_f,{kv},{hd},{rot},ROPEV,EPSV);\n\
641                 \x20 {attn}\n\
642                 \x20 gk_gate_mul<<<Gs({aq}),256,0,s>>>(attnb,pbuf+{aq},{aq});\n\
643                 \x20 {q_attn}{g_wo_attn}\n",
644                attn = fast_attn.replace("{L}", &l.to_string()),
645                two_aq = 2 * aq, h = cfg.h, kv = cfg.kv, hd = cfg.hd, rot = cfg.rope_dim, entry = entry,
646                g_qgkv = gemv("pbuf", &format!("qgkv{l}"), "aqE,asE", "x_f32", "E", &attnw.to_string()),
647                q_attn = if all_deq { String::new() }
648                    else if hl { format!("gk_quant_act_hl<<<Gs({aq}),256,0,s>>>(attnb,aqQ,aqQl,asQ,{aq});\n  ") }
649                    else { format!("gk_quant_act<<<Gs({aq}),256,0,s>>>(attnb,aqQ,asQ,{aq});\n  ") },
650                g_wo_attn = gemv("tmp", &format!("Wo{l}"), "aqQ,asQ", "attnb", &aq.to_string(), "E"),
651            ));
652        } else {
653            step.push_str(&format!(
654                "  {entry}\n\
655                 \x20 {p0}\
656                 \x20 {g_qkvz}\n\
657                 \x20 gk_gemv_f32w<<<Gw({two_nv}),256,0,s>>>(gbuf,ba{l}_f,x_f32,E,{two_nv});\n\
658                 \x20 {p1}gk_conv_silu_l2<<<{convc}/{ghd},{ghd},0,s>>>(pbuf,Wc{l}_f,cs{l},cbuf,{convc},{taps},{two_nk},EPSV);\n\
659                 \x20 {p2}\
660                 \x20 gk_gdn_gates<<<Gs({nv}),256,0,s>>>(gbuf,gbuf+{nv},Dt{l}_f,Al{l}_f,betab,decayb,{nv});\n\
661                 \x20 {p3}\
662                                  \x20 gdn_step<<<dim3({nv},({ghd}+3)/4),128,0,s>>>(cbuf,cbuf+{qk},cbuf+{two_qk},betab,decayb,st{l},obuf,{ghd},{nk});\n\
663                 \x20 {gate_norm}\n\
664                 \x20 {p4}\
665                 \x20 {g_wo_gdn}\n\
666                 \x20 {p5}\n",
667                p1 = if debug && l == 0 { "gk_dbg3<<<1,32,0,s>>>(pbuf,dbg+3*72); " } else { "" },
668                p3 = if debug && l == 0 { "gk_dbg3<<<1,32,0,s>>>(betab,dbg+3*74); gk_dbg3<<<1,32,0,s>>>(decayb,dbg+3*75);" } else { "" },
669                p4 = if debug && l == 0 { "gk_dbg3<<<1,32,0,s>>>(obuf,dbg+3*76); gk_dbg3<<<1,32,0,s>>>(gnbuf,dbg+3*77);" } else { "" },
670                p5 = if debug && l == 0 { "gk_dbg3<<<1,32,0,s>>>(tmp,dbg+3*78);" } else { "" },
671                p2 = if debug && l == 0 { "gk_dbg3<<<1,32,0,s>>>(cbuf,dbg+3*73);" } else { "" },
672                p0 = if debug && l == 0 {
673                    "gk_dbg3<<<1,32,0,s>>>(x,dbg+3*70); gk_dbg3<<<1,32,0,s>>>(x_f32,dbg+3*71);"
674                } else { "" },
675                two_nv = 2 * nv, two_nk = 2 * nk, two_qk = 2 * qk, entry = entry,
676                g_qkvz = gemv("pbuf", &format!("qkvz{l}"), "aqE,asE", "x_f32", "E", &projw.to_string()),
677                g_wo_gdn = gemv("tmp", &format!("Wo{l}"), "aqQ,asQ", "gnbuf", &vw.to_string(), "E"),
678                gate_norm = if hl {
679                    format!("gdn_gate_norm_hl<<<{nv},{ghd},0,s>>>(pbuf+{off},Gn{l}_f,obuf,gnbuf,aqQ,aqQl,asQ,{ghd},EPSV);", off = 2 * qk + vw)
680                } else if all_deq {
681                    format!("gdn_gate_norm<<<{nv},{ghd},0,s>>>(pbuf+{off},Gn{l}_f,obuf,gnbuf,{ghd},EPSV);", off = 2 * qk + vw)
682                } else {
683                    format!("gdn_gate_norm_q<<<{nv},{ghd},0,s>>>(pbuf+{off},Gn{l}_f,obuf,gnbuf,aqQ,asQ,{ghd},EPSV);", off = 2 * qk + vw)
684                },
685            ));
686        }
687        // shared tail — residual + post-norm + requantize in ONE kernel, then the dense SwiGLU FFN
688        step.push_str(&format!(
689            "  {tail_norm}\n\
690             \x20 {g_gu}\n\
691             \x20 {had}\n\
692             \x20 {g_wd}\n\
693             \x20 {resid}",
694            tail_norm = if hl { format!("gk_add_rmsnorm_q8_hl<<<1,256,0,s>>>(x,tmp,x2n,fn{l}_f,ffQ,ffQl,ffS,E,EPSV);") }
695                        else { format!("gk_add_rmsnorm_q8<<<1,256,0,s>>>(x,tmp,x2n,fn{l}_f,ffQ,ffS,E,EPSV);") },
696            g_gu = gemv("ffbuf", &format!("gu{l}"), "ffQ,ffS", "x2n", "E", &(2 * dff).to_string()),
697            g_wd = gemv("tmp", &format!("Wd{l}"), "hqQ,hqS", "hfbuf", &dff.to_string(), "E"),
698            had = if all_deq { format!("gk_silu_had_f<<<Gs({dff}),256,0,s>>>(ffbuf,ffbuf+{dff},hfbuf,{dff});") }
699                  else if hl { format!("gk_silu_had_q8_hl<<<Gs({dff}),256,0,s>>>(ffbuf,ffbuf+{dff},hqQ,hqQl,hqS,{dff});") }
700                  else { format!("gk_silu_had_q8<<<Gs({dff}),256,0,s>>>(ffbuf,ffbuf+{dff},hqQ,hqS,{dff});") },
701            // Folded into the next layer's entry norm; only the final layer still pays for its own add.
702            resid = if l + 1 == cfg.layers { "gk_add<<<Gs(E),256,0,s>>>(x,tmp,E);\n" } else { "\n" },
703        ));
704        if debug {
705            step.push_str(&format!("  gk_dbg3<<<1,32,0,s>>>(x,dbg+3*{l});\n"));
706        }
707    }
708
709    let prov = super::provenance::header(super::provenance::Provenance::HandWritten {
710        model: "Qwen3.8-27B",
711        lane: "generation",
712    });
713    format!(
714        "{prov}// Qwen3.8-27B generation.\n\
715         #include <cstdio>\n#include <cstdlib>\n#include <cstring>\n#include <cmath>\n#include <cuda_runtime.h>\n#include <cuda_fp16.h>\n\
716         {gdn_k}{q38_k}{gen_k}{extra_k}\n\
717         // The dimension macros come AFTER the kernels on purpose: the shared kernel set takes `int E` as a\n\
718         // parameter name, and a `#define E 5120` above it would rewrite that into `int 5120`.\n\
719         #define E {d}\n#define VOCAB {vocab}\n#define LAYERS {layers}\n#define MAXSEQ {maxseq}\n\
720         #define EPSV {eps:e}f\n#define ROPEV {rope:e}f\n\
721         static const float SCALEV = {scale}f;\n\
722         {decls}\n{state}\n\
723         static float* x; static float* x_f32; static float* x2n; static float* tmp;\n\
724         static float *pbuf,*cbuf,*obuf,*gnbuf,*gbuf,*betab,*decayb,*qbuf,*attnb,*ffbuf,*hfbuf,*skbuf,*logits;\n\
725         static float *acc_part,*m_part,*d_part;\n\
726         static signed char *aqE,*aqQ,*ffQ,*hqQ,*aqEl,*aqQl,*ffQl,*hqQl; static float *asE,*asQ,*ffS,*hqS;\n\
727         static int *d_pos,*d_tok,*d_zero; static float* dbg;\n\
728         static inline int Gw(int n){{ return (n*32+255)/256; }}\n\
729         static inline int Gw2(int n){{ return (((n+1)/2)*32+255)/256; }}\n\
730         static inline int Gs(int n){{ return (n+255)/256; }}\n\
731         #define LDQ(v,QN,SN,QP,SP) do{{ \\\n\
732         \x20 signed char* hq=(signed char*)malloc((size_t)QN); float* hs=(float*)malloc((size_t)SN*4); \\\n\
733         \x20 FILE* f=fopen(QP,\"rb\"); if(!f||fread(hq,1,(size_t)QN,f)!=(size_t)QN){{fprintf(stderr,\"load %s\\n\",QP);return 1;}} fclose(f); \\\n\
734         \x20 f=fopen(SP,\"rb\"); if(!f||fread(hs,4,(size_t)SN,f)!=(size_t)SN){{fprintf(stderr,\"load %s\\n\",SP);return 1;}} fclose(f); \\\n\
735         \x20 cudaMalloc(&v##_q,(size_t)QN); cudaMemcpy(v##_q,hq,(size_t)QN,cudaMemcpyHostToDevice); \\\n\
736         \x20 __half* hh=(__half*)malloc((size_t)(SN)*2); for(long i=0;i<(long)(SN);++i) hh[i]=__float2half(hs[i]); \\\n\
737         \x20 cudaMalloc(&v##_s,(size_t)(SN)*2); cudaMemcpy(v##_s,hh,(size_t)(SN)*2,cudaMemcpyHostToDevice); \\\n\
738         \x20 free(hq); free(hs); free(hh); }}while(0)\n\
739         #define LDF(v,N,P) do{{ \\\n\
740         \x20 float* h=(float*)malloc((size_t)N*4); FILE* f=fopen(P,\"rb\"); \\\n\
741         \x20 if(!f||fread(h,4,(size_t)N,f)!=(size_t)N){{fprintf(stderr,\"load %s\\n\",P);return 1;}} fclose(f); \\\n\
742         \x20 cudaMalloc(&v##_f,(size_t)N*4); cudaMemcpy(v##_f,h,(size_t)N*4,cudaMemcpyHostToDevice); free(h); }}while(0)\n\
743         static void decode_step(cudaStream_t s){{\n\
744         \x20 gk_embed_h<<<Gs(E),256,0,s>>>(x,emb_q,emb_s,d_tok,E);\n\
745         {step}\
746         \x20 {final_norm}\n\
747         \x20 {head}\n\
748         \x20 gk_argmax_adv<<<1,256,0,s>>>(logits,VOCAB,d_tok,d_pos);\n}}\n\
749         int main(){{\n{loads}\n{alloc}\n\
750         \x20 cudaMalloc(&x,E*4); cudaMalloc(&x_f32,E*4); cudaMalloc(&x2n,E*4); cudaMalloc(&tmp,E*4);\n\
751         \x20 cudaMalloc(&pbuf,{pmax}*4); cudaMalloc(&cbuf,{convc}*4); cudaMalloc(&obuf,{vw}*4); cudaMalloc(&gnbuf,{vw}*4);\n\
752         \x20 cudaMalloc(&gbuf,{two_nv}*4); cudaMalloc(&betab,{nv}*4); cudaMalloc(&decayb,{nv}*4);\n\
753         \x20 cudaMalloc(&qbuf,{aq}*4); cudaMalloc(&attnb,{aq}*4); cudaMalloc(&ffbuf,{two_dff}*4);\n\
754         \x20 cudaMalloc(&logits,(size_t)VOCAB*4); cudaMalloc(&hfbuf,(size_t){dff}*4);\n\
755         \x20 cudaMalloc(&skbuf,(size_t)8*8192*4);\n\
756         \x20 cudaMalloc(&acc_part,(size_t){h}*{p}*{hd}*4); cudaMalloc(&m_part,(size_t){h}*{p}*4); cudaMalloc(&d_part,(size_t){h}*{p}*4);\n\
757         \x20 cudaMalloc(&aqE,E); cudaMalloc(&asE,(size_t)(E/32)*4); cudaMalloc(&aqEl,E);\n\
758         \x20 cudaMalloc(&aqQ,{amax}); cudaMalloc(&asQ,(size_t)({amax}/32)*4); cudaMalloc(&aqQl,{amax});\n\
759         \x20 cudaMalloc(&ffQ,E); cudaMalloc(&ffS,(size_t)(E/32)*4); cudaMalloc(&ffQl,E);\n\
760         \x20 cudaMalloc(&hqQ,{dff}); cudaMalloc(&hqS,(size_t)({dff}/32)*4); cudaMalloc(&hqQl,{dff});\n\
761         \x20 cudaMalloc(&d_pos,4); cudaMalloc(&d_tok,4); cudaMalloc(&d_zero,4); cudaMalloc(&dbg,(size_t)(LAYERS+16)*12);\n\
762         \x20 {{ int z=0; cudaMemcpy(d_zero,&z,4,cudaMemcpyHostToDevice); }}\n\
763         \x20 cudaStream_t s; cudaStreamCreate(&s);\n\
764         \x20 static const int PROMPT[] = {{{prompt_c}}}; const int NP = sizeof(PROMPT)/sizeof(int);\n\
765         \x20 // ── prefill: the same step, one token at a time, growing the caches and the memories ──\n\
766         \x20 for(int i=0;i<NP;++i){{ int p=i; cudaMemcpy(d_pos,&p,4,cudaMemcpyHostToDevice);\n\
767         \x20   cudaMemcpy(d_tok,&PROMPT[i],4,cudaMemcpyHostToDevice); decode_step(s); cudaStreamSynchronize(s); {dbgrep} }}\n\
768         // The logit vector at the LAST prompt position -- the one that chooses the first generated
769         // token, and the same vector llama.cpp returns from `llama_get_logits_ith(n_prompt-1)`. Dumped
770         // raw so accuracy is settled against an f64 oracle rather than by whether two argmaxes agree.
771         \x20 if(const char* lp = getenv(\"LOGOS_Q38_LOGITS\")){{ static float hl[VOCAB];
772         \x20   cudaMemcpy(hl,logits,(size_t)VOCAB*4,cudaMemcpyDeviceToHost);
773         \x20   FILE* lf=fopen(lp,\"wb\"); if(lf){{ fwrite(hl,4,VOCAB,lf); fclose(lf);
774         \x20     fprintf(stderr,\"WROTE_LOGITS %s (%d)\\n\", lp, VOCAB); }} }}\n\
775         \x20 // ── capture ONE decode step and replay it: ~800 launches per token become one graph launch ──\n\
776         \x20 cudaGraph_t g; cudaGraphExec_t ge;\n\
777         \x20 if(cudaStreamBeginCapture(s,cudaStreamCaptureModeGlobal)!=cudaSuccess){{fprintf(stderr,\"capture\\n\");return 1;}}\n\
778         \x20 decode_step(s);\n\
779         \x20 if(cudaStreamEndCapture(s,&g)!=cudaSuccess){{fprintf(stderr,\"endcapture\\n\");return 1;}}\n\
780         \x20 if(cudaGraphInstantiate(&ge,g,0)!=cudaSuccess){{fprintf(stderr,\"inst\\n\");return 1;}}\n\
781         \x20 cudaEvent_t t0,t1; cudaEventCreate(&t0); cudaEventCreate(&t1);\n\
782         \x20 int tok=0; cudaMemcpy(&tok,d_tok,4,cudaMemcpyDeviceToHost);\n\
783         \x20 printf(\"GENERATED_TOKENS: %d\", tok);\n\
784         \x20 float genms=0.f; int steps=0;\n\
785         \x20 for(int i=1;i<{n_gen};++i){{ cudaEventRecord(t0,s); cudaGraphLaunch(ge,s); cudaEventRecord(t1,s);\n\
786         \x20   cudaStreamSynchronize(s); float ms; cudaEventElapsedTime(&ms,t0,t1); genms+=ms; steps++;\n\
787         \x20   cudaMemcpy(&tok,d_tok,4,cudaMemcpyDeviceToHost); printf(\" %d\", tok); }}\n\
788         \x20 printf(\"\\n\");\n\
789         \x20 if(steps) fprintf(stderr,\"GEN_TOK_S %.2f (%.3f ms/token, %d steps)\\n\", 1000.0*steps/genms, genms/steps, steps);\n\
790         \x20 {{ int z=0; cudaMemcpy(d_pos,&z,4,cudaMemcpyHostToDevice); cudaStreamSynchronize(s);\n\
791         \x20   cudaEventRecord(t0,s); for(int i=0;i<128;++i) cudaGraphLaunch(ge,s); cudaEventRecord(t1,s);\n\
792         \x20   cudaStreamSynchronize(s); float ms; cudaEventElapsedTime(&ms,t0,t1);\n\
793         \x20   fprintf(stderr,\"GEN_TOK_S_TG128 %.2f (128 replays from an empty cache = llama-bench tg128)\\n\", 128000.0/ms); }}\n\
794         \x20 return 0;\n}}\n",
795        vocab = cfg.vocab, layers = cfg.layers, eps = cfg.rms_eps, rope = cfg.rope_theta,
796        gdn_k = crate::codegen_cuda::gdn::GDN_KERNELS,
797        q38_k = crate::codegen_cuda::gdn::QWEN38_KERNELS,
798        final_norm = if deq == 3 {
799            "gk_rmsnorm_q8f_hl<<<1,256,0,s>>>(x,aqE,aqEl,asE,x_f32,on_f,E,EPSV);"
800        } else {
801            "gk_rmsnorm_q8f<<<1,256,0,s>>>(x,aqE,asE,x_f32,on_f,E,EPSV);"
802        },
803        head = if hl && unroll4 {
804            "gk_gemv_hlu4<<<Gw(VOCAB),256,0,s>>>(logits,Wout_q,Wout_s,aqE,aqEl,asE,E,VOCAB);"
805        } else if hl && unroll {
806            "gk_gemv_hlu<<<Gw(VOCAB),256,0,s>>>(logits,Wout_q,Wout_s,aqE,aqEl,asE,E,VOCAB);"
807        } else if hl && wide {
808            "gk_gemv_hl2<<<Gw2(VOCAB),256,0,s>>>(logits,Wout_q,Wout_s,aqE,aqEl,asE,E,VOCAB);"
809        } else if hl {
810            "gk_gemv_hl<<<Gw(VOCAB),256,0,s>>>(logits,Wout_q,Wout_s,aqE,aqEl,asE,E,VOCAB);"
811        } else if deq >= 1 {
812            "gk_gemv_deq_h<<<Gw(VOCAB),256,0,s>>>(logits,Wout_q,Wout_s,x_f32,E,VOCAB);"
813        } else {
814            "gk_gemv_h<<<Gw(VOCAB),256,0,s>>>(logits,Wout_q,Wout_s,aqE,asE,E,VOCAB);"
815        },
816        gen_k = crate::codegen_cuda::qwen_emit::GEN_DEVICE_KERNELS,
817        extra_k = QWEN38_EXTRA_KERNELS,
818        state = state_decl, alloc = state_alloc,
819        pmax = projw.max(attnw), two_nv = 2 * nv, two_dff = 2 * dff,
820        amax = vw.max(aq), h = cfg.h, hd = cfg.hd, p = attn_split,
821        dbgrep = if debug {
822            "if(i==0){ float hb[(LAYERS+16)*3]; cudaMemcpy(hb,dbg,(size_t)(LAYERS+16)*12,cudaMemcpyDeviceToHost); for(int L=0;L<4;++L) fprintf(stderr,\"DBG l_out-%d=[%.4f,%.4f,%.4f]\\n\",L,hb[3*L],hb[3*L+1],hb[3*L+2]); const char* nm[9]={\"embed\",\"xn0\",\"qkv0\",\"conv0\",\"beta\",\"decay\",\"gdnout\",\"gatenorm\",\"oproj\"}; for(int L=0;L<9;++L) fprintf(stderr,\"DBG %s=[%.6f,%.6f,%.6f]\\n\",nm[L],hb[3*(70+L)],hb[3*(70+L)+1],hb[3*(70+L)+2]); } if(i==NP-1){ float* al=(float*)malloc((size_t)VOCAB*4); cudaMemcpy(al,logits,(size_t)VOCAB*4,cudaMemcpyDeviceToHost); int bi=0; for(int L=1;L<VOCAB;++L) if(al[L]>al[bi]) bi=L; int rank=0; for(int L=0;L<VOCAB;++L) if(al[L]>al[11751]) rank++; fprintf(stderr,\"DBG argmax=%d(%.4g) golden11751=%.4g rank=%d\\n\",bi,al[bi],al[11751],rank); free(al); }"
823        } else { "" },
824    )
825}
826
827/// The last two kernels the hybrid needs: an f32-weight GEMV for GDN's tiny gate projections (quantizing a
828/// `[d, 48]` matrix would risk the gates for a rounding error that buys 0.26% of bandwidth), a KV-cache store
829/// that splits the fused projection's k and v halves into their caches, and the SwiGLU epilogue fused with the
830/// activation re-quantization so the FFN's middle never round-trips through global memory as f32.
831pub const QWEN38_EXTRA_KERNELS: &str = r#"
832
833// A plain argmax that does NOT advance the position — the MTP draft is a guess about the future, not a step
834// through it, so it must not touch the decode state it is speculating on.
835__global__ void gk_argmax_only(const float* logits, int vocab, int* out){
836  __shared__ float bv[256]; __shared__ int bi[256]; float bestv=-1e30f; int besti=0;
837  for(int i=threadIdx.x;i<vocab;i+=blockDim.x){ float v=logits[i]; if(v>bestv){bestv=v;besti=i;} }
838  bv[threadIdx.x]=bestv; bi[threadIdx.x]=besti; __syncthreads();
839  for(int k=blockDim.x/2;k>0;k>>=1){ if(threadIdx.x<k && bv[threadIdx.x+k]>bv[threadIdx.x]){ bv[threadIdx.x]=bv[threadIdx.x+k]; bi[threadIdx.x]=bi[threadIdx.x+k]; } __syncthreads(); }
840  if(threadIdx.x==0) *out=bi[0];
841}
842// Concatenate the two normed halves the nextn adapter consumes: [ rmsnorm(embed(t),enorm) | rmsnorm(h,hnorm) ].
843__global__ void gk_mtp_cat(float* __restrict__ out, const float* __restrict__ e, const float* __restrict__ h,
844                           const float* __restrict__ we, const float* __restrict__ wh, int n, float eps){
845  __shared__ float sh[256];
846  const float* src = blockIdx.x == 0 ? e : h;
847  const float* w   = blockIdx.x == 0 ? we : wh;
848  float* dst       = out + (long)blockIdx.x * n;
849  float s=0.f; for(int i=threadIdx.x;i<n;i+=blockDim.x) s+=src[i]*src[i];
850  sh[threadIdx.x]=s; __syncthreads();
851  for(int k=blockDim.x/2;k>0;k>>=1){ if(threadIdx.x<k) sh[threadIdx.x]+=sh[threadIdx.x+k]; __syncthreads(); }
852  float sc=rsqrtf(sh[0]/n+eps);
853  for(int i=threadIdx.x;i<n;i+=blockDim.x) dst[i]=src[i]*sc*w[i];
854}
855
856
857// ══ SPLIT-K FOR THE NARROW PROJECTIONS ══════════════════════════════════════════════════════════
858// One warp per output row means the o-projection and the down-projection (both N=5120) launch only 640
859// blocks — 38.8 of an H100's 64 warps per SM, against 100% for the wide matrices. Those two are 31.7% of the
860// model's weights, so a third of every token runs at 61% occupancy. Splitting K into S chunks multiplies the
861// block count by S and fills the machine.
862//
863// The combine is a SEPARATE kernel summing the partials in FIXED ascending order, not an atomicAdd: float
864// addition is not associative, so an atomic would make the result depend on scheduler order and the same
865// prompt could produce different tokens on different runs. Determinism is not negotiable here.
866//
867// This is NOT bit-identical to the rolled form — chunking K re-associates the sum — so it is gated on the
868// golden token stream and on distance from the f64 oracle, never adopted on throughput alone.
869__global__ void gk_gemv_hl_sk(float* __restrict__ part, const signed char* __restrict__ wq,
870                              const __half* __restrict__ ws, const signed char* __restrict__ xh,
871                              const signed char* __restrict__ xl, const float* __restrict__ xs,
872                              int K, int N, int S){
873  int o=(blockIdx.x*blockDim.x+threadIdx.x)>>5; if(o>=N) return;
874  int sl=blockIdx.y, lane=threadIdx.x&31;
875  const int4* w16=(const int4*)(wq+(long)o*K);
876  const int4* h16=(const int4*)xh; const int4* l16=(const int4*)xl;
877  const __half* wsr=ws+(long)o*(K/32);
878  int nq=K/512, per=(nq+S-1)/S, b0=sl*per, be=b0+per<nq?b0+per:nq;
879  float acc=0.f;
880  for(int b=b0;b<be;b++){
881    int4 w=w16[b*32+lane], hh=h16[b*32+lane], ll=l16[b*32+lane];
882    int blk=b*16+lane/2;
883    int dh=__dp4a(w.x,hh.x,0)+__dp4a(w.y,hh.y,0)+__dp4a(w.z,hh.z,0)+__dp4a(w.w,hh.w,0);
884    int dl=__dp4a(w.x,ll.x,0)+__dp4a(w.y,ll.y,0)+__dp4a(w.z,ll.z,0)+__dp4a(w.w,ll.w,0);
885    acc += ((float)dh + (float)dl*(1.0f/127.0f)) * (__half2float(wsr[blk])*xs[blk]);
886  }
887  if(sl==S-1){ int done=nq*512;
888    for(int j=done+lane;j<K;j+=32){ int blk=j/32;
889      float a=(float)xh[j] + (float)xl[j]*(1.0f/127.0f);
890      acc += a*(float)wq[(long)o*K+j]*(__half2float(wsr[blk])*xs[blk]); } }
891  for(int t=16;t>0;t>>=1) acc+=__shfl_down_sync(0xffffffffu,acc,t);
892  if(lane==0) part[(long)sl*N+o]=acc;
893}
894// Fixed ascending order over the K-chunks: same inputs always give the same bits.
895__global__ void gk_sk_combine(float* __restrict__ y, const float* __restrict__ part, int N, int S){
896  int o=blockIdx.x*blockDim.x+threadIdx.x; if(o>=N) return;
897  float a=0.f;
898  for(int s=0;s<S;++s) a+=part[(long)s*N+o];
899  y[o]=a;
900}
901
902
903// Four K-blocks in flight. Two measured +5.2% on the two-pass lane (38.30 -> 40.29); this is the same idea
904// pushed one step further, and stops there because the tail handling and register pressure both start to
905// cost more than the extra loads return. Accumulation order is unchanged, so it is still bit-identical.
906__global__ void gk_gemv_hlu4(float* y, const signed char* __restrict__ wq, const __half* __restrict__ ws,
907                             const signed char* __restrict__ xh, const signed char* __restrict__ xl,
908                             const float* __restrict__ xs, int K, int N){
909  int o=(blockIdx.x*blockDim.x+threadIdx.x)>>5; if(o>=N) return; int lane=threadIdx.x&31;
910  const int4* w16=(const int4*)(wq+(long)o*K);
911  const int4* h16=(const int4*)xh; const int4* l16=(const int4*)xl;
912  const __half* wsr=ws+(long)o*(K/32);
913  float acc=0.f; int nq=K/512; int b=0;
914  for(; b+3<nq; b+=4){
915    int4 w0=w16[b*32+lane],     h0=h16[b*32+lane],     l0=l16[b*32+lane];
916    int4 w1=w16[(b+1)*32+lane], h1=h16[(b+1)*32+lane], l1=l16[(b+1)*32+lane];
917    int4 w2=w16[(b+2)*32+lane], h2=h16[(b+2)*32+lane], l2=l16[(b+2)*32+lane];
918    int4 w3=w16[(b+3)*32+lane], h3=h16[(b+3)*32+lane], l3=l16[(b+3)*32+lane];
919    int k0=b*16+lane/2, k1=(b+1)*16+lane/2, k2=(b+2)*16+lane/2, k3=(b+3)*16+lane/2;
920    int a0=__dp4a(w0.x,h0.x,0)+__dp4a(w0.y,h0.y,0)+__dp4a(w0.z,h0.z,0)+__dp4a(w0.w,h0.w,0);
921    int c0=__dp4a(w0.x,l0.x,0)+__dp4a(w0.y,l0.y,0)+__dp4a(w0.z,l0.z,0)+__dp4a(w0.w,l0.w,0);
922    int a1=__dp4a(w1.x,h1.x,0)+__dp4a(w1.y,h1.y,0)+__dp4a(w1.z,h1.z,0)+__dp4a(w1.w,h1.w,0);
923    int c1=__dp4a(w1.x,l1.x,0)+__dp4a(w1.y,l1.y,0)+__dp4a(w1.z,l1.z,0)+__dp4a(w1.w,l1.w,0);
924    int a2=__dp4a(w2.x,h2.x,0)+__dp4a(w2.y,h2.y,0)+__dp4a(w2.z,h2.z,0)+__dp4a(w2.w,h2.w,0);
925    int c2=__dp4a(w2.x,l2.x,0)+__dp4a(w2.y,l2.y,0)+__dp4a(w2.z,l2.z,0)+__dp4a(w2.w,l2.w,0);
926    int a3=__dp4a(w3.x,h3.x,0)+__dp4a(w3.y,h3.y,0)+__dp4a(w3.z,h3.z,0)+__dp4a(w3.w,h3.w,0);
927    int c3=__dp4a(w3.x,l3.x,0)+__dp4a(w3.y,l3.y,0)+__dp4a(w3.z,l3.z,0)+__dp4a(w3.w,l3.w,0);
928    acc += ((float)a0 + (float)c0*(1.0f/127.0f)) * (__half2float(wsr[k0])*xs[k0]);
929    acc += ((float)a1 + (float)c1*(1.0f/127.0f)) * (__half2float(wsr[k1])*xs[k1]);
930    acc += ((float)a2 + (float)c2*(1.0f/127.0f)) * (__half2float(wsr[k2])*xs[k2]);
931    acc += ((float)a3 + (float)c3*(1.0f/127.0f)) * (__half2float(wsr[k3])*xs[k3]);
932  }
933  for(; b<nq; b++){
934    int4 w=w16[b*32+lane], hh=h16[b*32+lane], ll=l16[b*32+lane]; int blk=b*16+lane/2;
935    int dh=__dp4a(w.x,hh.x,0)+__dp4a(w.y,hh.y,0)+__dp4a(w.z,hh.z,0)+__dp4a(w.w,hh.w,0);
936    int dl=__dp4a(w.x,ll.x,0)+__dp4a(w.y,ll.y,0)+__dp4a(w.z,ll.z,0)+__dp4a(w.w,ll.w,0);
937    acc += ((float)dh + (float)dl*(1.0f/127.0f)) * (__half2float(wsr[blk])*xs[blk]);
938  }
939  int done=nq*512;
940  for(int j=done+lane;j<K;j+=32){ int blk=j/32;
941    float a=(float)xh[j] + (float)xl[j]*(1.0f/127.0f);
942    acc += a*(float)wq[(long)o*K+j]*(__half2float(wsr[blk])*xs[blk]); }
943  for(int s=16;s>0;s>>=1) acc+=__shfl_down_sync(0xffffffffu,acc,s); if(lane==0) y[o]=acc;
944}
945
946
947// ══ TWO K-BLOCKS IN FLIGHT ══════════════════════════════════════════════════════════════════════
948// Widening in N (two output rows per warp) was MEASURED slower on A100 -- 41.10 against 42.28 -- because it
949// halves the warp count, and this GEMV needs the parallelism more than it needs the reuse. Unrolling in K
950// costs no warps: the same warp issues the loads for two consecutive 512-weight blocks before consuming
951// either, so there are twice as many loads in flight per warp with the same occupancy.
952//
953// The accumulation ORDER is deliberately unchanged -- one accumulator, blocks folded in ascending order --
954// so this is bit-identical to the rolled form and cannot move a token.
955__global__ void gk_gemv_hu(float* y, const signed char* __restrict__ wq, const __half* __restrict__ ws,
956                           const signed char* __restrict__ xq, const float* __restrict__ xs, int K, int N){
957  int o=(blockIdx.x*blockDim.x+threadIdx.x)>>5; if(o>=N) return; int lane=threadIdx.x&31;
958  const int4* w16=(const int4*)(wq+(long)o*K); const int4* x16=(const int4*)xq;
959  const __half* wsr=ws+(long)o*(K/32);
960  float acc=0.f; int nq=K/512; int b=0;
961  for(; b+1<nq; b+=2){
962    int4 wa=w16[b*32+lane],     xa=x16[b*32+lane];
963    int4 wb=w16[(b+1)*32+lane], xb=x16[(b+1)*32+lane];
964    int ba=b*16+lane/2, bb=(b+1)*16+lane/2;
965    int da=__dp4a(wa.x,xa.x,0)+__dp4a(wa.y,xa.y,0)+__dp4a(wa.z,xa.z,0)+__dp4a(wa.w,xa.w,0);
966    int db=__dp4a(wb.x,xb.x,0)+__dp4a(wb.y,xb.y,0)+__dp4a(wb.z,xb.z,0)+__dp4a(wb.w,xb.w,0);
967    acc += (float)da * (__half2float(wsr[ba])*xs[ba]);
968    acc += (float)db * (__half2float(wsr[bb])*xs[bb]);
969  }
970  for(; b<nq; b++){
971    int4 w=w16[b*32+lane], xx=x16[b*32+lane]; int blk=b*16+lane/2;
972    int d=__dp4a(w.x,xx.x,0)+__dp4a(w.y,xx.y,0)+__dp4a(w.z,xx.z,0)+__dp4a(w.w,xx.w,0);
973    acc += (float)d * (__half2float(wsr[blk])*xs[blk]);
974  }
975  int done=nq*512; for(int j=done+lane;j<K;j+=32){ int blk=j/32;
976    acc += (float)((int)xq[j]*(int)wq[(long)o*K+j])*(__half2float(wsr[blk])*xs[blk]); }
977  for(int s=16;s>0;s>>=1) acc+=__shfl_down_sync(0xffffffffu,acc,s); if(lane==0) y[o]=acc;
978}
979
980// The same unrolling for the two-pass lane, where each iteration already has three streams to keep in flight.
981__global__ void gk_gemv_hlu(float* y, const signed char* __restrict__ wq, const __half* __restrict__ ws,
982                            const signed char* __restrict__ xh, const signed char* __restrict__ xl,
983                            const float* __restrict__ xs, int K, int N){
984  int o=(blockIdx.x*blockDim.x+threadIdx.x)>>5; if(o>=N) return; int lane=threadIdx.x&31;
985  const int4* w16=(const int4*)(wq+(long)o*K);
986  const int4* h16=(const int4*)xh; const int4* l16=(const int4*)xl;
987  const __half* wsr=ws+(long)o*(K/32);
988  float acc=0.f; int nq=K/512; int b=0;
989  for(; b+1<nq; b+=2){
990    int4 wa=w16[b*32+lane],     ha=h16[b*32+lane],     la=l16[b*32+lane];
991    int4 wb=w16[(b+1)*32+lane], hb=h16[(b+1)*32+lane], lb=l16[(b+1)*32+lane];
992    int ba=b*16+lane/2, bb=(b+1)*16+lane/2;
993    int dha=__dp4a(wa.x,ha.x,0)+__dp4a(wa.y,ha.y,0)+__dp4a(wa.z,ha.z,0)+__dp4a(wa.w,ha.w,0);
994    int dla=__dp4a(wa.x,la.x,0)+__dp4a(wa.y,la.y,0)+__dp4a(wa.z,la.z,0)+__dp4a(wa.w,la.w,0);
995    int dhb=__dp4a(wb.x,hb.x,0)+__dp4a(wb.y,hb.y,0)+__dp4a(wb.z,hb.z,0)+__dp4a(wb.w,hb.w,0);
996    int dlb=__dp4a(wb.x,lb.x,0)+__dp4a(wb.y,lb.y,0)+__dp4a(wb.z,lb.z,0)+__dp4a(wb.w,lb.w,0);
997    acc += ((float)dha + (float)dla*(1.0f/127.0f)) * (__half2float(wsr[ba])*xs[ba]);
998    acc += ((float)dhb + (float)dlb*(1.0f/127.0f)) * (__half2float(wsr[bb])*xs[bb]);
999  }
1000  for(; b<nq; b++){
1001    int4 w=w16[b*32+lane], hh=h16[b*32+lane], ll=l16[b*32+lane]; int blk=b*16+lane/2;
1002    int dh=__dp4a(w.x,hh.x,0)+__dp4a(w.y,hh.y,0)+__dp4a(w.z,hh.z,0)+__dp4a(w.w,hh.w,0);
1003    int dl=__dp4a(w.x,ll.x,0)+__dp4a(w.y,ll.y,0)+__dp4a(w.z,ll.z,0)+__dp4a(w.w,ll.w,0);
1004    acc += ((float)dh + (float)dl*(1.0f/127.0f)) * (__half2float(wsr[blk])*xs[blk]);
1005  }
1006  int done=nq*512;
1007  for(int j=done+lane;j<K;j+=32){ int blk=j/32;
1008    float a=(float)xh[j] + (float)xl[j]*(1.0f/127.0f);
1009    acc += a*(float)wq[(long)o*K+j]*(__half2float(wsr[blk])*xs[blk]); }
1010  for(int s=16;s>0;s>>=1) acc+=__shfl_down_sync(0xffffffffu,acc,s); if(lane==0) y[o]=acc;
1011}
1012
1013
1014// ══ TWO OUTPUT ROWS PER WARP ════════════════════════════════════════════════════════════════════
1015// A batch-1 GEMV at these shapes is not bandwidth-saturated -- it is LATENCY bound: one row per warp gives
1016// each warp a single outstanding weight load per iteration, and the measured 1050 GB/s against an A100 that
1017// delivers ~1500 is the gap that leaves. Giving a warp two adjacent rows doubles the loads in flight, and
1018// the activation word (and its scale) is fetched once and used twice, which halves the L2 traffic the
1019// activation generates across the 7760 warps that read it.
1020__global__ void gk_gemv_h2(float* y, const signed char* __restrict__ wq, const __half* __restrict__ ws,
1021                           const signed char* __restrict__ xq, const float* __restrict__ xs, int K, int N){
1022  int r=((blockIdx.x*blockDim.x+threadIdx.x)>>5)*2; if(r>=N) return; int lane=threadIdx.x&31;
1023  bool r1 = (r+1)<N;
1024  const int4* x16=(const int4*)xq;
1025  const int4* wa=(const int4*)(wq+(long)r*K);
1026  const int4* wb=(const int4*)(wq+(long)(r+1)*K);
1027  const __half* sa=ws+(long)r*(K/32); const __half* sb=ws+(long)(r+1)*(K/32);
1028  float acc0=0.f, acc1=0.f; int nq=K/512;
1029  for(int b=0;b<nq;b++){
1030    int4 xx=x16[b*32+lane]; int blk=b*16+lane/2; float xsv=xs[blk];
1031    int4 w0=wa[b*32+lane];
1032    int d0=__dp4a(w0.x,xx.x,0)+__dp4a(w0.y,xx.y,0)+__dp4a(w0.z,xx.z,0)+__dp4a(w0.w,xx.w,0);
1033    acc0 += (float)d0 * (__half2float(sa[blk])*xsv);
1034    if(r1){ int4 w1=wb[b*32+lane];
1035      int d1=__dp4a(w1.x,xx.x,0)+__dp4a(w1.y,xx.y,0)+__dp4a(w1.z,xx.z,0)+__dp4a(w1.w,xx.w,0);
1036      acc1 += (float)d1 * (__half2float(sb[blk])*xsv); }
1037  }
1038  int done=nq*512;
1039  for(int j=done+lane;j<K;j+=32){ int blk=j/32; float xv=(float)xq[j]*xs[blk];
1040    acc0 += xv*(float)wq[(long)r*K+j]*__half2float(sa[blk]);
1041    if(r1) acc1 += xv*(float)wq[(long)(r+1)*K+j]*__half2float(sb[blk]); }
1042  for(int s=16;s>0;s>>=1){ acc0+=__shfl_down_sync(0xffffffffu,acc0,s); acc1+=__shfl_down_sync(0xffffffffu,acc1,s); }
1043  if(lane==0){ y[r]=acc0; if(r1) y[r+1]=acc1; }
1044}
1045
1046// The same widening for the two-pass lane, where it pays double: the activation's HIGH and LOW words are both
1047// fetched once per iteration and used for both rows.
1048__global__ void gk_gemv_hl2(float* y, const signed char* __restrict__ wq, const __half* __restrict__ ws,
1049                            const signed char* __restrict__ xh, const signed char* __restrict__ xl,
1050                            const float* __restrict__ xs, int K, int N){
1051  int r=((blockIdx.x*blockDim.x+threadIdx.x)>>5)*2; if(r>=N) return; int lane=threadIdx.x&31;
1052  bool r1 = (r+1)<N;
1053  const int4* h16=(const int4*)xh; const int4* l16=(const int4*)xl;
1054  const int4* wa=(const int4*)(wq+(long)r*K);
1055  const int4* wb=(const int4*)(wq+(long)(r+1)*K);
1056  const __half* sa=ws+(long)r*(K/32); const __half* sb=ws+(long)(r+1)*(K/32);
1057  float acc0=0.f, acc1=0.f; int nq=K/512;
1058  for(int b=0;b<nq;b++){
1059    int4 hh=h16[b*32+lane], ll=l16[b*32+lane]; int blk=b*16+lane/2; float xsv=xs[blk];
1060    int4 w0=wa[b*32+lane];
1061    int dh0=__dp4a(w0.x,hh.x,0)+__dp4a(w0.y,hh.y,0)+__dp4a(w0.z,hh.z,0)+__dp4a(w0.w,hh.w,0);
1062    int dl0=__dp4a(w0.x,ll.x,0)+__dp4a(w0.y,ll.y,0)+__dp4a(w0.z,ll.z,0)+__dp4a(w0.w,ll.w,0);
1063    acc0 += ((float)dh0 + (float)dl0*(1.0f/127.0f)) * (__half2float(sa[blk])*xsv);
1064    if(r1){ int4 w1=wb[b*32+lane];
1065      int dh1=__dp4a(w1.x,hh.x,0)+__dp4a(w1.y,hh.y,0)+__dp4a(w1.z,hh.z,0)+__dp4a(w1.w,hh.w,0);
1066      int dl1=__dp4a(w1.x,ll.x,0)+__dp4a(w1.y,ll.y,0)+__dp4a(w1.z,ll.z,0)+__dp4a(w1.w,ll.w,0);
1067      acc1 += ((float)dh1 + (float)dl1*(1.0f/127.0f)) * (__half2float(sb[blk])*xsv); }
1068  }
1069  int done=nq*512;
1070  for(int j=done+lane;j<K;j+=32){ int blk=j/32;
1071    float a=((float)xh[j] + (float)xl[j]*(1.0f/127.0f))*xs[blk];
1072    acc0 += a*(float)wq[(long)r*K+j]*__half2float(sa[blk]);
1073    if(r1) acc1 += a*(float)wq[(long)(r+1)*K+j]*__half2float(sb[blk]); }
1074  for(int s=16;s>0;s>>=1){ acc0+=__shfl_down_sync(0xffffffffu,acc0,s); acc1+=__shfl_down_sync(0xffffffffu,acc1,s); }
1075  if(lane==0){ y[r]=acc0; if(r1) y[r+1]=acc1; }
1076}
1077
1078
1079// ══ TWO-PASS INT8 ACTIVATIONS ═══════════════════════════════════════════════════════════════════
1080// A batch-1 GEMV reads a whole weight matrix and ONE activation vector, so the activation costs no
1081// measurable bandwidth -- but rounding it onto a single int8 grid costs accuracy at every one of the 300+
1082// projections in a token. Splitting it into a high and a low int8 word represents it as
1083//     a  ~=  s * (qh + ql/127),      | a/s - (qh + ql/127) |  <=  0.5/127
1084// which is 254x tighter, and keeps `dp4a`. That last part is the point: the obvious alternative -- feeding
1085// the GEMV f32 activations -- was MEASURED at 32.27 tok/s against 42.28, because one int-to-float convert
1086// per weight is quarter rate on this chip. Two words of int8 double the dp4a count instead, on a kernel
1087// that is memory bound, and the weight matrix is still read exactly once.
1088
1089__global__ void gk_gemv_hl(float* y, const signed char* __restrict__ wq, const __half* __restrict__ ws,
1090                           const signed char* __restrict__ xh, const signed char* __restrict__ xl,
1091                           const float* __restrict__ xs, int K, int N){
1092  int o=(blockIdx.x*blockDim.x+threadIdx.x)>>5; if(o>=N) return; int lane=threadIdx.x&31;
1093  const int4* w16=(const int4*)(wq+(long)o*K);
1094  const int4* h16=(const int4*)xh; const int4* l16=(const int4*)xl;
1095  const __half* wsr=ws+(long)o*(K/32);
1096  float acc=0.f; int nq=K/512;
1097  for(int b=0;b<nq;b++){
1098    int4 w=w16[b*32+lane], hh=h16[b*32+lane], ll=l16[b*32+lane];
1099    int blk=b*16+lane/2;
1100    int dh=__dp4a(w.x,hh.x,0)+__dp4a(w.y,hh.y,0)+__dp4a(w.z,hh.z,0)+__dp4a(w.w,hh.w,0);
1101    int dl=__dp4a(w.x,ll.x,0)+__dp4a(w.y,ll.y,0)+__dp4a(w.z,ll.z,0)+__dp4a(w.w,ll.w,0);
1102    acc += ((float)dh + (float)dl*(1.0f/127.0f)) * (__half2float(wsr[blk])*xs[blk]);
1103  }
1104  int done=nq*512;
1105  for(int j=done+lane;j<K;j+=32){ int blk=j/32;
1106    float a=(float)xh[j] + (float)xl[j]*(1.0f/127.0f);
1107    acc += a*(float)wq[(long)o*K+j]*(__half2float(wsr[blk])*xs[blk]); }
1108  for(int s=16;s>0;s>>=1) acc+=__shfl_down_sync(0xffffffffu,acc,s); if(lane==0) y[o]=acc;
1109}
1110
1111// The producers, each the single-word kernel with its final rounding replaced by the two-word split. The
1112// scale and every float value are computed exactly as before, so the high word is bit-identical to what the
1113// single-word lane produced and the low word is pure addition.
1114__global__ void gk_quant_act_hl(const float* x, signed char* xq, signed char* xl, float* xs, int K){
1115  int blk=blockIdx.x*(blockDim.x/32)+threadIdx.x/32; if((long)blk*32>=K) return; int lane=threadIdx.x&31;
1116  float v=x[blk*32+lane], a=fabsf(v);
1117  for(int s=16;s>0;s>>=1) a=fmaxf(a,__shfl_down_sync(0xffffffffu,a,s)); a=__shfl_sync(0xffffffffu,a,0);
1118  float sc=a>0?a/127.0f:1.0f; if(lane==0) xs[blk]=sc;
1119  lgx_q8hl(v/sc, xq, xl, (long)blk*32+lane);
1120}
1121__global__ void gk_rmsnorm_q8f_hl(const float* __restrict__ x, signed char* __restrict__ xq,
1122                                  signed char* __restrict__ xl, float* __restrict__ xs,
1123                                  float* __restrict__ xf, const float* __restrict__ w, int n, float eps){
1124  __shared__ float sh[256];
1125  float s=0.f; for(int i=threadIdx.x;i<n;i+=blockDim.x) s+=x[i]*x[i];
1126  sh[threadIdx.x]=s; __syncthreads();
1127  for(int k=blockDim.x/2;k>0;k>>=1){ if(threadIdx.x<k) sh[threadIdx.x]+=sh[threadIdx.x+k]; __syncthreads(); }
1128  float sc=rsqrtf(sh[0]/n+eps); __syncthreads();
1129  for(int i=threadIdx.x;i<n;i+=blockDim.x) xf[i]=x[i]*sc*w[i];
1130  __syncthreads();
1131  int nb=n/32;
1132  for(int b=threadIdx.x;b<nb;b+=blockDim.x){
1133    float amax=1e-30f;
1134    for(int j=0;j<32;++j){ float a=fabsf(xf[b*32+j]); if(a>amax) amax=a; }
1135    float q=amax/127.0f; xs[b]=q;
1136    for(int j=0;j<32;++j) lgx_q8hl(xf[b*32+j]/q, xq, xl, (long)b*32+j);
1137  }
1138}
1139__global__ void gk_add_rmsnorm_q8f_hl(float* __restrict__ x, const float* __restrict__ y,
1140                                      signed char* __restrict__ xq, signed char* __restrict__ xl,
1141                                      float* __restrict__ xs, float* __restrict__ xf,
1142                                      const float* __restrict__ w, int n, float eps){
1143  __shared__ float sh[256];
1144  float s=0.f;
1145  for(int i=threadIdx.x;i<n;i+=blockDim.x){ float v=x[i]+y[i]; x[i]=v; s+=v*v; }
1146  sh[threadIdx.x]=s; __syncthreads();
1147  for(int k=blockDim.x/2;k>0;k>>=1){ if(threadIdx.x<k) sh[threadIdx.x]+=sh[threadIdx.x+k]; __syncthreads(); }
1148  float sc=rsqrtf(sh[0]/n+eps); __syncthreads();
1149  for(int i=threadIdx.x;i<n;i+=blockDim.x) xf[i]=x[i]*sc*w[i];
1150  __syncthreads();
1151  int nb=n/32;
1152  for(int b=threadIdx.x;b<nb;b+=blockDim.x){
1153    float amax=1e-30f;
1154    for(int j=0;j<32;++j){ float a=fabsf(xf[b*32+j]); if(a>amax) amax=a; }
1155    float q=amax/127.0f; xs[b]=q;
1156    for(int j=0;j<32;++j) lgx_q8hl(xf[b*32+j]/q, xq, xl, (long)b*32+j);
1157  }
1158}
1159__global__ void gk_add_rmsnorm_q8_hl(float* x, const float* y, float* out, const float* w,
1160                                     signed char* oq, signed char* ol, float* os_, int n, float eps){
1161  __shared__ float sh[256]; float s=0; for(int i=threadIdx.x;i<n;i+=blockDim.x){ float v=x[i]+y[i]; x[i]=v; s+=v*v; }
1162  sh[threadIdx.x]=s; __syncthreads();
1163  for(int k=blockDim.x/2;k>0;k>>=1){ if(threadIdx.x<k) sh[threadIdx.x]+=sh[threadIdx.x+k]; __syncthreads(); }
1164  float scale=rsqrtf(sh[0]/n+eps); for(int i=threadIdx.x;i<n;i+=blockDim.x) out[i]=x[i]*scale*w[i];
1165  __syncthreads();
1166  int warp=threadIdx.x>>5, lane=threadIdx.x&31, nb=n/32;
1167  for(int b=warp;b<nb;b+=(blockDim.x>>5)){ float v=out[b*32+lane], av=fabsf(v);
1168    for(int t=16;t>0;t>>=1) av=fmaxf(av,__shfl_down_sync(0xffffffffu,av,t));
1169    av=__shfl_sync(0xffffffffu,av,0); float amax=av>1e-30f?av:1e-30f; float qs=amax/127.0f;
1170    if(lane==0) os_[b]=qs; lgx_q8hl(v/qs, oq, ol, (long)b*32+lane); }
1171}
1172__global__ void gk_silu_had_q8_hl(const float* __restrict__ g, const float* __restrict__ u,
1173                                  signed char* __restrict__ hq, signed char* __restrict__ hl_,
1174                                  float* __restrict__ hs, int n){
1175  int blk = blockIdx.x * blockDim.x + threadIdx.x; int nb = n / 32; if(blk >= nb) return;
1176  float amax = 1e-30f; float t[32];
1177  for(int j = 0; j < 32; ++j){ float gv = g[blk*32+j]; float h = (gv / (1.0f + __expf(-gv))) * u[blk*32+j];
1178                               t[j] = h; float a = fabsf(h); if(a > amax) amax = a; }
1179  float sc = amax / 127.0f; hs[blk] = sc;
1180  for(int j = 0; j < 32; ++j) lgx_q8hl(t[j]/sc, hq, hl_, (long)blk*32+j);
1181}
1182
1183
1184// The Q8_0 GEMV that keeps its ACTIVATION in f32: the weights are still int8 with a __half block scale, so
1185// the memory traffic — the thing that decides batch-1 decode time — is byte for byte the same as the dp4a
1186// form. Only the arithmetic changes, from a quarter of a dp4a per weight to about three float ops, which
1187// leaves the kernel comfortably memory bound. What it removes is the activation quantization error, which at
1188// batch 1 was never buying anything: one activation vector against a whole weight matrix is not where the
1189// bandwidth goes.
1190__global__ void gk_gemv_deq_h(float* y, const signed char* __restrict__ wq, const __half* __restrict__ ws,
1191                              const float* __restrict__ x, int K, int N){
1192  int o=(blockIdx.x*blockDim.x+threadIdx.x)>>5; if(o>=N) return; int lane=threadIdx.x&31;
1193  const int4* w16=(const int4*)(wq+(long)o*K); const __half* wsr=ws+(long)o*(K/32);
1194  const float4* x4=(const float4*)x;
1195  float acc=0.f; int nq=K/512;
1196  // The four weight words stay in REGISTERS and are unpacked by shifting. Reading them back through a
1197  // `(signed char*)&wv` alias instead puts the int4 in local memory, and the resulting spill cost 12% of
1198  // throughput -- on a kernel whose whole premise was that it would be free.
1199#define LGX_W(W,S) ((float)(int)(signed char)(((W)>>(S))&0xff))
1200  for(int b=0;b<nq;b++){
1201    int4 wv=w16[b*32+lane];
1202    int base4=b*128+lane*4;
1203    float4 a0=x4[base4], a1=x4[base4+1], a2=x4[base4+2], a3=x4[base4+3];
1204    float p = LGX_W(wv.x,0)*a0.x + LGX_W(wv.x,8)*a0.y + LGX_W(wv.x,16)*a0.z + LGX_W(wv.x,24)*a0.w
1205            + LGX_W(wv.y,0)*a1.x + LGX_W(wv.y,8)*a1.y + LGX_W(wv.y,16)*a1.z + LGX_W(wv.y,24)*a1.w
1206            + LGX_W(wv.z,0)*a2.x + LGX_W(wv.z,8)*a2.y + LGX_W(wv.z,16)*a2.z + LGX_W(wv.z,24)*a2.w
1207            + LGX_W(wv.w,0)*a3.x + LGX_W(wv.w,8)*a3.y + LGX_W(wv.w,16)*a3.z + LGX_W(wv.w,24)*a3.w;
1208    acc += p*__half2float(wsr[b*16+lane/2]);
1209  }
1210#undef LGX_W
1211  int done=nq*512;
1212  for(int j=done+lane;j<K;j+=32){ int blk=j/32; acc += (float)wq[(long)o*K+j]*__half2float(wsr[blk])*x[j]; }
1213  for(int s=16;s>0;s>>=1) acc+=__shfl_down_sync(0xffffffffu,acc,s); if(lane==0) y[o]=acc;
1214}
1215
1216
1217// The Q8_0 GEMV with the block scale read as __half — identical arithmetic, 2 bytes per 32 weights instead
1218// of 4. At batch 1 the whole decode is a stream of these, so the 5.6% of weight traffic this returns is
1219// 5.6% off the token time. The scale was an f16 in the checkpoint; widening it on the way to the GPU only
1220// ever cost bandwidth.
1221__global__ void gk_gemv_h(float* y, const signed char* __restrict__ wq, const __half* __restrict__ ws,
1222                          const signed char* __restrict__ xq, const float* __restrict__ xs, int K, int N){
1223  int o=(blockIdx.x*blockDim.x+threadIdx.x)>>5; if(o>=N) return; int lane=threadIdx.x&31;
1224  const int4* w16=(const int4*)(wq+(long)o*K); const int4* x16=(const int4*)xq; const __half* wsr=ws+(long)o*(K/32);
1225  float acc=0.f; int nq=K/512;
1226  for(int b=0;b<nq;b++){ int4 w=w16[b*32+lane], xx=x16[b*32+lane]; int blk=b*16+lane/2;
1227    int d=__dp4a(w.x,xx.x,0)+__dp4a(w.y,xx.y,0)+__dp4a(w.z,xx.z,0)+__dp4a(w.w,xx.w,0);
1228    acc += (float)d * (__half2float(wsr[blk])*xs[blk]); }
1229  int done=nq*512; for(int j=done+lane;j<K;j+=32){ int blk=j/32;
1230    acc += (float)((int)xq[j]*(int)wq[(long)o*K+j])*(__half2float(wsr[blk])*xs[blk]); }
1231  for(int s=16;s>0;s>>=1) acc+=__shfl_down_sync(0xffffffffu,acc,s); if(lane==0) y[o]=acc;
1232}
1233__global__ void gk_embed_h(float* x, const signed char* wq, const __half* ws, const int* d_tok, int E){
1234  int t=blockIdx.x*blockDim.x+threadIdx.x; if(t>=E) return;
1235  long tok=*d_tok; x[t]=(float)wq[tok*E+t]*__half2float(ws[tok*(E/32)+t/32]);
1236}
1237
1238// RMSNorm that emits BOTH the int8-quantized activation (for the big Q8_0 GEMVs) and the f32 normed vector
1239// (for GDN's two small f32-weight gate projections). Emitting both from one pass costs a 20 KB store and
1240// saves re-reading and re-normalizing the hidden state.
1241// The same, with the RESIDUAL ADD fused in. Every layer but the first is entered from a residual add, and
1242// the add is a full pass over the hidden state that the norm is about to read again — so the layer entry
1243// folds `x += y` into the reduction it already does. Removes one launch and one round-trip per layer.
1244__global__ void gk_add_rmsnorm_q8f(float* __restrict__ x, const float* __restrict__ y,
1245                                   signed char* __restrict__ xq, float* __restrict__ xs,
1246                                   float* __restrict__ xf, const float* __restrict__ w, int n, float eps){
1247  __shared__ float sh[256];
1248  float s = 0.f;
1249  for(int i = threadIdx.x; i < n; i += blockDim.x){ float v = x[i] + y[i]; x[i] = v; s += v * v; }
1250  sh[threadIdx.x] = s; __syncthreads();
1251  for(int k = blockDim.x / 2; k > 0; k >>= 1){ if(threadIdx.x < k) sh[threadIdx.x] += sh[threadIdx.x + k]; __syncthreads(); }
1252  float sc = rsqrtf(sh[0] / n + eps); __syncthreads();
1253  for(int i = threadIdx.x; i < n; i += blockDim.x) xf[i] = x[i] * sc * w[i];
1254  __syncthreads();
1255  int nb = n / 32;
1256  for(int b = threadIdx.x; b < nb; b += blockDim.x){
1257    float amax = 1e-30f;
1258    for(int j = 0; j < 32; ++j){ float a = fabsf(xf[b*32+j]); if(a > amax) amax = a; }
1259    float q = amax / 127.0f; xs[b] = q;
1260    for(int j = 0; j < 32; ++j) xq[b*32+j] = (signed char)__float2int_rn(xf[b*32+j] / q);
1261  }
1262}
1263__global__ void gk_rmsnorm_q8f(const float* __restrict__ x, signed char* __restrict__ xq, float* __restrict__ xs,
1264                               float* __restrict__ xf, const float* __restrict__ w, int n, float eps){
1265  __shared__ float sh[256];
1266  float s = 0.f; for(int i = threadIdx.x; i < n; i += blockDim.x) s += x[i] * x[i];
1267  sh[threadIdx.x] = s; __syncthreads();
1268  for(int k = blockDim.x / 2; k > 0; k >>= 1){ if(threadIdx.x < k) sh[threadIdx.x] += sh[threadIdx.x + k]; __syncthreads(); }
1269  float sc = rsqrtf(sh[0] / n + eps); __syncthreads();
1270  for(int i = threadIdx.x; i < n; i += blockDim.x) xf[i] = x[i] * sc * w[i];
1271  __syncthreads();
1272  int nb = n / 32;
1273  for(int b = threadIdx.x; b < nb; b += blockDim.x){
1274    float amax = 1e-30f;
1275    for(int j = 0; j < 32; ++j){ float a = fabsf(xf[b*32+j]); if(a > amax) amax = a; }
1276    float q = amax / 127.0f; xs[b] = q;
1277    for(int j = 0; j < 32; ++j) xq[b*32+j] = (signed char)__float2int_rn(xf[b*32+j] / q);
1278  }
1279}
1280// Diagnostic: L2 norm of a vector, so a debug build can report where the hidden state collapses or explodes.
1281__global__ void gk_dbg3(const float* __restrict__ v, float* __restrict__ out){
1282  if(threadIdx.x < 3) out[threadIdx.x] = v[threadIdx.x];
1283}
1284__global__ void gk_l2probe(const float* __restrict__ v, int n, float* __restrict__ out){
1285  __shared__ float sh[256]; float s = 0.f;
1286  for(int i = threadIdx.x; i < n; i += blockDim.x) s += v[i] * v[i];
1287  sh[threadIdx.x] = s; __syncthreads();
1288  for(int k = blockDim.x / 2; k > 0; k >>= 1){ if(threadIdx.x < k) sh[threadIdx.x] += sh[threadIdx.x + k]; __syncthreads(); }
1289  if(threadIdx.x == 0) *out = sqrtf(sh[0]);
1290}
1291__global__ void gk_gemv_f32w(float* __restrict__ y, const float* __restrict__ w,
1292                             const float* __restrict__ x, int K, int N){
1293  int o = (blockIdx.x * blockDim.x + threadIdx.x) >> 5; if(o >= N) return;
1294  int lane = threadIdx.x & 31;
1295  const float* wr = w + (long)o * K;
1296  float acc = 0.f;
1297  for(int j = lane; j < K; j += 32) acc += wr[j] * x[j];
1298  for(int s = 16; s > 0; s >>= 1) acc += __shfl_down_sync(0xffffffffu, acc, s);
1299  if(lane == 0) y[o] = acc;
1300}
1301// Split the fused projection's k|v halves into their caches at the current position.
1302__global__ void gk_kv_store(float* __restrict__ kc, float* __restrict__ vc, const int* __restrict__ d_pos,
1303                            int KD, const float* __restrict__ kv){
1304  int i = blockIdx.x * blockDim.x + threadIdx.x; if(i >= 2 * KD) return;
1305  long base = (long)(*d_pos) * KD;
1306  if(i < KD) kc[base + i] = kv[i]; else vc[base + (i - KD)] = kv[i];
1307}
1308// silu(gate) * up, with the int8 re-quantization fused into the epilogue.
1309// The same SwiGLU epilogue, but leaving the result in f32 instead of an int8 grid. Used by the deq lane,
1310// where the projection that consumes it reads f32 activations.
1311__global__ void gk_silu_had_f(const float* __restrict__ g, const float* __restrict__ u,
1312                              float* __restrict__ out, int n){
1313  int i = blockIdx.x * blockDim.x + threadIdx.x; if(i >= n) return;
1314  float gv = g[i];
1315  out[i] = (gv / (1.0f + __expf(-gv))) * u[i];
1316}
1317__global__ void gk_silu_had_q8(const float* __restrict__ g, const float* __restrict__ u,
1318                               signed char* __restrict__ hq, float* __restrict__ hs, int n){
1319  int blk = blockIdx.x * blockDim.x + threadIdx.x; int nb = n / 32; if(blk >= nb) return;
1320  float amax = 1e-30f; float t[32];
1321  for(int j = 0; j < 32; ++j){ float gv = g[blk*32+j]; float h = (gv / (1.0f + __expf(-gv))) * u[blk*32+j];
1322                               t[j] = h; float a = fabsf(h); if(a > amax) amax = a; }
1323  float sc = amax / 127.0f; hs[blk] = sc;
1324  for(int j = 0; j < 32; ++j) hq[blk*32+j] = (signed char)__float2int_rn(t[j] / sc);
1325}
1326"#;
1327
1328/// Emit the MTP ACCEPT-RATE PROBE.
1329///
1330/// Multi-token prediction only pays if the draft head is usually right: the speedup is
1331/// `(1+alpha) * full / (full + draft)`, and with the draft costing 7% of a forward that is 1.24x at
1332/// alpha=0.33 and 1.59x at alpha=0.70. The expensive half of MTP is the two-token VERIFY step — GEMVs batched
1333/// over two positions while the recurrence still advances sequentially — so it is worth measuring alpha
1334/// BEFORE building it, not after.
1335///
1336/// This probe does exactly that and nothing more. It walks the known golden continuation, and at each step
1337/// runs the draft head on (last hidden state, token just produced) and asks whether it predicted the NEXT
1338/// golden token. No verification path, no speculation machinery — just the accept rate, which is the number
1339/// that decides whether the rest is worth writing.
1340///
1341/// The draft must not disturb the decode it speculates on: it has its own KV cache and uses an argmax that
1342/// does not advance the position.
1343pub fn emit_qwen38_mtp_probe(
1344    cfg: &Qwen38Cfg,
1345    wdir: &str,
1346    prompt: &[usize],
1347    golden: &[usize],
1348) -> String {
1349    let base = emit_qwen38_generate(cfg, wdir, prompt, golden.len(), true, 3);
1350    let (d, dff) = (cfg.d, cfg.dff);
1351    let (aq, akv) = (cfg.aq(), cfg.akv());
1352    let attnw = 2 * aq + 2 * akv;
1353    let l = cfg.layers; // the MTP block index, 64
1354    let two_d = 2 * d;
1355
1356    // weights the draft head needs, on top of everything the main model already loaded
1357    let mut decls = String::new();
1358    let mut loads = String::new();
1359    for (v, rows, inn, f) in [
1360        (format!("qgkv{l}"), attnw, d, format!("qgkv{l}")),
1361        (format!("Wo{l}"), d, aq, format!("Wo{l}")),
1362        (format!("gu{l}"), 2 * dff, d, format!("gu{l}")),
1363        (format!("Wd{l}"), d, dff, format!("Wd{l}")),
1364        ("ehproj".into(), d, two_d, "ehproj".into()),
1365    ] {
1366        decls.push_str(&format!(
1367            "static signed char* {v}_q; static __half* {v}_s;\n"
1368        ));
1369        loads.push_str(&format!(
1370            "  LDQ({v},(size_t){rows}*{inn},(size_t){rows}*({inn}/32),\"{wdir}/{f}.q\",\"{wdir}/{f}.s\");\n"));
1371    }
1372    for (v, n, f) in [
1373        (format!("an{l}"), d, format!("an{l}")),
1374        (format!("fn{l}"), d, format!("fn{l}")),
1375        (format!("Qn{l}"), cfg.hd, format!("Qn{l}")),
1376        (format!("Kn{l}"), cfg.hd, format!("Kn{l}")),
1377        ("enorm".into(), d, "enorm".into()),
1378        ("hnorm".into(), d, "hnorm".into()),
1379        ("shnorm".into(), d, "shnorm".into()),
1380    ] {
1381        decls.push_str(&format!("static float* {v}_f;\n"));
1382        loads.push_str(&format!("  LDF({v},(size_t){n},\"{wdir}/{f}.f\");\n"));
1383    }
1384
1385    let draft = format!(
1386"static float *mx,*mtmp,*m2n,*mcat,*membed,*mf32,*dlogits,*mkc,*mvc;
1387static signed char *maq,*maql; static float *mas;
1388static int *d_draft;
1389{decls}
1390// One draft step: the nextn adapter, then blk.{l} as an ordinary gated-attention layer + FFN, then the
1391// model's own output head. `x` is the main model's residual stream — the hidden state MTP conditions on.
1392static void mtp_draft(cudaStream_t s){{
1393  gk_embed_h<<<Gs(E),256,0,s>>>(membed,emb_q,emb_s,d_tok,E);
1394  gk_mtp_cat<<<2,256,0,s>>>(mcat,membed,x,enorm_f,hnorm_f,E,EPSV);
1395  gk_quant_act_hl<<<Gs({two_d}),256,0,s>>>(mcat,maq,maql,mas,{two_d});
1396  gk_gemv_hl<<<Gw(E),256,0,s>>>(mx,ehproj_q,ehproj_s,maq,maql,mas,{two_d},E);
1397  gk_rmsnorm_q8f_hl<<<1,256,0,s>>>(mx,maq,maql,mas,mf32,an{l}_f,E,EPSV);
1398  gk_gemv_hl<<<Gw({attnw}),256,0,s>>>(pbuf,qgkv{l}_q,qgkv{l}_s,maq,maql,mas,E,{attnw});
1399  gk_kv_store<<<Gs({akv}*2),256,0,s>>>(mkc,mvc,d_pos,{akv},pbuf+{two_aq});
1400  gk_qk_norm_rope_part<<<{h},128,0,s>>>(pbuf,d_zero,0,Qn{l}_f,{h},{hd},{rot},ROPEV,EPSV);
1401  gk_qk_norm_rope_part<<<{kv},128,0,s>>>(mkc,d_pos,{akv},Kn{l}_f,{kv},{hd},{rot},ROPEV,EPSV);
1402  gk_attn<<<{h},256,(size_t)MAXSEQ*4,s>>>(attnb,pbuf,mkc,mvc,d_pos,{h},{kv},{hd},SCALEV);
1403  gk_gate_mul<<<Gs({aq}),256,0,s>>>(attnb,pbuf+{aq},{aq});
1404  gk_quant_act_hl<<<Gs({aq}),256,0,s>>>(attnb,maq,maql,mas,{aq});
1405  gk_gemv_hl<<<Gw(E),256,0,s>>>(mtmp,Wo{l}_q,Wo{l}_s,maq,maql,mas,{aq},E);
1406  gk_add_rmsnorm_q8_hl<<<1,256,0,s>>>(mx,mtmp,m2n,fn{l}_f,maq,maql,mas,E,EPSV);
1407  gk_gemv_hl<<<Gw({two_dff}),256,0,s>>>(ffbuf,gu{l}_q,gu{l}_s,maq,maql,mas,E,{two_dff});
1408  gk_silu_had_q8_hl<<<Gs({dff}),256,0,s>>>(ffbuf,ffbuf+{dff},maq,maql,mas,{dff});
1409  gk_gemv_hl<<<Gw(E),256,0,s>>>(mtmp,Wd{l}_q,Wd{l}_s,maq,maql,mas,{dff},E);
1410  gk_add<<<Gs(E),256,0,s>>>(mx,mtmp,E);
1411  gk_rmsnorm_q8f_hl<<<1,256,0,s>>>(mx,maq,maql,mas,mf32,shnorm_f,E,EPSV);
1412  gk_gemv_hl<<<Gw(VOCAB),256,0,s>>>(dlogits,Wout_q,Wout_s,maq,maql,mas,E,VOCAB);
1413  gk_argmax_only<<<1,256,0,s>>>(dlogits,VOCAB,d_draft);
1414}}
1415",
1416        two_aq = 2 * aq, two_dff = 2 * dff, h = cfg.h, kv = cfg.kv, hd = cfg.hd, rot = cfg.rope_dim);
1417
1418    let mscratch = two_d.max(dff).max(aq);
1419    let alloc = format!(
1420"  cudaMalloc(&mx,(size_t)E*4); cudaMalloc(&mtmp,(size_t)E*4); cudaMalloc(&m2n,(size_t)E*4);
1421  cudaMalloc(&mcat,(size_t){two_d}*4); cudaMalloc(&membed,(size_t)E*4); cudaMalloc(&mf32,(size_t)E*4);
1422  cudaMalloc(&dlogits,(size_t)VOCAB*4); cudaMalloc(&d_draft,4);
1423  cudaMalloc(&mkc,(size_t)MAXSEQ*{akv}*4); cudaMalloc(&mvc,(size_t)MAXSEQ*{akv}*4);
1424  cudaMalloc(&maq,(size_t){mscratch}); cudaMalloc(&maql,(size_t){mscratch}); cudaMalloc(&mas,(size_t)({mscratch}/32)*4);
1425{loads}");
1426
1427    // splice the draft into the generated program, and replace its generation loop with the probe
1428    let mut out = base.replace(
1429        "static void decode_step(cudaStream_t s){",
1430        &format!("{draft}\nstatic void decode_step(cudaStream_t s){{"),
1431    );
1432    out = out.replace(
1433        "  cudaStream_t s; cudaStreamCreate(&s);",
1434        &format!("{alloc}\n  cudaStream_t s; cudaStreamCreate(&s);"),
1435    );
1436    let gl: Vec<String> = golden.iter().map(|t| t.to_string()).collect();
1437    let probe = format!(
1438"  static const int GOLD[] = {{{}}}; const int NG = sizeof(GOLD)/sizeof(int);
1439  int accepted = 0, checked = 0;
1440  for(int i=0;i<NG;++i){{
1441    // the draft head speculates on the token the main model just produced
1442    mtp_draft(s);
1443    if(cudaStreamSynchronize(s)!=cudaSuccess){{ fprintf(stderr,\"MTP DRAFT FAILED: %s\\n\",cudaGetErrorString(cudaGetLastError())); return 1; }}
1444    int dt=0, mt=0; cudaMemcpy(&dt,d_draft,4,cudaMemcpyDeviceToHost);
1445    cudaMemcpy(&mt,d_tok,4,cudaMemcpyDeviceToHost);
1446    if(mt!=GOLD[i]){{ fprintf(stderr,\"MAIN MODEL DIVERGED at %d: got %d want %d — accept rate would be meaningless\\n\",i,mt,GOLD[i]); return 1; }}
1447    if(i+1<NG){{ ++checked; if(dt==GOLD[i+1]) ++accepted;
1448      printf(\"step %2d: main=%d  draft=%d  next_golden=%d  %s\\n\", i, mt, dt, GOLD[i+1],
1449             dt==GOLD[i+1] ? \"ACCEPT\" : \"reject\"); }}
1450    if(i+1<NG){{ cudaGraphLaunch(ge,s); cudaStreamSynchronize(s); }}
1451  }}
1452  printf(\"MTP_ACCEPT_RATE %d/%d = %.3f\\n\", accepted, checked, checked? (double)accepted/checked : 0.0);
1453  {{ double f=25.85, dr=1.80, a = checked? (double)accepted/checked : 0.0;
1454     printf(\"MTP_PROJECTED_SPEEDUP %.3fx  (draft is %.1f%% of a forward)\\n\", (1+a)*f/(f+dr), 100*dr/f); }}
1455", gl.join(","));
1456    // cut the original generation loop, keep everything up to it
1457    if let Some(cut) = out.find("  printf(\"GENERATED_TOKENS:") {
1458        let end = out[cut..]
1459            .find("\n  {")
1460            .map(|e| cut + e)
1461            .unwrap_or(out.len());
1462        out.replace_range(cut..end, &probe);
1463    }
1464    out
1465}