miden_assembly/ast/instruction/
print.rs

1use super::Instruction;
2use crate::{
3    DisplayHex, Span,
4    ast::{Immediate, InvocationTarget},
5    prettier::{Document, PrettyPrint},
6};
7
8impl PrettyPrint for Instruction {
9    fn render(&self) -> Document {
10        use crate::prettier::*;
11
12        match self {
13            Self::Nop => const_text("nop"),
14            Self::Assert => const_text("assert"),
15            Self::AssertWithError(err_code) => {
16                flatten(const_text("assert.err") + const_text("=") + display(err_code))
17            },
18            Self::AssertEq => const_text("assert_eq"),
19            Self::AssertEqWithError(err_code) => {
20                flatten(const_text("assert_eq.err") + const_text("=") + display(err_code))
21            },
22            Self::AssertEqw => const_text("assert_eqw"),
23            Self::AssertEqwWithError(err_code) => {
24                flatten(const_text("assert_eqw.err") + const_text("=") + display(err_code))
25            },
26            Self::Assertz => const_text("assertz"),
27            Self::AssertzWithError(err_code) => {
28                flatten(const_text("assertz.err") + const_text("=") + display(err_code))
29            },
30            Self::Add => const_text("add"),
31            Self::AddImm(value) => inst_with_felt_imm("add", value),
32            Self::Sub => const_text("sub"),
33            Self::SubImm(value) => inst_with_felt_imm("sub", value),
34            Self::Mul => const_text("mul"),
35            Self::MulImm(value) => inst_with_felt_imm("mul", value),
36            Self::Div => const_text("div"),
37            Self::DivImm(value) => inst_with_felt_imm("div", value),
38            Self::Neg => const_text("neg"),
39            Self::ILog2 => const_text("ilog2"),
40            Self::Inv => const_text("inv"),
41            Self::Incr => const_text("add.1"),
42            Self::Pow2 => const_text("pow2"),
43            Self::Exp => const_text("exp"),
44            Self::ExpImm(value) => inst_with_felt_imm("exp", value),
45            Self::ExpBitLength(value) => text(format!("exp.u{value}")),
46            Self::Not => const_text("not"),
47            Self::And => const_text("and"),
48            Self::Or => const_text("or"),
49            Self::Xor => const_text("xor"),
50            Self::Eq => const_text("eq"),
51            Self::EqImm(value) => inst_with_felt_imm("eq", value),
52            Self::Neq => const_text("neq"),
53            Self::NeqImm(value) => inst_with_felt_imm("neq", value),
54            Self::Eqw => const_text("eqw"),
55            Self::Lt => const_text("lt"),
56            Self::Lte => const_text("lte"),
57            Self::Gt => const_text("gt"),
58            Self::Gte => const_text("gte"),
59            Self::IsOdd => const_text("is_odd"),
60
61            // ----- ext2 operations --------------------------------------------------------------
62            Self::Ext2Add => const_text("ext2add"),
63            Self::Ext2Sub => const_text("ext2sub"),
64            Self::Ext2Mul => const_text("ext2mul"),
65            Self::Ext2Div => const_text("ext2div"),
66            Self::Ext2Neg => const_text("ext2neg"),
67            Self::Ext2Inv => const_text("ext2inv"),
68
69            // ----- u32 manipulation -------------------------------------------------------------
70            Self::U32Test => const_text("u32test"),
71            Self::U32TestW => const_text("u32testw"),
72            Self::U32Assert => const_text("u32assert"),
73            Self::U32AssertWithError(err_code) => {
74                flatten(const_text("u32assert.err") + const_text("=") + display(err_code))
75            },
76            Self::U32Assert2 => const_text("u32assert2"),
77            Self::U32Assert2WithError(err_code) => {
78                flatten(const_text("u32assert2.err") + const_text("=") + display(err_code))
79            },
80            Self::U32AssertW => const_text("u32assertw"),
81            Self::U32AssertWWithError(err_code) => {
82                flatten(const_text("u32assertw.err") + const_text("=") + display(err_code))
83            },
84            Self::U32Split => const_text("u32split"),
85            Self::U32Cast => const_text("u32cast"),
86            Self::U32WrappingAdd => const_text("u32wrapping_add"),
87            Self::U32WrappingAddImm(value) => inst_with_imm("u32wrapping_add", value),
88            Self::U32OverflowingAdd => const_text("u32overflowing_add"),
89            Self::U32OverflowingAddImm(value) => inst_with_imm("u32overflowing_add", value),
90            Self::U32OverflowingAdd3 => const_text("u32overflowing_add3"),
91            Self::U32WrappingAdd3 => const_text("u32wrapping_add3"),
92            Self::U32WrappingSub => const_text("u32wrapping_sub"),
93            Self::U32WrappingSubImm(value) => inst_with_imm("u32wrapping_sub", value),
94            Self::U32OverflowingSub => const_text("u32overflowing_sub"),
95            Self::U32OverflowingSubImm(value) => inst_with_imm("u32overflowing_sub", value),
96            Self::U32WrappingMul => const_text("u32wrapping_mul"),
97            Self::U32WrappingMulImm(value) => inst_with_imm("u32wrapping_mul", value),
98            Self::U32OverflowingMul => const_text("u32overflowing_mul"),
99            Self::U32OverflowingMulImm(value) => inst_with_imm("u32overflowing_mul", value),
100            Self::U32OverflowingMadd => const_text("u32overflowing_madd"),
101            Self::U32WrappingMadd => const_text("u32wrapping_madd"),
102            Self::U32Div => const_text("u32div"),
103            Self::U32DivImm(value) => inst_with_imm("u32div", value),
104            Self::U32Mod => const_text("u32mod"),
105            Self::U32ModImm(value) => inst_with_imm("u32mod", value),
106            Self::U32DivMod => const_text("u32divmod"),
107            Self::U32DivModImm(value) => inst_with_imm("u32divmod", value),
108            Self::U32And => const_text("u32and"),
109            Self::U32Or => const_text("u32or"),
110            Self::U32Xor => const_text("u32xor"),
111            Self::U32Not => const_text("u32not"),
112            Self::U32Shr => const_text("u32shr"),
113            Self::U32ShrImm(value) => inst_with_imm("u32shr", value),
114            Self::U32Shl => const_text("u32shl"),
115            Self::U32ShlImm(value) => inst_with_imm("u32shl", value),
116            Self::U32Rotr => const_text("u32rotr"),
117            Self::U32RotrImm(value) => inst_with_imm("u32rotr", value),
118            Self::U32Rotl => const_text("u32rotl"),
119            Self::U32RotlImm(value) => inst_with_imm("u32rotl", value),
120            Self::U32Popcnt => const_text("u32popcnt"),
121            Self::U32Clz => const_text("u32clz"),
122            Self::U32Ctz => const_text("u32ctz"),
123            Self::U32Clo => const_text("u32clo"),
124            Self::U32Cto => const_text("u32cto"),
125            Self::U32Lt => const_text("u32lt"),
126            Self::U32Lte => const_text("u32lte"),
127            Self::U32Gt => const_text("u32gt"),
128            Self::U32Gte => const_text("u32gte"),
129            Self::U32Min => const_text("u32min"),
130            Self::U32Max => const_text("u32max"),
131
132            // ----- stack manipulation -----------------------------------------------------------
133            Self::Drop => const_text("drop"),
134            Self::DropW => const_text("dropw"),
135            Self::PadW => const_text("padw"),
136            Self::Dup0 => const_text("dup.0"),
137            Self::Dup1 => const_text("dup.1"),
138            Self::Dup2 => const_text("dup.2"),
139            Self::Dup3 => const_text("dup.3"),
140            Self::Dup4 => const_text("dup.4"),
141            Self::Dup5 => const_text("dup.5"),
142            Self::Dup6 => const_text("dup.6"),
143            Self::Dup7 => const_text("dup.7"),
144            Self::Dup8 => const_text("dup.8"),
145            Self::Dup9 => const_text("dup.9"),
146            Self::Dup10 => const_text("dup.10"),
147            Self::Dup11 => const_text("dup.11"),
148            Self::Dup12 => const_text("dup.12"),
149            Self::Dup13 => const_text("dup.13"),
150            Self::Dup14 => const_text("dup.14"),
151            Self::Dup15 => const_text("dup.15"),
152            Self::DupW0 => const_text("dupw.0"),
153            Self::DupW1 => const_text("dupw.1"),
154            Self::DupW2 => const_text("dupw.2"),
155            Self::DupW3 => const_text("dupw.3"),
156            Self::Swap1 => const_text("swap.1"),
157            Self::Swap2 => const_text("swap.2"),
158            Self::Swap3 => const_text("swap.3"),
159            Self::Swap4 => const_text("swap.4"),
160            Self::Swap5 => const_text("swap.5"),
161            Self::Swap6 => const_text("swap.6"),
162            Self::Swap7 => const_text("swap.7"),
163            Self::Swap8 => const_text("swap.8"),
164            Self::Swap9 => const_text("swap.9"),
165            Self::Swap10 => const_text("swap.10"),
166            Self::Swap11 => const_text("swap.11"),
167            Self::Swap12 => const_text("swap.12"),
168            Self::Swap13 => const_text("swap.13"),
169            Self::Swap14 => const_text("swap.14"),
170            Self::Swap15 => const_text("swap.15"),
171            Self::SwapW1 => const_text("swapw.1"),
172            Self::SwapW2 => const_text("swapw.2"),
173            Self::SwapW3 => const_text("swapw.3"),
174            Self::SwapDw => const_text("swapdw"),
175            Self::MovUp2 => const_text("movup.2"),
176            Self::MovUp3 => const_text("movup.3"),
177            Self::MovUp4 => const_text("movup.4"),
178            Self::MovUp5 => const_text("movup.5"),
179            Self::MovUp6 => const_text("movup.6"),
180            Self::MovUp7 => const_text("movup.7"),
181            Self::MovUp8 => const_text("movup.8"),
182            Self::MovUp9 => const_text("movup.9"),
183            Self::MovUp10 => const_text("movup.10"),
184            Self::MovUp11 => const_text("movup.11"),
185            Self::MovUp12 => const_text("movup.12"),
186            Self::MovUp13 => const_text("movup.13"),
187            Self::MovUp14 => const_text("movup.14"),
188            Self::MovUp15 => const_text("movup.15"),
189            Self::MovUpW2 => const_text("movupw.2"),
190            Self::MovUpW3 => const_text("movupw.3"),
191            Self::MovDn2 => const_text("movdn.2"),
192            Self::MovDn3 => const_text("movdn.3"),
193            Self::MovDn4 => const_text("movdn.4"),
194            Self::MovDn5 => const_text("movdn.5"),
195            Self::MovDn6 => const_text("movdn.6"),
196            Self::MovDn7 => const_text("movdn.7"),
197            Self::MovDn8 => const_text("movdn.8"),
198            Self::MovDn9 => const_text("movdn.9"),
199            Self::MovDn10 => const_text("movdn.10"),
200            Self::MovDn11 => const_text("movdn.11"),
201            Self::MovDn12 => const_text("movdn.12"),
202            Self::MovDn13 => const_text("movdn.13"),
203            Self::MovDn14 => const_text("movdn.14"),
204            Self::MovDn15 => const_text("movdn.15"),
205            Self::MovDnW2 => const_text("movdnw.2"),
206            Self::MovDnW3 => const_text("movdnw.3"),
207            Self::CSwap => const_text("cswap"),
208            Self::CSwapW => const_text("cswapw"),
209            Self::CDrop => const_text("cdrop"),
210            Self::CDropW => const_text("cdropw"),
211
212            // ----- input / output operations ----------------------------------------------------
213            Self::Push(imm) => inst_with_felt_imm("push", imm),
214            Self::PushU8(value) => inst_with_imm("push", value),
215            Self::PushU16(value) => inst_with_imm("push", value),
216            Self::PushU32(value) => inst_with_imm("push", value),
217            Self::PushFelt(value) => {
218                inst_with_felt_imm("push", &Immediate::Value(Span::unknown(*value)))
219            },
220            Self::PushWord(values) => inst_with_pretty_felt_params("push", values),
221            Self::PushU8List(values) => inst_with_pretty_params("push", values),
222            Self::PushU16List(values) => inst_with_pretty_params("push", values),
223            Self::PushU32List(values) => inst_with_pretty_params("push", values),
224            Self::PushFeltList(values) => inst_with_pretty_felt_params("push", values),
225
226            Self::Locaddr(value) => inst_with_imm("locaddr", value),
227            Self::Sdepth => const_text("sdepth"),
228            Self::Caller => const_text("caller"),
229            Self::Clk => const_text("clk"),
230
231            Self::MemLoad => const_text("mem_load"),
232            Self::MemLoadImm(value) => inst_with_imm("mem_load", value),
233            Self::MemLoadW => const_text("mem_loadw"),
234            Self::MemLoadWImm(value) => inst_with_imm("mem_loadw", value),
235            Self::LocLoad(value) => inst_with_imm("loc_load", value),
236            Self::LocLoadW(value) => inst_with_imm("loc_loadw", value),
237
238            Self::MemStore => const_text("mem_store"),
239            Self::MemStoreImm(value) => inst_with_imm("mem_store", value),
240            Self::LocStore(value) => inst_with_imm("loc_store", value),
241            Self::MemStoreW => const_text("mem_storew"),
242            Self::MemStoreWImm(value) => inst_with_imm("mem_storew", value),
243            Self::LocStoreW(value) => inst_with_imm("loc_storew", value),
244
245            Self::MemStream => const_text("mem_stream"),
246            Self::AdvPipe => const_text("adv_pipe"),
247
248            Self::AdvPush(value) => inst_with_imm("adv_push", value),
249            Self::AdvLoadW => const_text("adv_loadw"),
250
251            Self::SysEvent(sys_event) => inst_with_imm("adv", sys_event),
252
253            // ----- cryptographic operations -----------------------------------------------------
254            Self::Hash => const_text("hash"),
255            Self::HMerge => const_text("hmerge"),
256            Self::HPerm => const_text("hperm"),
257            Self::MTreeGet => const_text("mtree_get"),
258            Self::MTreeSet => const_text("mtree_set"),
259            Self::MTreeMerge => const_text("mtree_merge"),
260            Self::MTreeVerify => const_text("mtree_verify"),
261            Self::MTreeVerifyWithError(err_code) => {
262                flatten(const_text("mtree_verify.err") + const_text("=") + display(err_code))
263            },
264
265            // ----- STARK proof verification -----------------------------------------------------
266            Self::FriExt2Fold4 => const_text("fri_ext2fold4"),
267            Self::HornerBase => const_text("horner_eval_base"),
268            Self::HornerExt => const_text("horner_eval_ext"),
269            Self::ArithmeticCircuitEval => const_text("arithmetic_circuit_eval"),
270
271            // ----- exec / call ------------------------------------------------------------------
272            Self::Exec(InvocationTarget::MastRoot(root)) => flatten(
273                const_text("exec")
274                    + const_text(".")
275                    + text(format!("{:#x}", DisplayHex(root.as_bytes().as_slice()))),
276            ),
277            Self::Exec(InvocationTarget::ProcedureName(name)) => {
278                flatten(const_text("exec") + const_text(".") + text(name))
279            },
280            Self::Exec(InvocationTarget::ProcedurePath { name, module }) => {
281                const_text("exec") + const_text(".") + text(format!("{module}::{name}"))
282            },
283            Self::Exec(InvocationTarget::AbsoluteProcedurePath { name, path }) => {
284                const_text("exec") + const_text(".") + text(format!("::{path}::{name}"))
285            },
286            Self::Call(InvocationTarget::MastRoot(root)) => {
287                const_text("call")
288                    + const_text(".")
289                    + text(format!("{:#x}", DisplayHex(root.as_bytes().as_slice())))
290            },
291            Self::Call(InvocationTarget::ProcedureName(name)) => {
292                flatten(const_text("call") + const_text(".") + text(name))
293            },
294            Self::Call(InvocationTarget::ProcedurePath { name, module }) => {
295                const_text("call") + const_text(".") + text(format!("{module}::{name}"))
296            },
297            Self::Call(InvocationTarget::AbsoluteProcedurePath { name, path }) => {
298                const_text("call") + const_text(".") + text(format!("::{path}::{name}"))
299            },
300            Self::SysCall(InvocationTarget::MastRoot(root)) => {
301                const_text("syscall")
302                    + const_text(".")
303                    + text(format!("{:#x}", DisplayHex(root.as_bytes().as_slice())))
304            },
305            Self::SysCall(InvocationTarget::ProcedureName(name)) => {
306                flatten(const_text("syscall") + const_text(".") + text(format!("{name}")))
307            },
308            Self::SysCall(InvocationTarget::ProcedurePath { name, module }) => {
309                const_text("syscall") + const_text(".") + text(format!("{module}::{name}"))
310            },
311            Self::SysCall(InvocationTarget::AbsoluteProcedurePath { name, path }) => {
312                const_text("syscall") + const_text(".") + text(format!("::{path}::{name}"))
313            },
314            Self::DynExec => const_text("dynexec"),
315            Self::DynCall => const_text("dyncall"),
316            Self::ProcRef(InvocationTarget::MastRoot(_)) => {
317                panic!("invalid procref instruction: expected name not MAST root")
318            },
319            Self::ProcRef(InvocationTarget::ProcedureName(name)) => {
320                flatten(const_text("procref") + const_text(".") + text(name))
321            },
322            Self::ProcRef(InvocationTarget::ProcedurePath { name, module }) => {
323                flatten(const_text("procref") + const_text(".") + text(format!("{module}::{name}")))
324            },
325            Self::ProcRef(InvocationTarget::AbsoluteProcedurePath { name, path }) => {
326                flatten(const_text("procref") + const_text(".") + text(format!("::{path}::{name}")))
327            },
328
329            // ----- debug decorators -------------------------------------------------------------
330            Self::Breakpoint => const_text("breakpoint"),
331            Self::Debug(options) => inst_with_imm("debug", options),
332
333            // ----- event decorators -------------------------------------------------------------
334            Self::Emit(value) => inst_with_imm("emit", value),
335            Self::Trace(value) => inst_with_imm("trace", value),
336        }
337    }
338}
339
340fn inst_with_imm(name: &'static str, imm: &dyn PrettyPrint) -> Document {
341    use crate::prettier::*;
342
343    let imm = imm.render();
344
345    flatten(const_text(name) + const_text(".") + imm)
346}
347
348fn inst_with_felt_imm(name: &'static str, imm: &Immediate<crate::Felt>) -> Document {
349    use crate::prettier::*;
350
351    let value = match imm {
352        Immediate::Value(value) => display(*value),
353        Immediate::Constant(name) => text(name),
354    };
355
356    flatten(const_text(name) + const_text(".") + value)
357}
358
359fn inst_with_pretty_felt_params(inst: &'static str, params: &[crate::Felt]) -> Document {
360    use crate::prettier::*;
361
362    let single_line = text(inst)
363        + const_text(".")
364        + params
365            .iter()
366            .copied()
367            .map(display)
368            .reduce(|acc, doc| acc + const_text(".") + doc)
369            .unwrap_or_default();
370
371    let multi_line = params
372        .iter()
373        .copied()
374        .map(|v| text(inst) + const_text(".") + display(v))
375        .reduce(|acc, doc| acc + nl() + doc)
376        .unwrap_or_default();
377    single_line | multi_line
378}
379
380fn inst_with_pretty_params<P: PrettyPrint>(inst: &'static str, params: &[P]) -> Document {
381    use crate::prettier::*;
382
383    let single_line = text(inst)
384        + const_text(".")
385        + params
386            .iter()
387            .map(|p| p.render())
388            .reduce(|acc, doc| acc + const_text(".") + doc)
389            .unwrap_or_default();
390
391    let multi_line = params
392        .iter()
393        .map(|v| text(inst) + const_text(".") + v.render())
394        .reduce(|acc, doc| acc + nl() + doc)
395        .unwrap_or_default();
396    single_line | multi_line
397}
398
399// TESTS
400// ================================================================================================
401
402#[cfg(test)]
403mod tests {
404    use vm_core::crypto::hash::Rpo256;
405
406    use crate::{Felt, Span, ast::*};
407
408    #[test]
409    fn test_instruction_display() {
410        let instruction = format!("{}", Instruction::Assert);
411        assert_eq!("assert", instruction);
412
413        let instruction = format!("{}", Instruction::Add);
414        assert_eq!("add", instruction);
415
416        let instruction = format!("{}", Instruction::AddImm(Felt::new(5).into()));
417        assert_eq!("add.5", instruction);
418
419        let instruction = format!("{}", Instruction::ExpBitLength(32));
420        assert_eq!("exp.u32", instruction);
421
422        let instruction = format!(
423            "{}",
424            Instruction::PushFeltList(vec![Felt::new(3), Felt::new(4), Felt::new(8), Felt::new(9)])
425        );
426        assert_eq!("push.3.4.8.9", instruction);
427
428        let digest = Rpo256::hash(b"std::math::u64::add");
429        let target = InvocationTarget::MastRoot(Span::unknown(digest));
430        let instruction = format!("{}", Instruction::Exec(target));
431        assert_eq!(
432            "exec.0x90b3926941061b28638b6cc0bbdb3bcb335e834dc9ab8044250875055202d2fe",
433            instruction
434        );
435    }
436}