Skip to main content

rill_lang/
ir.rs

1//! Flat, register-machine intermediate representation.
2//!
3//! The IR computes the program's single output sample from its input sample(s)
4//! using a scratch register file (`Vec<f64>`, cleared per sample) plus a
5//! persistent state vector for feedback, `@` delays, and built-in calls.
6//! Instructions are in evaluation order; each writes exactly one register (SSA-like).
7//!
8//! The interpreter executes this per sample. The future Cranelift backend
9//! consumes the same structure.
10
11use crate::builtin::BuiltinKind;
12
13/// A register index into the per-sample scratch file.
14pub type Reg = usize;
15
16/// A slot index into the persistent state vector.
17pub type StateSlot = usize;
18
19/// A single unary math primitive.
20#[derive(Debug, Clone, Copy, PartialEq)]
21pub enum UnOp {
22    /// negate
23    Neg,
24    /// absolute value
25    Abs,
26    /// sine
27    Sin,
28    /// cosine
29    Cos,
30    /// tangent
31    Tan,
32    /// square root
33    Sqrt,
34    /// e^x
35    Exp,
36    /// natural log
37    Ln,
38    /// hyperbolic tangent
39    Tanh,
40}
41
42/// A single binary math primitive.
43#[derive(Debug, Clone, Copy, PartialEq)]
44pub enum BinArith {
45    /// +
46    Add,
47    /// -
48    Sub,
49    /// *
50    Mul,
51    /// /
52    Div,
53    /// %
54    Rem,
55    /// min
56    Min,
57    /// max
58    Max,
59}
60
61/// One IR instruction. `dst` is the scratch register it writes.
62#[derive(Debug, Clone, PartialEq)]
63pub enum Instr {
64    /// Load a constant.
65    Const {
66        /// Destination register.
67        dst: Reg,
68        /// Constant value to load.
69        value: f64,
70    },
71    /// Load the k-th program input for the current sample.
72    LoadInput {
73        /// Destination register.
74        dst: Reg,
75        /// Program input index.
76        index: usize,
77    },
78    /// Read a persistent state slot (its value from the *previous* sample).
79    ReadState {
80        /// Destination register.
81        dst: Reg,
82        /// State slot to read.
83        slot: StateSlot,
84    },
85    /// Read from a delay line: value `len` samples ago.
86    ReadDelay {
87        /// Destination register.
88        dst: Reg,
89        /// Delay line index.
90        line: usize,
91    },
92    /// Unary op.
93    Un {
94        /// Destination register.
95        dst: Reg,
96        /// Unary operation.
97        op: UnOp,
98        /// Source register.
99        src: Reg,
100    },
101    /// Binary op.
102    Bin {
103        /// Destination register.
104        dst: Reg,
105        /// Binary operation.
106        op: BinArith,
107        /// First operand register.
108        a: Reg,
109        /// Second operand register.
110        b: Reg,
111    },
112    /// Copy one register to another (wire).
113    Move {
114        /// Destination register.
115        dst: Reg,
116        /// Source register.
117        src: Reg,
118    },
119    /// Schedule a write of `src` into state slot at end of the sample.
120    WriteState {
121        /// State slot to write.
122        slot: StateSlot,
123        /// Source register.
124        src: Reg,
125    },
126    /// Schedule a push of `src` into a delay line at end of the sample.
127    WriteDelay {
128        /// Delay line index.
129        line: usize,
130        /// Source register.
131        src: Reg,
132    },
133    /// Call a per-sample built-in: `srcs` inputs → `dst`, instance index.
134    CallSample {
135        /// Destination register.
136        dst: Reg,
137        /// Source registers.
138        srcs: Vec<Reg>,
139        /// Index into [`Ir::builtins`].
140        instance: usize,
141    },
142    /// Call a whole-buffer built-in (1→1): `src` → `dst`, instance index.
143    CallBlock {
144        /// Destination register.
145        dst: Reg,
146        /// Source register.
147        src: Reg,
148        /// Index into [`Ir::builtins`].
149        instance: usize,
150    },
151    /// Read a named parameter slot. Value is constant within a block.
152    ReadParam {
153        /// Destination register.
154        dst: Reg,
155        /// Index into [`Ir::params`].
156        idx: usize,
157    },
158}
159
160/// Layout describing pre-allocated persistent storage.
161#[derive(Debug, Clone, Default, PartialEq)]
162pub struct StateLayout {
163    /// Number of scalar feedback state slots.
164    pub state_slots: usize,
165    /// Length (in samples) of each delay line.
166    pub delay_lens: Vec<usize>,
167}
168
169/// A resolved built-in call site: its name, folded constant params, and kind.
170/// Runtime instances are built from these by `RillProgram::new_with`.
171#[derive(Debug, Clone, PartialEq)]
172pub struct BuiltinInstance {
173    /// Registered built-in name.
174    pub name: String,
175    /// Folded constant params.
176    pub params: Vec<f64>,
177    /// Sample vs block.
178    pub kind: BuiltinKind,
179    /// (arg_position, param_idx) dynamic param drivers.
180    pub param_bindings: Vec<(usize, usize)>,
181}
182
183/// A named runtime parameter definition (a mutable control slot).
184#[derive(Debug, Clone, PartialEq)]
185pub struct ParamDef {
186    /// Parameter name.
187    pub name: String,
188    /// Initial/default value.
189    pub default: f64,
190    /// Minimum (clamp lower bound).
191    pub min: f64,
192    /// Maximum (clamp upper bound).
193    pub max: f64,
194}
195
196/// A complete lowered program.
197#[derive(Debug, Clone, PartialEq)]
198pub struct Ir {
199    /// Instructions in evaluation order.
200    pub instrs: Vec<Instr>,
201    /// Number of scratch registers required.
202    pub num_regs: usize,
203    /// The register holding the single program output at sample end.
204    pub output_reg: Reg,
205    /// Number of program inputs (0 or 1 for MVP).
206    pub num_inputs: usize,
207    /// Persistent state layout.
208    pub state: StateLayout,
209    /// Built-in call-site descriptors, indexed by the `instance` field of
210    /// [`Instr::CallSample`]/[`Instr::CallBlock`].
211    pub builtins: Vec<BuiltinInstance>,
212    /// Named parameter definitions, indexed by [`Instr::ReadParam::idx`].
213    pub params: Vec<ParamDef>,
214}