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 CreateClosure(String, usize),
223 CreateSemanticClosure(FunctionId, String, usize),
224 LoadStaticProperty(String, String),
225 LoadWorkspaceFirstStaticProperty {
226 name: String,
227 class_name: String,
228 property: String,
229 },
230
231 RegisterClass {
233 name: String,
234 super_class: Option<String>,
235 is_sealed: bool,
236 is_abstract: bool,
237 properties: Vec<(
238 String,
239 bool,
240 bool,
241 Option<PropertyDefaultLiteral>,
242 String,
243 String,
244 )>,
245 methods: Vec<(String, String, bool, bool, bool, String)>,
246 enumerations: Vec<String>,
247 },
248
249 CallFevalMulti(usize, usize),
251 CallFevalMultiUsingOutputSlot(usize, usize),
252 CallFevalExpandMultiOutput(Vec<ArgSpec>, usize),
253 CallFevalExpandMultiOutputUsingOutputSlot(Vec<ArgSpec>, usize),
254 CreateSemanticFuture(FunctionId, usize, usize),
256 CreateSemanticFutureExpandMultiOutput(FunctionId, Vec<ArgSpec>, usize),
257 Spawn,
259 Await,
261
262 Swap,
264 EnterTry(usize, Option<usize>),
265 PopTry,
266 Return,
267 ReturnValue,
268
269 CallBuiltinMulti(String, usize, usize),
271 CallBuiltinMultiUsingOutputSlot(String, usize, usize),
272 CallSuperConstructorMulti {
273 current_class: String,
274 super_class: String,
275 arg_count: usize,
276 out_count: usize,
277 },
278 CallSuperMethodMulti {
279 current_class: String,
280 super_class: String,
281 method: String,
282 arg_count: usize,
283 out_count: usize,
284 },
285
286 CallFunctionMulti {
288 identity: CallableIdentity,
289 fallback_policy: CallableFallbackPolicy,
290 arg_count: usize,
291 out_count: usize,
292 },
293 CallFunctionMultiUsingOutputSlot {
294 identity: CallableIdentity,
295 fallback_policy: CallableFallbackPolicy,
296 arg_count: usize,
297 out_count_slot: usize,
298 },
299 CallWorkspaceFirstMulti {
300 name: String,
301 identity: CallableIdentity,
302 fallback_policy: CallableFallbackPolicy,
303 bare_identifier: bool,
304 arg_count: usize,
305 out_count: usize,
306 },
307 CallWorkspaceFirstMultiUsingOutputSlot {
308 name: String,
309 identity: CallableIdentity,
310 fallback_policy: CallableFallbackPolicy,
311 bare_identifier: bool,
312 arg_count: usize,
313 out_count_slot: usize,
314 },
315 CallSemanticFunctionMulti(FunctionId, usize, usize),
316 CallSemanticFunctionMultiUsingOutputSlot(FunctionId, usize, usize),
317 CallSemanticNestedFunctionMulti {
318 function: FunctionId,
319 capture_slots: Vec<usize>,
320 arg_count: usize,
321 out_count: usize,
322 },
323 CallSemanticNestedFunctionMultiUsingOutputSlot {
324 function: FunctionId,
325 capture_slots: Vec<usize>,
326 arg_count: usize,
327 out_count_slot: usize,
328 },
329
330 CallFunctionExpandMultiOutput {
331 identity: CallableIdentity,
332 fallback_policy: CallableFallbackPolicy,
333 specs: Vec<ArgSpec>,
334 out_count: usize,
335 },
336 CallWorkspaceFirstExpandMultiOutput {
337 name: String,
338 identity: CallableIdentity,
339 fallback_policy: CallableFallbackPolicy,
340 bare_identifier: bool,
341 specs: Vec<ArgSpec>,
342 out_count: usize,
343 },
344 CallWorkspaceFirstExpandMultiOutputUsingOutputSlot {
345 name: String,
346 identity: CallableIdentity,
347 fallback_policy: CallableFallbackPolicy,
348 bare_identifier: bool,
349 specs: Vec<ArgSpec>,
350 out_count_slot: usize,
351 },
352 CallSemanticFunctionExpandMultiOutput(FunctionId, Vec<ArgSpec>, usize),
353 CallSemanticNestedFunctionExpandMultiOutput {
354 function: FunctionId,
355 capture_slots: Vec<usize>,
356 specs: Vec<ArgSpec>,
357 out_count: usize,
358 },
359 CallBuiltinExpandMultiOutput(String, Vec<ArgSpec>, usize),
360 CallSuperConstructorExpandMultiOutput {
361 current_class: String,
362 super_class: String,
363 specs: Vec<ArgSpec>,
364 out_count: usize,
365 },
366 CallSuperMethodExpandMultiOutput {
367 current_class: String,
368 super_class: String,
369 method: String,
370 specs: Vec<ArgSpec>,
371 out_count: usize,
372 },
373
374 PackToRow(usize),
376 PackToCol(usize),
377
378 EnterScope(usize),
380 ExitScope(usize),
381 LoadLocal(usize),
382 StoreLocal(usize),
383
384 RegisterImport {
386 path: Vec<String>,
387 wildcard: bool,
388 },
389
390 DeclareGlobal(Vec<usize>),
392 DeclarePersistent(Vec<usize>),
393 DeclareGlobalNamed(Vec<usize>, Vec<String>),
394 DeclarePersistentNamed(Vec<usize>, Vec<String>),
395
396 EmitStackTop {
398 label: EmitLabel,
399 },
400 EmitVar {
401 var_index: usize,
402 label: EmitLabel,
403 },
404}
405
406#[derive(Debug, Clone, Serialize, Deserialize)]
407pub struct ArgSpec {
408 pub is_expand: bool,
409 pub num_indices: usize,
410 pub expand_all: bool,
411}
412
413impl Instr {
414 pub fn stack_effect(&self) -> Option<StackEffect> {
415 fn effect(pops: usize, pushes: usize) -> Option<StackEffect> {
416 Some(StackEffect { pops, pushes })
417 }
418
419 match self {
420 Instr::LoadConst(_)
421 | Instr::LoadComplex(_, _)
422 | Instr::LoadBool(_)
423 | Instr::LoadString(_)
424 | Instr::LoadCharRow(_)
425 | Instr::CreateFunctionHandle(_)
426 | Instr::CreateExternalFunctionHandle(_)
427 | Instr::CreateMethodFunctionHandle(_)
428 | Instr::CreateBoundFunctionHandle(_, _)
429 | Instr::LoadVar(_)
430 | Instr::LoadVarForIndexAssignment(_)
431 | Instr::LoadLocal(_) => effect(0, 1),
432 Instr::StoreVar(_)
433 | Instr::StoreLocal(_)
434 | Instr::Pop
435 | Instr::JumpIfFalse(_)
436 | Instr::AndAnd(_)
437 | Instr::OrOr(_) => effect(1, 0),
438 Instr::Add
439 | Instr::Sub
440 | Instr::Mul
441 | Instr::RightDiv
442 | Instr::LeftDiv
443 | Instr::Pow
444 | Instr::ElemMul
445 | Instr::ElemDiv
446 | Instr::ElemPow
447 | Instr::ElemLeftDiv
448 | Instr::LessEqual
449 | Instr::Less
450 | Instr::Greater
451 | Instr::GreaterEqual
452 | Instr::Equal
453 | Instr::NotEqual
454 | Instr::LogicalAnd
455 | Instr::LogicalOr => effect(2, 1),
456 Instr::Swap => effect(2, 2),
457 Instr::Neg
458 | Instr::UPlus
459 | Instr::LogicalNot
460 | Instr::Transpose
461 | Instr::ConjugateTranspose
462 | Instr::LoadMember(_)
463 | Instr::LoadMemberOrInit(_)
464 | Instr::LoadMethod(_) => effect(1, 1),
465 Instr::CallBuiltinMulti(_, argc, _) => effect(*argc, 1),
466 Instr::CallBuiltinMultiUsingOutputSlot(_, argc, _) => effect(*argc, 1),
467 Instr::CallSuperConstructorMulti { arg_count, .. } => effect(*arg_count, 1),
468 Instr::CallSuperMethodMulti { arg_count, .. } => effect(*arg_count, 1),
469 Instr::CallFunctionMulti {
470 arg_count,
471 out_count,
472 ..
473 } => effect(*arg_count, *out_count),
474 Instr::CallFunctionMultiUsingOutputSlot { arg_count, .. } => effect(*arg_count, 1),
475 Instr::CallWorkspaceFirstMulti {
476 arg_count,
477 out_count,
478 ..
479 } => effect(*arg_count, *out_count),
480 Instr::CallWorkspaceFirstMultiUsingOutputSlot { arg_count, .. } => {
481 effect(*arg_count, 1)
482 }
483 Instr::CallSemanticFunctionMulti(_, argc, out_count) => effect(*argc, *out_count),
484 Instr::CallSemanticFunctionMultiUsingOutputSlot(_, argc, _) => effect(*argc, 1),
485 Instr::CallSemanticNestedFunctionMulti {
486 arg_count,
487 out_count,
488 ..
489 } => effect(*arg_count, *out_count),
490 Instr::CallSemanticNestedFunctionMultiUsingOutputSlot { arg_count, .. } => {
491 effect(*arg_count, 1)
492 }
493 Instr::CallMethodOrMemberIndexMulti { arg_count, .. } => effect(arg_count + 1, 1),
494 Instr::CallFevalMulti(argc, _) => effect(argc + 1, 1),
495 Instr::CallFevalMultiUsingOutputSlot(argc, _) => effect(argc + 1, 1),
496 Instr::CreateSemanticFuture(_, arg_count, _) => effect(*arg_count, 1),
497 Instr::CreateMatrix(rows, cols) | Instr::CreateCell2D(rows, cols) => {
498 effect(rows * cols, 1)
499 }
500 Instr::CreateStructLiteral(fields) => effect(fields.len(), 1),
501 Instr::CreateObjectLiteral { fields, .. } => effect(fields.len(), 1),
502 Instr::CreateMatrixDynamic(rows) => effect(*rows, 1),
503 Instr::CreateRange(has_step) => effect(if *has_step { 3 } else { 2 }, 1),
504 Instr::Unpack(n) => effect(1, *n),
505 Instr::Index(n) => effect(n + 1, 1),
506 Instr::IndexCell { num_indices, .. } | Instr::IndexCellList { num_indices, .. } => {
507 effect(num_indices + 1, 1)
508 }
509 Instr::IndexCellExpand {
510 num_indices,
511 out_count,
512 ..
513 } => effect(num_indices + 1, *out_count),
514 Instr::StoreIndex(n)
515 | Instr::StoreIndexDelete(n)
516 | Instr::StoreIndexCell { num_indices: n, .. }
517 | Instr::StoreIndexCellDelete { num_indices: n, .. } => effect(n + 2, 1),
518 Instr::IndexSlice(dims, numeric_count, _, _)
519 | Instr::StoreSlice(dims, numeric_count, _, _)
520 | Instr::StoreSliceDelete(dims, numeric_count, _, _) => {
521 let pops = 1 + numeric_count;
522 if matches!(
523 self,
524 Instr::StoreSlice(_, _, _, _) | Instr::StoreSliceDelete(_, _, _, _)
525 ) {
526 effect(pops + 1, 1)
527 } else {
528 let _ = dims;
529 effect(pops, 1)
530 }
531 }
532 Instr::IndexSliceExpr {
533 numeric_count,
534 range_dims,
535 ..
536 } => effect(1 + numeric_count + range_dims.len(), 1),
537 Instr::StoreSliceExpr {
538 numeric_count,
539 range_dims,
540 ..
541 }
542 | Instr::StoreSliceExprDelete {
543 numeric_count,
544 range_dims,
545 ..
546 } => effect(2 + numeric_count + range_dims.len(), 1),
547 Instr::StoreMember(_)
548 | Instr::StoreMemberOrInit(_)
549 | Instr::StoreMemberDynamic
550 | Instr::StoreMemberDynamicOrInit => effect(2, 1),
551 Instr::LoadMemberDynamic | Instr::LoadMemberDynamicOrInit => effect(2, 1),
552 Instr::CreateClosure(_, capture_count)
553 | Instr::CreateSemanticClosure(_, _, capture_count) => effect(*capture_count, 1),
554 Instr::LoadStaticProperty(_, _) | Instr::LoadWorkspaceFirstStaticProperty { .. } => {
555 effect(0, 1)
556 }
557 Instr::RegisterClass { .. } => effect(0, 0),
558 Instr::CallFevalExpandMultiOutput(specs, _)
559 | Instr::CallFevalExpandMultiOutputUsingOutputSlot(specs, _)
560 | Instr::CreateSemanticFutureExpandMultiOutput(_, specs, _)
561 | Instr::CallFunctionExpandMultiOutput { specs, .. }
562 | Instr::CallWorkspaceFirstExpandMultiOutput { specs, .. }
563 | Instr::CallWorkspaceFirstExpandMultiOutputUsingOutputSlot { specs, .. }
564 | Instr::CallSemanticFunctionExpandMultiOutput(_, specs, _)
565 | Instr::CallSemanticNestedFunctionExpandMultiOutput { specs, .. }
566 | Instr::CallBuiltinExpandMultiOutput(_, specs, _)
567 | Instr::CallSuperConstructorExpandMultiOutput { specs, .. }
568 | Instr::CallSuperMethodExpandMultiOutput { specs, .. }
569 | Instr::CallMethodOrMemberIndexExpandMultiOutput { specs, .. } => {
570 let fixed = specs.iter().filter(|s| !s.is_expand).count();
571 let expanded: usize = specs
572 .iter()
573 .filter(|s| s.is_expand)
574 .map(|s| 1 + s.num_indices)
575 .sum();
576 let handle = usize::from(matches!(
577 self,
578 Instr::CallFevalExpandMultiOutput(_, _)
579 | Instr::CallFevalExpandMultiOutputUsingOutputSlot(_, _)
580 ));
581 effect(handle + fixed + expanded, 1)
582 }
583 Instr::PackToRow(n) | Instr::PackToCol(n) => effect(*n, 1),
584 Instr::EnterScope(_) | Instr::ExitScope(_) | Instr::Jump(_) | Instr::PopTry => {
585 effect(0, 0)
586 }
587 Instr::EnterTry(_, _) => effect(0, 0),
588 Instr::Return => effect(0, 0),
589 Instr::ReturnValue => effect(1, 0),
590 Instr::RegisterImport { .. }
591 | Instr::DeclareGlobal(_)
592 | Instr::DeclarePersistent(_)
593 | Instr::DeclareGlobalNamed(_, _)
594 | Instr::DeclarePersistentNamed(_, _) => effect(0, 0),
595 Instr::Spawn => effect(1, 1),
596 Instr::Await => effect(1, 1),
597 Instr::EmitStackTop { .. } => effect(1, 1),
598 Instr::EmitVar { .. } => effect(0, 0),
599 Instr::StochasticEvolution => None,
600 }
601 }
602}