logicaffeine_compile/codegen_cuda/
fused_row.rs1use crate::codegen_cuda::knobs::CudaKnobs;
15use crate::tensor_recognize::{Epsilon, FusedRowSpec, RowReduceKind, SwiGluSpec};
16
17const ROW_THREADS: usize = 256;
20
21pub fn emit_fused_row(spec: &FusedRowSpec, knobs: &CudaKnobs) -> String {
25 let rows = spec.rows.max(1);
26 let cols = spec.cols.max(1);
27 let chip = knobs.chip;
28 let is_rms = matches!(spec.reduce, RowReduceKind::RmsNorm);
29 let layernorm = matches!(spec.reduce, RowReduceKind::LayerNorm);
30 let residual = is_rms && spec.residual.is_some();
31 let weighted = is_rms && spec.weight.is_some();
32 let has_w = weighted || layernorm; let has_b = layernorm; let kernel_body = match spec.reduce {
35 RowReduceKind::RmsNorm => rmsnorm_kernel(residual, weighted, spec.eps),
36 RowReduceKind::Softmax => SOFTMAX_KERNEL.to_string(),
37 RowReduceKind::LayerNorm => layernorm_kernel(spec.eps),
38 };
39 let mut allocs = String::new();
43 let mut fills = String::new();
44 let mut args = String::from("x,");
45 if residual {
46 allocs.push_str(" float* res; if(cudaMallocManaged(&res,n*sizeof(float))){ fprintf(stderr,\"malloc\\n\"); return 1; }\n");
47 fills.push_str(" for(size_t i=0;i<n;++i) res[i]=(float)((int)((i+1)%5)-2);\n");
48 args.push_str("res,");
49 }
50 if has_w {
51 allocs.push_str(" float* w; if(cudaMallocManaged(&w,(size_t)COLS*sizeof(float))){ fprintf(stderr,\"malloc\\n\"); return 1; }\n");
52 fills.push_str(" for(int c=0;c<COLS;++c) w[c]=1.0f+0.5f*(float)(c%3);\n");
53 args.push_str("w,");
54 }
55 if has_b {
56 allocs.push_str(" float* b; if(cudaMallocManaged(&b,(size_t)COLS*sizeof(float))){ fprintf(stderr,\"malloc\\n\"); return 1; }\n");
57 fills.push_str(" for(int c=0;c<COLS;++c) b[c]=0.1f*(float)(c+1);\n");
58 args.push_str("b,");
59 }
60 args.push('y');
61 let tag = format!(
62 "{}{}{}",
63 if residual { " (fused-add)" } else { "" },
64 if weighted { " (weighted)" } else { "" },
65 if layernorm { " (weight+bias)" } else { "" },
66 );
67 format!(
68 r#"// Auto-generated by LOGOS codegen_cuda::fused_row — a recognized LOGOS {op}{tag} lowered to CUDA.
69// Per-row reduction over rows={rows} x cols={cols}; one block per row, shared-memory tree reduction.
70// Target: {chip_name} (sm_{arch}). Not a template — the launch bounds are a function of the recognized shape.
71#include <cstdio>
72#include <cmath>
73#define ROWS {rows}
74#define COLS {cols}
75#define THREADS {threads}
76{kernel}
77int main(void){{
78 float *x,*y;
79 size_t n = (size_t)ROWS*COLS;
80 if(cudaMallocManaged(&x,n*sizeof(float))||cudaMallocManaged(&y,n*sizeof(float))){{ fprintf(stderr,"malloc\n"); return 1; }}
81{allocs} for(size_t i=0;i<n;++i) x[i]=(float)((int)(i%7)-3);
82{fills} fused_row<<<ROWS,THREADS>>>({args});
83 if(cudaDeviceSynchronize()!=cudaSuccess){{ fprintf(stderr,"sync\n"); return 1; }}
84 double sum=0.0; for(size_t i=0;i<n;++i) sum+=y[i];
85 printf("%.6f\n", sum);
86 return 0;
87}}
88"#,
89 op = spec.reduce.name(),
90 tag = tag,
91 rows = rows,
92 cols = cols,
93 threads = ROW_THREADS,
94 chip_name = chip.name,
95 arch = chip.sm_arch,
96 kernel = kernel_body,
97 allocs = allocs,
98 fills = fills,
99 args = args,
100 )
101}
102
103pub fn emit_swiglu(spec: &SwiGluSpec, knobs: &CudaKnobs) -> String {
106 let n = spec.total.max(1);
107 let chip = knobs.chip;
108 format!(
109 r#"// Auto-generated by LOGOS codegen_cuda::fused_row — a recognized LOGOS swiglu lowered to CUDA.
110// Y[i] = silu(gate[i]) * up[i]; silu(g) = g / (1 + e^-g); N={n} elements, one thread each.
111// Target: {chip_name} (sm_{arch}). Not a template — N is a function of the recognized shape.
112#include <cstdio>
113#include <cmath>
114#define N {n}
115#define THREADS 256
116__global__ void swiglu(const float* gate, const float* up, float* y){{
117 int i = blockIdx.x*blockDim.x + threadIdx.x; if(i>=N) return;
118 float g = gate[i];
119 y[i] = (g/(1.0f+expf(-g))) * up[i];
120}}
121int main(void){{
122 float *gate,*up,*y;
123 size_t n=(size_t)N;
124 if(cudaMallocManaged(&gate,n*sizeof(float))||cudaMallocManaged(&up,n*sizeof(float))||cudaMallocManaged(&y,n*sizeof(float))){{ fprintf(stderr,"malloc\n"); return 1; }}
125 for(size_t i=0;i<n;++i){{ gate[i]=(float)((int)(i%7)-3); up[i]=(float)((int)((i+1)%5)-2); }}
126 swiglu<<<(N+THREADS-1)/THREADS,THREADS>>>(gate,up,y);
127 if(cudaDeviceSynchronize()!=cudaSuccess){{ fprintf(stderr,"sync\n"); return 1; }}
128 double sum=0.0; for(size_t i=0;i<n;++i) sum+=y[i];
129 printf("%.6f\n", sum);
130 return 0;
131}}
132"#,
133 n = n,
134 chip_name = chip.name,
135 arch = chip.sm_arch,
136 )
137}
138
139fn rmsnorm_kernel(residual: bool, weighted: bool, eps: Epsilon) -> String {
143 let params = format!(
144 "const float* x, {}{}float* y",
145 if residual { "const float* res, " } else { "" },
146 if weighted { "const float* w, " } else { "" },
147 );
148 let res_row = if residual {
149 " const float* rr = res + (long)row*COLS;\n"
150 } else {
151 ""
152 };
153 let elem = if residual { "(xr[i]+rr[i])" } else { "xr[i]" };
154 let wmul = if weighted { "*w[i]" } else { "" };
155 format!(
156 r#"__global__ void fused_row({params}){{
157 int row = blockIdx.x;
158 const float* xr = x + (long)row*COLS;
159{res_row} float* yr = y + (long)row*COLS;
160 __shared__ float sh[THREADS];
161 float s = 0.0f;
162 for(int i = threadIdx.x; i < COLS; i += blockDim.x){{ float e = {elem}; s += e*e; }}
163 sh[threadIdx.x] = s; __syncthreads();
164 for(int k = blockDim.x/2; k > 0; k >>= 1){{ if(threadIdx.x < k) sh[threadIdx.x] += sh[threadIdx.x+k]; __syncthreads(); }}
165 float scale = rsqrtf(sh[0]/(float)COLS + {eps});
166 for(int i = threadIdx.x; i < COLS; i += blockDim.x){{ float e = {elem}; yr[i] = e*scale{wmul}; }}
167}}"#,
168 params = params,
169 res_row = res_row,
170 elem = elem,
171 wmul = wmul,
172 eps = eps_literal(eps),
173 )
174}
175
176fn eps_literal(eps: Epsilon) -> String {
178 format!("{:e}f", eps.get() as f32)
179}
180
181fn layernorm_kernel(eps: Epsilon) -> String {
184 r#"__global__ void fused_row(const float* x, const float* w, const float* b, float* y){
185 int row = blockIdx.x;
186 const float* xr = x + (long)row*COLS;
187 float* yr = y + (long)row*COLS;
188 __shared__ float sh[THREADS];
189 float s = 0.0f;
190 for(int i = threadIdx.x; i < COLS; i += blockDim.x) s += xr[i];
191 sh[threadIdx.x] = s; __syncthreads();
192 for(int k = blockDim.x/2; k > 0; k >>= 1){ if(threadIdx.x < k) sh[threadIdx.x] += sh[threadIdx.x+k]; __syncthreads(); }
193 float mean = sh[0]/(float)COLS; __syncthreads();
194 float v = 0.0f;
195 for(int i = threadIdx.x; i < COLS; i += blockDim.x){ float d = xr[i]-mean; v += d*d; }
196 sh[threadIdx.x] = v; __syncthreads();
197 for(int k = blockDim.x/2; k > 0; k >>= 1){ if(threadIdx.x < k) sh[threadIdx.x] += sh[threadIdx.x+k]; __syncthreads(); }
198 float scale = rsqrtf(sh[0]/(float)COLS + EPS);
199 for(int i = threadIdx.x; i < COLS; i += blockDim.x) yr[i] = (xr[i]-mean)*scale*w[i]+b[i];
200}"#
201 .replace("EPS", &eps_literal(eps))
202}
203
204const SOFTMAX_KERNEL: &str = r#"__global__ void fused_row(const float* x, float* y){
206 int row = blockIdx.x;
207 const float* xr = x + (long)row*COLS;
208 float* yr = y + (long)row*COLS;
209 __shared__ float sh[THREADS];
210 float m = -1e30f;
211 for(int i = threadIdx.x; i < COLS; i += blockDim.x) m = fmaxf(m, xr[i]);
212 sh[threadIdx.x] = m; __syncthreads();
213 for(int k = blockDim.x/2; k > 0; k >>= 1){ if(threadIdx.x < k) sh[threadIdx.x] = fmaxf(sh[threadIdx.x], sh[threadIdx.x+k]); __syncthreads(); }
214 float mx = sh[0]; __syncthreads();
215 float s = 0.0f;
216 for(int i = threadIdx.x; i < COLS; i += blockDim.x) s += expf(xr[i]-mx);
217 sh[threadIdx.x] = s; __syncthreads();
218 for(int k = blockDim.x/2; k > 0; k >>= 1){ if(threadIdx.x < k) sh[threadIdx.x] += sh[threadIdx.x+k]; __syncthreads(); }
219 float sm = sh[0];
220 for(int i = threadIdx.x; i < COLS; i += blockDim.x) yr[i] = expf(xr[i]-mx)/sm;
221}"#;