1use runmat_hir::{CallableFallbackPolicy, CallableIdentity, FunctionId};
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub struct StackEffect {
6 pub pops: usize,
7 pub pushes: usize,
8}
9
10#[derive(Debug, Clone, Serialize, Deserialize)]
11pub enum EmitLabel {
12 Ans,
13 Var(usize),
14}
15
16#[derive(Debug, Clone, Serialize, Deserialize)]
17pub enum EndExpr {
18 End,
19 Const(f64),
20 Var(usize),
21 ResolvedCall {
22 identity: CallableIdentity,
23 fallback_policy: CallableFallbackPolicy,
24 args: Vec<EndExpr>,
25 },
26 Add(Box<EndExpr>, Box<EndExpr>),
27 Sub(Box<EndExpr>, Box<EndExpr>),
28 Mul(Box<EndExpr>, Box<EndExpr>),
29 Div(Box<EndExpr>, Box<EndExpr>),
30 LeftDiv(Box<EndExpr>, Box<EndExpr>),
31 Pow(Box<EndExpr>, Box<EndExpr>),
32 Neg(Box<EndExpr>),
33 Pos(Box<EndExpr>),
34 Floor(Box<EndExpr>),
35 Ceil(Box<EndExpr>),
36 Round(Box<EndExpr>),
37 Fix(Box<EndExpr>),
38}
39
40#[derive(Debug, Clone, Serialize, Deserialize)]
41pub enum PropertyDefaultLiteral {
42 Num(f64),
43 Bool(bool),
44 String(String),
45}
46
47#[derive(Debug, Clone, Serialize, Deserialize)]
48pub enum Instr {
49 LoadConst(f64),
51 LoadComplex(f64, f64),
52 LoadBool(bool),
53 LoadString(String),
54 LoadCharRow(String),
55 LoadVar(usize),
56 LoadVarForIndexAssignment(usize),
57 StoreVar(usize),
58
59 Add,
61 Sub,
62 Mul,
63 RightDiv,
64 LeftDiv,
65 Pow,
66 Neg,
67 UPlus,
68 Transpose,
69 ConjugateTranspose,
70 ElemMul,
71 ElemDiv,
72 ElemPow,
73 ElemLeftDiv,
74 LessEqual,
75 Less,
76 Greater,
77 GreaterEqual,
78 Equal,
79 NotEqual,
80 LogicalNot,
81 LogicalAnd,
82 LogicalOr,
83
84 AndAnd(usize),
86 OrOr(usize),
87 JumpIfFalse(usize),
88 Jump(usize),
89 Pop,
90
91 Unpack(usize),
93
94 StochasticEvolution,
96
97 CreateMatrix(usize, usize),
99 CreateMatrixDynamic(usize),
100 CreateRange(bool),
101 Index(usize),
102
103 IndexSlice(usize, usize, u32, u32),
105
106 IndexSliceExpr {
108 dims: usize,
109 numeric_count: usize,
110 colon_mask: u32,
111 end_mask: u32,
112 range_dims: Vec<usize>,
113 range_has_step: Vec<bool>,
114 range_start_exprs: Vec<Option<EndExpr>>,
115 range_step_exprs: Vec<Option<EndExpr>>,
116 range_end_exprs: Vec<EndExpr>,
117 end_numeric_exprs: Vec<(usize, EndExpr)>,
118 },
119
120 StoreSliceExpr {
122 dims: usize,
123 numeric_count: usize,
124 colon_mask: u32,
125 end_mask: u32,
126 range_dims: Vec<usize>,
127 range_has_step: Vec<bool>,
128 range_start_exprs: Vec<Option<EndExpr>>,
129 range_step_exprs: Vec<Option<EndExpr>>,
130 range_end_exprs: Vec<EndExpr>,
131 end_numeric_exprs: Vec<(usize, EndExpr)>,
132 },
133 StoreSliceExprDelete {
134 dims: usize,
135 numeric_count: usize,
136 colon_mask: u32,
137 end_mask: u32,
138 range_dims: Vec<usize>,
139 range_has_step: Vec<bool>,
140 range_start_exprs: Vec<Option<EndExpr>>,
141 range_step_exprs: Vec<Option<EndExpr>>,
142 range_end_exprs: Vec<EndExpr>,
143 end_numeric_exprs: Vec<(usize, EndExpr)>,
144 },
145
146 CreateCell2D(usize, usize),
148 CreateStructLiteral(Vec<String>),
149 CreateObjectLiteral {
150 class_name: String,
151 fields: Vec<String>,
152 },
153 IndexCell {
154 num_indices: usize,
155 end_offsets: Vec<(usize, isize)>,
156 end_exprs: Vec<(usize, EndExpr)>,
157 },
158
159 IndexCellExpand {
161 num_indices: usize,
162 out_count: usize,
163 end_offsets: Vec<(usize, isize)>,
164 end_exprs: Vec<(usize, EndExpr)>,
165 },
166
167 IndexCellList {
169 num_indices: usize,
170 end_offsets: Vec<(usize, isize)>,
171 end_exprs: Vec<(usize, EndExpr)>,
172 },
173
174 StoreIndex(usize),
176 StoreIndexCell {
177 num_indices: usize,
178 end_offsets: Vec<(usize, isize)>,
179 end_exprs: Vec<(usize, EndExpr)>,
180 },
181 StoreIndexDelete(usize),
182 StoreIndexCellDelete {
183 num_indices: usize,
184 end_offsets: Vec<(usize, isize)>,
185 end_exprs: Vec<(usize, EndExpr)>,
186 },
187
188 StoreSlice(usize, usize, u32, u32),
190 StoreSliceDelete(usize, usize, u32, u32),
191
192 LoadMember(String),
194 LoadMemberOrInit(String),
195 LoadMemberDynamic,
196 LoadMemberDynamicOrInit,
197 StoreMember(String),
198 StoreMemberOrInit(String),
199 StoreMemberDynamic,
200 StoreMemberDynamicOrInit,
201 LoadMethod(String),
202
203 CallMethodOrMemberIndexMulti {
205 identity: CallableIdentity,
206 fallback_policy: CallableFallbackPolicy,
207 arg_count: usize,
208 out_count: usize,
209 },
210 CallMethodOrMemberIndexExpandMultiOutput {
211 identity: CallableIdentity,
212 fallback_policy: CallableFallbackPolicy,
213 specs: Vec<ArgSpec>,
214 out_count: usize,
215 },
216
217 CreateFunctionHandle(String),
219 CreateExternalFunctionHandle(String),
220 CreateMethodFunctionHandle(String),
221 CreateBoundFunctionHandle(FunctionId, String),
222 CreateExternalBoundFunctionHandle(FunctionId, String),
223 CreateClosure(String, usize),
224 CreateSemanticClosure(FunctionId, String, usize),
225 LoadStaticProperty(String, String),
226 LoadWorkspaceFirstStaticProperty {
227 name: String,
228 class_name: String,
229 property: String,
230 },
231
232 RegisterClass {
234 name: String,
235 super_class: Option<String>,
236 is_sealed: bool,
237 is_abstract: bool,
238 properties: Vec<(
239 String,
240 bool,
241 bool,
242 Option<PropertyDefaultLiteral>,
243 String,
244 String,
245 )>,
246 methods: Vec<(String, String, bool, bool, bool, String)>,
247 enumerations: Vec<String>,
248 },
249
250 CallFevalMulti(usize, usize),
252 CallFevalMultiUsingOutputSlot(usize, usize),
253 CallFevalExpandMultiOutput(Vec<ArgSpec>, usize),
254 CallFevalExpandMultiOutputUsingOutputSlot(Vec<ArgSpec>, usize),
255 CreateSemanticFuture(FunctionId, usize, usize),
257 CreateSemanticFutureExpandMultiOutput(FunctionId, Vec<ArgSpec>, usize),
258 Spawn,
260 Await,
262
263 Swap,
265 EnterTry(usize, Option<usize>),
266 PopTry,
267 Return,
268 ReturnValue,
269
270 CallBuiltinMulti(String, usize, usize),
272 CallBuiltinMultiUsingOutputSlot(String, usize, usize),
273 CallSuperConstructorMulti {
274 current_class: String,
275 super_class: String,
276 arg_count: usize,
277 out_count: usize,
278 },
279 CallSuperMethodMulti {
280 current_class: String,
281 super_class: String,
282 method: String,
283 arg_count: usize,
284 out_count: usize,
285 },
286
287 CallFunctionMulti {
289 identity: CallableIdentity,
290 fallback_policy: CallableFallbackPolicy,
291 arg_count: usize,
292 out_count: usize,
293 },
294 CallFunctionMultiUsingOutputSlot {
295 identity: CallableIdentity,
296 fallback_policy: CallableFallbackPolicy,
297 arg_count: usize,
298 out_count_slot: usize,
299 },
300 CallWorkspaceFirstMulti {
301 name: String,
302 identity: CallableIdentity,
303 fallback_policy: CallableFallbackPolicy,
304 bare_identifier: bool,
305 arg_count: usize,
306 out_count: usize,
307 },
308 CallWorkspaceFirstMultiUsingOutputSlot {
309 name: String,
310 identity: CallableIdentity,
311 fallback_policy: CallableFallbackPolicy,
312 bare_identifier: bool,
313 arg_count: usize,
314 out_count_slot: usize,
315 },
316 CallSemanticFunctionMulti(FunctionId, usize, usize),
317 CallSemanticFunctionMultiUsingOutputSlot(FunctionId, usize, usize),
318 CallSemanticNestedFunctionMulti {
319 function: FunctionId,
320 capture_slots: Vec<usize>,
321 arg_count: usize,
322 out_count: usize,
323 },
324 CallSemanticNestedFunctionMultiUsingOutputSlot {
325 function: FunctionId,
326 capture_slots: Vec<usize>,
327 arg_count: usize,
328 out_count_slot: usize,
329 },
330
331 CallFunctionExpandMultiOutput {
332 identity: CallableIdentity,
333 fallback_policy: CallableFallbackPolicy,
334 specs: Vec<ArgSpec>,
335 out_count: usize,
336 },
337 CallWorkspaceFirstExpandMultiOutput {
338 name: String,
339 identity: CallableIdentity,
340 fallback_policy: CallableFallbackPolicy,
341 bare_identifier: bool,
342 specs: Vec<ArgSpec>,
343 out_count: usize,
344 },
345 CallWorkspaceFirstExpandMultiOutputUsingOutputSlot {
346 name: String,
347 identity: CallableIdentity,
348 fallback_policy: CallableFallbackPolicy,
349 bare_identifier: bool,
350 specs: Vec<ArgSpec>,
351 out_count_slot: usize,
352 },
353 CallSemanticFunctionExpandMultiOutput(FunctionId, Vec<ArgSpec>, usize),
354 CallSemanticNestedFunctionExpandMultiOutput {
355 function: FunctionId,
356 capture_slots: Vec<usize>,
357 specs: Vec<ArgSpec>,
358 out_count: usize,
359 },
360 CallBuiltinExpandMultiOutput(String, Vec<ArgSpec>, usize),
361 CallSuperConstructorExpandMultiOutput {
362 current_class: String,
363 super_class: String,
364 specs: Vec<ArgSpec>,
365 out_count: usize,
366 },
367 CallSuperMethodExpandMultiOutput {
368 current_class: String,
369 super_class: String,
370 method: String,
371 specs: Vec<ArgSpec>,
372 out_count: usize,
373 },
374
375 PackToRow(usize),
377 PackToCol(usize),
378
379 EnterScope(usize),
381 ExitScope(usize),
382 LoadLocal(usize),
383 StoreLocal(usize),
384
385 RegisterImport {
387 path: Vec<String>,
388 wildcard: bool,
389 },
390
391 DeclareGlobal(Vec<usize>),
393 DeclarePersistent(Vec<usize>),
394 DeclareGlobalNamed(Vec<usize>, Vec<String>),
395 DeclarePersistentNamed(Vec<usize>, Vec<String>),
396
397 EmitStackTop {
399 label: EmitLabel,
400 },
401 EmitVar {
402 var_index: usize,
403 label: EmitLabel,
404 },
405}
406
407#[derive(Debug, Clone, Serialize, Deserialize)]
408pub struct ArgSpec {
409 pub is_expand: bool,
410 pub num_indices: usize,
411 pub expand_all: bool,
412}
413
414impl Instr {
415 pub fn stack_effect(&self) -> Option<StackEffect> {
416 fn effect(pops: usize, pushes: usize) -> Option<StackEffect> {
417 Some(StackEffect { pops, pushes })
418 }
419
420 match self {
421 Instr::LoadConst(_)
422 | Instr::LoadComplex(_, _)
423 | Instr::LoadBool(_)
424 | Instr::LoadString(_)
425 | Instr::LoadCharRow(_)
426 | Instr::CreateFunctionHandle(_)
427 | Instr::CreateExternalFunctionHandle(_)
428 | Instr::CreateMethodFunctionHandle(_)
429 | Instr::CreateBoundFunctionHandle(_, _)
430 | Instr::CreateExternalBoundFunctionHandle(_, _)
431 | Instr::LoadVar(_)
432 | Instr::LoadVarForIndexAssignment(_)
433 | Instr::LoadLocal(_) => effect(0, 1),
434 Instr::StoreVar(_)
435 | Instr::StoreLocal(_)
436 | Instr::Pop
437 | Instr::JumpIfFalse(_)
438 | Instr::AndAnd(_)
439 | Instr::OrOr(_) => effect(1, 0),
440 Instr::Add
441 | Instr::Sub
442 | Instr::Mul
443 | Instr::RightDiv
444 | Instr::LeftDiv
445 | Instr::Pow
446 | Instr::ElemMul
447 | Instr::ElemDiv
448 | Instr::ElemPow
449 | Instr::ElemLeftDiv
450 | Instr::LessEqual
451 | Instr::Less
452 | Instr::Greater
453 | Instr::GreaterEqual
454 | Instr::Equal
455 | Instr::NotEqual
456 | Instr::LogicalAnd
457 | Instr::LogicalOr => effect(2, 1),
458 Instr::Swap => effect(2, 2),
459 Instr::Neg
460 | Instr::UPlus
461 | Instr::LogicalNot
462 | Instr::Transpose
463 | Instr::ConjugateTranspose
464 | Instr::LoadMember(_)
465 | Instr::LoadMemberOrInit(_)
466 | Instr::LoadMethod(_) => effect(1, 1),
467 Instr::CallBuiltinMulti(_, argc, _) => effect(*argc, 1),
468 Instr::CallBuiltinMultiUsingOutputSlot(_, argc, _) => effect(*argc, 1),
469 Instr::CallSuperConstructorMulti { arg_count, .. } => effect(*arg_count, 1),
470 Instr::CallSuperMethodMulti { arg_count, .. } => effect(*arg_count, 1),
471 Instr::CallFunctionMulti {
472 arg_count,
473 out_count,
474 ..
475 } => effect(*arg_count, *out_count),
476 Instr::CallFunctionMultiUsingOutputSlot { arg_count, .. } => effect(*arg_count, 1),
477 Instr::CallWorkspaceFirstMulti {
478 arg_count,
479 out_count,
480 ..
481 } => effect(*arg_count, *out_count),
482 Instr::CallWorkspaceFirstMultiUsingOutputSlot { arg_count, .. } => {
483 effect(*arg_count, 1)
484 }
485 Instr::CallSemanticFunctionMulti(_, argc, out_count) => effect(*argc, *out_count),
486 Instr::CallSemanticFunctionMultiUsingOutputSlot(_, argc, _) => effect(*argc, 1),
487 Instr::CallSemanticNestedFunctionMulti {
488 arg_count,
489 out_count,
490 ..
491 } => effect(*arg_count, *out_count),
492 Instr::CallSemanticNestedFunctionMultiUsingOutputSlot { arg_count, .. } => {
493 effect(*arg_count, 1)
494 }
495 Instr::CallMethodOrMemberIndexMulti { arg_count, .. } => effect(arg_count + 1, 1),
496 Instr::CallFevalMulti(argc, _) => effect(argc + 1, 1),
497 Instr::CallFevalMultiUsingOutputSlot(argc, _) => effect(argc + 1, 1),
498 Instr::CreateSemanticFuture(_, arg_count, _) => effect(*arg_count, 1),
499 Instr::CreateMatrix(rows, cols) | Instr::CreateCell2D(rows, cols) => {
500 effect(rows * cols, 1)
501 }
502 Instr::CreateStructLiteral(fields) => effect(fields.len(), 1),
503 Instr::CreateObjectLiteral { fields, .. } => effect(fields.len(), 1),
504 Instr::CreateMatrixDynamic(rows) => effect(*rows, 1),
505 Instr::CreateRange(has_step) => effect(if *has_step { 3 } else { 2 }, 1),
506 Instr::Unpack(n) => effect(1, *n),
507 Instr::Index(n) => effect(n + 1, 1),
508 Instr::IndexCell { num_indices, .. } | Instr::IndexCellList { num_indices, .. } => {
509 effect(num_indices + 1, 1)
510 }
511 Instr::IndexCellExpand {
512 num_indices,
513 out_count,
514 ..
515 } => effect(num_indices + 1, *out_count),
516 Instr::StoreIndex(n)
517 | Instr::StoreIndexDelete(n)
518 | Instr::StoreIndexCell { num_indices: n, .. }
519 | Instr::StoreIndexCellDelete { num_indices: n, .. } => effect(n + 2, 1),
520 Instr::IndexSlice(dims, numeric_count, _, _)
521 | Instr::StoreSlice(dims, numeric_count, _, _)
522 | Instr::StoreSliceDelete(dims, numeric_count, _, _) => {
523 let pops = 1 + numeric_count;
524 if matches!(
525 self,
526 Instr::StoreSlice(_, _, _, _) | Instr::StoreSliceDelete(_, _, _, _)
527 ) {
528 effect(pops + 1, 1)
529 } else {
530 let _ = dims;
531 effect(pops, 1)
532 }
533 }
534 Instr::IndexSliceExpr {
535 numeric_count,
536 range_dims,
537 ..
538 } => effect(1 + numeric_count + range_dims.len(), 1),
539 Instr::StoreSliceExpr {
540 numeric_count,
541 range_dims,
542 ..
543 }
544 | Instr::StoreSliceExprDelete {
545 numeric_count,
546 range_dims,
547 ..
548 } => effect(2 + numeric_count + range_dims.len(), 1),
549 Instr::StoreMember(_)
550 | Instr::StoreMemberOrInit(_)
551 | Instr::StoreMemberDynamic
552 | Instr::StoreMemberDynamicOrInit => effect(2, 1),
553 Instr::LoadMemberDynamic | Instr::LoadMemberDynamicOrInit => effect(2, 1),
554 Instr::CreateClosure(_, capture_count)
555 | Instr::CreateSemanticClosure(_, _, capture_count) => effect(*capture_count, 1),
556 Instr::LoadStaticProperty(_, _) | Instr::LoadWorkspaceFirstStaticProperty { .. } => {
557 effect(0, 1)
558 }
559 Instr::RegisterClass { .. } => effect(0, 0),
560 Instr::CallFevalExpandMultiOutput(specs, _)
561 | Instr::CallFevalExpandMultiOutputUsingOutputSlot(specs, _)
562 | Instr::CreateSemanticFutureExpandMultiOutput(_, specs, _)
563 | Instr::CallFunctionExpandMultiOutput { specs, .. }
564 | Instr::CallWorkspaceFirstExpandMultiOutput { specs, .. }
565 | Instr::CallWorkspaceFirstExpandMultiOutputUsingOutputSlot { specs, .. }
566 | Instr::CallSemanticFunctionExpandMultiOutput(_, specs, _)
567 | Instr::CallSemanticNestedFunctionExpandMultiOutput { specs, .. }
568 | Instr::CallBuiltinExpandMultiOutput(_, specs, _)
569 | Instr::CallSuperConstructorExpandMultiOutput { specs, .. }
570 | Instr::CallSuperMethodExpandMultiOutput { specs, .. }
571 | Instr::CallMethodOrMemberIndexExpandMultiOutput { specs, .. } => {
572 let fixed = specs.iter().filter(|s| !s.is_expand).count();
573 let expanded: usize = specs
574 .iter()
575 .filter(|s| s.is_expand)
576 .map(|s| 1 + s.num_indices)
577 .sum();
578 let handle = usize::from(matches!(
579 self,
580 Instr::CallFevalExpandMultiOutput(_, _)
581 | Instr::CallFevalExpandMultiOutputUsingOutputSlot(_, _)
582 ));
583 effect(handle + fixed + expanded, 1)
584 }
585 Instr::PackToRow(n) | Instr::PackToCol(n) => effect(*n, 1),
586 Instr::EnterScope(_) | Instr::ExitScope(_) | Instr::Jump(_) | Instr::PopTry => {
587 effect(0, 0)
588 }
589 Instr::EnterTry(_, _) => effect(0, 0),
590 Instr::Return => effect(0, 0),
591 Instr::ReturnValue => effect(1, 0),
592 Instr::RegisterImport { .. }
593 | Instr::DeclareGlobal(_)
594 | Instr::DeclarePersistent(_)
595 | Instr::DeclareGlobalNamed(_, _)
596 | Instr::DeclarePersistentNamed(_, _) => effect(0, 0),
597 Instr::Spawn => effect(1, 1),
598 Instr::Await => effect(1, 1),
599 Instr::EmitStackTop { .. } => effect(1, 1),
600 Instr::EmitVar { .. } => effect(0, 0),
601 Instr::StochasticEvolution => None,
602 }
603 }
604}