1use crate::{
3 compiler::IoChannelInfo,
4 interner::{Symbol, TypeNodeId},
5 types::{PType, RecordTypeField, Type, TypeSize},
6};
7use std::{cell::OnceCell, path::PathBuf, sync::Arc};
8use state_tree::tree::{SizedType, StateTreeSkeleton};
10
11pub mod print;
12
13#[derive(Debug, Clone, PartialEq, Eq, Hash)]
17pub struct Argument(pub Symbol, pub TypeNodeId);
18
19pub type VReg = u64;
20#[derive(Debug, PartialEq, Eq, Hash, Clone)]
21pub enum Value {
22 Global(VPtr),
23 Argument(usize),
25 Register(VReg),
27 State(VPtr),
28 Function(usize),
30 ExtFunction(Symbol, TypeNodeId),
32 None,
34}
35
36pub type VPtr = Arc<Value>;
37
38#[derive(Debug, Clone, PartialEq)]
39pub enum Instruction {
40 Uinteger(u64),
41 Integer(i64),
42 Float(f64),
44 String(Symbol),
45 Alloc(TypeNodeId),
47 Load(VPtr, TypeNodeId),
49 Store(VPtr, VPtr, TypeNodeId),
51 GetElement {
54 value: VPtr,
55 ty: TypeNodeId, tuple_offset: u64,
57 },
58 Call(VPtr, Vec<(VPtr, TypeNodeId)>, TypeNodeId),
60 CallCls(VPtr, Vec<(VPtr, TypeNodeId)>, TypeNodeId),
61 GetGlobal(VPtr, TypeNodeId),
62 SetGlobal(VPtr, VPtr, TypeNodeId),
63 Closure(VPtr),
65 CloseUpValues(VPtr, TypeNodeId),
67 GetUpValue(u64, TypeNodeId),
69 SetUpValue(u64, VPtr, TypeNodeId),
70 PushStateOffset(u64),
72 PopStateOffset(u64),
73 GetState(TypeNodeId),
75
76 JmpIf(VPtr, u64, u64, u64),
78 Jmp(i16),
80 Phi(VPtr, VPtr),
82
83 Return(VPtr, TypeNodeId),
84 ReturnFeed(VPtr, TypeNodeId),
86
87 Delay(u64, VPtr, VPtr),
88 Mem(VPtr),
89
90 AddF(VPtr, VPtr),
92 SubF(VPtr, VPtr),
93 MulF(VPtr, VPtr),
94 DivF(VPtr, VPtr),
95 ModF(VPtr, VPtr),
96 NegF(VPtr),
97 AbsF(VPtr),
98 SinF(VPtr),
99 CosF(VPtr),
100 PowF(VPtr, VPtr),
101 LogF(VPtr),
102 SqrtF(VPtr),
103
104 AddI(VPtr, VPtr),
106 SubI(VPtr, VPtr),
107 MulI(VPtr, VPtr),
108 DivI(VPtr, VPtr),
109 ModI(VPtr, VPtr),
110 NegI(VPtr),
111 AbsI(VPtr),
112
113 PowI(VPtr),
114 LogI(VPtr, VPtr),
115 Not(VPtr),
117 Eq(VPtr, VPtr),
118 Ne(VPtr, VPtr),
119 Gt(VPtr, VPtr),
120 Ge(VPtr, VPtr),
121 Lt(VPtr, VPtr),
122 Le(VPtr, VPtr),
123 And(VPtr, VPtr),
124 Or(VPtr, VPtr),
125
126 CastFtoI(VPtr),
127 CastItoF(VPtr),
128 CastItoB(VPtr),
129
130 Array(Vec<VPtr>, TypeNodeId), GetArrayElem(VPtr, VPtr, TypeNodeId), SetArrayElem(VPtr, VPtr, VPtr, TypeNodeId), Error,
137}
138
139#[derive(Debug, Default, Clone, PartialEq)]
140pub struct Block(pub Vec<(VPtr, Instruction)>);
141
142impl Block {
143 pub fn get_total_stateskeleton(
144 &self,
145 functions: &[Function],
146 ) -> Vec<StateTreeSkeleton<StateType>> {
147 let mut children = vec![];
148 for (_v, instr) in &self.0 {
149 match instr {
150 Instruction::Delay(len, _, _) => {
151 children.push(Box::new(StateTreeSkeleton::Delay { len: *len }))
152 }
153 Instruction::Mem(_) => {
154 children.push(Box::new(StateTreeSkeleton::Mem(StateType(1))))
155 }
156 Instruction::ReturnFeed(_, ty) => {
157 children.push(Box::new(StateTreeSkeleton::Feed(StateType::from(*ty))))
158 }
159 Instruction::Call(v, _, _) => {
160 if let Value::Function(idx) = **v {
161 let func = &functions[idx];
162 if func.is_stateful() {
163 children.push(Box::new(func.state_skeleton.clone()))
164 }
165 }
166 }
167 _ => {}
168 }
169 }
170 children.into_iter().map(|e| *e).collect()
171 }
172}
173
174#[derive(Debug, Clone, PartialEq)]
175pub enum UpIndex {
176 Local(usize), Upvalue(usize), }
179
180#[derive(Clone, Copy, Debug, PartialEq)]
181pub struct OpenUpValue {
182 pub pos: usize,
183 pub size: TypeSize,
184 pub is_closure: bool,
185}
186
187#[derive(Debug, Clone, PartialEq)]
188pub struct StateType(pub u64);
189impl state_tree::tree::SizedType for StateType {
190 fn word_size(&self) -> u64 {
191 self.0
192 }
193}
194impl From<TypeNodeId> for StateType {
195 fn from(t: TypeNodeId) -> Self {
196 match t.to_type() {
197 Type::Primitive(PType::Unit) => StateType(0),
198 Type::Primitive(PType::Numeric) | Type::Function { .. } => StateType(1),
199 Type::Record(fields) => StateType(
200 fields
201 .iter()
202 .map(|RecordTypeField { ty, .. }| ty.word_size())
203 .sum(),
204 ),
205 Type::Tuple(elems) => StateType(elems.iter().map(|ty| ty.word_size()).sum()),
206 Type::Array(_elem_ty) => StateType(1),
207 _ => todo!(),
208 }
209 }
210}
211
212#[derive(Debug, Clone, PartialEq)]
213pub struct Function {
214 pub index: usize,
215 pub label: Symbol,
216 pub args: Vec<Argument>,
217 pub return_type: OnceCell<TypeNodeId>, pub upindexes: Vec<Arc<Value>>,
220 pub upperfn_i: Option<usize>,
221 pub body: Vec<Block>,
222 pub state_skeleton: StateTreeSkeleton<StateType>,
224}
225
226impl Function {
227 pub fn new(
228 index: usize,
229 name: Symbol,
230 args: &[Argument],
231 state_skeleton: Vec<StateTreeSkeleton<StateType>>,
233 upperfn_i: Option<usize>,
234 ) -> Self {
235 let state_boxed = state_skeleton.into_iter().map(Box::new).collect();
236 Self {
237 index,
238 label: name,
239 args: args.to_vec(),
240 return_type: OnceCell::new(),
242 upindexes: vec![],
243 upperfn_i,
244 body: vec![Block::default()],
245 state_skeleton: StateTreeSkeleton::FnCall(state_boxed),
246 }
247 }
248 pub fn add_new_basicblock(&mut self) -> usize {
249 self.body.push(Block(vec![]));
250 self.body.len() - 1
251 }
252 pub fn get_argtypes(&self) -> Vec<TypeNodeId> {
253 self.args.iter().map(|a| a.1).collect()
254 }
255 pub fn get_or_insert_upvalue(&mut self, v: &Arc<Value>) -> usize {
256 self.upindexes
257 .iter()
258 .position(|vt| v == vt)
259 .unwrap_or_else(|| {
260 self.upindexes.push(v.clone());
261 self.upindexes.len() - 1
262 })
263 }
264 pub fn push_state_skeleton(&mut self, skeleton: StateTreeSkeleton<StateType>) {
265 if let StateTreeSkeleton::FnCall(children) = &mut self.state_skeleton {
266 children.push(Box::new(skeleton))
267 } else {
268 panic!("State skeleton for function must be FnCall type");
269 }
270 }
271 pub fn is_stateful(&self) -> bool {
272 if let StateTreeSkeleton::FnCall(children) = &self.state_skeleton {
273 !children.is_empty()
274 } else {
275 panic!("State skeleton for function must be FnCall type");
276 }
277 }
278}
279
280#[derive(Debug, Clone, Default)]
281pub struct Mir {
282 pub functions: Vec<Function>,
283 pub file_path: Option<PathBuf>,
284}
285
286impl Mir {
287 pub fn new(file_path: Option<PathBuf>) -> Self {
288 Self {
289 file_path,
290 ..Default::default()
291 }
292 }
293 pub fn get_dsp_iochannels(&self) -> Option<IoChannelInfo> {
294 self.functions
295 .iter()
296 .find(|f| f.label.as_str() == "dsp")
297 .and_then(|f| {
298 let input = match f.get_argtypes().as_slice() {
300 [] => Some(0),
301 [t] => t.to_type().get_iochannel_count(),
302 _ => None,
303 };
304 let output = f
305 .return_type
306 .get()
307 .and_then(|t| t.to_type().get_iochannel_count());
308 input.and_then(|input| output.map(|output| IoChannelInfo { input, output }))
309 })
310 }
311
312 pub fn get_function_state_skeleton(
314 &self,
315 function_name: &str,
316 ) -> Option<&StateTreeSkeleton<StateType>> {
317 self.functions.iter().find_map(|f| {
318 if f.label.as_str() == function_name {
319 Some(&f.state_skeleton)
320 } else {
321 None
322 }
323 })
324 }
325
326 pub fn get_dsp_state_skeleton(&self) -> Option<&StateTreeSkeleton<StateType>> {
328 self.get_function_state_skeleton("dsp")
329 }
330}