1use super::numerics::{
14 absmax, argmax, exp, f32_to_f16, fadd, fdot, fmax, fsub, fsum, hadamard, int8_codes, ldexp, ln1p, recip, rope, rsqrt,
15 sigmoid, silu, softplus, FpUnit, INV_127,
16};
17use crate::model::quant::f16_to_f32;
18
19pub type VReg = u8;
21pub type SReg = u8;
23
24#[derive(Clone, Copy, Debug, PartialEq, Eq)]
26pub enum Func {
27 Exp,
28 Recip,
29 Rsqrt,
30 Sigmoid,
31 Silu,
32 Softplus,
33 Ln1p,
34 Neg,
36 F16,
38}
39
40impl Func {
41 pub fn apply(self, fp: FpUnit, x: f32) -> f32 {
43 match self {
44 Func::Exp => exp(fp, x),
45 Func::Recip => recip(fp, x),
46 Func::Rsqrt => rsqrt(fp, x),
47 Func::Sigmoid => sigmoid(fp, x),
48 Func::Silu => silu(fp, x),
49 Func::Softplus => softplus(fp, x),
50 Func::Ln1p => ln1p(fp, x),
51 Func::Neg => -x,
52 Func::F16 => f16_to_f32(f32_to_f16(x)),
53 }
54 }
55}
56
57#[derive(Clone, Copy, Debug, PartialEq, Eq)]
59pub enum Bin {
60 Mul,
61 Add,
62 Sub,
63}
64
65impl Bin {
66 pub fn apply(self, fp: FpUnit, a: f32, b: f32) -> f32 {
68 match self {
69 Bin::Mul => fp.mul(a, b),
70 Bin::Add => fadd(a, b),
71 Bin::Sub => fsub(a, b),
72 }
73 }
74}
75
76#[derive(Clone, Copy, Debug, PartialEq)]
78pub enum Op {
79 Dot { a: VReg, b: VReg, d: SReg },
81 Sum { a: VReg, d: SReg },
83 Max { a: VReg, d: SReg },
85 Vec { op: Bin, a: VReg, b: VReg, d: VReg },
87 VecScalar { op: Bin, a: VReg, s: SReg, d: VReg },
89 Map { f: Func, a: VReg, d: VReg },
91 Scalar { op: Bin, a: SReg, b: SReg, d: SReg },
93 ScalarMap { f: Func, a: SReg, d: SReg },
95 Const { value: f32, d: SReg },
97 Hadamard { a: VReg, d: VReg },
99 Rotate { a: VReg, cos: VReg, sin: VReg, d: VReg, neox: bool },
102 ArgMax { a: VReg, d: SReg },
104 AbsMax { a: VReg, d: SReg },
106 Codes { a: VReg, s: SReg, d: VReg },
109 Scale { a: VReg, n: i8, d: VReg },
112 MulAdd { a: VReg, b: VReg, c: VReg, d: VReg },
114 MulAddScalar { a: VReg, b: VReg, s: SReg, d: VReg },
116}
117
118impl Op {
119 pub fn reads(self) -> (Vec<VReg>, Vec<SReg>) {
121 match self {
122 Op::Dot { a, b, .. } | Op::Vec { a, b, .. } => (vec![a, b], vec![]),
123 Op::Sum { a, .. } | Op::Max { a, .. } | Op::Map { a, .. } | Op::Hadamard { a, .. } | Op::ArgMax { a, .. } | Op::AbsMax { a, .. } | Op::Scale { a, .. } => (vec![a], vec![]),
124 Op::VecScalar { a, s, .. } | Op::Codes { a, s, .. } => (vec![a], vec![s]),
125 Op::Scalar { a, b, .. } => (vec![], vec![a, b]),
126 Op::ScalarMap { a, .. } => (vec![], vec![a]),
127 Op::Const { .. } => (vec![], vec![]),
128 Op::Rotate { a, cos, sin, .. } => (vec![a, cos, sin], vec![]),
129 Op::MulAdd { a, b, c, .. } => (vec![a, b, c], vec![]),
130 Op::MulAddScalar { a, b, s, .. } => (vec![a, b], vec![s]),
131 }
132 }
133
134 pub fn writes_scalar(self) -> Option<SReg> {
136 match self {
137 Op::Dot { d, .. } | Op::Sum { d, .. } | Op::Max { d, .. } | Op::Scalar { d, .. } | Op::ScalarMap { d, .. } | Op::Const { d, .. } | Op::ArgMax { d, .. } | Op::AbsMax { d, .. } => Some(d),
138 Op::Vec { .. }
139 | Op::VecScalar { .. }
140 | Op::Map { .. }
141 | Op::Hadamard { .. }
142 | Op::Rotate { .. }
143 | Op::Codes { .. }
144 | Op::Scale { .. }
145 | Op::MulAdd { .. }
146 | Op::MulAddScalar { .. } => None,
147 }
148 }
149
150 pub fn writes(self) -> Option<VReg> {
152 match self {
153 Op::Vec { d, .. }
154 | Op::VecScalar { d, .. }
155 | Op::Map { d, .. }
156 | Op::Hadamard { d, .. }
157 | Op::Rotate { d, .. }
158 | Op::Codes { d, .. }
159 | Op::Scale { d, .. }
160 | Op::MulAdd { d, .. }
161 | Op::MulAddScalar { d, .. } => Some(d),
162 Op::Dot { .. } | Op::Sum { .. } | Op::Max { .. } | Op::Scalar { .. } | Op::ScalarMap { .. } | Op::Const { .. } | Op::ArgMax { .. } | Op::AbsMax { .. } => None,
163 }
164 }
165}
166
167#[derive(Clone, Debug, Default)]
169pub struct Regs {
170 pub v: Vec<Vec<f32>>,
171 pub s: Vec<f32>,
172}
173
174impl Regs {
175 pub fn new(vectors: usize, scalars: usize) -> Regs {
176 Regs { v: vec![Vec::new(); vectors], s: vec![0.0; scalars] }
177 }
178}
179
180pub fn run(fp: FpUnit, program: &[Op], regs: &mut Regs) {
182 for &op in program {
183 match op {
184 Op::Dot { a, b, d } => regs.s[d as usize] = fdot(fp, ®s.v[a as usize], ®s.v[b as usize]),
185 Op::Sum { a, d } => regs.s[d as usize] = fsum(®s.v[a as usize]),
186 Op::Max { a, d } => regs.s[d as usize] = fmax(®s.v[a as usize]),
187 Op::Vec { op, a, b, d } => {
188 let out: Vec<f32> = regs.v[a as usize].iter().zip(®s.v[b as usize]).map(|(&x, &y)| op.apply(fp, x, y)).collect();
189 regs.v[d as usize] = out;
190 }
191 Op::VecScalar { op, a, s, d } => {
192 let k = regs.s[s as usize];
193 let out: Vec<f32> = regs.v[a as usize].iter().map(|&x| op.apply(fp, x, k)).collect();
194 regs.v[d as usize] = out;
195 }
196 Op::Map { f, a, d } => {
197 let out: Vec<f32> = regs.v[a as usize].iter().map(|&x| f.apply(fp, x)).collect();
198 regs.v[d as usize] = out;
199 }
200 Op::Scalar { op, a, b, d } => regs.s[d as usize] = op.apply(fp, regs.s[a as usize], regs.s[b as usize]),
201 Op::ScalarMap { f, a, d } => regs.s[d as usize] = f.apply(fp, regs.s[a as usize]),
202 Op::Const { value, d } => regs.s[d as usize] = value,
203 Op::Hadamard { a, d } => {
204 let mut out = regs.v[a as usize].clone();
205 hadamard(&mut out);
206 regs.v[d as usize] = out;
207 }
208 Op::Rotate { a, cos, sin, d, neox } => {
209 let mut out = regs.v[a as usize].clone();
210 rope(fp, &mut out, ®s.v[cos as usize], ®s.v[sin as usize], neox);
211 regs.v[d as usize] = out;
212 }
213 Op::ArgMax { a, d } => regs.s[d as usize] = argmax(®s.v[a as usize]) as f32,
214 Op::AbsMax { a, d } => regs.s[d as usize] = absmax(®s.v[a as usize]),
215 Op::Codes { a, s, d } => {
216 let out: Vec<f32> = int8_codes(fp, ®s.v[a as usize], regs.s[s as usize]).into_iter().map(f32::from).collect();
217 regs.v[d as usize] = out;
218 }
219 Op::Scale { a, n, d } => {
220 let out: Vec<f32> = regs.v[a as usize].iter().map(|&x| ldexp(x, n as i32)).collect();
221 regs.v[d as usize] = out;
222 }
223 Op::MulAdd { a, b, c, d } => {
224 let (x, y, z) = (®s.v[a as usize], ®s.v[b as usize], ®s.v[c as usize]);
225 let out: Vec<f32> = x.iter().zip(y).zip(z).map(|((&x, &y), &z)| Bin::Add.apply(fp, z, Bin::Mul.apply(fp, x, y))).collect();
226 regs.v[d as usize] = out;
227 }
228 Op::MulAddScalar { a, b, s, d } => {
229 let k = regs.s[s as usize];
230 let out: Vec<f32> = regs.v[a as usize].iter().zip(®s.v[b as usize]).map(|(&x, &y)| Bin::Add.apply(fp, Bin::Mul.apply(fp, x, y), k)).collect();
231 regs.v[d as usize] = out;
232 }
233 }
234 }
235}
236
237pub fn rmsnorm(fp: FpUnit, x: VReg, w: VReg, out: VReg, t: VReg, n: usize, eps: f32) -> Vec<Op> {
242 vec![
243 Op::Dot { a: x, b: x, d: 0 },
244 Op::Const { value: recip(fp, n as f32), d: 1 },
245 Op::Scalar { op: Bin::Mul, a: 0, b: 1, d: 0 },
246 Op::Const { value: eps, d: 2 },
247 Op::Scalar { op: Bin::Add, a: 0, b: 2, d: 0 },
248 Op::ScalarMap { f: Func::Rsqrt, a: 0, d: 0 },
249 Op::VecScalar { op: Bin::Mul, a: x, s: 0, d: t },
250 Op::Vec { op: Bin::Mul, a: t, b: w, d: out },
251 ]
252}
253
254pub fn l2norm(x: VReg, out: VReg, eps: f32) -> Vec<Op> {
256 vec![
257 Op::Dot { a: x, b: x, d: 0 },
258 Op::Const { value: eps, d: 1 },
259 Op::Scalar { op: Bin::Add, a: 0, b: 1, d: 0 },
260 Op::ScalarMap { f: Func::Rsqrt, a: 0, d: 0 },
261 Op::VecScalar { op: Bin::Mul, a: x, s: 0, d: out },
262 ]
263}
264
265pub fn softmax(x: VReg, out: VReg) -> Vec<Op> {
268 vec![
269 Op::Max { a: x, d: 0 },
270 Op::VecScalar { op: Bin::Sub, a: x, s: 0, d: out },
271 Op::Map { f: Func::Exp, a: out, d: out },
272 Op::Sum { a: out, d: 1 },
273 Op::ScalarMap { f: Func::Recip, a: 1, d: 1 },
274 Op::VecScalar { op: Bin::Mul, a: out, s: 1, d: out },
275 ]
276}
277
278pub fn swiglu(g: VReg, u: VReg, out: VReg) -> Vec<Op> {
280 vec![Op::Map { f: Func::Silu, a: g, d: out }, Op::Vec { op: Bin::Mul, a: out, b: u, d: out }]
281}
282
283pub fn sigmoid_gate(o: VReg, g: VReg, out: VReg, t: VReg) -> Vec<Op> {
285 vec![Op::Map { f: Func::Sigmoid, a: g, d: t }, Op::Vec { op: Bin::Mul, a: o, b: t, d: out }]
286}
287
288pub fn gdn_gates(alpha: SReg, dt: SReg, a: SReg, beta: SReg, log_decay: SReg, decay: SReg, gate: SReg) -> Vec<Op> {
292 vec![
293 Op::Scalar { op: Bin::Add, a: alpha, b: dt, d: log_decay },
294 Op::ScalarMap { f: Func::Softplus, a: log_decay, d: log_decay },
295 Op::Scalar { op: Bin::Mul, a: log_decay, b: a, d: log_decay },
296 Op::ScalarMap { f: Func::Exp, a: log_decay, d: decay },
297 Op::ScalarMap { f: Func::Sigmoid, a: beta, d: gate },
298 ]
299}
300
301pub fn delta_gates(alpha: VReg, dt: VReg, a: VReg, beta: VReg, log_decay: VReg, decay: VReg, gate: VReg) -> Vec<Op> {
304 vec![
305 Op::Vec { op: Bin::Add, a: alpha, b: dt, d: log_decay },
306 Op::Map { f: Func::Softplus, a: log_decay, d: log_decay },
307 Op::Vec { op: Bin::Mul, a: log_decay, b: a, d: log_decay },
308 Op::Map { f: Func::Exp, a: log_decay, d: decay },
309 Op::Map { f: Func::Sigmoid, a: beta, d: gate },
310 ]
311}
312
313pub fn rotary(x: VReg, cos: VReg, sin: VReg, out: VReg, neox: bool) -> Vec<Op> {
315 vec![Op::Rotate { a: x, cos, sin, d: out, neox }]
316}
317
318pub fn cache_row(x: VReg, codes: VReg, scale: SReg) -> Vec<Op> {
321 let t = scale + 1;
322 vec![
323 Op::AbsMax { a: x, d: scale },
324 Op::Const { value: INV_127, d: t },
325 Op::Scalar { op: Bin::Mul, a: scale, b: t, d: scale },
326 Op::ScalarMap { f: Func::F16, a: scale, d: scale },
327 Op::ScalarMap { f: Func::Recip, a: scale, d: t },
328 Op::Codes { a: x, s: t, d: codes },
329 ]
330}
331
332pub fn conv(ring: &[VReg], x: VReg, taps: &[VReg], acc: VReg, out: VReg) -> Vec<Op> {
338 assert_eq!(taps.len(), ring.len() + 1, "a tap for every ring row and the token's own");
339 let mut p = vec![Op::Const { value: 0.0, d: 0 }];
340 let rows = ring.iter().copied().chain(std::iter::once(x));
341 for (j, (row, &tap)) in rows.zip(taps).enumerate() {
342 p.push(if j == 0 { Op::MulAddScalar { a: row, b: tap, s: 0, d: acc } } else { Op::MulAdd { a: row, b: tap, c: acc, d: acc } });
343 }
344 p.push(Op::Map { f: Func::Silu, a: acc, d: out });
345 p
346}
347
348pub fn gdn_out(fp: FpUnit, o: VReg, w: VReg, z: VReg, out: VReg, t: VReg, n: usize, eps: f32) -> Vec<Op> {
351 let mut p = rmsnorm(fp, o, w, out, t, n, eps);
352 p.push(Op::Map { f: Func::Silu, a: z, d: t });
353 p.push(Op::Vec { op: Bin::Mul, a: out, b: t, d: out });
354 p
355}
356
357pub fn greedy(x: VReg, d: SReg) -> Vec<Op> {
359 vec![Op::ArgMax { a: x, d }]
360}