miden_assembly/instruction/
procedures.rs1use alloc::vec::Vec;
2
3use miden_assembly_syntax::{
4 Word,
5 ast::{InvocationTarget, InvokeKind},
6 diagnostics::Report,
7};
8use miden_core::{
9 mast::{CallNodeBuilder, DynNodeBuilder, MastForestContributor, MastNodeExt, MastNodeId},
10 operations::{AssemblyOp, Operation},
11};
12use smallvec::SmallVec;
13
14use crate::{
15 Assembler, GlobalItemIndex, basic_block_builder::BasicBlockBuilder,
16 mast_forest_builder::MastForestBuilder,
17};
18
19impl Assembler {
21 pub(super) fn invoke(
27 &self,
28 kind: InvokeKind,
29 callee: &InvocationTarget,
30 caller: GlobalItemIndex,
31 mast_forest_builder: &mut MastForestBuilder,
32 before_enter: Vec<miden_core::mast::DecoratorId>,
33 asm_op: Option<AssemblyOp>,
34 ) -> Result<MastNodeId, Report> {
35 let resolved = self
36 .resolve_target(kind, callee, caller, mast_forest_builder)?
37 .expect("invocation target is not a procedure");
38
39 match kind {
40 InvokeKind::ProcRef | InvokeKind::Exec => Ok(resolved.node),
41 InvokeKind::Call => mast_forest_builder.ensure_node_with_asm_op(
42 CallNodeBuilder::new(resolved.node)
43 .with_before_enter(before_enter)
44 .with_after_exit(vec![]),
45 asm_op.expect("call invocations must provide an AssemblyOp"),
46 ),
47 InvokeKind::SysCall => mast_forest_builder.ensure_node_with_asm_op(
48 CallNodeBuilder::new_syscall(resolved.node)
49 .with_before_enter(before_enter)
50 .with_after_exit(vec![]),
51 asm_op.expect("syscall invocations must provide an AssemblyOp"),
52 ),
53 }
54 }
55
56 pub(super) fn dynexec(
58 &self,
59 mast_forest_builder: &mut MastForestBuilder,
60 before_enter: Vec<miden_core::mast::DecoratorId>,
61 asm_op: AssemblyOp,
62 ) -> Result<Option<MastNodeId>, Report> {
63 let dyn_node_id = mast_forest_builder.ensure_node_with_asm_op(
64 DynNodeBuilder::new_dyn()
65 .with_before_enter(before_enter)
66 .with_after_exit(vec![]),
67 asm_op,
68 )?;
69
70 Ok(Some(dyn_node_id))
71 }
72
73 pub(super) fn dyncall(
75 &self,
76 mast_forest_builder: &mut MastForestBuilder,
77 before_enter: Vec<miden_core::mast::DecoratorId>,
78 asm_op: AssemblyOp,
79 ) -> Result<Option<MastNodeId>, Report> {
80 let dyn_call_node_id = mast_forest_builder.ensure_node_with_asm_op(
81 DynNodeBuilder::new_dyncall()
82 .with_before_enter(before_enter)
83 .with_after_exit(vec![]),
84 asm_op,
85 )?;
86
87 Ok(Some(dyn_call_node_id))
88 }
89
90 pub(super) fn procref(
91 &self,
92 callee: &InvocationTarget,
93 caller: GlobalItemIndex,
94 block_builder: &mut BasicBlockBuilder,
95 ) -> Result<(), Report> {
96 let mast_root = {
97 let resolved = self
98 .resolve_target(
99 InvokeKind::ProcRef,
100 callee,
101 caller,
102 block_builder.mast_forest_builder_mut(),
103 )?
104 .expect("invocation target is not a procedure");
105 block_builder
108 .mast_forest_builder()
109 .get_mast_node(resolved.node)
110 .unwrap()
111 .digest()
112 };
113
114 self.procref_mast_root(mast_root, block_builder)
115 }
116
117 fn procref_mast_root(
118 &self,
119 mast_root: Word,
120 block_builder: &mut BasicBlockBuilder,
121 ) -> Result<(), Report> {
122 let ops = mast_root
125 .iter()
126 .rev()
127 .map(|elem| Operation::Push(*elem))
128 .collect::<SmallVec<[_; 4]>>();
129 block_builder.push_ops(ops);
130 Ok(())
131 }
132}