1use std::collections::HashMap;
19
20use logicaffeine_language::ast::stmt::{Expr, Literal, Stmt};
21
22use crate::intern::{Interner, Symbol};
23use crate::model::quant::GgmlType;
24use crate::tensor_graph::front::TensorOpSpec;
25use crate::tensor_graph::fuse::{leaves, optimize};
26use crate::tensor_graph::graph::{Fused, Op, Storage, Sym, TensorGraph};
27use crate::tensor_graph::symbols::ClassId;
28use crate::tensor_recognize::qwen;
29use crate::tensor_recognize::{ElementwiseOp, ElementwiseSpec, FusedRowSpec, RowReduceKind};
30
31use super::forward_shim::{kernel_refusal, ForwardShim};
32
33#[derive(Debug, Clone, Copy)]
35pub enum InitVal {
36 I(i64),
37 F(f64),
38}
39
40#[derive(Debug, Clone)]
44pub struct Q8Ref {
45 pub quants: String,
46 pub scales: String,
47 pub in_dim: usize,
48 pub out_dim: usize,
49}
50
51#[derive(Debug, Clone)]
56pub struct MoeWeights {
57 pub router: Q8Ref,
58 pub gate: Q8Ref,
59 pub up: Q8Ref,
60 pub down: Q8Ref,
61 pub d: usize,
62 pub dff: usize,
63 pub ne: usize,
64 pub k: usize,
65}
66
67pub fn emit_moe_forward(x: &[f64], w: &MoeWeights) -> String {
75 let (d, dff, ne, k) = (w.d, w.dff, w.ne, w.k);
76 let (dnb, fnb) = (d / 32, dff / 32); assert!(
78 ne <= 256,
79 "moe emitter caps E at 256 (top-K scratch is a 256-float stack array)"
80 );
81
82 let kernels = format!(
86 "__global__ void moe_gemv(const float* a, const signed char* wq, const float* ws, float* y, int N, int K){{\n\
87 \x20 int o=blockIdx.x*blockDim.x+threadIdx.x; if(o>=N) return; int nb=K/32;\n\
88 \x20 const signed char* wr=wq+(long)o*K; const float* wsr=ws+(long)o*nb; double acc=0.0;\n\
89 \x20 for(int bl=0;bl<nb;++bl){{ double dot=0.0; for(int j=0;j<32;++j) dot+=(double)wr[bl*32+j]*(double)a[bl*32+j]; acc+=dot*(double)wsr[bl]; }}\n\
90 \x20 y[o]=(float)acc;\n}}\n\
91 __global__ void moe_silu_had(const float* g, const float* u, float* he, int n){{\n\
92 \x20 int i=blockIdx.x*blockDim.x+threadIdx.x; if(i>=n) return; float gv=g[i]; he[i]=(gv/(1.0f+expf(-gv)))*u[i];\n}}\n\
93 __global__ void moe_zero(float* y, int n){{ int i=blockIdx.x*blockDim.x+threadIdx.x; if(i<n) y[i]=0.0f; }}\n\
94 __global__ void moe_combine(float* H, const float* oute, const float* wv, int e, int d){{\n\
95 \x20 int o=blockIdx.x*blockDim.x+threadIdx.x; if(o<d) H[o]+=wv[e]*oute[o];\n}}\n\
96 // top-K router: softmax over the E logits, keep the K largest (masked argmax), renormalize. w[e]=0 for\n\
97 // the non-selected — the data-dependent routing decision, computed on-device.\n\
98 __global__ void moe_topk(const float* logits, float* w, int E, int K){{\n\
99 \x20 if(threadIdx.x!=0) return; float p[256]; float pm[256];\n\
100 \x20 float m=logits[0]; for(int e=1;e<E;++e) if(logits[e]>m) m=logits[e];\n\
101 \x20 float s=0.0f; for(int e=0;e<E;++e) s+=expf(logits[e]-m);\n\
102 \x20 for(int e=0;e<E;++e){{ p[e]=expf(logits[e]-m)/s; pm[e]=p[e]; w[e]=0.0f; }}\n\
103 \x20 float wsum=0.0f;\n\
104 \x20 for(int r=0;r<K;++r){{ float bv=-1e30f; int bi=0; for(int e=0;e<E;++e) if(pm[e]>bv){{ bv=pm[e]; bi=e; }} wsum+=p[bi]; w[bi]=p[bi]; pm[bi]=-1e30f; }}\n\
105 \x20 for(int e=0;e<E;++e) w[e]/=wsum;\n}}\n"
106 );
107
108 let load_q8 = |var: &str, q: &Q8Ref| -> String {
110 let nb = q.in_dim / 32;
111 let (qn, sn) = (q.in_dim * q.out_dim, q.out_dim * nb);
112 format!(
113 " signed char* {var}_q; if(cudaMallocManaged(&{var}_q,(size_t){qn})){{ fprintf(stderr,\"malloc\\n\"); return 1; }}\n\
114 \x20 float* {var}_s; if(cudaMallocManaged(&{var}_s,(size_t){sn}*sizeof(float))){{ fprintf(stderr,\"malloc\\n\"); return 1; }}\n\
115 \x20 {{ FILE* f=fopen(\"{qp}\",\"rb\"); if(!f||fread({var}_q,1,(size_t){qn},f)!=(size_t){qn}){{ fprintf(stderr,\"q {var}\\n\"); return 1; }} fclose(f); }}\n\
116 \x20 {{ FILE* f=fopen(\"{sp}\",\"rb\"); if(!f||fread({var}_s,sizeof(float),(size_t){sn},f)!=(size_t){sn}){{ fprintf(stderr,\"s {var}\\n\"); return 1; }} fclose(f); }}\n",
117 qp = q.quants, sp = q.scales
118 )
119 };
120 let mut allocs = String::new();
121 allocs.push_str(&load_q8("Wr", &w.router));
122 allocs.push_str(&load_q8("Wg", &w.gate));
123 allocs.push_str(&load_q8("Wu", &w.up));
124 allocs.push_str(&load_q8("Wd", &w.down));
125 for (nm, n) in [
127 ("x", d),
128 ("logits", ne),
129 ("w", ne),
130 ("gate_e", dff),
131 ("up_e", dff),
132 ("he", dff),
133 ("oute", d),
134 ("H", d),
135 ] {
136 allocs.push_str(&format!(" float* {nm}; if(cudaMallocManaged(&{nm},(size_t){n}*sizeof(float))){{ fprintf(stderr,\"malloc\\n\"); return 1; }}\n"));
137 }
138 let mut fills = String::new();
139 for (i, v) in x.iter().enumerate() {
140 fills.push_str(&format!(" x[{i}]={:?}f;\n", v));
141 }
142
143 let etopk = ne.min(1024);
145 let mut body = String::new();
146 body.push_str(&format!(
147 " moe_gemv<<<({ne}+255)/256,256,0,_st>>>(x,Wr_q,Wr_s,logits,{ne},{d});\n"
148 ));
149 body.push_str(&format!(
150 " moe_topk<<<1,{etopk},0,_st>>>(logits,w,{ne},{k});\n"
151 ));
152 body.push_str(&format!(
153 " moe_zero<<<({d}+255)/256,256,0,_st>>>(H,{d});\n"
154 ));
155 for e in 0..ne {
156 let (goff, gsoff) = (e * dff * d, e * dff * dnb);
157 let (doff, dsoff) = (e * d * dff, e * d * fnb);
158 body.push_str(&format!(
159 " moe_gemv<<<({dff}+255)/256,256,0,_st>>>(x,Wg_q+{goff},Wg_s+{gsoff},gate_e,{dff},{d});\n\
160 \x20 moe_gemv<<<({dff}+255)/256,256,0,_st>>>(x,Wu_q+{goff},Wu_s+{gsoff},up_e,{dff},{d});\n\
161 \x20 moe_silu_had<<<({dff}+255)/256,256,0,_st>>>(gate_e,up_e,he,{dff});\n\
162 \x20 moe_gemv<<<({d}+255)/256,256,0,_st>>>(he,Wd_q+{doff},Wd_s+{dsoff},oute,{d},{dff});\n\
163 \x20 moe_combine<<<({d}+255)/256,256,0,_st>>>(H,oute,w,{e},{d});\n"
164 ));
165 }
166
167 format!(
168 "// Auto-generated by LOGOS codegen_cuda::qwen_emit — a Mixture-of-Experts FFN block (E={ne}, top-{k},\n\
169 // d={d}, dff={dff}) over real int8 weights, captured as one CUDA graph. The SAME emitter serves any E.\n\
170 #include <cstdio>\n#include <cstdlib>\n#include <cuda_runtime.h>\n#include <cmath>\n\n\
171 {kernels}\nint main(void){{\n{allocs}{fills}\n\
172 \x20 cudaStream_t _st; if(cudaStreamCreate(&_st)!=cudaSuccess){{ fprintf(stderr,\"stream\\n\"); return 1; }}\n\
173 {body} if(cudaStreamSynchronize(_st)!=cudaSuccess){{ fprintf(stderr,\"sync\\n\"); return 1; }}\n\
174 \x20 cudaGraph_t _g; cudaGraphExec_t _ge;\n\
175 \x20 if(cudaStreamBeginCapture(_st, cudaStreamCaptureModeGlobal)!=cudaSuccess){{ fprintf(stderr,\"capture\\n\"); return 1; }}\n\
176 {body} if(cudaStreamEndCapture(_st,&_g)!=cudaSuccess){{ fprintf(stderr,\"endcap\\n\"); return 1; }}\n\
177 \x20 if(cudaGraphInstantiate(&_ge,_g,0)!=cudaSuccess){{ fprintf(stderr,\"inst\\n\"); return 1; }}\n\
178 \x20 cudaGraphLaunch(_ge,_st); cudaStreamSynchronize(_st);\n\
179 \x20 cudaEvent_t _e0,_e1; cudaEventCreate(&_e0); cudaEventCreate(&_e1);\n\
180 \x20 cudaEventRecord(_e0,_st); for(int _it=0;_it<20;++_it){{ cudaGraphLaunch(_ge,_st); }}\n\
181 \x20 cudaEventRecord(_e1,_st); cudaStreamSynchronize(_st); float _ms=0.0f; cudaEventElapsedTime(&_ms,_e0,_e1);\n\
182 \x20 fprintf(stderr,\"MOE_MS %f\\n\", _ms/20.0f);\n\
183 \x20 for(int o=0;o<{d};++o) printf(\"%.6f\\n\",(double)H[o]);\n return 0;\n}}\n"
184 )
185}
186
187pub use crate::tensor_recognize::qwen::{recognize_moe, MoeSpec};
188
189pub fn collect_inits(
194 stmts: &[Stmt],
195 interner: &Interner,
196) -> HashMap<String, Vec<(usize, InitVal)>> {
197 fn lit_int(e: &Expr) -> Option<i64> {
198 match e {
199 Expr::Literal(Literal::Number(n)) => Some(*n),
200 _ => None,
201 }
202 }
203 fn lit_val(e: &Expr) -> Option<InitVal> {
204 match e {
205 Expr::Literal(Literal::Number(n)) => Some(InitVal::I(*n)),
206 Expr::Literal(Literal::Float(f)) => Some(InitVal::F(*f)),
207 _ => None,
208 }
209 }
210 fn walk(stmts: &[Stmt], interner: &Interner, out: &mut HashMap<String, Vec<(usize, InitVal)>>) {
211 for s in stmts {
212 match s {
213 Stmt::SetIndex {
214 collection,
215 index,
216 value,
217 } => {
218 let (coll, idx, val): (&Expr, &Expr, &Expr) = (*collection, *index, *value);
219 if let (Expr::Identifier(c), Some(k), Some(v)) =
220 (coll, lit_int(idx), lit_val(val))
221 {
222 if k >= 1 {
223 out.entry(interner.resolve(*c).to_string())
224 .or_default()
225 .push((k as usize - 1, v));
226 }
227 }
228 }
229 Stmt::Splice { body } => walk(body, interner, out),
230 Stmt::While { body, .. } | Stmt::Repeat { body, .. } => walk(body, interner, out),
231 Stmt::If {
232 then_block,
233 else_block,
234 ..
235 } => {
236 walk(then_block, interner, out);
237 if let Some(eb) = else_block {
238 walk(eb, interner, out);
239 }
240 }
241 _ => {}
242 }
243 }
244 }
245 let mut out = HashMap::new();
246 walk(stmts, interner, &mut out);
247 out
248}
249
250#[derive(Debug, Clone, PartialEq, Eq)]
252pub enum ForwardError {
253 NoStages,
255 MissingMoeWeights(String),
257 Refused(Vec<StageRefusal>),
259}
260
261impl std::fmt::Display for ForwardError {
262 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
263 match self {
264 ForwardError::NoStages => write!(f, "no tensor-op stage recognized in the program"),
265 ForwardError::MissingMoeWeights(v) => {
266 write!(f, "moe stage `{v}` has no entry in the MoE weight manifest")
267 }
268 ForwardError::Refused(rs) => {
269 write!(f, "the CUDA forward refuses {} statement(s): ", rs.len())?;
270 for (k, r) in rs.iter().enumerate() {
271 if k > 0 {
272 write!(f, "; ")?;
273 }
274 write!(f, "{r}")?;
275 }
276 Ok(())
277 }
278 }
279 }
280}
281
282#[derive(Debug, Clone, PartialEq, Eq)]
284pub enum StageRefusal {
285 Unrecognized { stmt: usize, what: String },
288 UnliftedWrite {
290 stmt: usize,
291 tensor: String,
292 why: &'static str,
293 },
294 NoKernel {
297 stmt: usize,
298 kind: &'static str,
299 out: String,
300 why: &'static str,
301 },
302}
303
304impl std::fmt::Display for StageRefusal {
305 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
306 match self {
307 StageRefusal::Unrecognized { stmt, what } => {
308 write!(f, "statement {stmt} ({what}) is no tensor op the front end lifts")
309 }
310 StageRefusal::UnliftedWrite { stmt, tensor, why } => {
311 write!(f, "statement {stmt} writes `{tensor}`: {why}")
312 }
313 StageRefusal::NoKernel {
314 stmt,
315 kind,
316 out,
317 why,
318 } => write!(
319 f,
320 "statement {stmt} binds `{out}` with {kind}, which the CUDA forward cannot lower: {why}"
321 ),
322 }
323 }
324}
325
326const MOE_ROUTER_TOPK_KERNELS: &str = "\
336// FAST router GEMV (warp per output row, `char4`-coalesced int8 × f32 activation, f32 accumulate) — replaces the
337// dense f64 thread-per-output `moe_gemv` that ran the WHOLE 128-expert routing on ONE block/SM (the batch-1\n\
338// bottleneck: 2000× slower than bandwidth). f32 vs f64 does not change which top-K experts route ⇒ token-exact.\n\
339__global__ void moe_router_fast(const float* a, const signed char* wq, const float* ws, float* y, int N, int K){\n\
340\x20 int o=(blockIdx.x*blockDim.x+threadIdx.x)>>5; if(o>=N) return; int lane=threadIdx.x&31; int nb=K/32, nq=K/128;\n\
341\x20 const signed char* wr=wq+(long)o*K; const float* wsr=ws+(long)o*nb; const char4* w4=(const char4*)wr;\n\
342\x20 float acc=0.0f;\n\
343\x20 for(int b=0;b<nq;++b){ char4 w=w4[b*32+lane]; int blk=b*4+lane/8; const float* at=a+b*128+lane*4;\n\
344\x20 acc += wsr[blk]*((float)w.x*at[0]+(float)w.y*at[1]+(float)w.z*at[2]+(float)w.w*at[3]); }\n\
345\x20 for(int t=nq*128+lane;t<K;t+=32){ int blk=t/32; acc += wsr[blk]*(float)wr[t]*a[t]; }\n\
346\x20 for(int s=16;s>0;s>>=1) acc+=__shfl_down_sync(0xffffffffu,acc,s);\n\
347\x20 if(lane==0) y[o]=acc;\n}\n\
348// Top-K router select. The 128-expert softmax (max + exp + sum) is done BLOCK-PARALLEL into shared `sp` (each\n\
349// global logit read + expf once, not serialized in one thread — the old single-thread form was 30us/call, the\n\
350// #2 batch-1 hog); only the tiny top-K argmax scan stays on thread 0, now over fast shared memory. E<=1024.\n\
351__global__ void moe_topk_idx(const float* logits, int* idx, float* w, int E, int K){\n\
352\x20 __shared__ float sp[1024]; __shared__ float red[32];\n\
353\x20 int t=threadIdx.x, nt=blockDim.x, wp=t>>5, ln=t&31, nw=(nt+31)>>5;\n\
354\x20 float lm=-1e30f; for(int e=t;e<E;e+=nt) lm=fmaxf(lm,logits[e]);\n\
355\x20 for(int s=16;s>0;s>>=1) lm=fmaxf(lm,__shfl_down_sync(0xffffffffu,lm,s));\n\
356\x20 if(ln==0) red[wp]=lm; __syncthreads();\n\
357\x20 if(t==0){ float m=red[0]; for(int i=1;i<nw;++i) m=fmaxf(m,red[i]); red[0]=m; } __syncthreads();\n\
358\x20 float mx=red[0];\n\
359\x20 float ls=0.0f; for(int e=t;e<E;e+=nt){ float p=expf(logits[e]-mx); sp[e]=p; ls+=p; }\n\
360\x20 for(int s=16;s>0;s>>=1) ls+=__shfl_down_sync(0xffffffffu,ls,s);\n\
361\x20 if(ln==0) red[wp]=ls; __syncthreads();\n\
362\x20 if(t==0){ float s=0.0f; for(int i=0;i<nw;++i) s+=red[i]; red[0]=s; } __syncthreads();\n\
363\x20 float sum=red[0];\n\
364\x20 if(t==0){ float wsum=0.0f;\n\
365\x20 for(int r=0;r<K;++r){ float bv=-1e30f; int bi=0; for(int e=0;e<E;++e) if(sp[e]>bv){ bv=sp[e]; bi=e; } idx[r]=bi; float pv=sp[bi]/sum; w[r]=pv; wsum+=pv; sp[bi]=-1e30f; }\n\
366\x20 for(int r=0;r<K;++r) w[r]/=wsum; }\n}\n";
367
368const MOE_TWO_PASS_KERNELS: &str = "\
370// DEEPEST FUSION + TWO-PASS INT8-ACTIVATION dp4a (batch-1 latency-optimal AND ~14-bit exact). Two hard barriers
371// (router, h-complete); everything between fuses. gate+up+SwiGLU collapse into ONE kernel, down+combine into
372// another; only h and H touch HBM. The shared activation is quantized ONCE per MoE stage into a hi byte + a lo
373// residual byte (moe_qact); both fused kernels run TWO int8×int8 `__dp4a` per block (hi and lo) — the SHORT
374// dependency chain that wins the latency-bound regime, but with ~14-bit activation so a near-tie token does NOT
375// flip (single int8 flips it — like llama.cpp). Weights read once ⇒ memory cost unchanged. sl=sh/128. Scalar
376// tails cover Kd%128. N=dff/d, Kd=d/dff.\n\
377__global__ void moe_qact(const float* a, signed char* aqh, signed char* aql, float* as_, int K){\n\
378\x20 int nb=K/32; int blk=blockIdx.x*(blockDim.x/32)+threadIdx.x/32; if(blk>=nb) return;\n\
379\x20 int lane=threadIdx.x&31; float v=a[blk*32+lane], av=fabsf(v);\n\
380\x20 for(int s=16;s>0;s>>=1) av=fmaxf(av,__shfl_down_sync(0xffffffffu,av,s));\n\
381\x20 av=__shfl_sync(0xffffffffu,av,0); float amax=av>1e-30f?av:1e-30f; float sh=amax/127.0f;\n\
382\x20 if(lane==0) as_[blk]=sh;\n\
383\x20 int qh=(int)rintf(v/sh); if(qh>127)qh=127; if(qh<-128)qh=-128; aqh[blk*32+lane]=(signed char)qh;\n\
384\x20 float r=v-qh*sh; float sl=sh*0.0078125f; int ql=(int)rintf(r/sl); if(ql>127)ql=127; if(ql<-128)ql=-128; aql[blk*32+lane]=(signed char)ql;\n}\n\
385__global__ void moe_gate_up_silu(const signed char* xqh, const signed char* xql, const float* xs, const signed char* wg_q, const float* wg_s, const signed char* wu_q, const float* wu_s, const int* idx, float* h, int K, int N, int Kd){\n\
386\x20 long row=(blockIdx.x*(long)blockDim.x+threadIdx.x)>>5; if(row>=(long)K*N) return; int lane=threadIdx.x&31;\n\
387\x20 int kk=row/N, j=row%N; int e=idx[kk]; int nb=Kd/32, nq=Kd/128;\n\
388\x20 const signed char* gwr=wg_q+((long)e*N+j)*Kd; const int* gw4=(const int*)gwr; const float* gsr=wg_s+((long)e*N+j)*nb;\n\
389\x20 const signed char* uwr=wu_q+((long)e*N+j)*Kd; const int* uw4=(const int*)uwr; const float* usr=wu_s+((long)e*N+j)*nb;\n\
390\x20 const signed char* xhb=xqh; const int* xh4=(const int*)xqh; const signed char* xlb=xql; const int* xl4=(const int*)xql;\n\
391\x20 float ga=0.0f, ua=0.0f;\n\
392\x20 for(int b=0;b<nq;++b){ int blk=b*4+lane/8; int aih=xh4[b*32+lane]; int ail=xl4[b*32+lane]; float sh=xs[blk]; float sl=sh*0.0078125f; int gwi=gw4[b*32+lane]; int uwi=uw4[b*32+lane];\n\
393\x20 ga+=gsr[blk]*(sh*(float)__dp4a(gwi,aih,0)+sl*(float)__dp4a(gwi,ail,0));\n\
394\x20 ua+=usr[blk]*(sh*(float)__dp4a(uwi,aih,0)+sl*(float)__dp4a(uwi,ail,0)); }\n\
395\x20 for(int t=nq*128+lane;t<Kd;t+=32){ int blk=t/32; float sh=xs[blk]; float sl=sh*0.0078125f; int gwj=(int)gwr[t]; int uwj=(int)uwr[t]; int xh=(int)xhb[t]; int xl=(int)xlb[t]; ga+=gsr[blk]*(sh*(float)(gwj*xh)+sl*(float)(gwj*xl)); ua+=usr[blk]*(sh*(float)(uwj*xh)+sl*(float)(uwj*xl)); }\n\
396\x20 for(int s=16;s>0;s>>=1){ ga+=__shfl_down_sync(0xffffffffu,ga,s); ua+=__shfl_down_sync(0xffffffffu,ua,s); }\n\
397\x20 if(lane==0) h[row]=(ga/(1.0f+expf(-ga)))*ua;\n}\n\
398__global__ void moe_down_combine(const signed char* hqh, const signed char* hql, const float* hs, const signed char* wd_q, const float* wd_s, const int* idx, const float* wc, float* H, int K, int N, int Kd){\n\
399\x20 int o=blockIdx.x; int warp=threadIdx.x>>5, lane=threadIdx.x&31;\n\
400\x20 int e=idx[warp]; int nb=Kd/32, nq=Kd/128;\n\
401\x20 const signed char* hhb=hqh+(long)warp*Kd; const int* hh4=(const int*)hhb; const signed char* hlb=hql+(long)warp*Kd; const int* hl4=(const int*)hlb; const float* hsr=hs+(long)warp*nb;\n\
402\x20 const signed char* wr=wd_q+((long)e*N+o)*Kd; const int* w4=(const int*)wr; const float* wsr=wd_s+((long)e*N+o)*nb;\n\
403\x20 float acc=0.0f;\n\
404\x20 for(int b=0;b<nq;++b){ int blk=b*4+lane/8; int wi=w4[b*32+lane]; float sh=hsr[blk]; float sl=sh*0.0078125f; acc+=wsr[blk]*(sh*(float)__dp4a(wi,hh4[b*32+lane],0)+sl*(float)__dp4a(wi,hl4[b*32+lane],0)); }\n\
405\x20 for(int t=nq*128+lane;t<Kd;t+=32){ int blk=t/32; float sh=hsr[blk]; float sl=sh*0.0078125f; int wj=(int)wr[t]; acc+=wsr[blk]*(sh*(float)(wj*(int)hhb[t])+sl*(float)(wj*(int)hlb[t])); }\n\
406\x20 for(int s=16;s>0;s>>=1) acc+=__shfl_down_sync(0xffffffffu,acc,s);\n\
407\x20 __shared__ float part[64];\n\
408\x20 if(lane==0) part[warp]=wc[warp]*acc;\n\
409\x20 __syncthreads();\n\
410\x20 if(threadIdx.x==0){ float sum=0.0f; for(int kk=0;kk<K;++kk) sum+=part[kk]; H[o]=sum; }\n}\n";
411
412const MOE_SINGLE_PASS_KERNELS: &str = "\
417// DEEPEST FUSION + SINGLE-PASS INT8-ACTIVATION dp4a (batch-1 latency-optimal, llama.cpp-matched precision).
418// Two hard barriers (router, h-complete); everything between fuses. gate+up+SwiGLU collapse into ONE kernel,\n\
419// down+combine into another; only h and H touch HBM. The shared activation is quantized ONCE per MoE stage\n\
420// (moe_qact); both fused kernels run ONE int8×int8 `__dp4a` per block — the SHORT dependency chain that wins\n\
421// the latency-bound regime, at llama.cpp's activation precision (a near-tie logit can flip exactly as its\n\
422// does; the TwoPassInt8 mode holds it). Weights read once ⇒ memory cost unchanged. Scalar tails cover Kd%128.\n\
423__global__ void moe_qact(const float* a, signed char* aq, float* as_, int K){\n\
424\x20 int nb=K/32; int blk=blockIdx.x*(blockDim.x/32)+threadIdx.x/32; if(blk>=nb) return;\n\
425\x20 int lane=threadIdx.x&31; float v=a[blk*32+lane], av=fabsf(v);\n\
426\x20 for(int s=16;s>0;s>>=1) av=fmaxf(av,__shfl_down_sync(0xffffffffu,av,s));\n\
427\x20 av=__shfl_sync(0xffffffffu,av,0); float amax=av>1e-30f?av:1e-30f; float sc=amax/127.0f;\n\
428\x20 if(lane==0) as_[blk]=sc;\n\
429\x20 int q=(int)rintf(v/sc); if(q>127)q=127; if(q<-128)q=-128; aq[blk*32+lane]=(signed char)q;\n}\n\
430__global__ void moe_gate_up_silu(const signed char* xq, const float* xs, const signed char* wg_q, const float* wg_s, const signed char* wu_q, const float* wu_s, const int* idx, float* h, int K, int N, int Kd){\n\
431\x20 long row=(blockIdx.x*(long)blockDim.x+threadIdx.x)>>5; if(row>=(long)K*N) return; int lane=threadIdx.x&31;\n\
432\x20 int kk=row/N, j=row%N; int e=idx[kk]; int nb=Kd/32, nq=Kd/128;\n\
433\x20 const signed char* gwr=wg_q+((long)e*N+j)*Kd; const int* gw4=(const int*)gwr; const float* gsr=wg_s+((long)e*N+j)*nb;\n\
434\x20 const signed char* uwr=wu_q+((long)e*N+j)*Kd; const int* uw4=(const int*)uwr; const float* usr=wu_s+((long)e*N+j)*nb;\n\
435\x20 const signed char* xb=xq; const int* x4=(const int*)xq;\n\
436\x20 float ga=0.0f, ua=0.0f; int nq16=Kd/512;\n\
437\x20 const int4* gw16=(const int4*)gwr; const int4* uw16=(const int4*)uwr; const int4* x16=(const int4*)xq;\n\
438\x20 for(int b=0;b<nq16;++b){ int blk=b*16+lane/2; float sc=xs[blk]; int4 av=x16[b*32+lane]; int4 gv=gw16[b*32+lane]; int4 uv=uw16[b*32+lane];\n\
439\x20 int gd=__dp4a(gv.x,av.x,0); gd=__dp4a(gv.y,av.y,gd); gd=__dp4a(gv.z,av.z,gd); gd=__dp4a(gv.w,av.w,gd);\n\
440\x20 int ud=__dp4a(uv.x,av.x,0); ud=__dp4a(uv.y,av.y,ud); ud=__dp4a(uv.z,av.z,ud); ud=__dp4a(uv.w,av.w,ud);\n\
441\x20 ga+=gsr[blk]*sc*(float)gd; ua+=usr[blk]*sc*(float)ud; }\n\
442\x20 for(int b4=nq16*4;b4<nq;++b4){ int blk=b4*4+lane/8; int ai=x4[b4*32+lane]; float sc=xs[blk]; int gwi=gw4[b4*32+lane]; int uwi=uw4[b4*32+lane]; ga+=gsr[blk]*sc*(float)__dp4a(gwi,ai,0); ua+=usr[blk]*sc*(float)__dp4a(uwi,ai,0); }\n\
443\x20 for(int t=nq*128+lane;t<Kd;t+=32){ int blk=t/32; float sc=xs[blk]; int gwj=(int)gwr[t]; int uwj=(int)uwr[t]; int xv=(int)xb[t]; ga+=gsr[blk]*sc*(float)(gwj*xv); ua+=usr[blk]*sc*(float)(uwj*xv); }\n\
444\x20 for(int s=16;s>0;s>>=1){ ga+=__shfl_down_sync(0xffffffffu,ga,s); ua+=__shfl_down_sync(0xffffffffu,ua,s); }\n\
445\x20 if(lane==0) h[row]=(ga/(1.0f+expf(-ga)))*ua;\n}\n\
446__global__ void moe_down_combine(const signed char* hq, const float* hs, const signed char* wd_q, const float* wd_s, const int* idx, const float* wc, float* H, int K, int N, int Kd){\n\
447\x20 int o=blockIdx.x; int warp=threadIdx.x>>5, lane=threadIdx.x&31;\n\
448\x20 int e=idx[warp]; int nb=Kd/32, nq=Kd/128;\n\
449\x20 const signed char* hb=hq+(long)warp*Kd; const int* h4=(const int*)hb; const float* hsr=hs+(long)warp*nb;\n\
450\x20 const signed char* wr=wd_q+((long)e*N+o)*Kd; const int* w4=(const int*)wr; const float* wsr=wd_s+((long)e*N+o)*nb;\n\
451\x20 float acc=0.0f; int nq16=Kd/512;\n\
452\x20 const int4* w16=(const int4*)wr; const int4* h16=(const int4*)hb;\n\
453\x20 for(int b=0;b<nq16;++b){ int blk=b*16+lane/2; int4 wv=w16[b*32+lane]; int4 hv=h16[b*32+lane];\n\
454\x20 int d=__dp4a(wv.x,hv.x,0); d=__dp4a(wv.y,hv.y,d); d=__dp4a(wv.z,hv.z,d); d=__dp4a(wv.w,hv.w,d);\n\
455\x20 acc+=wsr[blk]*hsr[blk]*(float)d; }\n\
456\x20 for(int b4=nq16*4;b4<nq;++b4){ int blk=b4*4+lane/8; int wi=w4[b4*32+lane]; acc+=wsr[blk]*hsr[blk]*(float)__dp4a(wi,h4[b4*32+lane],0); }\n\
457\x20 for(int t=nq*128+lane;t<Kd;t+=32){ int blk=t/32; int wj=(int)wr[t]; acc+=wsr[blk]*hsr[blk]*(float)(wj*(int)hb[t]); }\n\
458\x20 for(int s=16;s>0;s>>=1) acc+=__shfl_down_sync(0xffffffffu,acc,s);\n\
459\x20 __shared__ float part[64];\n\
460\x20 if(lane==0) part[warp]=wc[warp]*acc;\n\
461\x20 __syncthreads();\n\
462\x20 if(threadIdx.x==0){ float sum=0.0f; for(int kk=0;kk<K;++kk) sum+=part[kk]; H[o]=sum; }\n}\n";
463
464pub fn moe_dp4a_kernels(two_pass: bool) -> String {
468 let mut s = String::from(MOE_ROUTER_TOPK_KERNELS);
469 s.push_str(if two_pass {
470 MOE_TWO_PASS_KERNELS
471 } else {
472 MOE_SINGLE_PASS_KERNELS
473 });
474 s
475}
476
477const MOE_KERNELS: &str = "\
482__global__ void moe_gemv(const float* a, const signed char* wq, const float* ws, float* y, int N, int K){\n\
483\x20 int o=blockIdx.x*blockDim.x+threadIdx.x; if(o>=N) return; int nb=K/32;\n\
484\x20 const signed char* wr=wq+(long)o*K; const float* wsr=ws+(long)o*nb; double acc=0.0;\n\
485\x20 for(int bl=0;bl<nb;++bl){ double dot=0.0; for(int j=0;j<32;++j) dot+=(double)wr[bl*32+j]*(double)a[bl*32+j]; acc+=dot*(double)wsr[bl]; }\n\
486\x20 y[o]=(float)acc;\n}\n\
487__global__ void moe_silu_had(const float* g, const float* u, float* he, int n){\n\
488\x20 int i=blockIdx.x*blockDim.x+threadIdx.x; if(i>=n) return; float gv=g[i]; he[i]=(gv/(1.0f+expf(-gv)))*u[i];\n}\n\
489__global__ void moe_zero(float* y, int n){ int i=blockIdx.x*blockDim.x+threadIdx.x; if(i<n) y[i]=0.0f; }\n\
490__global__ void moe_combine(float* H, const float* oute, const float* wv, int e, int d){\n\
491\x20 int o=blockIdx.x*blockDim.x+threadIdx.x; if(o<d) H[o]+=wv[e]*oute[o];\n}\n\
492__global__ void moe_topk(const float* logits, float* w, int E, int K){\n\
493\x20 if(threadIdx.x!=0) return; float p[256]; float pm[256];\n\
494\x20 float m=logits[0]; for(int e=1;e<E;++e) if(logits[e]>m) m=logits[e];\n\
495\x20 float s=0.0f; for(int e=0;e<E;++e) s+=expf(logits[e]-m);\n\
496\x20 for(int e=0;e<E;++e){ p[e]=expf(logits[e]-m)/s; pm[e]=p[e]; w[e]=0.0f; }\n\
497\x20 float wsum=0.0f;\n\
498\x20 for(int r=0;r<K;++r){ float bv=-1e30f; int bi=0; for(int e=0;e<E;++e) if(pm[e]>bv){ bv=pm[e]; bi=e; } wsum+=p[bi]; w[bi]=p[bi]; pm[bi]=-1e30f; }\n\
499\x20 for(int e=0;e<E;++e) w[e]/=wsum;\n}\n";
500
501#[allow(clippy::type_complexity)]
504pub fn recognize_attention(
505 stmts: &[Stmt],
506) -> Option<(Symbol, Symbol, Symbol, Symbol, usize, usize, usize, usize)> {
507 qwen::recognize_attention(stmts).map(|a| (a.q, a.kc, a.vc, a.out, a.h, a.kv, a.hd, a.l))
508}
509
510pub fn forward_graph(
516 stmts: &[Stmt],
517 interner: &Interner,
518 q8: &HashMap<String, Q8Ref>,
519 moe: &HashMap<String, MoeWeights>,
520 kind: Q8MatKind,
521) -> Result<TensorGraph, ForwardError> {
522 forward_graph_holding(stmts, interner, q8, moe, kind, &[])
523}
524
525pub fn forward_graph_holding(
527 stmts: &[Stmt],
528 interner: &Interner,
529 q8: &HashMap<String, Q8Ref>,
530 moe: &HashMap<String, MoeWeights>,
531 kind: Q8MatKind,
532 held: &[&str],
533) -> Result<TensorGraph, ForwardError> {
534 let front = crate::spatial::passes::recognize_stages::walk(stmts, interner);
535 let mut refusals: Vec<StageRefusal> = front
536 .unrecognized
537 .iter()
538 .map(|(stmt, what)| StageRefusal::Unrecognized {
539 stmt: *stmt,
540 what: what.clone(),
541 })
542 .chain(
543 front
544 .unlifted_writes
545 .iter()
546 .map(|(stmt, tensor, why)| StageRefusal::UnliftedWrite {
547 stmt: *stmt,
548 tensor: tensor.clone(),
549 why,
550 }),
551 )
552 .collect();
553 for st in &front.stages {
554 if let Some(why) = kernel_refusal(&st.op) {
555 refusals.push(StageRefusal::NoKernel {
556 stmt: st.stmt_index,
557 kind: st.op.kind(),
558 out: st.out.clone(),
559 why,
560 });
561 }
562 }
563 if !refusals.is_empty() {
564 refusals.sort_by_key(StageRefusal::stmt);
565 return Err(ForwardError::Refused(refusals));
566 }
567 if front.stages.is_empty() {
568 return Err(ForwardError::NoStages);
569 }
570 let mut stored: std::collections::BTreeSet<&str> = q8.keys().map(String::as_str).collect();
571 for st in &front.stages {
572 if matches!(st.op, TensorOpSpec::Moe(_)) && moe.contains_key(&st.out) {
573 stored.extend(st.ins[1..5].iter().map(String::as_str));
574 }
575 }
576 let storage = |t: &str| {
577 if stored.contains(t) {
578 Storage::Rows { format: GgmlType::Q8_0, transposed: true }
579 } else {
580 Storage::Values
581 }
582 };
583 let lifted = TensorGraph::lift_stages(&front, None, None, &storage);
584 Ok(optimize(&lifted, &ForwardShim { kind }, held).graph)
585}
586
587impl StageRefusal {
588 pub fn stmt(&self) -> usize {
590 match self {
591 StageRefusal::Unrecognized { stmt, .. }
592 | StageRefusal::UnliftedWrite { stmt, .. }
593 | StageRefusal::NoKernel { stmt, .. } => *stmt,
594 }
595 }
596}
597
598#[derive(Debug, Clone)]
601pub enum ChainStep {
602 Binary(ElementwiseOp, Symbol),
603 Silu,
604}
605
606fn folded(op: &Op) -> (&Op, bool) {
608 match &op.sym {
609 Sym::Fused(f) if matches!(f.class, ClassId::NormQuant | ClassId::AddNormQuant | ClassId::AttnOutputQuant) => (&f.parts[0], true),
610 _ => (op, false),
611 }
612}
613
614fn kernels_of(graph: &TensorGraph) -> (Vec<(usize, &Op)>, usize) {
618 let mut at = 0;
619 let mut out = Vec::new();
620 for op in &graph.ops {
621 if matches!(op.sym, Sym::Quantize(_)) {
622 continue;
623 }
624 out.push((at, op));
625 at += match &folded(op).0.sym {
626 Sym::Fused(Fused { class: ClassId::AddNorm, .. }) => 2,
627 _ => 1,
628 };
629 }
630 (out, at)
631}
632
633fn sum_and_norm(op: &Op) -> (&ElementwiseSpec, Option<&FusedRowSpec>) {
635 match (&op.sym, op.prim()) {
636 (Sym::Fused(f), _) => match (f.parts[0].prim(), f.parts[1].prim()) {
637 (Some(TensorOpSpec::Elementwise(e)), Some(TensorOpSpec::FusedRow(r))) => (e, Some(r)),
638 _ => unreachable!("a sum and the norm it adds into"),
639 },
640 (_, Some(TensorOpSpec::Elementwise(e))) => (e, None),
641 _ => unreachable!("an elementwise op"),
642 }
643}
644
645fn chain(members: &[Op]) -> (Symbol, Symbol, ElementwiseOp, Vec<ChainStep>, Symbol, usize) {
648 let Some(TensorOpSpec::Elementwise(e0)) = members[0].prim() else { unreachable!("a run starts with an elementwise op") };
649 let mut carry = e0.c;
650 let mut tail = Vec::new();
651 for m in &members[1..] {
652 match m.prim() {
653 Some(TensorOpSpec::Elementwise(e)) => {
654 tail.push(ChainStep::Binary(e.op, if e.a == carry { e.b } else { e.a }));
655 carry = e.c;
656 }
657 Some(TensorOpSpec::Silu(u)) => {
658 tail.push(ChainStep::Silu);
659 carry = u.out;
660 }
661 _ => unreachable!("a run carries elementwise ops and SiLUs"),
662 }
663 }
664 (e0.a, e0.b, e0.op, tail, carry, e0.n)
665}
666
667fn q8_fed(ops: &[Op], q8: &HashMap<String, Q8Ref>, kind: Q8MatKind, interner: &Interner) -> HashMap<String, (usize, usize)> {
670 let mut fed = HashMap::new();
671 if kind == Q8MatKind::Int8Act {
672 for op in ops {
673 if let Some(TensorOpSpec::Matmul(m)) = op.prim() {
674 if q8.contains_key(interner.resolve(m.b)) {
675 fed.insert(interner.resolve(m.a).to_string(), (m.m, m.k));
676 }
677 }
678 }
679 }
680 fed
681}
682
683fn kernel_vars(op: &Op, interner: &Interner) -> Vec<(String, usize)> {
686 let name = |s: Symbol| interner.resolve(s).to_string();
687 let host = folded(op).0;
688 match &host.sym {
689 Sym::Fused(f) if f.class == ClassId::ElementwiseChains => {
690 let (a, b, _, tail, out, n) = chain(&leaves(host.clone()));
691 let mut v = vec![(name(a), n), (name(b), n), (name(out), n)];
692 v.extend(tail.iter().filter_map(|step| match step {
693 ChainStep::Binary(_, ext) => Some((name(*ext), n)),
694 ChainStep::Silu => None,
695 }));
696 v
697 }
698 Sym::Fused(f) if f.class == ClassId::ElementwiseRegions => {
699 let n = region_body(host, "float").1;
700 host.ins.iter().cloned().chain(region_outputs(host)).map(|v| (v, n)).collect()
701 }
702 Sym::Fused(f) => f.parts.iter().flat_map(|p| kernel_vars(p, interner)).collect(),
703 _ => match host.prim().expect("a lifted op") {
704 TensorOpSpec::Matmul(m) => vec![(name(m.a), m.m * m.k), (name(m.b), m.k * m.n), (name(m.c), m.m * m.n)],
705 TensorOpSpec::Elementwise(e) => vec![(name(e.a), e.n), (name(e.b), e.n), (name(e.c), e.n)],
706 TensorOpSpec::FusedRow(r) => {
707 let mut v = vec![(name(r.x), r.rows * r.cols), (name(r.y), r.rows * r.cols)];
708 if let Some(w) = r.weight {
709 v.push((name(w), r.cols));
710 }
711 if let Some(res) = r.residual {
713 v.push((name(res), r.rows * r.cols));
714 }
715 if let Some(bias) = r.bias {
716 v.push((name(bias), r.cols));
717 }
718 v
719 }
720 TensorOpSpec::Transpose(t) => vec![(name(t.x), t.rows * t.cols), (name(t.out), t.rows * t.cols)],
721 TensorOpSpec::Silu(u) => vec![(name(u.x), u.n), (name(u.out), u.n)],
722 TensorOpSpec::Rope(r) => {
723 let d = r.h * 2 * r.half;
724 vec![(name(r.q), d), (name(r.rc), r.half), (name(r.rs), r.half), (name(r.out), d)]
725 }
726 TensorOpSpec::Moe(m) => vec![(name(m.x), m.d), (name(m.out), m.d)],
728 TensorOpSpec::Attention(a) => vec![
729 (name(a.q), a.h * a.hd),
730 (name(a.kc), a.l * a.kv * a.hd),
731 (name(a.vc), a.l * a.kv * a.hd),
732 (name(a.out), a.h * a.hd),
733 ],
734 other => unreachable!("the forward's shim admits no {}", other.kind()),
735 },
736 }
737}
738
739fn kernel_outputs(op: &Op) -> Vec<String> {
741 match &folded(op).0.sym {
742 Sym::Fused(f) if f.class == ClassId::AddNorm => f.parts.iter().map(|p| p.out.clone()).collect(),
743 Sym::Fused(f) if f.class == ClassId::ElementwiseRegions => region_outputs(op),
744 _ => vec![op.out.clone()],
745 }
746}
747
748fn region_outputs(op: &Op) -> Vec<String> {
750 std::iter::once(op.out.clone()).chain(op.keeps.iter().cloned()).collect()
751}
752
753fn region_body(op: &Op, ty: &str) -> (Vec<String>, usize) {
758 let members = leaves(op.clone());
759 let value = |t: &str, upto: usize| match members[..upto].iter().position(|m| m.out == t) {
760 Some(k) => format!("t{k}"),
761 None => format!("i{}[idx]", op.ins.iter().position(|x| x == t).expect("a region reads its operands")),
762 };
763 let mut n = 0;
764 let lines = members
765 .iter()
766 .enumerate()
767 .map(|(k, m)| match m.prim() {
768 Some(TensorOpSpec::Elementwise(e)) => {
769 n = e.n;
770 let (x, y) = (value(&m.ins[0], k), value(&m.ins[1], k));
771 match e.op {
772 ElementwiseOp::Mul if ty == "float" => format!("{ty} t{k} = __fmul_rn({x}, {y});"),
773 op => format!("{ty} t{k} = {x} {} {y};", op.c_op()),
774 }
775 }
776 Some(TensorOpSpec::Silu(u)) => {
777 n = u.n;
778 format!("{ty} t{k}; {{ float v=(float){}; t{k} = v/(1.0f+expf(-v)); }}", value(&m.ins[0], k))
779 }
780 _ => unreachable!("a region the forward links holds elementwise ops and SiLUs"),
781 })
782 .collect();
783 (lines, n)
784}
785
786#[derive(Clone, Copy, PartialEq, Eq, Debug)]
789pub enum Q8MatKind {
790 Dequant,
792 Int8Act,
797 TwoPassInt8,
801}
802
803pub fn emit_forward(
808 graph: &TensorGraph,
809 inits: &HashMap<String, Vec<(usize, InitVal)>>,
810 weights: &HashMap<String, (String, usize)>,
811 q8: &HashMap<String, Q8Ref>,
812 moe: &HashMap<String, MoeWeights>,
813 kind: Q8MatKind,
814 interner: &Interner,
815) -> Result<String, ForwardError> {
816 let (kernel_ops, stage_count) = kernels_of(graph);
817 if kernel_ops.is_empty() {
818 return Err(ForwardError::NoStages);
819 }
820 let lifted: Vec<Op> = graph.ops.iter().flat_map(|op| leaves(op.clone())).collect();
821 let has_float_init = inits
826 .values()
827 .flatten()
828 .any(|(_, v)| matches!(v, InitVal::F(_)));
829 let any_moe = lifted.iter().any(|o| matches!(o.prim(), Some(TensorOpSpec::Moe(_))));
830 let floaty = lifted.iter().any(|o| {
831 matches!(o.prim(), Some(TensorOpSpec::FusedRow(_) | TensorOpSpec::Moe(_) | TensorOpSpec::Attention(_) | TensorOpSpec::Silu(_)))
832 }) || has_float_init;
833 let ty = if floaty { "float" } else { "long long" };
834
835 let mut sizes: Vec<(String, usize)> = Vec::new();
837 let mut outputs: Vec<String> = Vec::new();
838 let mut seen = std::collections::HashSet::new();
839 for (_, op) in &kernel_ops {
840 for (v, sz) in kernel_vars(op, interner) {
841 if seen.insert(v.clone()) {
842 sizes.push((v, sz));
843 }
844 }
845 outputs.extend(kernel_outputs(op));
846 }
847 let is_output = |v: &str| outputs.iter().any(|o| o == v);
848
849 let mut kernels = String::new();
851 if any_moe {
855 kernels.push_str(MOE_KERNELS);
856 if kind != Q8MatKind::Dequant {
857 kernels.push_str(&moe_dp4a_kernels(kind == Q8MatKind::TwoPassInt8));
858 }
859 }
860 let mut launches = String::new();
861 let mut dp4a_scratch: Vec<(String, usize, usize)> = Vec::new();
864 let q8_fed = q8_fed(&lifted, q8, kind, interner);
869 let mut producer_quantized: std::collections::HashSet<String> =
870 std::collections::HashSet::new();
871 for &(i, op) in &kernel_ops {
872 let (host, quantized) = folded(op);
873 match &host.sym {
874 Sym::Prim(TensorOpSpec::Matmul(m)) => {
875 let (a, b, c) = (
876 interner.resolve(m.a),
877 interner.resolve(m.b),
878 interner.resolve(m.c),
879 );
880 if q8.contains_key(b) {
881 match kind {
882 Q8MatKind::TwoPassInt8 => {
883 let nb_ct = m.k / 32;
894 kernels.push_str(&format!(
895 "__global__ void k{i}_qact(const float* a, signed char* aqh, signed char* aql, float* as_, int M, int K){{\n\
896 \x20 int nb=K/32; int blk=blockIdx.x*(blockDim.x/32)+threadIdx.x/32; if(blk>=M*nb) return;\n\
897 \x20 int lane=threadIdx.x&31; float v=a[blk*32+lane], av=fabsf(v);\n\
898 \x20 for(int s=16;s>0;s>>=1) av=fmaxf(av,__shfl_down_sync(0xffffffffu,av,s));\n\
899 \x20 av=__shfl_sync(0xffffffffu,av,0); float amax=av>1e-30f?av:1e-30f; float sh=amax/127.0f;\n\
900 \x20 if(lane==0) as_[blk]=sh;\n\
901 \x20 int qh=(int)rintf(v/sh); if(qh>127)qh=127; if(qh<-128)qh=-128; aqh[blk*32+lane]=(signed char)qh;\n\
902 \x20 float r=v-qh*sh; float sl=sh*0.0078125f; int ql=(int)rintf(r/sl); if(ql>127)ql=127; if(ql<-128)ql=-128; aql[blk*32+lane]=(signed char)ql;\n}}\n\
903 __global__ void k{i}_q8dp4a(const signed char* aqh, const signed char* aql, const float* as_, const signed char* wq, const __half* ws, float* y, int M, int N, int K){{\n\
904 \x20 int o=(blockIdx.x*blockDim.x+threadIdx.x)>>5; if(o>=N) return; int lane=threadIdx.x&31; int nb=K/32;\n\
905 \x20 const signed char* wrow=wq+(long)o*K; const int* w4=(const int*)wrow; const __half* wsr=ws+(long)o*nb;\n\
906 \x20 for(int r=0;r<M;++r){{\n\
907 \x20 const signed char* arh=aqh+(long)r*K; const int* ah4=(const int*)arh; const signed char* arl=aql+(long)r*K; const int* al4=(const int*)arl; const float* asr=as_+(long)r*nb;\n\
908 \x20 float acc=0.0f; int nq=K/128;\n\
909 \x20 for(int b4=0;b4<nq;++b4){{ int wi=w4[b4*32+lane]; int blk=b4*4+lane/8; float ws_=__half2float(wsr[blk]); float sh=asr[blk];\n\
910 \x20 acc += ws_*(sh*(float)__dp4a(wi,ah4[b4*32+lane],0) + sh*0.0078125f*(float)__dp4a(wi,al4[b4*32+lane],0)); }}\n\
911 \x20 for(int j=nq*128+lane;j<K;j+=32){{ int blk=j/32; float ws_=__half2float(wsr[blk]); float sh=asr[blk]; int wj=(int)wrow[j];\n\
912 \x20 acc += ws_*(sh*(float)(wj*(int)arh[j]) + sh*0.0078125f*(float)(wj*(int)arl[j])); }}\n\
913 \x20 for(int s=16;s>0;s>>=1) acc+=__shfl_down_sync(0xffffffffu,acc,s);\n\
914 \x20 if(lane==0) y[(long)r*N+o]=acc;\n\
915 \x20 }}\n}}\n"
916 ));
917 if !dp4a_scratch.iter().any(|(v, _, _)| v == a) {
918 dp4a_scratch.push((a.to_string(), m.m, m.k));
919 }
920 launches.push_str(&format!(
921 " {{ k{i}_qact<<<({M}*{NB}+7)/8,256>>>(buf_{a},buf_{a}_q8act,buf_{a}_q8actlo,buf_{a}_q8scl,{M},{K});\n\
922 \x20 k{i}_q8dp4a<<<({N}+7)/8,256>>>(buf_{a}_q8act,buf_{a}_q8actlo,buf_{a}_q8scl,buf_{b}_q,buf_{b}_s,buf_{c},{M},{N},{K}); }}\n",
923 M = m.m, N = m.n, K = m.k, NB = nb_ct
924 ));
925 }
926 Q8MatKind::Int8Act => {
927 let nb_ct = m.k / 32;
936 kernels.push_str(&format!(
937 "__global__ void k{i}_qact(const float* a, signed char* aq, float* as_, int M, int K){{\n\
938 \x20 int nb=K/32; int blk=blockIdx.x*(blockDim.x/32)+threadIdx.x/32; if(blk>=M*nb) return;\n\
939 \x20 int lane=threadIdx.x&31; float v=a[blk*32+lane], av=fabsf(v);\n\
940 \x20 for(int s=16;s>0;s>>=1) av=fmaxf(av,__shfl_down_sync(0xffffffffu,av,s));\n\
941 \x20 av=__shfl_sync(0xffffffffu,av,0); float amax=av>1e-30f?av:1e-30f; float scale=amax/127.0f;\n\
942 \x20 if(lane==0) as_[blk]=scale;\n\
943 \x20 int q=(int)rintf(v/scale); if(q>127)q=127; if(q<-128)q=-128; aq[blk*32+lane]=(signed char)q;\n}}\n\
944 __global__ void k{i}_q8dp4a(const signed char* aq, const float* as_, const signed char* wq, const __half* ws, float* y, int M, int N, int K){{\n\
945 \x20 int o=(blockIdx.x*blockDim.x+threadIdx.x)>>5; if(o>=N) return; int lane=threadIdx.x&31; int nb=K/32;\n\
946 \x20 const signed char* wrow=wq+(long)o*K; const int* w4=(const int*)wrow; const __half* wsr=ws+(long)o*nb;\n\
947 \x20 for(int r=0;r<M;++r){{\n\
948 \x20 const signed char* arow=aq+(long)r*K; const int* a4=(const int*)arow; const float* asr=as_+(long)r*nb;\n\
949 \x20 float acc=0.0f; int nq16=K/512; int nq=K/128;\n\
950 \x20 const int4* w16=(const int4*)wrow; const int4* a16=(const int4*)arow;\n\
951 \x20 for(int b=0;b<nq16;++b){{ int4 wv=w16[b*32+lane]; int4 av=a16[b*32+lane]; int blk=b*16+lane/2; float sw=__half2float(wsr[blk])*asr[blk];\n\
952 \x20 int d=__dp4a(wv.x,av.x,0); d=__dp4a(wv.y,av.y,d); d=__dp4a(wv.z,av.z,d); d=__dp4a(wv.w,av.w,d); acc += (float)d * sw; }}\n\
953 \x20 for(int b4=nq16*4;b4<nq;++b4){{ int wi=w4[b4*32+lane], ai=a4[b4*32+lane]; int blk=b4*4+lane/8; acc += (float)__dp4a(wi,ai,0) * (__half2float(wsr[blk])*asr[blk]); }}\n\
954 \x20 for(int j=nq*128+lane;j<K;j+=32){{ int blk=j/32; acc += (float)((int)arow[j]*(int)wrow[j]) * (__half2float(wsr[blk])*asr[blk]); }}\n\
955 \x20 for(int s=16;s>0;s>>=1) acc+=__shfl_down_sync(0xffffffffu,acc,s);\n\
956 \x20 if(lane==0) y[(long)r*N+o]=acc;\n\
957 \x20 }}\n}}\n"
958 ));
959 let first_qact = !dp4a_scratch.iter().any(|(v, _, _)| v == a);
964 if first_qact {
965 dp4a_scratch.push((a.to_string(), m.m, m.k));
966 }
967 let qact_launch = if first_qact && !producer_quantized.contains(a) {
971 format!("k{i}_qact<<<({M}*{NB}+7)/8,256>>>(buf_{a},buf_{a}_q8act,buf_{a}_q8scl,{M},{K}); ", M = m.m, K = m.k, NB = nb_ct)
972 } else {
973 String::new()
974 };
975 launches.push_str(&format!(
976 " {{ {qact_launch}k{i}_q8dp4a<<<({N}+7)/8,256>>>(buf_{a}_q8act,buf_{a}_q8scl,buf_{b}_q,buf_{b}_s,buf_{c},{M},{N},{K}); }}\n",
977 M = m.m, N = m.n, K = m.k
978 ));
979 }
980 Q8MatKind::Dequant => {
981 kernels.push_str(&format!(
985 "__global__ void k{i}_q8gemv(const float* a, const signed char* wq, const float* ws, float* y, int M, int N, int K){{\n\
986 \x20 int idx = blockIdx.x*blockDim.x + threadIdx.x; if(idx >= M*N) return;\n\
987 \x20 int r = idx / N, n = idx % N; int nb = K/32; double acc = 0.0;\n\
988 \x20 for(int bl=0;bl<nb;++bl){{ double dot=0.0; for(int j=0;j<32;++j) dot += (double)wq[n*K + bl*32 + j] * (double)a[r*K + bl*32 + j]; acc += dot * (double)ws[n*nb + bl]; }}\n\
989 \x20 y[idx] = (float)acc;\n}}\n"
990 ));
991 launches.push_str(&format!(
992 " {{ int total={M}*{N}; k{i}_q8gemv<<<(total+255)/256,256>>>(buf_{a},buf_{b}_q,buf_{b}_s,buf_{c},{M},{N},{K}); }}\n",
993 M = m.m, N = m.n, K = m.k
994 ));
995 }
996 }
997 } else {
998 kernels.push_str(&format!(
999 "__global__ void k{i}_matmul(const {ty}* a, const {ty}* b, {ty}* c, int M, int N, int K){{\n\
1000 \x20 int idx = blockIdx.x*blockDim.x + threadIdx.x; if(idx >= M*N) return;\n\
1001 \x20 int r = idx / N, col = idx % N; {ty} s = 0;\n\
1002 \x20 for(int k=0;k<K;++k) s += a[r*K+k]*b[k*N+col];\n\
1003 \x20 c[idx] = s;\n}}\n"
1004 ));
1005 launches.push_str(&format!(
1006 " {{ int total={M}*{N}; k{i}_matmul<<<(total+255)/256,256>>>(buf_{a},buf_{b},buf_{c},{M},{N},{K}); }}\n",
1007 M = m.m, N = m.n, K = m.k
1008 ));
1009 }
1010 }
1011 Sym::Prim(TensorOpSpec::Elementwise(_)) | Sym::Fused(Fused { class: ClassId::AddNorm, .. }) => {
1012 let (e, normed) = sum_and_norm(host);
1013 let (a, b, c) = (
1014 interner.resolve(e.a),
1015 interner.resolve(e.b),
1016 interner.resolve(e.c),
1017 );
1018 let op = e.op.c_op();
1019 if let Some(r) = normed {
1024 let (cols, rows, y) = (r.cols, r.rows, interner.resolve(r.y));
1025 let eps = format!("{:e}", r.eps.get());
1026 let wparam = if r.weight.is_some() {
1027 ", const float* w"
1028 } else {
1029 ""
1030 };
1031 let ymul = if r.weight.is_some() { "*w[i]" } else { "" };
1032 let qact_out = quantized;
1035 let qparam = if qact_out {
1036 ", signed char* yq, float* ys"
1037 } else {
1038 ""
1039 };
1040 let qepilogue = if qact_out {
1041 format!(
1042 "\x20 __syncthreads(); {{ int qlane=threadIdx.x&31, qwp=threadIdx.x>>5, qnw=blockDim.x>>5; int qnb={cols}/32;\n\
1043 \x20 for(int blk=qwp;blk<qnb;blk+=qnw){{ float v=yr[blk*32+qlane], av=fabsf(v);\n\
1044 \x20 for(int s=16;s>0;s>>=1) av=fmaxf(av,__shfl_down_sync(0xffffffffu,av,s)); av=__shfl_sync(0xffffffffu,av,0);\n\
1045 \x20 float amax=av>1e-30f?av:1e-30f, scale=amax/127.0f; if(qlane==0) ys[blk]=scale;\n\
1046 \x20 int qq=(int)rintf(v/scale); if(qq>127)qq=127; if(qq<-128)qq=-128; yq[blk*32+qlane]=(signed char)qq; }} }}\n",
1047 cols = cols
1048 )
1049 } else {
1050 String::new()
1051 };
1052 kernels.push_str(&format!(
1053 "__global__ void k{i}_add_row(const float* a, const float* b{wparam}, float* c, float* y{qparam}){{\n\
1054 \x20 int row=blockIdx.x; const float* ar=a+(long)row*{cols}; const float* br=b+(long)row*{cols};\n\
1055 \x20 float* cr=c+(long)row*{cols}; float* yr=y+(long)row*{cols}; __shared__ double sh[256];\n\
1056 \x20 double sc=0; for(int i=threadIdx.x;i<{cols};i+=blockDim.x){{ float v=ar[i]+br[i]; cr[i]=v; sc+=(double)v*v; }}\n\
1057 \x20 sh[threadIdx.x]=sc; __syncthreads();\n\
1058 \x20 for(int k=blockDim.x/2;k>0;k>>=1){{ if(threadIdx.x<k) sh[threadIdx.x]+=sh[threadIdx.x+k]; __syncthreads(); }}\n\
1059 \x20 double scale=1.0/sqrt(sh[0]/(double){cols}+{eps});\n\
1060 \x20 for(int i=threadIdx.x;i<{cols};i+=blockDim.x) yr[i]=(float)((double)cr[i]*scale){ymul};\n{qepilogue}}}\n"
1061 ));
1062 let warg = if let Some(w) = r.weight {
1063 format!(",buf_{}", interner.resolve(w))
1064 } else {
1065 String::new()
1066 };
1067 let qarg = if qact_out {
1068 format!(",buf_{y}_q8act,buf_{y}_q8scl")
1069 } else {
1070 String::new()
1071 };
1072 launches.push_str(&format!(
1073 " k{i}_add_row<<<{rows},256>>>(buf_{a},buf_{b}{warg},buf_{c},buf_{y}{qarg});\n"
1074 ));
1075 if qact_out {
1076 if !dp4a_scratch.iter().any(|(v, _, _)| v == y) {
1077 let (mm, kk) = q8_fed[y];
1078 dp4a_scratch.push((y.to_string(), mm, kk));
1079 }
1080 producer_quantized.insert(y.to_string());
1081 }
1082 } else {
1083 kernels.push_str(&format!(
1084 "__global__ void k{i}_elem(const {ty}* a, const {ty}* b, {ty}* c, int N){{\n\
1085 \x20 int idx = blockIdx.x*blockDim.x + threadIdx.x; if(idx < N) c[idx] = a[idx] {op} b[idx];\n}}\n"
1086 ));
1087 launches.push_str(&format!(
1088 " k{i}_elem<<<({N}+255)/256,256>>>(buf_{a},buf_{b},buf_{c},{N});\n",
1089 N = e.n
1090 ));
1091 }
1092 }
1093 Sym::Fused(Fused { class: ClassId::ElementwiseChains, .. }) => {
1094 let (a, b, first_op, tail, out, n) = chain(&leaves(host.clone()));
1095 let (a, b, first_op, tail, out, n) = (&a, &b, &first_op, &tail, &out, &n);
1096 let (a, b, out) = (
1100 interner.resolve(*a),
1101 interner.resolve(*b),
1102 interner.resolve(*out),
1103 );
1104 let summed = |k: usize| ty == "float" && matches!(tail.get(k), Some(ChainStep::Binary(ElementwiseOp::Add, _)));
1108 let apply = |op: ElementwiseOp, x: &str, y: &str, k: usize| match op {
1109 ElementwiseOp::Mul if summed(k) => format!("__fmul_rn({x}, {y})"),
1110 op => format!("{x} {} {y}", op.c_op()),
1111 };
1112 let mut params = format!("const {ty}* i0, const {ty}* i1");
1113 let mut args = format!("buf_{a},buf_{b}");
1114 let mut body = format!("{ty} t = {};", apply(*first_op, "i0[idx]", "i1[idx]", 0));
1115 let mut pk = 2; for (k, step) in tail.iter().enumerate() {
1117 match step {
1118 ChainStep::Binary(op, ext) => {
1119 params.push_str(&format!(", const {ty}* i{pk}"));
1120 args.push_str(&format!(",buf_{}", interner.resolve(*ext)));
1121 body.push_str(&format!(" t = {};", apply(*op, "t", &format!("i{pk}[idx]"), k + 1)));
1122 pk += 1;
1123 }
1124 ChainStep::Silu => body.push_str(" t = t/(1.0f+expf(-t));"),
1125 }
1126 }
1127 kernels.push_str(&format!(
1128 "__global__ void k{i}_fused({params}, {ty}* o, int N){{\n\
1129 \x20 int idx = blockIdx.x*blockDim.x + threadIdx.x; if(idx < N){{ {body} o[idx] = t; }}\n}}\n"
1130 ));
1131 launches.push_str(&format!(
1132 " k{i}_fused<<<({N}+255)/256,256>>>({args},buf_{out},{N});\n",
1133 N = n
1134 ));
1135 }
1136 Sym::Fused(Fused { class: ClassId::ElementwiseRegions, .. }) => {
1137 let (lines, n) = region_body(host, ty);
1140 let members = leaves(host.clone());
1141 let outputs = region_outputs(host);
1142 let mut params: Vec<String> = (0..host.ins.len()).map(|p| format!("const {ty}* i{p}")).collect();
1143 params.extend((0..outputs.len()).map(|q| format!("{ty}* o{q}")));
1144 let stores: String = outputs
1145 .iter()
1146 .enumerate()
1147 .map(|(q, o)| format!(" o{q}[idx] = t{};", members.iter().position(|m| m.out == *o).expect("a region writes its members")))
1148 .collect();
1149 kernels.push_str(&format!(
1150 "__global__ void k{i}_region({}, int N){{\n\
1151 \x20 int idx = blockIdx.x*blockDim.x + threadIdx.x; if(idx < N){{ {}{stores} }}\n}}\n",
1152 params.join(", "),
1153 lines.join(" ")
1154 ));
1155 let args: Vec<String> = host.ins.iter().chain(&outputs).map(|v| format!("buf_{v}")).collect();
1156 launches.push_str(&format!(" k{i}_region<<<({n}+255)/256,256>>>({},{n});\n", args.join(",")));
1157 }
1158 Sym::Prim(TensorOpSpec::FusedRow(r)) => {
1159 let (x, y) = (interner.resolve(r.x), interner.resolve(r.y));
1160 let cols = r.cols;
1161 let eps = format!("{:e}", r.eps.get());
1162 let xv = |i: &str| match r.residual {
1165 Some(_) => format!("((double)xr[{i}]+(double)rr[{i}])"),
1166 None => format!("(double)xr[{i}]"),
1167 };
1168 let body = match (r.reduce, r.weight.is_some()) {
1169 (RowReduceKind::RmsNorm, false) => format!(
1170 " double sc=0; for(int i=threadIdx.x;i<{cols};i+=blockDim.x) sc+={v}*{v};\n\
1171 \x20 sh[threadIdx.x]=sc; __syncthreads();\n\
1172 \x20 for(int k=blockDim.x/2;k>0;k>>=1){{ if(threadIdx.x<k) sh[threadIdx.x]+=sh[threadIdx.x+k]; __syncthreads(); }}\n\
1173 \x20 double scale=1.0/sqrt(sh[0]/(double){cols}+{eps});\n\
1174 \x20 for(int i=threadIdx.x;i<{cols};i+=blockDim.x) yr[i]=(float)({v}*scale);\n",
1175 v = xv("i")
1176 ),
1177 (RowReduceKind::RmsNorm, true) => format!(
1178 " double sc=0; for(int i=threadIdx.x;i<{cols};i+=blockDim.x) sc+={v}*{v};\n\
1179 \x20 sh[threadIdx.x]=sc; __syncthreads();\n\
1180 \x20 for(int k=blockDim.x/2;k>0;k>>=1){{ if(threadIdx.x<k) sh[threadIdx.x]+=sh[threadIdx.x+k]; __syncthreads(); }}\n\
1181 \x20 double scale=1.0/sqrt(sh[0]/(double){cols}+{eps});\n\
1182 \x20 for(int i=threadIdx.x;i<{cols};i+=blockDim.x) yr[i]=(float)({v}*scale)*w[i];\n",
1183 v = xv("i")
1184 ),
1185 (RowReduceKind::Softmax, _) => format!(
1186 " double m=-1e30; for(int i=threadIdx.x;i<{cols};i+=blockDim.x) m=fmax(m,(double)xr[i]);\n\
1187 \x20 sh[threadIdx.x]=m; __syncthreads();\n\
1188 \x20 for(int k=blockDim.x/2;k>0;k>>=1){{ if(threadIdx.x<k) sh[threadIdx.x]=fmax(sh[threadIdx.x],sh[threadIdx.x+k]); __syncthreads(); }}\n\
1189 \x20 double mx=sh[0]; __syncthreads();\n\
1190 \x20 double s=0; for(int i=threadIdx.x;i<{cols};i+=blockDim.x) s+=exp((double)xr[i]-mx);\n\
1191 \x20 sh[threadIdx.x]=s; __syncthreads();\n\
1192 \x20 for(int k=blockDim.x/2;k>0;k>>=1){{ if(threadIdx.x<k) sh[threadIdx.x]+=sh[threadIdx.x+k]; __syncthreads(); }}\n\
1193 \x20 double sm=sh[0]; for(int i=threadIdx.x;i<{cols};i+=blockDim.x) yr[i]=(float)(exp((double)xr[i]-mx)/sm);\n"
1194 ),
1195 (RowReduceKind::LayerNorm, _) => {
1198 let wmul = if r.weight.is_some() { "*(double)w[i]" } else { "" };
1199 let badd = if r.bias.is_some() { "+(double)bias[i]" } else { "" };
1200 format!(
1201 " double sm=0; for(int i=threadIdx.x;i<{cols};i+=blockDim.x) sm+=(double)xr[i];\n\
1202 \x20 sh[threadIdx.x]=sm; __syncthreads();\n\
1203 \x20 for(int k=blockDim.x/2;k>0;k>>=1){{ if(threadIdx.x<k) sh[threadIdx.x]+=sh[threadIdx.x+k]; __syncthreads(); }}\n\
1204 \x20 double mean=sh[0]/(double){cols}; __syncthreads();\n\
1205 \x20 double vs=0; for(int i=threadIdx.x;i<{cols};i+=blockDim.x){{ double d=(double)xr[i]-mean; vs+=d*d; }}\n\
1206 \x20 sh[threadIdx.x]=vs; __syncthreads();\n\
1207 \x20 for(int k=blockDim.x/2;k>0;k>>=1){{ if(threadIdx.x<k) sh[threadIdx.x]+=sh[threadIdx.x+k]; __syncthreads(); }}\n\
1208 \x20 double denom=sqrt(sh[0]/(double){cols}+{eps});\n\
1209 \x20 for(int i=threadIdx.x;i<{cols};i+=blockDim.x) yr[i]=(float)(((double)xr[i]-mean)/denom{wmul}{badd});\n"
1210 )
1211 }
1212 };
1213 let wparam = format!(
1214 "{}{}{}",
1215 if r.weight.is_some() { ", const float* w" } else { "" },
1216 if r.residual.is_some() { ", const float* res" } else { "" },
1217 if r.bias.is_some() { ", const float* bias" } else { "" },
1218 );
1219 let rrow = if r.residual.is_some() {
1220 format!(" const float* rr = res + (long)row*{cols};")
1221 } else {
1222 String::new()
1223 };
1224 let qact_out = quantized;
1228 let qparam = if qact_out {
1229 ", signed char* yq, float* ys"
1230 } else {
1231 ""
1232 };
1233 let qepilogue = if qact_out {
1234 format!(
1235 "\x20 __syncthreads(); {{ int qlane=threadIdx.x&31, qwp=threadIdx.x>>5, qnw=blockDim.x>>5; int qnb={cols}/32;\n\
1236 \x20 for(int blk=qwp;blk<qnb;blk+=qnw){{ float v=yr[blk*32+qlane], av=fabsf(v);\n\
1237 \x20 for(int s=16;s>0;s>>=1) av=fmaxf(av,__shfl_down_sync(0xffffffffu,av,s)); av=__shfl_sync(0xffffffffu,av,0);\n\
1238 \x20 float amax=av>1e-30f?av:1e-30f, scale=amax/127.0f; if(qlane==0) ys[blk]=scale;\n\
1239 \x20 int qq=(int)rintf(v/scale); if(qq>127)qq=127; if(qq<-128)qq=-128; yq[blk*32+qlane]=(signed char)qq; }} }}\n",
1240 cols = cols
1241 )
1242 } else {
1243 String::new()
1244 };
1245 kernels.push_str(&format!(
1246 "__global__ void k{i}_row(const float* x{wparam}, float* y{qparam}){{\n\
1247 \x20 int row = blockIdx.x; const float* xr = x + (long)row*{cols}; float* yr = y + (long)row*{cols};{rrow}\n\
1248 \x20 __shared__ double sh[256];\n{body}{qepilogue}}}\n"
1249 ));
1250 let warg: String = [r.weight, r.residual, r.bias]
1251 .into_iter()
1252 .flatten()
1253 .map(|t| format!(",buf_{}", interner.resolve(t)))
1254 .collect();
1255 let qarg = if qact_out {
1256 format!(",buf_{y}_q8act,buf_{y}_q8scl")
1257 } else {
1258 String::new()
1259 };
1260 launches.push_str(&format!(
1261 " k{i}_row<<<{rows},256>>>(buf_{x}{warg},buf_{y}{qarg});\n",
1262 rows = r.rows
1263 ));
1264 if qact_out {
1265 if !dp4a_scratch.iter().any(|(v, _, _)| v == y) {
1266 let (mm, kk) = q8_fed[y];
1267 dp4a_scratch.push((y.to_string(), mm, kk));
1268 }
1269 producer_quantized.insert(y.to_string());
1270 }
1271 }
1272 Sym::Prim(TensorOpSpec::Transpose(t)) => {
1273 let (x, out, rows, cols) = (&t.x, &t.out, &t.rows, &t.cols);
1274 let (xn, on) = (interner.resolve(*x), interner.resolve(*out));
1275 kernels.push_str(&format!(
1276 "__global__ void k{i}_transpose(const {ty}* x, {ty}* y, int R, int C){{\n\
1277 \x20 int idx = blockIdx.x*blockDim.x + threadIdx.x; if(idx >= R*C) return;\n\
1278 \x20 int r = idx / C, c = idx % C; y[c*R + r] = x[r*C + c];\n}}\n"
1279 ));
1280 launches.push_str(&format!(
1281 " {{ int total={R}*{C}; k{i}_transpose<<<(total+255)/256,256>>>(buf_{xn},buf_{on},{R},{C}); }}\n",
1282 R = rows, C = cols
1283 ));
1284 }
1285 Sym::Prim(TensorOpSpec::Silu(s)) => {
1286 let (x, out, n) = (&s.x, &s.out, &s.n);
1287 let (xn, on) = (interner.resolve(*x), interner.resolve(*out));
1288 kernels.push_str(&format!(
1289 "__global__ void k{i}_silu(const {ty}* x, {ty}* y, int N){{\n\
1290 \x20 int idx = blockIdx.x*blockDim.x + threadIdx.x; if(idx < N){{ float v=(float)x[idx]; y[idx] = v/(1.0f+expf(-v)); }}\n}}\n"
1291 ));
1292 launches.push_str(&format!(
1293 " k{i}_silu<<<({N}+255)/256,256>>>(buf_{xn},buf_{on},{N});\n",
1294 N = n
1295 ));
1296 }
1297 Sym::Prim(TensorOpSpec::Rope(r)) => {
1298 let (q, rc, rs, out, h, half) = (&r.q, &r.rc, &r.rs, &r.out, &r.h, &r.half);
1299 let (qn, rcn, rsn, on) = (
1300 interner.resolve(*q),
1301 interner.resolve(*rc),
1302 interner.resolve(*rs),
1303 interner.resolve(*out),
1304 );
1305 kernels.push_str(&format!(
1306 "__global__ void k{i}_rope(const float* q, const float* rc, const float* rs, float* y, int H, int HALF){{\n\
1307 \x20 int hd = 2*HALF; int idx = blockIdx.x*blockDim.x + threadIdx.x; if(idx >= H*HALF) return;\n\
1308 \x20 int hh = idx/HALF, i = idx%HALF; float a=q[hh*hd+i], b=q[hh*hd+i+HALF], c=rc[i], s=rs[i];\n\
1309 \x20 y[hh*hd+i] = a*c - b*s; y[hh*hd+i+HALF] = a*s + b*c;\n}}\n"
1310 ));
1311 launches.push_str(&format!(
1312 " {{ int total={H}*{HALF}; k{i}_rope<<<(total+255)/256,256>>>(buf_{qn},buf_{rcn},buf_{rsn},buf_{on},{H},{HALF}); }}\n",
1313 H = h, HALF = half
1314 ));
1315 }
1316 Sym::Prim(TensorOpSpec::Moe(m)) => {
1317 let (x, out) = (interner.resolve(m.x), interner.resolve(m.out));
1322 let (d, dff, ne, k) = (m.d, m.dff, m.ne, m.k);
1323 let (dnb, fnb) = (d / 32, dff / 32);
1324 let etopk = ne.min(1024);
1325 if kind != Q8MatKind::Dequant {
1326 if kind == Q8MatKind::TwoPassInt8 {
1334 launches.push_str(&format!(
1335 " moe_router_fast<<<({ne}+7)/8,256>>>(buf_{x},buf_{out}_Wr_q,buf_{out}_Wr_s,moe_logits,{ne},{d});\n\
1336 \x20 moe_topk_idx<<<1,{etopk}>>>(moe_logits,moe_idx,moe_w,{ne},{k});\n\
1337 \x20 moe_qact<<<(({d}/32)+7)/8,256>>>(buf_{x},moe_xqh,moe_xql,moe_xs,{d});\n\
1338 \x20 moe_gate_up_silu<<<({k}*{dff}+7)/8,256>>>(moe_xqh,moe_xql,moe_xs,buf_{out}_Wg_q,buf_{out}_Wg_s,buf_{out}_Wu_q,buf_{out}_Wu_s,moe_idx,moe_he_all,{k},{dff},{d});\n\
1339 \x20 moe_qact<<<((({k}*{dff})/32)+7)/8,256>>>(moe_he_all,moe_hqh,moe_hql,moe_hs,{k}*{dff});\n\
1340 \x20 moe_down_combine<<<{d},{k}*32>>>(moe_hqh,moe_hql,moe_hs,buf_{out}_Wd_q,buf_{out}_Wd_s,moe_idx,moe_w,buf_{out},{k},{d},{dff});\n"
1341 ));
1342 } else {
1343 launches.push_str(&format!(
1344 " moe_router_fast<<<({ne}+7)/8,256>>>(buf_{x},buf_{out}_Wr_q,buf_{out}_Wr_s,moe_logits,{ne},{d});\n\
1345 \x20 moe_topk_idx<<<1,{etopk}>>>(moe_logits,moe_idx,moe_w,{ne},{k});\n\
1346 \x20 moe_qact<<<(({d}/32)+7)/8,256>>>(buf_{x},moe_xqh,moe_xs,{d});\n\
1347 \x20 moe_gate_up_silu<<<({k}*{dff}+7)/8,256>>>(moe_xqh,moe_xs,buf_{out}_Wg_q,buf_{out}_Wg_s,buf_{out}_Wu_q,buf_{out}_Wu_s,moe_idx,moe_he_all,{k},{dff},{d});\n\
1348 \x20 moe_qact<<<((({k}*{dff})/32)+7)/8,256>>>(moe_he_all,moe_hqh,moe_hs,{k}*{dff});\n\
1349 \x20 moe_down_combine<<<{d},{k}*32>>>(moe_hqh,moe_hs,buf_{out}_Wd_q,buf_{out}_Wd_s,moe_idx,moe_w,buf_{out},{k},{d},{dff});\n"
1350 ));
1351 }
1352 } else {
1353 launches.push_str(&format!(
1358 " moe_gemv<<<({ne}+255)/256,256>>>(buf_{x},buf_{out}_Wr_q,buf_{out}_Wr_s,moe_logits,{ne},{d});\n\
1359 \x20 moe_topk<<<1,{etopk}>>>(moe_logits,moe_w,{ne},{k});\n\
1360 \x20 moe_zero<<<({d}+255)/256,256>>>(buf_{out},{d});\n\
1361 \x20 for(int _e=0;_e<{ne};++_e){{\n\
1362 \x20 moe_gemv<<<({dff}+255)/256,256>>>(buf_{x},buf_{out}_Wg_q+(long)_e*{gstride},buf_{out}_Wg_s+(long)_e*{gsstride},moe_gate_e,{dff},{d});\n\
1363 \x20 moe_gemv<<<({dff}+255)/256,256>>>(buf_{x},buf_{out}_Wu_q+(long)_e*{gstride},buf_{out}_Wu_s+(long)_e*{gsstride},moe_up_e,{dff},{d});\n\
1364 \x20 moe_silu_had<<<({dff}+255)/256,256>>>(moe_gate_e,moe_up_e,moe_he,{dff});\n\
1365 \x20 moe_gemv<<<({d}+255)/256,256>>>(moe_he,buf_{out}_Wd_q+(long)_e*{dstride},buf_{out}_Wd_s+(long)_e*{dsstride},moe_oute,{d},{dff});\n\
1366 \x20 moe_combine<<<({d}+255)/256,256>>>(buf_{out},moe_oute,moe_w,_e,{d});\n\
1367 \x20 }}\n",
1368 gstride = dff * d, gsstride = dff * dnb, dstride = d * dff, dsstride = d * fnb, etopk = etopk
1369 ));
1370 }
1371 }
1372 Sym::Prim(TensorOpSpec::Attention(a)) => {
1373 assert!(a.softcap.is_none(), "the forward's shim admits no soft-capped attention");
1374 let (q, kc, vc, out, h, kv, hd, l) = (&a.q, &a.kc, &a.vc, &a.out, &a.h, &a.kv, &a.hd, &a.l);
1375 let (qn, kcn, vcn, on) = (
1380 interner.resolve(*q),
1381 interner.resolve(*kc),
1382 interner.resolve(*vc),
1383 interner.resolve(*out),
1384 );
1385 let scale = 1.0f64 / (*hd as f64).sqrt();
1386 let qact_out = quantized;
1390 let qparam = if qact_out {
1391 ", signed char* yq, float* ys"
1392 } else {
1393 ""
1394 };
1395 let qepilogue = if qact_out {
1396 "\x20 __syncthreads(); {{ int qlane=threadIdx.x&31, qwp=threadIdx.x>>5, qnw=blockDim.x>>5; int qnb=HD/32; int base=head*HD;\n\
1397 \x20 for(int lb=qwp;lb<qnb;lb+=qnw){{ float v=ctx[base+lb*32+qlane], av=fabsf(v);\n\
1398 \x20 for(int s=16;s>0;s>>=1) av=fmaxf(av,__shfl_down_sync(0xffffffffu,av,s)); av=__shfl_sync(0xffffffffu,av,0);\n\
1399 \x20 float amax=av>1e-30f?av:1e-30f, scl=amax/127.0f; int gb=base/32+lb; if(qlane==0) ys[gb]=scl;\n\
1400 \x20 int qq=(int)rintf(v/scl); if(qq>127)qq=127; if(qq<-128)qq=-128; yq[gb*32+qlane]=(signed char)qq; }} }}\n"
1401 } else {
1402 ""
1403 };
1404 kernels.push_str(&format!(
1405 "__global__ void k{i}_attn(const float* q, const float* kc, const float* vc, float* ctx, int L, int H, int KV, int HD, float scale{qparam}){{\n\
1406 \x20 int head=blockIdx.x; if(head>=H) return; int kvh=head/(H/KV); const float* qh=q+head*HD;\n\
1407 \x20 __shared__ float sc[{L}]; __shared__ float red[32];\n\
1408 \x20 int lane=threadIdx.x&31, wp=threadIdx.x>>5, nw=(blockDim.x+31)>>5;\n\
1409 \x20 for(int j=wp;j<L;j+=nw){{ const float* kj=kc+(long)j*KV*HD+kvh*HD; float s=0.0f; for(int e=lane;e<HD;e+=32) s+=qh[e]*kj[e]; for(int r=16;r>0;r>>=1) s+=__shfl_down_sync(0xffffffffu,s,r); if(lane==0) sc[j]=s*scale; }}\n\
1410 \x20 __syncthreads();\n\
1411 \x20 float m=-1e30f; for(int j=threadIdx.x;j<L;j+=blockDim.x) m=fmaxf(m,sc[j]);\n\
1412 \x20 for(int s=16;s>0;s>>=1) m=fmaxf(m,__shfl_down_sync(0xffffffffu,m,s)); if(lane==0) red[wp]=m; __syncthreads();\n\
1413 \x20 if(threadIdx.x==0){{ float mm=red[0]; for(int i=1;i<nw;++i) mm=fmaxf(mm,red[i]); red[0]=mm; }} __syncthreads(); float mx=red[0];\n\
1414 \x20 float ss=0.0f; for(int j=threadIdx.x;j<L;j+=blockDim.x){{ float e=expf(sc[j]-mx); sc[j]=e; ss+=e; }}\n\
1415 \x20 for(int s=16;s>0;s>>=1) ss+=__shfl_down_sync(0xffffffffu,ss,s); if(lane==0) red[wp]=ss; __syncthreads();\n\
1416 \x20 if(threadIdx.x==0){{ float su=0.0f; for(int i=0;i<nw;++i) su+=red[i]; red[0]=su; }} __syncthreads(); float den=red[0];\n\
1417 \x20 for(int e=threadIdx.x;e<HD;e+=blockDim.x){{ float acc=0.0f; for(int j=0;j<L;++j) acc+=sc[j]*vc[(long)j*KV*HD+kvh*HD+e]; ctx[head*HD+e]=acc/den; }}\n{qepilogue}}}\n",
1418 L = l
1419 ));
1420 let qarg = if qact_out {
1423 format!(",buf_{on}_q8act,buf_{on}_q8scl")
1424 } else {
1425 String::new()
1426 };
1427 launches.push_str(&format!(
1428 " k{i}_attn<<<{H},256>>>(buf_{qn},buf_{kcn},buf_{vcn},buf_{on},{L},{H},{KV},{HD},{scale}f{qarg});\n",
1429 H = h, KV = kv, HD = hd, L = l, scale = scale
1430 ));
1431 if qact_out {
1432 if !dp4a_scratch.iter().any(|(v, _, _)| v == on) {
1433 let (mm, kk) = q8_fed[on];
1434 dp4a_scratch.push((on.to_string(), mm, kk));
1435 }
1436 producer_quantized.insert(on.to_string());
1437 }
1438 }
1439 _ => unreachable!("the forward's shim links no `{}` whole", host.kind()),
1440 }
1441 }
1442
1443 let final_out = outputs.last().cloned().unwrap();
1445 let final_size = sizes
1446 .iter()
1447 .find(|(v, _)| v == &final_out)
1448 .map(|(_, s)| *s)
1449 .unwrap_or(0);
1450 let mut allocs = String::new();
1451 let mut fills = String::new();
1452 for (v, sz) in &sizes {
1453 if let Some(q) = q8.get(v) {
1456 let nb = q.in_dim / 32;
1457 let (qn, sn) = (q.in_dim * q.out_dim, q.out_dim * nb);
1458 allocs.push_str(&format!(
1459 " signed char* buf_{v}_q; if(cudaMallocManaged(&buf_{v}_q,(size_t){qn})){{ fprintf(stderr,\"malloc q\\n\"); return 1; }}\n"
1460 ));
1461 fills.push_str(&format!(
1462 " {{ FILE* f=fopen(\"{qp}\",\"rb\"); if(!f||fread(buf_{v}_q,1,(size_t){qn},f)!=(size_t){qn}){{ fprintf(stderr,\"q8 quants {v}\\n\"); return 1; }} fclose(f); }}\n",
1463 qp = q.quants
1464 ));
1465 if kind != Q8MatKind::Dequant {
1466 allocs.push_str(&format!(
1469 " __half* buf_{v}_s; if(cudaMallocManaged(&buf_{v}_s,(size_t){sn}*sizeof(__half))){{ fprintf(stderr,\"malloc s\\n\"); return 1; }}\n"
1470 ));
1471 fills.push_str(&format!(
1472 " {{ float* _t=(float*)malloc((size_t){sn}*sizeof(float)); FILE* f=fopen(\"{sp}\",\"rb\"); if(!f||fread(_t,sizeof(float),(size_t){sn},f)!=(size_t){sn}){{ fprintf(stderr,\"q8 scales {v}\\n\"); return 1; }} fclose(f); for(size_t _i=0;_i<(size_t){sn};++_i) buf_{v}_s[_i]=__float2half(_t[_i]); free(_t); }}\n",
1473 sp = q.scales
1474 ));
1475 } else {
1476 allocs.push_str(&format!(
1477 " float* buf_{v}_s; if(cudaMallocManaged(&buf_{v}_s,(size_t){sn}*sizeof(float))){{ fprintf(stderr,\"malloc s\\n\"); return 1; }}\n"
1478 ));
1479 fills.push_str(&format!(
1480 " {{ FILE* f=fopen(\"{sp}\",\"rb\"); if(!f||fread(buf_{v}_s,sizeof(float),(size_t){sn},f)!=(size_t){sn}){{ fprintf(stderr,\"q8 scales {v}\\n\"); return 1; }} fclose(f); }}\n",
1481 sp = q.scales
1482 ));
1483 }
1484 continue;
1485 }
1486 allocs.push_str(&format!(
1487 " {ty}* buf_{v}; if(cudaMallocManaged(&buf_{v}, (size_t){sz}*sizeof({ty}))){{ fprintf(stderr,\"malloc\\n\"); return 1; }}\n"
1488 ));
1489 if is_output(v) {
1490 continue;
1491 }
1492 if let Some((path, count)) = weights.get(v) {
1496 fills.push_str(&format!(
1497 " {{ FILE* wf=fopen(\"{path}\",\"rb\"); if(!wf){{ fprintf(stderr,\"weight open {v}\\n\"); return 1; }}\n\
1498 \x20 size_t rd=fread(buf_{v},sizeof(float),(size_t){count},wf); fclose(wf);\n\
1499 \x20 if(rd!=(size_t){count}){{ fprintf(stderr,\"weight size {v}\\n\"); return 1; }} }}\n"
1500 ));
1501 continue;
1502 }
1503 if let Some(vals) = inits.get(v) {
1506 let zero = if floaty { "0.0f" } else { "0" };
1507 fills.push_str(&format!(
1508 " for(size_t p=0;p<(size_t){sz};++p) buf_{v}[p]={zero};\n"
1509 ));
1510 for (idx, val) in vals {
1511 if *idx >= *sz {
1512 continue;
1513 }
1514 let lit = match (floaty, val) {
1515 (true, InitVal::F(f)) => format!("(float){:?}", f),
1516 (true, InitVal::I(n)) => format!("(float){n}"),
1517 (false, InitVal::I(n)) => format!("{n}"),
1518 (false, InitVal::F(f)) => format!("(long long){}", *f as i64),
1519 };
1520 fills.push_str(&format!(" buf_{v}[{idx}]={lit};\n"));
1521 }
1522 continue;
1523 }
1524 let fill = if floaty {
1526 "buf_{v}[p] = (float)((int)(p%7)-3) * 0.5f;"
1527 } else {
1528 "buf_{v}[p] = (long long)((int)(p%7)-3);"
1529 };
1530 fills.push_str(&format!(
1531 " for(size_t p=0;p<(size_t){sz};++p) {}\n",
1532 fill.replace("{v}", v)
1533 ));
1534 }
1535 for (a, m_rows, k_dim) in &dp4a_scratch {
1539 let (qn, sn) = (m_rows * k_dim, m_rows * (k_dim / 32));
1540 allocs.push_str(&format!(
1541 " signed char* buf_{a}_q8act; if(cudaMallocManaged(&buf_{a}_q8act,(size_t){qn})){{ fprintf(stderr,\"malloc qact\\n\"); return 1; }}\n"
1542 ));
1543 if kind == Q8MatKind::TwoPassInt8 {
1544 allocs.push_str(&format!(
1545 " signed char* buf_{a}_q8actlo; if(cudaMallocManaged(&buf_{a}_q8actlo,(size_t){qn})){{ fprintf(stderr,\"malloc qactlo\\n\"); return 1; }}\n"
1546 ));
1547 }
1548 allocs.push_str(&format!(
1549 " float* buf_{a}_q8scl; if(cudaMallocManaged(&buf_{a}_q8scl,(size_t){sn}*sizeof(float))){{ fprintf(stderr,\"malloc qscl\\n\"); return 1; }}\n"
1550 ));
1551 }
1552 let mut moe_scratch: Option<(usize, usize, usize)> = None; for (_, op) in &kernel_ops {
1555 if let Some(TensorOpSpec::Moe(m)) = folded(op).0.prim() {
1556 let out = interner.resolve(m.out);
1557 let w = moe
1558 .get(out)
1559 .ok_or_else(|| ForwardError::MissingMoeWeights(out.to_string()))?;
1560 for (tag, q) in [
1561 ("Wr", &w.router),
1562 ("Wg", &w.gate),
1563 ("Wu", &w.up),
1564 ("Wd", &w.down),
1565 ] {
1566 let nb = q.in_dim / 32;
1567 let (qn, sn) = (q.in_dim * q.out_dim, q.out_dim * nb);
1568 allocs.push_str(&format!(
1569 " signed char* buf_{out}_{tag}_q; if(cudaMallocManaged(&buf_{out}_{tag}_q,(size_t){qn})){{ fprintf(stderr,\"malloc moe q\\n\"); return 1; }}\n\
1570 \x20 float* buf_{out}_{tag}_s; if(cudaMallocManaged(&buf_{out}_{tag}_s,(size_t){sn}*sizeof(float))){{ fprintf(stderr,\"malloc moe s\\n\"); return 1; }}\n"
1571 ));
1572 fills.push_str(&format!(
1573 " {{ FILE* f=fopen(\"{qp}\",\"rb\"); if(!f||fread(buf_{out}_{tag}_q,1,(size_t){qn},f)!=(size_t){qn}){{ fprintf(stderr,\"moe q {out}_{tag}\\n\"); return 1; }} fclose(f); }}\n\
1574 \x20 {{ FILE* f=fopen(\"{sp}\",\"rb\"); if(!f||fread(buf_{out}_{tag}_s,sizeof(float),(size_t){sn},f)!=(size_t){sn}){{ fprintf(stderr,\"moe s {out}_{tag}\\n\"); return 1; }} fclose(f); }}\n",
1575 qp = q.quants, sp = q.scales
1576 ));
1577 }
1578 let (md, mdff, me) = moe_scratch.unwrap_or((0, 0, 0));
1579 moe_scratch = Some((md.max(m.d), mdff.max(m.dff), me.max(m.ne)));
1580 }
1581 }
1582 if let Some((md, mdff, me)) = moe_scratch {
1583 for (nm, n) in [
1584 ("moe_logits", me),
1585 ("moe_w", me),
1586 ("moe_gate_e", mdff),
1587 ("moe_up_e", mdff),
1588 ("moe_he", mdff),
1589 ("moe_oute", md),
1590 ] {
1591 allocs.push_str(&format!(
1592 " float* {nm}; if(cudaMallocManaged(&{nm},(size_t){n}*sizeof(float))){{ fprintf(stderr,\"malloc moe scratch\\n\"); return 1; }}\n"
1593 ));
1594 }
1595 if kind != Q8MatKind::Dequant {
1596 allocs.push_str(&format!(" int* moe_idx; if(cudaMallocManaged(&moe_idx,(size_t){me}*sizeof(int))){{ fprintf(stderr,\"malloc idx\\n\"); return 1; }}\n"));
1600 allocs.push_str(&format!(" float* moe_he_all; if(cudaMallocManaged(&moe_he_all,(size_t){n}*sizeof(float))){{ fprintf(stderr,\"malloc moe fused\\n\"); return 1; }}\n", n = me * mdff));
1601 allocs.push_str(&format!(" signed char* moe_xqh; if(cudaMallocManaged(&moe_xqh,(size_t){md})){{ fprintf(stderr,\"malloc xqh\\n\"); return 1; }}\n", md = md));
1605 allocs.push_str(&format!(" float* moe_xs; if(cudaMallocManaged(&moe_xs,(size_t)(({md}/32)+1)*sizeof(float))){{ fprintf(stderr,\"malloc xs\\n\"); return 1; }}\n", md = md));
1606 allocs.push_str(&format!(" signed char* moe_hqh; if(cudaMallocManaged(&moe_hqh,(size_t){n})){{ fprintf(stderr,\"malloc hqh\\n\"); return 1; }}\n", n = me * mdff));
1607 allocs.push_str(&format!(" float* moe_hs; if(cudaMallocManaged(&moe_hs,(size_t)(({n}/32)+1)*sizeof(float))){{ fprintf(stderr,\"malloc hs\\n\"); return 1; }}\n", n = me * mdff));
1608 if kind == Q8MatKind::TwoPassInt8 {
1609 allocs.push_str(&format!(" signed char* moe_xql; if(cudaMallocManaged(&moe_xql,(size_t){md})){{ fprintf(stderr,\"malloc xql\\n\"); return 1; }}\n", md = md));
1610 allocs.push_str(&format!(" signed char* moe_hql; if(cudaMallocManaged(&moe_hql,(size_t){n})){{ fprintf(stderr,\"malloc hql\\n\"); return 1; }}\n", n = me * mdff));
1611 }
1612 }
1613 }
1614 let printf = if floaty {
1615 "printf(\"%.6f\\n\", (double)buf_{v}[p]);"
1616 } else {
1617 "printf(\"%lld\\n\", (long long)buf_{v}[p]);"
1618 };
1619 let print_final = format!(
1620 " for(size_t p=0;p<(size_t){final_size};++p) {}\n",
1621 printf.replace("{v}", &final_out)
1622 );
1623
1624 let launches_st = launches.replace(">>>", ",0,_st>>>");
1629 let bucket = |k: &str| -> usize {
1635 if k.contains("moe_router") || k.contains("moe_topk") {
1636 3
1637 } else if k.contains("moe_qact") {
1638 4
1639 } else if k.contains("moe_gate_up")
1640 || k.contains("moe_down")
1641 || k.contains("moe_silu")
1642 || k.contains("moe_combine")
1643 || k.contains("moe_zero")
1644 || k.contains("moe_gemv")
1645 {
1646 5
1647 } else if k.contains("_attn") {
1648 1
1649 } else if k.contains("_q8dp4a") {
1650 2
1651 } else if k.contains("_add_row") || k.contains("_row") {
1652 0
1653 } else if k.contains("_qact") {
1654 6
1655 } else {
1656 7
1657 }
1658 };
1659 let mut pinned = String::new();
1660 for line in launches.lines() {
1661 let t = line.trim_start();
1662 if let Some(pos) = t.find("<<<") {
1663 let kname = t[..pos]
1664 .rsplit(|c: char| c == ' ' || c == '{' || c == '}' || c == ';')
1665 .find(|s| !s.is_empty())
1666 .unwrap_or("");
1667 let b = bucket(kname);
1668 let ln = line.replace(">>>", ",0,_st>>>");
1669 pinned.push_str(&format!(
1670 " cudaEventRecord(_pa,_st); {} cudaEventRecord(_pb,_st); cudaEventSynchronize(_pb); {{ float _dt=0; cudaEventElapsedTime(&_dt,_pa,_pb); _pin[{b}]+=_dt; _cnt[{b}]++; }}\n",
1671 ln.trim_start()
1672 ));
1673 } else if !t.is_empty() {
1674 pinned.push_str(&line.replace(">>>", ",0,_st>>>"));
1675 pinned.push('\n');
1676 }
1677 }
1678 let pins_pass = format!(
1679 "\x20 if(getenv(\"LOGOS_CUDA_PINS\")){{\n\
1680 \x20 const char* _bn[8]={{\"norm+quant\",\"attention\",\"attn_proj+lmhead\",\"moe_router+topk\",\"moe_qact\",\"moe_ffn\",\"qact\",\"other\"}};\n\
1681 \x20 double _pin[8]={{0}}; long _cnt[8]={{0}}; cudaEvent_t _pa,_pb; cudaEventCreate(&_pa); cudaEventCreate(&_pb);\n\
1682 {pinned}\
1683 \x20 double _tot=0; for(int _b=0;_b<8;++_b) _tot+=_pin[_b];\n\
1684 \x20 for(int _b=0;_b<8;++_b) fprintf(stderr,\"PIN %-18s %8.4f ms x%-5ld %5.1f%%\\n\",_bn[_b],_pin[_b],_cnt[_b], _tot>0?100.0*_pin[_b]/_tot:0.0);\n\
1685 \x20 fprintf(stderr,\"PIN %-18s %8.4f ms (%.1f tok/s single-pass, event-serialized)\\n\",\"TOTAL\",_tot, _tot>0?1000.0/_tot:0.0);\n\
1686 \x20 }}\n"
1687 );
1688 let prov = super::provenance::header(super::provenance::Provenance::Compiled);
1689 Ok(format!(
1690 "{prov}// A multi-stage tensor-op forward composed as chained PARALLEL kernels through shared device buffers\n\
1691 // ({n} stages), captured as one CUDA graph for replay.\n\
1692 #include <cstdio>\n#include <cstdlib>\n#include <cuda_runtime.h>\n#include <cuda_fp16.h>\n#include <cmath>\n\n\
1693 {kernels}\nint main(void){{\n{allocs}{fills}\n\
1694 \x20 cudaStream_t _st; if(cudaStreamCreate(&_st)!=cudaSuccess){{ fprintf(stderr,\"stream\\n\"); return 1; }}\n\
1695 \x20 // Warm-up launch: runs the forward once, migrating the managed weight pages resident on the GPU.\n\
1696 {launches_st}\
1697 \x20 if(cudaStreamSynchronize(_st)!=cudaSuccess){{ fprintf(stderr,\"sync\\n\"); return 1; }}\n\
1698 {pins_pass}\
1699 \x20 // Capture the entire forward into a single CUDA graph, then instantiate + replay it.\n\
1700 \x20 cudaGraph_t _g; cudaGraphExec_t _ge;\n\
1701 \x20 if(cudaStreamBeginCapture(_st, cudaStreamCaptureModeGlobal)!=cudaSuccess){{ fprintf(stderr,\"capture\\n\"); return 1; }}\n\
1702 {launches_st}\
1703 \x20 if(cudaStreamEndCapture(_st, &_g)!=cudaSuccess){{ fprintf(stderr,\"endcap\\n\"); return 1; }}\n\
1704 \x20 if(cudaGraphInstantiate(&_ge, _g, 0)!=cudaSuccess){{ fprintf(stderr,\"instantiate\\n\"); return 1; }}\n\
1705 \x20 cudaGraphLaunch(_ge, _st); cudaStreamSynchronize(_st);\n\
1706 \x20 cudaEvent_t _e0,_e1; cudaEventCreate(&_e0); cudaEventCreate(&_e1);\n\
1707 \x20 cudaEventRecord(_e0,_st); for(int _it=0;_it<20;++_it){{ cudaGraphLaunch(_ge,_st); }}\n\
1708 \x20 cudaEventRecord(_e1,_st); cudaStreamSynchronize(_st); float _ms=0.0f; cudaEventElapsedTime(&_ms,_e0,_e1);\n\
1709 \x20 fprintf(stderr,\"FORWARD_MS %f\\n\", _ms/20.0f);\n\
1710 {print_final} return 0;\n}}\n",
1711 n = stage_count
1712 ))
1713}
1714
1715pub struct Qwen30bCfg {
1718 pub d: usize, pub dff: usize, pub ne: usize, pub k: usize, pub layers: usize, pub h: usize, pub kv: usize, pub hd: usize, pub vocab: usize, pub rope_theta: f64,
1731 pub rms_eps: f64,
1733 pub attn_split: usize,
1736}
1737
1738impl Qwen30bCfg {
1739 pub fn real() -> Self {
1740 Qwen30bCfg {
1741 d: 2048,
1742 dff: 768,
1743 ne: 128,
1744 k: 8,
1745 layers: 48,
1746 h: 32,
1747 kv: 4,
1748 hd: 128,
1749 vocab: 151936,
1750 rope_theta: 1.0e6,
1751 rms_eps: 1e-6,
1752 attn_split: 8,
1753 }
1754 }
1755}
1756
1757fn q8ref(dir: &str, tag: &str, inn: usize, out: usize) -> Q8Ref {
1759 Q8Ref {
1760 quants: format!("{dir}/{tag}.q"),
1761 scales: format!("{dir}/{tag}.s"),
1762 in_dim: inn,
1763 out_dim: out,
1764 }
1765}
1766
1767pub fn emit_marlin_q8_gemm(nt: usize) -> String {
1784 format!(
1785 r#"// AUTO-TUNED (nt={nt}) + SAT-CERTIFIED (fragment bijection, k==Q8_0-block==32, no int32 overflow) + GOLDEN
1786// (<=4.2e-7 vs dp4a: int32 exact, only f32 reassociation). Register-dequant tensor-core Q8_0 GEMM, emitted by our
1787// compiler from the recognized `A matmul Wq8` op -- the world's-smartest-compiler Marlin lowering.
1788__global__ void gk_marlin_q8(const signed char* Xq,const float* Xs,const signed char* Wq,const float* Ws,float* Y,int B,int N,int K){{
1789 const int NT={nt}; int KB=K/32;
1790 int warp=(blockIdx.x*blockDim.x+threadIdx.x)>>5; int lane=threadIdx.x&31;
1791 int ntiles=N/(8*NT); int mtile=warp/ntiles, ntile=warp%ntiles; int m0=mtile*16, n0=ntile*8*NT;
1792 int gid=lane>>2, tid=lane&3;
1793 float d[NT][4]; for(int j=0;j<NT;j++){{d[j][0]=d[j][1]=d[j][2]=d[j][3]=0;}}
1794 for(int kb=0;kb<KB;kb++){{ int k0=kb*32;
1795 int a0=*(const int*)(Xq+(long)(m0+gid)*K+k0+tid*4);
1796 int a1=*(const int*)(Xq+(long)(m0+gid+8)*K+k0+tid*4);
1797 int a2=*(const int*)(Xq+(long)(m0+gid)*K+k0+16+tid*4);
1798 int a3=*(const int*)(Xq+(long)(m0+gid+8)*K+k0+16+tid*4);
1799 float xs0=Xs[(long)(m0+gid)*KB+kb], xs1=Xs[(long)(m0+gid+8)*KB+kb];
1800 #pragma unroll
1801 for(int j=0;j<NT;j++){{ int nn=n0+j*8;
1802 int b0=*(const int*)(Wq+(long)(nn+gid)*K+k0+tid*4);
1803 int b1=*(const int*)(Wq+(long)(nn+gid)*K+k0+16+tid*4);
1804 int c0=0,c1=0,c2=0,c3=0;
1805 asm volatile("mma.sync.aligned.m16n8k32.row.col.s32.s8.s8.s32 {{%0,%1,%2,%3}}, {{%4,%5,%6,%7}}, {{%8,%9}}, {{%0,%1,%2,%3}};"
1806 : "+r"(c0),"+r"(c1),"+r"(c2),"+r"(c3) : "r"(a0),"r"(a1),"r"(a2),"r"(a3), "r"(b0),"r"(b1));
1807 float ws0=Ws[(long)(nn+tid*2)*KB+kb], ws1=Ws[(long)(nn+tid*2+1)*KB+kb];
1808 d[j][0]+=(float)c0*(ws0*xs0); d[j][1]+=(float)c1*(ws1*xs0);
1809 d[j][2]+=(float)c2*(ws0*xs1); d[j][3]+=(float)c3*(ws1*xs1);
1810 }}
1811 }}
1812 for(int j=0;j<NT;j++){{ int nn=n0+j*8; int r0=m0+gid,r1=m0+gid+8,cc0=nn+tid*2,cc1=nn+tid*2+1;
1813 if(r0<B){{ if(cc0<N)Y[(long)r0*N+cc0]=d[j][0]; if(cc1<N)Y[(long)r0*N+cc1]=d[j][1]; }}
1814 if(r1<B){{ if(cc0<N)Y[(long)r1*N+cc0]=d[j][2]; if(cc1<N)Y[(long)r1*N+cc1]=d[j][3]; }} }}
1815}}
1816"#
1817 )
1818}
1819
1820pub const GEN_DEVICE_KERNELS: &str = r#"
1821__global__ void gk_embed(float* x, const signed char* wq, const float* ws, const int* d_tok, int E){
1822 int t=blockIdx.x*blockDim.x+threadIdx.x; if(t>=E) return;
1823 long tok=*d_tok; x[t]=(float)wq[tok*E+t]*ws[tok*(E/32)+t/32];
1824}
1825__global__ void gk_rmsnorm(float* out, const float* x, const float* w, int n, float eps){
1826 __shared__ float sh[256]; float s=0; for(int i=threadIdx.x;i<n;i+=blockDim.x) s+=x[i]*x[i];
1827 sh[threadIdx.x]=s; __syncthreads();
1828 for(int k=blockDim.x/2;k>0;k>>=1){ if(threadIdx.x<k) sh[threadIdx.x]+=sh[threadIdx.x+k]; __syncthreads(); }
1829 float sc=rsqrtf(sh[0]/n+eps); for(int i=threadIdx.x;i<n;i+=blockDim.x) out[i]=x[i]*sc*w[i];
1830}
1831// FUSED residual-add + RMSNorm: `x += y` (the residual, kept for the next block) AND `out = rmsnorm(x)*w`, in
1832// ONE kernel launch and ONE pass over x. The reduction is the SAME 256-thread tree as gk_rmsnorm over the SAME
1833// summed values (v = x[i]+y[i]), so the float sum is bit-identical ⇒ token-exact. Removes a kernel node and the
1834// residual write/re-read per layer — the win in the latency-bound batch-1 H100 decode.
1835__global__ void gk_add_rmsnorm(float* x, const float* y, float* out, const float* w, int n, float eps){
1836 __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; }
1837 sh[threadIdx.x]=s; __syncthreads();
1838 for(int k=blockDim.x/2;k>0;k>>=1){ if(threadIdx.x<k) sh[threadIdx.x]+=sh[threadIdx.x+k]; __syncthreads(); }
1839 float sc=rsqrtf(sh[0]/n+eps); for(int i=threadIdx.x;i<n;i+=blockDim.x) out[i]=x[i]*sc*w[i];
1840}
1841// FUSED residual-add + RMSNorm + INT8 QUANT: like gk_add_rmsnorm, but ALSO emits `out` quantized to int8 per
1842// 32-block (oq + per-block scale os_) in the SAME kernel — folding the standalone `moe_qact(x2n)` away. `out`
1843// (float) still feeds the router; `oq`/`os_` (int8) feed the experts. The quant replicates moe_qact's per-32
1844// amax/127 scheme EXACTLY (one warp per 32-block, shfl amax) ⇒ the experts see bit-identical int8 (token-exact).
1845__global__ void gk_add_rmsnorm_q8(float* x, const float* y, float* out, const float* w, signed char* oq, float* os_, int n, float eps){
1846 __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; }
1847 sh[threadIdx.x]=s; __syncthreads();
1848 for(int k=blockDim.x/2;k>0;k>>=1){ if(threadIdx.x<k) sh[threadIdx.x]+=sh[threadIdx.x+k]; __syncthreads(); }
1849 float scale=rsqrtf(sh[0]/n+eps); for(int i=threadIdx.x;i<n;i+=blockDim.x) out[i]=x[i]*scale*w[i];
1850 __syncthreads();
1851 int warp=threadIdx.x>>5, lane=threadIdx.x&31, nb=n/32;
1852 for(int b=warp;b<nb;b+=(blockDim.x>>5)){ float v=out[b*32+lane], av=fabsf(v);
1853 for(int t=16;t>0;t>>=1) av=fmaxf(av,__shfl_down_sync(0xffffffffu,av,t));
1854 av=__shfl_sync(0xffffffffu,av,0); float amax=av>1e-30f?av:1e-30f; float qs=amax/127.0f;
1855 if(lane==0) os_[b]=qs; int q=(int)rintf(v/qs); if(q>127)q=127; if(q<-128)q=-128; oq[b*32+lane]=(signed char)q; }
1856}
1857__global__ void gk_rmsnorm_q8(const float* x, signed char* xq, float* xs, const float* w, int n, float eps){
1858 __shared__ float red[256]; float s=0; for(int i=threadIdx.x;i<n;i+=blockDim.x) s+=x[i]*x[i];
1859 red[threadIdx.x]=s; __syncthreads();
1860 for(int k=128;k>0;k>>=1){ if(threadIdx.x<k) red[threadIdx.x]+=red[threadIdx.x+k]; __syncthreads(); }
1861 float rms=rsqrtf(red[0]/n+eps); int warp=threadIdx.x>>5, lane=threadIdx.x&31, nb=n/32;
1862 for(int b=warp;b<nb;b+=8){ float y=x[b*32+lane]*rms*w[b*32+lane], a=fabsf(y);
1863 for(int sh=16;sh>0;sh>>=1) a=fmaxf(a,__shfl_down_sync(0xffffffffu,a,sh));
1864 a=__shfl_sync(0xffffffffu,a,0); float sc=a>0?a/127.0f:1.0f;
1865 if(lane==0) xs[b]=sc; xq[b*32+lane]=(signed char)__float2int_rn(y/sc); }
1866}
1867// FUSED residual-add + RMSNorm + int8 quant for the ATTENTION norm: `x += y` (residual kept) AND quantize
1868// rmsnorm(x)*w to int8 (xq/xs) — folds the post-MoE `gk_add` into the NEXT layer's attn norm+quant. Identical
1869// 128-thread reduction + per-32 quant as gk_rmsnorm_q8 over v=x[i]+y[i] ⇒ bit-identical ⇒ token-exact.
1870__global__ void gk_add_rmsnorm_q8a(float* x, const float* y, signed char* xq, float* xs, const float* w, int n, float eps){
1871 __shared__ float red[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; }
1872 red[threadIdx.x]=s; __syncthreads();
1873 for(int k=128;k>0;k>>=1){ if(threadIdx.x<k) red[threadIdx.x]+=red[threadIdx.x+k]; __syncthreads(); }
1874 float rms=rsqrtf(red[0]/n+eps); int warp=threadIdx.x>>5, lane=threadIdx.x&31, nb=n/32;
1875 for(int b=warp;b<nb;b+=8){ float y2=x[b*32+lane]*rms*w[b*32+lane], a=fabsf(y2);
1876 for(int sh=16;sh>0;sh>>=1) a=fmaxf(a,__shfl_down_sync(0xffffffffu,a,sh));
1877 a=__shfl_sync(0xffffffffu,a,0); float sc=a>0?a/127.0f:1.0f;
1878 if(lane==0) xs[b]=sc; xq[b*32+lane]=(signed char)__float2int_rn(y2/sc); }
1879}
1880__global__ void gk_quant_act(const float* x, signed char* xq, float* xs, int K){
1881 int blk=blockIdx.x*(blockDim.x/32)+threadIdx.x/32; if((long)blk*32>=K) return; int lane=threadIdx.x&31;
1882 float v=x[blk*32+lane], a=fabsf(v);
1883 for(int s=16;s>0;s>>=1) a=fmaxf(a,__shfl_down_sync(0xffffffffu,a,s)); a=__shfl_sync(0xffffffffu,a,0);
1884 float sc=a>0?a/127.0f:1.0f; if(lane==0) xs[blk]=sc; xq[blk*32+lane]=(signed char)__float2int_rn(v/sc);
1885}
1886__global__ void gk_gemv(float* y, const signed char* wq, const float* ws, const signed char* xq, const float* xs, int K, int N){
1887 int o=(blockIdx.x*blockDim.x+threadIdx.x)>>5; if(o>=N) return; int lane=threadIdx.x&31;
1888 const int4* w16=(const int4*)(wq+(long)o*K); const int4* x16=(const int4*)xq; const float* wsr=ws+(long)o*(K/32);
1889 float acc=0.f; int nq=K/512;
1890 for(int b=0;b<nq;b++){ int4 w=w16[b*32+lane], xx=x16[b*32+lane]; int blk=b*16+lane/2;
1891 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);
1892 acc += (float)d * (wsr[blk]*xs[blk]); }
1893 int done=nq*512; for(int j=done+lane;j<K;j+=32){ int blk=j/32; acc += (float)((int)xq[j]*(int)wq[(long)o*K+j])*(wsr[blk]*xs[blk]); }
1894 for(int s=16;s>0;s>>=1) acc+=__shfl_down_sync(0xffffffffu,acc,s); if(lane==0) y[o]=acc;
1895}
1896__global__ void gk_gemv_kv(float* cache, const int* d_pos, int KD, const signed char* wq, const float* ws, const signed char* xq, const float* xs, int K, int N){
1897 int o=(blockIdx.x*blockDim.x+threadIdx.x)>>5; if(o>=N) return; int lane=threadIdx.x&31;
1898 const int4* w16=(const int4*)(wq+(long)o*K); const int4* x16=(const int4*)xq; const float* wsr=ws+(long)o*(K/32);
1899 float acc=0.f; int nq=K/512;
1900 for(int b=0;b<nq;b++){ int4 w=w16[b*32+lane], xx=x16[b*32+lane]; int blk=b*16+lane/2;
1901 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);
1902 acc += (float)d * (wsr[blk]*xs[blk]); }
1903 int done=nq*512; for(int j=done+lane;j<K;j+=32){ int blk=j/32; acc += (float)((int)xq[j]*(int)wq[(long)o*K+j])*(wsr[blk]*xs[blk]); }
1904 for(int s=16;s>0;s>>=1) acc+=__shfl_down_sync(0xffffffffu,acc,s); if(lane==0) cache[(long)(*d_pos)*KD+o]=acc;
1905}
1906// FUSED Q/K/V projection: one launch over QD+2·KD output warps, each picking its weight matrix by output range
1907// (Q→qbuf, K→cache[pos], V→cache[pos]) and reading the SHARED int8 activation once. Replaces three separate
1908// launch-bound gemvs with one — measured the single largest decode-throughput win (A100: +7 tok/s), because
1909// batch-1 decode is dominated by per-kernel launch/latency, not weight bandwidth.
1910__global__ void gk_gemv_qkv(float* qbuf,float* kc,float* vc,const int* d_pos,int KD,
1911 const signed char* wqq,const float* wqs,const signed char* wkq,const float* wks,const signed char* wvq,const float* wvs,
1912 const signed char* xq,const float* xs,int K,int QD){
1913 int og=(blockIdx.x*blockDim.x+threadIdx.x)>>5; int lane=threadIdx.x&31; int Ntot=QD+2*KD; if(og>=Ntot) return;
1914 const signed char* wq; const float* ws; int o; float* dst; long dsti;
1915 if(og<QD){ wq=wqq; ws=wqs; o=og; dst=qbuf; dsti=o; }
1916 else if(og<QD+KD){ wq=wkq; ws=wks; o=og-QD; dst=kc; dsti=(long)(*d_pos)*KD+o; }
1917 else { wq=wvq; ws=wvs; o=og-QD-KD; dst=vc; dsti=(long)(*d_pos)*KD+o; }
1918 const int4* w16=(const int4*)(wq+(long)o*K); const int4* x16=(const int4*)xq; const float* wsr=ws+(long)o*(K/32);
1919 float acc=0.f; int nq=K/512;
1920 for(int b=0;b<nq;b++){ int4 w=w16[b*32+lane], xx=x16[b*32+lane]; int blk=b*16+lane/2;
1921 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);
1922 acc += (float)d * (wsr[blk]*xs[blk]); }
1923 int done=nq*512; for(int j=done+lane;j<K;j+=32){ int blk=j/32; acc += (float)((int)xq[j]*(int)wq[(long)o*K+j])*(wsr[blk]*xs[blk]); }
1924 for(int s=16;s>0;s>>=1) acc+=__shfl_down_sync(0xffffffffu,acc,s); if(lane==0) dst[dsti]=acc;
1925}
1926__global__ void gk_qk_norm_rope(float* base, const int* d_pos, int stride, const float* nw, int n_heads, int hd, float rbase, float eps){
1927 int head=blockIdx.x; if(head>=n_heads) return; float* h=base+(long)(*d_pos)*stride+head*hd;
1928 __shared__ float sh[128]; float s=0; for(int i=threadIdx.x;i<hd;i+=blockDim.x) s+=h[i]*h[i]; sh[threadIdx.x]=s; __syncthreads();
1929 for(int k=blockDim.x/2;k>0;k>>=1){ if(threadIdx.x<k) sh[threadIdx.x]+=sh[threadIdx.x+k]; __syncthreads(); }
1930 float sc=rsqrtf(sh[0]/hd+eps); __syncthreads();
1931 for(int i=threadIdx.x;i<hd;i+=blockDim.x) h[i]=h[i]*sc*nw[i]; __syncthreads();
1932 int half=hd/2; int pos=*d_pos;
1933 for(int i=threadIdx.x;i<half;i+=blockDim.x){ float f=powf(rbase,-2.0f*i/hd); float a=pos*f,c=cosf(a),si=sinf(a);
1934 float x0=h[i],x1=h[i+half]; h[i]=x0*c-x1*si; h[i+half]=x0*si+x1*c; }
1935}
1936// FUSED Q+K per-head RMSNorm+RoPE: one launch over NH+NKV head-blocks, picking Q params (block<NH) or K params
1937// (block≥NH). Replaces two underfilled launches (NH and NKV blocks) with one — the Q and K norm-rope are the
1938// same body over different (base,stride,weight), so a branch on blockIdx fuses them (A100: +4 tok/s).
1939__global__ void gk_qk_norm_rope2(float* qbase, float* kbase, const int* d_pos, int kstride, const float* qnw, const float* knw, int nh, int nkv, int hd, float rbase, float eps){
1940 int b=blockIdx.x; float* base; const float* nw; int stride; int head;
1941 if(b<nh){ base=qbase; nw=qnw; stride=0; head=b; } else { base=kbase; nw=knw; stride=kstride; head=b-nh; }
1942 float* h=base+(long)(*d_pos)*stride+head*hd;
1943 __shared__ float sh[128]; float s=0; for(int i=threadIdx.x;i<hd;i+=blockDim.x) s+=h[i]*h[i]; sh[threadIdx.x]=s; __syncthreads();
1944 for(int k=blockDim.x/2;k>0;k>>=1){ if(threadIdx.x<k) sh[threadIdx.x]+=sh[threadIdx.x+k]; __syncthreads(); }
1945 float sc=rsqrtf(sh[0]/hd+eps); __syncthreads();
1946 for(int i=threadIdx.x;i<hd;i+=blockDim.x) h[i]=h[i]*sc*nw[i]; __syncthreads();
1947 int half=hd/2; int pos=*d_pos;
1948 for(int i=threadIdx.x;i<half;i+=blockDim.x){ float f=powf(rbase,-2.0f*i/hd); float a=pos*f,c=cosf(a),si=sinf(a);
1949 float x0=h[i],x1=h[i+half]; h[i]=x0*c-x1*si; h[i+half]=x0*si+x1*c; }
1950}
1951// Flash-attention-style single-query decode: one block per query head, a WARP per cached key (parallel qh·kj
1952// dot, warp-reduced), a parallel block-softmax (shuffle max/sum + shared cross-warp reduce), then a parallel
1953// weighted sum over V. Q is normed+roped by the preceding gk_qk_norm_rope; fusing it in here perturbs the float
1954// order enough to flip a precise near-tie AND doesn't cut graph time (the work just moves) — so kept separate.
1955__global__ void gk_attn(float* out, const float* q, const float* kc, const float* vc, const int* d_pos, int n_head, int n_kv, int hd, float scale){
1956 int head=blockIdx.x; if(head>=n_head) return; int kvh=head/(n_head/n_kv); int L=*d_pos+1; int KD=n_kv*hd;
1957 const float* qh=q+(long)head*hd; extern __shared__ float sc[]; __shared__ float red[32];
1958 int lane=threadIdx.x&31, wp=threadIdx.x>>5, nw=(blockDim.x+31)>>5;
1959 for(int j=wp;j<L;j+=nw){ const float* kj=kc+(long)j*KD+kvh*hd; float s=0.f; for(int e=lane;e<hd;e+=32) s+=qh[e]*kj[e];
1960 for(int r=16;r>0;r>>=1) s+=__shfl_down_sync(0xffffffffu,s,r); if(lane==0) sc[j]=s*scale; }
1961 __syncthreads();
1962 float m=-1e30f; for(int j=threadIdx.x;j<L;j+=blockDim.x) m=fmaxf(m,sc[j]);
1963 for(int r=16;r>0;r>>=1) m=fmaxf(m,__shfl_down_sync(0xffffffffu,m,r)); if(lane==0) red[wp]=m; __syncthreads();
1964 if(threadIdx.x==0){ float mm=red[0]; for(int i=1;i<nw;i++) mm=fmaxf(mm,red[i]); red[0]=mm; } __syncthreads(); float mx=red[0];
1965 float ss=0.f; for(int j=threadIdx.x;j<L;j+=blockDim.x){ float e=expf(sc[j]-mx); sc[j]=e; ss+=e; }
1966 for(int r=16;r>0;r>>=1) ss+=__shfl_down_sync(0xffffffffu,ss,r); if(lane==0) red[wp]=ss; __syncthreads();
1967 if(threadIdx.x==0){ float su=0.f; for(int i=0;i<nw;i++) su+=red[i]; red[0]=su; } __syncthreads(); float den=red[0];
1968 for(int e=threadIdx.x;e<hd;e+=blockDim.x){ float a=0.f; for(int j=0;j<L;j++) a+=sc[j]*vc[(long)j*KD+kvh*hd+e]; out[(long)head*hd+e]=a/den; }
1969}
1970// ONLINE-SOFTMAX flash-attention decode (llama's fattn-vec shape): one block per query head, warps stream
1971// DISJOINT slabs of the KV cache, each keeping a RUNNING (max, sum) + weighted-V accumulator in REGISTERS —
1972// a single pass, warp-shuffle score reduce (no per-key __syncthreads, no shared score array), then ONE
1973// cross-warp flash-combine. Q lives in registers. Replaces the multi-pass score→sync→max→sync→exp→sync→V form.
1974__global__ void gk_attn_online(float* out, const float* q, const float* kc, const float* vc, const int* d_pos, int n_head, int n_kv, int hd, float scale){
1975 int head=blockIdx.x; if(head>=n_head) return; int kvh=head/(n_head/n_kv); int L=*d_pos+1; int KD=n_kv*hd;
1976 const float* qh=q+(long)head*hd;
1977 int lane=threadIdx.x&31, wp=threadIdx.x>>5, nw=blockDim.x>>5; int dpl=hd>>5;
1978 float qreg[8], acc[8]; for(int i=0;i<dpl;i++){ qreg[i]=qh[lane+(i<<5)]; acc[i]=0.f; }
1979 float m=-1e30f, dsum=0.f;
1980 for(int j=wp;j<L;j+=nw){
1981 const float* kj=kc+(long)j*KD+kvh*hd; float part=0.f;
1982 for(int i=0;i<dpl;i++) part+=qreg[i]*kj[lane+(i<<5)];
1983 for(int r=16;r>0;r>>=1) part+=__shfl_xor_sync(0xffffffffu,part,r);
1984 float sj=part*scale; float mn=fmaxf(m,sj), c=__expf(m-mn), p=__expf(sj-mn); m=mn; dsum=dsum*c+p;
1985 const float* vj=vc+(long)j*KD+kvh*hd;
1986 for(int i=0;i<dpl;i++) acc[i]=acc[i]*c + p*vj[lane+(i<<5)];
1987 }
1988 __shared__ float sm[8], sd[8], sa[8][128];
1989 if(lane==0){ sm[wp]=m; sd[wp]=dsum; }
1990 for(int i=0;i<dpl;i++) sa[wp][lane+(i<<5)]=acc[i];
1991 __syncthreads();
1992 float M=-1e30f; for(int w=0;w<nw;w++) M=fmaxf(M,sm[w]);
1993 float D=0.f; for(int w=0;w<nw;w++) D+=sd[w]*__expf(sm[w]-M);
1994 for(int d=threadIdx.x; d<hd; d+=blockDim.x){ float a=0.f; for(int w=0;w<nw;w++) a+=sa[w][d]*__expf(sm[w]-M); out[(long)head*hd+d]=a/D; }
1995}
1996// SPLIT-K flash-attention (llama's fattn-vec `parallel_blocks`): P blocks PER query head each stream a disjoint
1997// slab of the KV cache with a register online-softmax → a partial (local max, denom, un-normalized weighted-V)
1998// in scratch; grid = n_head*P for FULL SM occupancy at decode (32 heads × 4 = 128 blocks vs 32). `gk_attn_comb`
1999// then flash-merges the P partials per head. This is the measured +14 tok/s edge llama gets from `-fa`.
2000__global__ void gk_attn_part(const float* q, const float* kc, const float* vc, const int* d_pos, int n_head, int n_kv, int hd, float scale, int P, float* acc_part, float* m_part, float* d_part){
2001 int b=blockIdx.x; int head=b/P, p=b%P; if(head>=n_head) return;
2002 int kvh=head/(n_head/n_kv); int L=*d_pos+1; int KD=n_kv*hd; const float* qh=q+(long)head*hd;
2003 int lane=threadIdx.x&31, wp=threadIdx.x>>5, nw=blockDim.x>>5; int dpl=hd>>5;
2004 float qreg[8], acc[8]; for(int i=0;i<dpl;i++){ qreg[i]=qh[lane+(i<<5)]; acc[i]=0.f; }
2005 float m=-1e30f, dsum=0.f;
2006 for(int idx=wp; ; idx+=nw){ int j=p+idx*P; if(j>=L) break;
2007 const float* kj=kc+(long)j*KD+kvh*hd; float pt=0.f;
2008 for(int i=0;i<dpl;i++) pt+=qreg[i]*kj[lane+(i<<5)];
2009 for(int r=16;r>0;r>>=1) pt+=__shfl_xor_sync(0xffffffffu,pt,r);
2010 float sj=pt*scale; float mn=fmaxf(m,sj), c=__expf(m-mn), pp=__expf(sj-mn); m=mn; dsum=dsum*c+pp;
2011 const float* vj=vc+(long)j*KD+kvh*hd; for(int i=0;i<dpl;i++) acc[i]=acc[i]*c + pp*vj[lane+(i<<5)];
2012 }
2013 __shared__ float sm[8], sd[8], sa[8][128];
2014 if(lane==0){ sm[wp]=m; sd[wp]=dsum; }
2015 for(int i=0;i<dpl;i++) sa[wp][lane+(i<<5)]=acc[i];
2016 __syncthreads();
2017 float M=-1e30f; for(int w=0;w<nw;w++) M=fmaxf(M,sm[w]);
2018 float D=0.f; for(int w=0;w<nw;w++) D+=sd[w]*__expf(sm[w]-M);
2019 if(threadIdx.x==0){ m_part[b]=M; d_part[b]=D; }
2020 for(int d=threadIdx.x; d<hd; d+=blockDim.x){ float a=0.f; for(int w=0;w<nw;w++) a+=sa[w][d]*__expf(sm[w]-M); acc_part[(long)b*hd+d]=a; }
2021}
2022__global__ void gk_attn_comb(float* out, int n_head, int hd, int P, const float* acc_part, const float* m_part, const float* d_part){
2023 int head=blockIdx.x; if(head>=n_head) return; __shared__ float GM, GD;
2024 if(threadIdx.x==0){ float M=-1e30f; for(int p=0;p<P;p++) M=fmaxf(M,m_part[head*P+p]); GM=M;
2025 float D=0.f; for(int p=0;p<P;p++) D+=d_part[head*P+p]*__expf(m_part[head*P+p]-M); GD=D; }
2026 __syncthreads(); float M=GM, D=GD;
2027 for(int d=threadIdx.x; d<hd; d+=blockDim.x){ float a=0.f;
2028 for(int p=0;p<P;p++) a += acc_part[(long)(head*P+p)*hd+d]*__expf(m_part[head*P+p]-M);
2029 out[(long)head*hd+d]=a/D; }
2030}
2031// FUSED split-K combine + activation-quant: the combine already lands each head's hd attention outputs in one
2032// block, so it quantizes them into int8 32-blocks in its epilogue (per-32-block warp max-abs) instead of a
2033// separate gk_quant_act launch feeding the O-projection. One fewer kernel on the decode critical path (+~1).
2034__global__ void gk_attn_comb_q(signed char* aq, float* as_, int n_head, int hd, int P, const float* acc_part, const float* m_part, const float* d_part){
2035 int head=blockIdx.x; if(head>=n_head) return; __shared__ float GM,GD; __shared__ float so[128];
2036 if(threadIdx.x==0){ float M=-1e30f; for(int p=0;p<P;p++) M=fmaxf(M,m_part[head*P+p]); GM=M;
2037 float D=0.f; for(int p=0;p<P;p++) D+=d_part[head*P+p]*__expf(m_part[head*P+p]-M); GD=D; }
2038 __syncthreads(); float M=GM,D=GD;
2039 for(int d=threadIdx.x; d<hd; d+=blockDim.x){ float a=0.f; for(int p=0;p<P;p++) a+=acc_part[(long)(head*P+p)*hd+d]*__expf(m_part[head*P+p]-M); so[d]=a/D; }
2040 __syncthreads();
2041 int nb=hd/32, warp=threadIdx.x>>5, lane=threadIdx.x&31, nw=blockDim.x>>5;
2042 for(int blk=warp; blk<nb; blk+=nw){ int gi=head*nb+blk; float v=so[blk*32+lane], av=fabsf(v);
2043 for(int s2=16;s2>0;s2>>=1) av=fmaxf(av,__shfl_down_sync(0xffffffffu,av,s2));
2044 av=__shfl_sync(0xffffffffu,av,0); float amax=av>1e-30f?av:1e-30f; float qsc=amax/127.0f;
2045 if(lane==0) as_[gi]=qsc; int q=(int)rintf(v/qsc); if(q>127)q=127; if(q<-128)q=-128; aq[gi*32+lane]=(signed char)q; }
2046}
2047__global__ void gk_add(float* x, const float* y, int n){ int i=blockIdx.x*blockDim.x+threadIdx.x; if(i<n) x[i]+=y[i]; }
2048__global__ void gk_argmax_adv(const float* logits, int vocab, int* d_tok, int* d_pos){
2049 __shared__ float bv[256]; __shared__ int bi[256]; float bestv=-1e30f; int besti=0;
2050 for(int i=threadIdx.x;i<vocab;i+=blockDim.x){ float v=logits[i]; if(v>bestv){bestv=v;besti=i;} }
2051 bv[threadIdx.x]=bestv; bi[threadIdx.x]=besti; __syncthreads();
2052 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(); }
2053 if(threadIdx.x==0){ *d_tok=bi[0]; *d_pos=*d_pos+1; }
2054}
2055// ── PRECISE (dequant) lane — llama's batch-1 recipe: f32 activation × int8 weight (no activation quantization),
2056// so the logits have clear margins (no int8-act near-ties) and the attention can be FUSED without flipping a
2057// token. Memory-bound on the same int8 weights ⇒ ~same bandwidth as the dp4a lane, but robustly llama-exact. ──
2058__global__ void gk_gemv_deq(float* y, const signed char* wq, const float* ws, const float* x, int K, int N){
2059 int o=(blockIdx.x*blockDim.x+threadIdx.x)>>5; if(o>=N) return; int lane=threadIdx.x&31;
2060 const int4* w16=(const int4*)(wq+(long)o*K); const float* wsr=ws+(long)o*(K/32); float acc=0.f; int nq=K/512;
2061 for(int b=0;b<nq;b++){ int4 wv=w16[b*32+lane]; int blk=b*16+lane/2; float sc=wsr[blk];
2062 const signed char* wb=(const signed char*)&wv; const float* xt=x+b*512+lane*16;
2063 float ba=0.f; for(int i=0;i<16;i++) ba += (float)wb[i]*xt[i]; acc += sc*ba; }
2064 for(int t=nq*512+lane;t<K;t+=32){ int blk=t/32; acc += wsr[blk]*(float)wq[(long)o*K+t]*x[t]; }
2065 for(int s=16;s>0;s>>=1) acc+=__shfl_down_sync(0xffffffffu,acc,s); if(lane==0) y[o]=acc;
2066}
2067__global__ void gk_gemv_kv_deq(float* cache, const int* d_pos, int KD, const signed char* wq, const float* ws, const float* x, int K, int N){
2068 int o=(blockIdx.x*blockDim.x+threadIdx.x)>>5; if(o>=N) return; int lane=threadIdx.x&31;
2069 const int4* w16=(const int4*)(wq+(long)o*K); const float* wsr=ws+(long)o*(K/32); float acc=0.f; int nq=K/512;
2070 for(int b=0;b<nq;b++){ int4 wv=w16[b*32+lane]; int blk=b*16+lane/2; float sc=wsr[blk];
2071 const signed char* wb=(const signed char*)&wv; const float* xt=x+b*512+lane*16;
2072 float ba=0.f; for(int i=0;i<16;i++) ba += (float)wb[i]*xt[i]; acc += sc*ba; }
2073 for(int t=nq*512+lane;t<K;t+=32){ int blk=t/32; acc += wsr[blk]*(float)wq[(long)o*K+t]*x[t]; }
2074 for(int s=16;s>0;s>>=1) acc+=__shfl_down_sync(0xffffffffu,acc,s); if(lane==0) cache[(long)(*d_pos)*KD+o]=acc;
2075}
2076// FUSED flash-attention: Q per-head QK-RMSNorm + RoPE + scores + block-softmax + weighted-V, all in one kernel.
2077__global__ void gk_fused_attn(float* out, const float* q, const float* kc, const float* vc, const int* d_pos, int n_head, int n_kv, int hd, float scale, const float* qnw, float rbase, float eps){
2078 int head=blockIdx.x; if(head>=n_head) return; int kvh=head/(n_head/n_kv); int pos=*d_pos; int L=pos+1; int KD=n_kv*hd;
2079 extern __shared__ float sc[]; __shared__ float red[32]; __shared__ float qh[256];
2080 int lane=threadIdx.x&31, wp=threadIdx.x>>5, nw=(blockDim.x+31)>>5;
2081 const float* qsrc=q+(long)head*hd;
2082 float qsum=0.f; for(int i=threadIdx.x;i<hd;i+=blockDim.x) qsum+=qsrc[i]*qsrc[i];
2083 for(int r=16;r>0;r>>=1) qsum+=__shfl_down_sync(0xffffffffu,qsum,r); if(lane==0) red[wp]=qsum; __syncthreads();
2084 if(threadIdx.x==0){ float s=0.f; for(int i=0;i<nw;i++) s+=red[i]; red[0]=s; } __syncthreads();
2085 float qrms=rsqrtf(red[0]/hd+eps);
2086 for(int i=threadIdx.x;i<hd;i+=blockDim.x) qh[i]=qsrc[i]*qrms*qnw[i]; __syncthreads();
2087 int half=hd/2;
2088 for(int i=threadIdx.x;i<half;i+=blockDim.x){ float f=powf(rbase,-2.0f*i/hd); float a=pos*f,c=cosf(a),si=sinf(a); float x0=qh[i],x1=qh[i+half]; qh[i]=x0*c-x1*si; qh[i+half]=x0*si+x1*c; }
2089 __syncthreads();
2090 for(int j=wp;j<L;j+=nw){ const float* kj=kc+(long)j*KD+kvh*hd; float s=0.f; for(int e=lane;e<hd;e+=32) s+=qh[e]*kj[e];
2091 for(int r=16;r>0;r>>=1) s+=__shfl_down_sync(0xffffffffu,s,r); if(lane==0) sc[j]=s*scale; }
2092 __syncthreads();
2093 float m=-1e30f; for(int j=threadIdx.x;j<L;j+=blockDim.x) m=fmaxf(m,sc[j]);
2094 for(int r=16;r>0;r>>=1) m=fmaxf(m,__shfl_down_sync(0xffffffffu,m,r)); if(lane==0) red[wp]=m; __syncthreads();
2095 if(threadIdx.x==0){ float mm=red[0]; for(int i=1;i<nw;i++) mm=fmaxf(mm,red[i]); red[0]=mm; } __syncthreads(); float mx=red[0];
2096 float ss=0.f; for(int j=threadIdx.x;j<L;j+=blockDim.x){ float e=expf(sc[j]-mx); sc[j]=e; ss+=e; }
2097 for(int r=16;r>0;r>>=1) ss+=__shfl_down_sync(0xffffffffu,ss,r); if(lane==0) red[wp]=ss; __syncthreads();
2098 if(threadIdx.x==0){ float su=0.f; for(int i=0;i<nw;i++) su+=red[i]; red[0]=su; } __syncthreads(); float den=red[0];
2099 for(int e=threadIdx.x;e<hd;e+=blockDim.x){ float a=0.f; for(int j=0;j<L;j++) a+=sc[j]*vc[(long)j*KD+kvh*hd+e]; out[(long)head*hd+e]=a/den; }
2100}
2101// Dequant MoE (f32 activation): gate/up SwiGLU + down-combine over the top-K experts, no activation quant.
2102__global__ void gk_moe_gate_up_deq(const float* x, const signed char* wg_q, const float* wg_s, const signed char* wu_q, const float* wu_s, const int* idx, float* h, int K, int N, int Kd){
2103 long row=(blockIdx.x*(long)blockDim.x+threadIdx.x)>>5; if(row>=(long)K*N) return; int lane=threadIdx.x&31;
2104 int kk=row/N, j=row%N; int e=idx[kk]; int nb=Kd/32, nq=Kd/512;
2105 const signed char* gwr=wg_q+((long)e*N+j)*Kd; const float* gsr=wg_s+((long)e*N+j)*nb;
2106 const signed char* uwr=wu_q+((long)e*N+j)*Kd; const float* usr=wu_s+((long)e*N+j)*nb;
2107 const int4* gw16=(const int4*)gwr; const int4* uw16=(const int4*)uwr; float ga=0.f, ua=0.f;
2108 for(int b=0;b<nq;b++){ int blk=b*16+lane/2; int4 gv=gw16[b*32+lane], uv=uw16[b*32+lane];
2109 const signed char* gb=(const signed char*)&gv; const signed char* ub=(const signed char*)&uv; const float* xt=x+b*512+lane*16;
2110 float gsc=gsr[blk], usc=usr[blk]; float gba=0.f, uba=0.f;
2111 for(int i=0;i<16;i++){ float xi=xt[i]; gba+=(float)gb[i]*xi; uba+=(float)ub[i]*xi; } ga+=gsc*gba; ua+=usc*uba; }
2112 for(int t=nq*512+lane;t<Kd;t+=32){ int blk=t/32; float xi=x[t]; ga+=gsr[blk]*(float)gwr[t]*xi; ua+=usr[blk]*(float)uwr[t]*xi; }
2113 for(int s=16;s>0;s>>=1){ ga+=__shfl_down_sync(0xffffffffu,ga,s); ua+=__shfl_down_sync(0xffffffffu,ua,s); }
2114 if(lane==0) h[row]=(ga/(1.0f+expf(-ga)))*ua;
2115}
2116__global__ void gk_moe_down_deq(const float* hbuf, const signed char* wd_q, const float* wd_s, const int* idx, const float* wc, float* H, int K, int N, int Kd){
2117 int o=blockIdx.x; int warp=threadIdx.x>>5, lane=threadIdx.x&31; int e=idx[warp]; int nb=Kd/32, nq=Kd/512;
2118 const float* hb=hbuf+(long)warp*Kd; const signed char* wr=wd_q+((long)e*N+o)*Kd; const float* wsr=wd_s+((long)e*N+o)*nb;
2119 const int4* w16=(const int4*)wr; float acc=0.f;
2120 for(int b=0;b<nq;b++){ int blk=b*16+lane/2; int4 wv=w16[b*32+lane]; const signed char* wb=(const signed char*)&wv; const float* ht=hb+b*512+lane*16;
2121 float sc=wsr[blk]; float ba=0.f; for(int i=0;i<16;i++) ba += (float)wb[i]*ht[i]; acc += sc*ba; }
2122 for(int t=nq*512+lane;t<Kd;t+=32){ int blk=t/32; acc += wsr[blk]*(float)wr[t]*hb[t]; }
2123 for(int s=16;s>0;s>>=1) acc+=__shfl_down_sync(0xffffffffu,acc,s);
2124 __shared__ float part[64]; if(lane==0) part[warp]=wc[warp]*acc; __syncthreads();
2125 if(threadIdx.x==0){ float sum=0.f; for(int kk=0;kk<K;kk++) sum+=part[kk]; H[o]=sum; }
2126}
2127"#;
2128
2129pub fn emit_qwen30b_generate(
2136 cfg: &Qwen30bCfg,
2137 wdir: &str,
2138 prompt: &[usize],
2139 n_gen: usize,
2140 precise: bool,
2141 flash: bool,
2142) -> String {
2143 let (e, qd, kd, ff) = (cfg.d, cfg.h * cfg.hd, cfg.kv * cfg.hd, cfg.dff);
2144 let (ne, ktop, vocab, layers) = (cfg.ne, cfg.k, cfg.vocab, cfg.layers);
2145 let (nh, nkv, hd) = (cfg.h, cfg.kv, cfg.hd);
2146 let (rope_theta, rms_eps, attn_split) = (cfg.rope_theta, cfg.rms_eps, cfg.attn_split);
2147 let maxseq = prompt.len() + n_gen + 110;
2148 let scale = 1.0f64 / (hd as f64).sqrt();
2149 let prompt_c = prompt
2150 .iter()
2151 .map(|t| t.to_string())
2152 .collect::<Vec<_>>()
2153 .join(",");
2154 let moe_kernels = moe_dp4a_kernels(false);
2155 let fast_attn: &str = if flash {
2159 "gk_attn_part<<<NH*ATTN_SPLIT,256,0,s>>>(qbuf,kc[l],vc[l],d_pos,NH,NKV,HD,SCALEV,ATTN_SPLIT,acc_part,m_part,d_part); gk_attn_comb_q<<<NH,128,0,s>>>(aqQ,asQ,NH,HD,ATTN_SPLIT,acc_part,m_part,d_part);"
2160 } else {
2161 "gk_attn<<<NH,256,(size_t)MAXSEQ*4,s>>>(attnb,qbuf,kc[l],vc[l],d_pos,NH,NKV,HD,SCALEV); gk_quant_act<<<(QD+255)/256,256,0,s>>>(attnb,aqQ,asQ,QD);"
2162 };
2163 let decode_fn: String = if precise {
2167 r#"static void decode_step(cudaStream_t s){
2168 gk_embed<<<(E+255)/256,256,0,s>>>(x,emb_q,emb_s,d_tok,E);
2169 for(int l=0;l<LAYERS;l++){
2170 gk_rmsnorm<<<1,256,0,s>>>(xn,x,an[l],E,EPSV);
2171 gk_gemv_deq<<<Gg(QD),256,0,s>>>(qbuf,wq_q[l],wq_s[l],xn,E,QD);
2172 gk_gemv_kv_deq<<<Gg(KD),256,0,s>>>(kc[l],d_pos,KD,wk_q[l],wk_s[l],xn,E,KD);
2173 gk_gemv_kv_deq<<<Gg(KD),256,0,s>>>(vc[l],d_pos,KD,wv_q[l],wv_s[l],xn,E,KD);
2174 gk_qk_norm_rope<<<NKV,128,0,s>>>(kc[l],d_pos,KD,akn[l],NKV,HD,ROPEV,EPSV);
2175 gk_fused_attn<<<NH,256,(size_t)MAXSEQ*4,s>>>(attnb,qbuf,kc[l],vc[l],d_pos,NH,NKV,HD,SCALEV,aqn[l],ROPEV,EPSV);
2176 gk_gemv_deq<<<Gg(E),256,0,s>>>(tmp,wo_q[l],wo_s[l],attnb,QD,E);
2177 gk_add_rmsnorm<<<1,256,0,s>>>(x,tmp,x2n,fn_[l],E,EPSV);
2178 moe_router_fast<<<(NE+7)/8,256,0,s>>>(x2n,wr_q[l],wr_s[l],moe_logits,NE,E);
2179 moe_topk_idx<<<1,NE,0,s>>>(moe_logits,moe_idx,moe_w,NE,KTOP);
2180 gk_moe_gate_up_deq<<<(KTOP*FF+7)/8,256,0,s>>>(x2n,wg_q[l],wg_s[l],wu_q[l],wu_s[l],moe_idx,moe_he,KTOP,FF,E);
2181 gk_moe_down_deq<<<E,KTOP*32,0,s>>>(moe_he,wd_q[l],wd_s[l],moe_idx,moe_w,moe_out,KTOP,E,FF);
2182 gk_add<<<(E+255)/256,256,0,s>>>(x,moe_out,E);
2183 }
2184 gk_rmsnorm<<<1,256,0,s>>>(xn,x,on_w,E,EPSV);
2185 gk_gemv_deq<<<Gg(VOCAB),256,0,s>>>(logits,wout_q,wout_s,xn,E,VOCAB);
2186}
2187"#.to_string()
2188 } else {
2189 r#"static void decode_step(cudaStream_t s){
2190 gk_embed<<<(E+255)/256,256,0,s>>>(x,emb_q,emb_s,d_tok,E);
2191 gk_rmsnorm_q8<<<1,256,0,s>>>(x,aqE,asE,an[0],E,EPSV);
2192 for(int l=0;l<LAYERS;l++){
2193 gk_gemv_qkv<<<Gg(QD+2*KD),256,0,s>>>(qbuf,kc[l],vc[l],d_pos,KD,wq_q[l],wq_s[l],wk_q[l],wk_s[l],wv_q[l],wv_s[l],aqE,asE,E,QD);
2194 gk_qk_norm_rope2<<<NH+NKV,128,0,s>>>(qbuf,kc[l],d_pos,KD,aqn[l],akn[l],NH,NKV,HD,ROPEV,EPSV);
2195 {fast_attn}
2196 gk_gemv<<<Gg(E),256,0,s>>>(tmp,wo_q[l],wo_s[l],aqQ,asQ,QD,E);
2197 gk_add_rmsnorm_q8<<<1,256,0,s>>>(x,tmp,x2n,fn_[l],moe_xq,moe_xs,E,EPSV);
2198 moe_router_fast<<<(NE+7)/8,256,0,s>>>(x2n,wr_q[l],wr_s[l],moe_logits,NE,E);
2199 moe_topk_idx<<<1,NE,0,s>>>(moe_logits,moe_idx,moe_w,NE,KTOP);
2200 moe_gate_up_silu<<<(KTOP*FF+7)/8,256,0,s>>>(moe_xq,moe_xs,wg_q[l],wg_s[l],wu_q[l],wu_s[l],moe_idx,moe_he,KTOP,FF,E);
2201 moe_qact<<<(((KTOP*FF)/32)+7)/8,256,0,s>>>(moe_he,moe_hq,moe_hs,KTOP*FF);
2202 moe_down_combine<<<E,KTOP*32,0,s>>>(moe_hq,moe_hs,wd_q[l],wd_s[l],moe_idx,moe_w,moe_out,KTOP,E,FF);
2203 if(l+1<LAYERS) gk_add_rmsnorm_q8a<<<1,256,0,s>>>(x,moe_out,aqE,asE,an[l+1],E,EPSV);
2204 else gk_add_rmsnorm_q8a<<<1,256,0,s>>>(x,moe_out,aqE,asE,on_w,E,EPSV);
2205 }
2206 gk_gemv<<<Gg(VOCAB),256,0,s>>>(logits,wout_q,wout_s,aqE,asE,E,VOCAB);
2207}
2208"#.replace("{fast_attn}", fast_attn)
2209 };
2210 let prov = super::provenance::header(super::provenance::Provenance::HandWritten {
2212 model: "Qwen3-30B-A3B",
2213 lane: "generation",
2214 });
2215 format!(
2216 "{prov}// Qwen3-30B-A3B autoregressive generation: a prefill, then a CUDA-graph decode replay over a growing\n\
2217 // KV cache. Weights fopen from {wdir}.\n\
2218 #include <cstdio>\n#include <cstdlib>\n#include <cstring>\n#include <vector>\n#include <cuda_runtime.h>\n#include <cuda_fp16.h>\n#include <cmath>\n\n\
2219 {moe_kernels}\n{GEN_DEVICE_KERNELS}\n\
2220 #define E {e}\n#define QD {qd}\n#define KD {kd}\n#define FF {ff}\n#define NE {ne}\n#define KTOP {ktop}\n\
2221 #define VOCAB {vocab}\n#define LAYERS {layers}\n#define NH {nh}\n#define NKV {nkv}\n#define HD {hd}\n\
2222 #define MAXSEQ {maxseq}\n#define ATTN_SPLIT {attn_split}\n#define EPSV {rms_eps:e}f\n#define ROPEV {rope_theta:e}f\n\
2223 static const float SCALEV = {scale}f;\n\
2224 static signed char *emb_q,*wq_q[LAYERS],*wk_q[LAYERS],*wv_q[LAYERS],*wo_q[LAYERS],*wout_q,*wr_q[LAYERS],*wg_q[LAYERS],*wu_q[LAYERS],*wd_q[LAYERS];\n\
2225 static float *emb_s,*wq_s[LAYERS],*wk_s[LAYERS],*wv_s[LAYERS],*wo_s[LAYERS],*wout_s;\n\
2226 static float *wr_s[LAYERS],*wg_s[LAYERS],*wu_s[LAYERS],*wd_s[LAYERS];\n\
2227 static float *an[LAYERS],*fn_[LAYERS],*aqn[LAYERS],*akn[LAYERS],*on_w;\n\
2228 static float *x,*xn,*x2n,*qbuf,*attnb,*tmp,*logits,*kc[LAYERS],*vc[LAYERS],*acc_part,*m_part,*d_part;\n\
2229 static signed char *aqE,*aqQ,*moe_xq,*moe_hq; static float *asE,*asQ,*moe_logits,*moe_w,*moe_xs,*moe_he,*moe_hs,*moe_out; static int *moe_idx,*d_pos,*d_tok;\n\
2230 static signed char* Li(const char* p, long n){{ signed char* d; if(cudaMalloc(&d,n)){{fprintf(stderr,\"malloc %s\\n\",p);exit(1);}} signed char* h=(signed char*)malloc(n); FILE* f=fopen(p,\"rb\"); if(!f||fread(h,1,n,f)!=(size_t)n){{fprintf(stderr,\"read %s\\n\",p);exit(1);}} fclose(f); cudaMemcpy(d,h,n,cudaMemcpyHostToDevice); free(h); return d; }}\n\
2231 static float* Lf(const char* p, long n){{ float* d; if(cudaMalloc(&d,n*4)){{fprintf(stderr,\"malloc %s\\n\",p);exit(1);}} float* h=(float*)malloc(n*4); FILE* f=fopen(p,\"rb\"); if(!f||fread(h,4,n,f)!=(size_t)n){{fprintf(stderr,\"read %s\\n\",p);exit(1);}} fclose(f); cudaMemcpy(d,h,n*4,cudaMemcpyHostToDevice); free(h); return d; }}\n\
2232 static __half* Lh(const char* p, long n){{ __half* d; if(cudaMalloc(&d,n*2)){{fprintf(stderr,\"malloc %s\\n\",p);exit(1);}} float* h=(float*)malloc(n*4); FILE* f=fopen(p,\"rb\"); if(!f||fread(h,4,n,f)!=(size_t)n){{fprintf(stderr,\"read %s\\n\",p);exit(1);}} fclose(f); __half* hh=(__half*)malloc(n*2); for(long i=0;i<n;i++) hh[i]=__float2half(h[i]); cudaMemcpy(d,hh,n*2,cudaMemcpyHostToDevice); free(h); free(hh); return d; }}\n\
2233 static inline unsigned Gg(long N){{ return (unsigned)((N+7)/8); }}\n\
2234 {decode_fn}
2235\
2236 static void prof_step(){{ cudaEvent_t pa,pb; cudaEventCreate(&pa); cudaEventCreate(&pb); float ms; double te=0,tp=0,tr=0,ta=0,tm=0,tl=0,trt=0,tqa=0,tgu=0,tqd=0,tdc=0;\n\
2237 \x20 cudaEventRecord(pa,0); gk_embed<<<(E+255)/256,256>>>(x,emb_q,emb_s,d_tok,E); cudaEventRecord(pb,0); cudaEventSynchronize(pb); cudaEventElapsedTime(&ms,pa,pb); te+=ms;\n\
2238 \x20 for(int l=0;l<LAYERS;l++){{\n\
2239 \x20 cudaEventRecord(pa,0); gk_rmsnorm_q8<<<1,256>>>(x,aqE,asE,an[l],E,EPSV); gk_gemv<<<Gg(QD),256>>>(qbuf,wq_q[l],wq_s[l],aqE,asE,E,QD); gk_gemv_kv<<<Gg(KD),256>>>(kc[l],d_pos,KD,wk_q[l],wk_s[l],aqE,asE,E,KD); gk_gemv_kv<<<Gg(KD),256>>>(vc[l],d_pos,KD,wv_q[l],wv_s[l],aqE,asE,E,KD); cudaEventRecord(pb,0); cudaEventSynchronize(pb); cudaEventElapsedTime(&ms,pa,pb); tp+=ms;\n\
2240 \x20 cudaEventRecord(pa,0); gk_qk_norm_rope<<<NH,128>>>(qbuf,d_pos,0,aqn[l],NH,HD,ROPEV,EPSV); gk_qk_norm_rope<<<NKV,128>>>(kc[l],d_pos,KD,akn[l],NKV,HD,ROPEV,EPSV); cudaEventRecord(pb,0); cudaEventSynchronize(pb); cudaEventElapsedTime(&ms,pa,pb); tr+=ms;\n\
2241 \x20 cudaEventRecord(pa,0); gk_attn<<<NH,256,(size_t)MAXSEQ*4>>>(attnb,qbuf,kc[l],vc[l],d_pos,NH,NKV,HD,SCALEV); gk_quant_act<<<(QD+255)/256,256>>>(attnb,aqQ,asQ,QD); gk_gemv<<<Gg(E),256>>>(tmp,wo_q[l],wo_s[l],aqQ,asQ,QD,E); gk_add<<<(E+255)/256,256>>>(x,tmp,E); cudaEventRecord(pb,0); cudaEventSynchronize(pb); cudaEventElapsedTime(&ms,pa,pb); ta+=ms;\n\
2242 \x20 cudaEventRecord(pa,0); gk_rmsnorm<<<1,256>>>(x2n,x,fn_[l],E,EPSV); moe_router_fast<<<(NE+7)/8,256>>>(x2n,wr_q[l],wr_s[l],moe_logits,NE,E); moe_topk_idx<<<1,NE>>>(moe_logits,moe_idx,moe_w,NE,KTOP); cudaEventRecord(pb,0); cudaEventSynchronize(pb); cudaEventElapsedTime(&ms,pa,pb); trt+=ms;\n\
2243 \x20 cudaEventRecord(pa,0); moe_qact<<<((E/32)+7)/8,256>>>(x2n,moe_xq,moe_xs,E); cudaEventRecord(pb,0); cudaEventSynchronize(pb); cudaEventElapsedTime(&ms,pa,pb); tqa+=ms;\n\
2244 \x20 cudaEventRecord(pa,0); moe_gate_up_silu<<<(KTOP*FF+7)/8,256>>>(moe_xq,moe_xs,wg_q[l],wg_s[l],wu_q[l],wu_s[l],moe_idx,moe_he,KTOP,FF,E); cudaEventRecord(pb,0); cudaEventSynchronize(pb); cudaEventElapsedTime(&ms,pa,pb); tgu+=ms;\n\
2245 \x20 cudaEventRecord(pa,0); moe_qact<<<(((KTOP*FF)/32)+7)/8,256>>>(moe_he,moe_hq,moe_hs,KTOP*FF); cudaEventRecord(pb,0); cudaEventSynchronize(pb); cudaEventElapsedTime(&ms,pa,pb); tqd+=ms;\n\
2246 \x20 cudaEventRecord(pa,0); moe_down_combine<<<E,KTOP*32>>>(moe_hq,moe_hs,wd_q[l],wd_s[l],moe_idx,moe_w,moe_out,KTOP,E,FF); gk_add<<<(E+255)/256,256>>>(x,moe_out,E); cudaEventRecord(pb,0); cudaEventSynchronize(pb); cudaEventElapsedTime(&ms,pa,pb); tdc+=ms;\n\
2247 \x20 }}\n\
2248 \x20 cudaEventRecord(pa,0); gk_rmsnorm_q8<<<1,256>>>(x,aqE,asE,on_w,E,EPSV); gk_gemv<<<Gg(VOCAB),256>>>(logits,wout_q,wout_s,aqE,asE,E,VOCAB); cudaEventRecord(pb,0); cudaEventSynchronize(pb); cudaEventElapsedTime(&ms,pa,pb); tl+=ms;\n\
2249 \x20 tm=trt+tqa+tgu+tqd+tdc; fprintf(stderr,\"PROF embed=%.3f proj=%.3f qknorm_rope=%.3f attn=%.3f moe=%.3f [router+topk=%.3f qact_x=%.3f gate_up=%.3f qact_h=%.3f down=%.3f] lmhead=%.3f total=%.3f ms\\n\", te,tp,tr,ta,tm,trt,tqa,tgu,tqd,tdc,tl, te+tp+tr+ta+tm+tl);\n\
2250 }}\n\
2251 int main(void){{\n\
2252 \x20 char p[512]; const char* W=\"{wdir}\";\n\
2253 \x20 snprintf(p,512,\"%s/emb.q\",W); emb_q=Li(p,(long)VOCAB*E); snprintf(p,512,\"%s/emb.s\",W); emb_s=Lf(p,(long)VOCAB*(E/32));\n\
2254 \x20 for(int l=0;l<LAYERS;l++){{\n\
2255 \x20 snprintf(p,512,\"%s/an%d.f\",W,l); an[l]=Lf(p,E); snprintf(p,512,\"%s/fn%d.f\",W,l); fn_[l]=Lf(p,E);\n\
2256 \x20 snprintf(p,512,\"%s/aqn%d.f\",W,l); aqn[l]=Lf(p,HD); snprintf(p,512,\"%s/akn%d.f\",W,l); akn[l]=Lf(p,HD);\n\
2257 \x20 snprintf(p,512,\"%s/wq%d.q\",W,l); wq_q[l]=Li(p,(long)QD*E); snprintf(p,512,\"%s/wq%d.s\",W,l); wq_s[l]=Lf(p,(long)QD*(E/32));\n\
2258 \x20 snprintf(p,512,\"%s/wk%d.q\",W,l); wk_q[l]=Li(p,(long)KD*E); snprintf(p,512,\"%s/wk%d.s\",W,l); wk_s[l]=Lf(p,(long)KD*(E/32));\n\
2259 \x20 snprintf(p,512,\"%s/wv%d.q\",W,l); wv_q[l]=Li(p,(long)KD*E); snprintf(p,512,\"%s/wv%d.s\",W,l); wv_s[l]=Lf(p,(long)KD*(E/32));\n\
2260 \x20 snprintf(p,512,\"%s/wo%d.q\",W,l); wo_q[l]=Li(p,(long)E*QD); snprintf(p,512,\"%s/wo%d.s\",W,l); wo_s[l]=Lf(p,(long)E*(QD/32));\n\
2261 \x20 snprintf(p,512,\"%s/wr%d.q\",W,l); wr_q[l]=Li(p,(long)NE*E); snprintf(p,512,\"%s/wr%d.s\",W,l); wr_s[l]=Lf(p,(long)NE*(E/32));\n\
2262 \x20 snprintf(p,512,\"%s/wg%d.q\",W,l); wg_q[l]=Li(p,(long)NE*FF*E); snprintf(p,512,\"%s/wg%d.s\",W,l); wg_s[l]=Lf(p,(long)NE*FF*(E/32));\n\
2263 \x20 snprintf(p,512,\"%s/wu%d.q\",W,l); wu_q[l]=Li(p,(long)NE*FF*E); snprintf(p,512,\"%s/wu%d.s\",W,l); wu_s[l]=Lf(p,(long)NE*FF*(E/32));\n\
2264 \x20 snprintf(p,512,\"%s/wd%d.q\",W,l); wd_q[l]=Li(p,(long)NE*E*FF); snprintf(p,512,\"%s/wd%d.s\",W,l); wd_s[l]=Lf(p,(long)NE*E*(FF/32));\n\
2265 \x20 }}\n\
2266 \x20 snprintf(p,512,\"%s/on.f\",W); on_w=Lf(p,E); snprintf(p,512,\"%s/wout.q\",W); wout_q=Li(p,(long)VOCAB*E); snprintf(p,512,\"%s/wout.s\",W); wout_s=Lf(p,(long)VOCAB*(E/32));\n\
2267 \x20 fprintf(stderr,\"weights loaded\\n\");\n\
2268 \x20 cudaMalloc(&x,E*4); cudaMalloc(&xn,E*4); cudaMalloc(&x2n,E*4); cudaMalloc(&acc_part,(long)NH*ATTN_SPLIT*HD*4); cudaMalloc(&m_part,(long)NH*ATTN_SPLIT*4); cudaMalloc(&d_part,(long)NH*ATTN_SPLIT*4); cudaMalloc(&qbuf,QD*4); cudaMalloc(&attnb,QD*4); cudaMalloc(&tmp,E*4); cudaMalloc(&logits,(long)VOCAB*4);\n\
2269 \x20 cudaMalloc(&aqE,E); cudaMalloc(&asE,(E/32)*4); cudaMalloc(&aqQ,QD); cudaMalloc(&asQ,(QD/32)*4);\n\
2270 \x20 cudaMalloc(&moe_logits,NE*4); cudaMalloc(&moe_w,NE*4); cudaMalloc(&moe_idx,NE*4); cudaMalloc(&moe_xq,E); cudaMalloc(&moe_xs,(E/32)*4);\n\
2271 \x20 cudaMalloc(&moe_he,(long)KTOP*FF*4); cudaMalloc(&moe_hq,(long)KTOP*FF); cudaMalloc(&moe_hs,(long)(KTOP*FF/32)*4); cudaMalloc(&moe_out,E*4);\n\
2272 \x20 for(int l=0;l<LAYERS;l++){{ cudaMalloc(&kc[l],(long)MAXSEQ*KD*4); cudaMalloc(&vc[l],(long)MAXSEQ*KD*4); }}\n\
2273 \x20 cudaMalloc(&d_pos,4); cudaMalloc(&d_tok,4);\n\
2274 \x20 int prompt[]={{{prompt_c}}}; int PL=sizeof(prompt)/sizeof(int);\n\
2275 \x20 // ── PREFILL: run each prompt token through the decode step (fills the KV cache), no argmax ──\n\
2276 \x20 for(int i=0;i<PL;i++){{ cudaMemcpy(d_pos,&i,4,cudaMemcpyHostToDevice); cudaMemcpy(d_tok,&prompt[i],4,cudaMemcpyHostToDevice); decode_step(0); cudaDeviceSynchronize(); }}\n\
2277 \x20 std::vector<int> gen; {{ std::vector<float> hl(VOCAB); cudaMemcpy(hl.data(),logits,(long)VOCAB*4,cudaMemcpyDeviceToHost); int b=0; for(int i=1;i<VOCAB;i++) if(hl[i]>hl[b]) b=i; gen.push_back(b); int pl=PL; cudaMemcpy(d_pos,&pl,4,cudaMemcpyHostToDevice); cudaMemcpy(d_tok,&b,4,cudaMemcpyHostToDevice); }}\n\
2278 \x20 if(getenv(\"LOGOS_GEN_PROF\")){{ prof_step(); prof_step(); }}\n\
2279 \x20 // ── capture the T=1 decode step as ONE graph, replay per token (device-side position + token) ──\n\
2280 \x20 cudaStream_t st; cudaStreamCreate(&st); cudaGraph_t g; cudaGraphExec_t ge;\n\
2281 \x20 cudaStreamBeginCapture(st,cudaStreamCaptureModeGlobal); decode_step(st); gk_argmax_adv<<<1,256,0,st>>>(logits,VOCAB,d_tok,d_pos); cudaStreamEndCapture(st,&g); cudaGraphInstantiate(&ge,g,0);\n\
2282 \x20 cudaEvent_t t0,t1; cudaEventCreate(&t0); cudaEventCreate(&t1); float genms=0; int steps=0;\n\
2283 \x20 for(int step=1; step<{n_gen}; step++){{ cudaEventRecord(t0,st); cudaGraphLaunch(ge,st); cudaEventRecord(t1,st); cudaStreamSynchronize(st); float ms; cudaEventElapsedTime(&ms,t0,t1); genms+=ms; steps++; int tok; cudaMemcpy(&tok,d_tok,4,cudaMemcpyDeviceToHost); gen.push_back(tok); }}\n\
2284 \x20 printf(\"GENERATED_TOKENS:\"); for(size_t i=0;i<gen.size();++i) printf(\" %d\",gen[i]); printf(\"\\n\");\n\
2285 \x20 if(steps) fprintf(stderr,\"GEN_TOK_S %.2f (%.3f ms/token, %d steps, growing KV cache)\\n\", 1000.0*steps/genms, genms/steps, steps);\n\
2286 \x20 {{ cudaEventRecord(t0,st); for(int i=0;i<100;i++) cudaGraphLaunch(ge,st); cudaEventRecord(t1,st); cudaStreamSynchronize(st); float bms; cudaEventElapsedTime(&bms,t0,t1); fprintf(stderr,\"GEN_TOK_S_BATCH %.2f (%.3f ms/token, 100 back-to-back replays, one sync)\\n\", 100000.0/bms, bms/100.0); }}\n\
2287 \x20 {{ int z=0; cudaMemcpy(d_pos,&z,4,cudaMemcpyHostToDevice); cudaStreamSynchronize(st); cudaEventRecord(t0,st); for(int i=0;i<128;i++) cudaGraphLaunch(ge,st); cudaEventRecord(t1,st); cudaStreamSynchronize(st); float tms; cudaEventElapsedTime(&tms,t0,t1); fprintf(stderr,\"GEN_TOK_S_TG128 %.2f (128 replays from an empty KV cache = llama-bench tg128, the apples-to-apples decode metric)\\n\", 128000.0/tms); }}\n\
2288 \x20 return 0;\n}}\n"
2289 )
2290}
2291
2292pub fn gen_qwen30b_lg(
2293 cfg: &Qwen30bCfg,
2294 dir: &str,
2295) -> (
2296 String,
2297 HashMap<String, (String, usize)>,
2298 HashMap<String, Q8Ref>,
2299 HashMap<String, MoeWeights>,
2300) {
2301 let (d, dff, ne, k, h, kv, hd) = (cfg.d, cfg.dff, cfg.ne, cfg.k, cfg.h, cfg.kv, cfg.hd);
2302 let vh = h * hd; let kvd = kv * hd; let mut weights: HashMap<String, (String, usize)> = HashMap::new();
2306 let mut q8: HashMap<String, Q8Ref> = HashMap::new();
2307 let mut moe: HashMap<String, MoeWeights> = HashMap::new();
2308 let mut f32w =
2309 |var: &str, cnt: usize| weights.insert(var.into(), (format!("{dir}/{var}.f"), cnt));
2310
2311 let mut src = String::from("## Main\n");
2312 let decl = |src: &mut String, nm: &str, r: usize, c: usize| {
2313 src.push_str(&format!("Let {nm} be a {r} by {c} tensor of Real.\n"))
2314 };
2315
2316 f32w("x", d);
2318 decl(&mut src, "x", 1, d);
2319 let mut xin = "x".to_string();
2320
2321 for l in 0..cfg.layers {
2322 f32w(&format!("an{l}"), d);
2324 f32w(&format!("fn{l}"), d);
2325 q8.insert(format!("Wq{l}"), q8ref(dir, &format!("wq{l}"), d, vh)); q8.insert(format!("Wk{l}"), q8ref(dir, &format!("wk{l}"), d, kvd)); q8.insert(format!("Wv{l}"), q8ref(dir, &format!("wv{l}"), d, kvd)); q8.insert(format!("Wo{l}"), q8ref(dir, &format!("wo{l}"), vh, d)); moe.insert(
2330 format!("ff{l}"),
2331 MoeWeights {
2332 router: q8ref(dir, &format!("wr{l}"), d, ne),
2333 gate: q8ref(dir, &format!("wg{l}"), d, ne * dff),
2334 up: q8ref(dir, &format!("wu{l}"), d, ne * dff),
2335 down: q8ref(dir, &format!("wd{l}"), dff, ne * d),
2336 d,
2337 dff,
2338 ne,
2339 k,
2340 },
2341 );
2342 decl(&mut src, &format!("an{l}"), 1, d);
2343 decl(&mut src, &format!("fn{l}"), 1, d);
2344 decl(&mut src, &format!("Wq{l}"), d, vh);
2345 decl(&mut src, &format!("Wk{l}"), d, kvd);
2346 decl(&mut src, &format!("Wv{l}"), d, kvd);
2347 decl(&mut src, &format!("Wo{l}"), vh, d);
2348 decl(&mut src, &format!("Wr{l}"), d, ne);
2349 decl(&mut src, &format!("Wg{l}"), ne * dff, d);
2350 decl(&mut src, &format!("Wu{l}"), ne * dff, d);
2351 decl(&mut src, &format!("Wd{l}"), ne * d, dff);
2352 src.push_str(&format!(
2358 "Let xn{l} be rmsnorm of {xin} with weight an{l}.\n"
2359 ));
2360 src.push_str(&format!("Let q{l} be xn{l} matmul Wq{l}.\n"));
2361 src.push_str(&format!("Let kk{l} be xn{l} matmul Wk{l}.\n"));
2362 src.push_str(&format!("Let vv{l} be xn{l} matmul Wv{l}.\n"));
2363 src.push_str(&format!(
2364 "Let ctx{l} be attention of q{l} over kk{l} and vv{l} with {h} heads {kv} groups.\n"
2365 ));
2366 src.push_str(&format!("Let ao{l} be ctx{l} matmul Wo{l}.\n"));
2367 src.push_str(&format!("Let xr{l} be {xin} plus ao{l}.\n"));
2368 src.push_str(&format!(
2369 "Let x2n{l} be rmsnorm of xr{l} with weight fn{l}.\n"
2370 ));
2371 src.push_str(&format!("Let ff{l} be moe of x2n{l} with router Wr{l} gate Wg{l} up Wu{l} down Wd{l} choosing {k} of {ne}.\n"));
2372 src.push_str(&format!("Let xo{l} be xr{l} plus ff{l}.\n"));
2373 xin = format!("xo{l}");
2374 }
2375
2376 f32w("on", d);
2378 q8.insert("Wout".into(), q8ref(dir, "wout", d, cfg.vocab));
2379 decl(&mut src, "on", 1, d);
2380 decl(&mut src, "Wout", d, cfg.vocab);
2381 src.push_str(&format!("Let xf be rmsnorm of {xin} with weight on.\n"));
2382 src.push_str("Let logits be xf matmul Wout.\n");
2383
2384 (src, weights, q8, moe)
2385}