midenc_hir/asm/
isa.rs

1use std::{collections::BTreeSet, fmt};
2
3use cranelift_entity::entity_impl;
4pub use miden_assembly::ast::{AdviceInjectorNode, DebugOptions};
5use smallvec::{smallvec, SmallVec};
6
7use crate::{
8    diagnostics::{SourceSpan, Span},
9    Felt, FunctionIdent, Ident, LocalId,
10};
11
12/// A handle that refers to a MASM code block
13#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
14pub struct MasmBlockId(u32);
15entity_impl!(MasmBlockId, "blk");
16
17/// Represents a single code block in Miden Assembly
18#[derive(Debug, Clone, PartialEq)]
19pub struct MasmBlock {
20    pub id: MasmBlockId,
21    pub ops: SmallVec<[Span<MasmOp>; 4]>,
22}
23impl MasmBlock {
24    /// Returns true if there are no instructions in this block
25    #[inline(always)]
26    pub fn is_empty(&self) -> bool {
27        self.ops.is_empty()
28    }
29
30    /// Returns the instructions contained in this block as a slice
31    #[inline(always)]
32    pub fn ops(&self) -> &[Span<MasmOp>] {
33        self.ops.as_slice()
34    }
35
36    /// Appends `op` to this code block
37    #[inline(always)]
38    pub fn push(&mut self, op: MasmOp, span: SourceSpan) {
39        self.ops.push(Span::new(span, op));
40    }
41
42    /// Append `n` copies of `op` to the current block
43    #[inline]
44    pub fn push_n(&mut self, count: usize, op: MasmOp, span: SourceSpan) {
45        let op = Span::new(span, op);
46        for _ in 0..count {
47            self.ops.push(op);
48        }
49    }
50
51    /// Append `n` copies of the sequence `ops` to this block
52    #[inline]
53    pub fn push_repeat(&mut self, ops: &[Span<MasmOp>], count: usize) {
54        for _ in 0..count {
55            self.ops.extend_from_slice(ops);
56        }
57    }
58
59    /// Append `n` copies of the sequence `ops` to this block
60    #[inline]
61    pub fn push_template<const N: usize, F>(&mut self, count: usize, template: F)
62    where
63        F: Fn(usize) -> [Span<MasmOp>; N],
64    {
65        for n in 0..count {
66            self.ops.extend_from_slice(&template(n));
67        }
68    }
69
70    /// Appends instructions from `slice` to the end of this block
71    #[inline]
72    pub fn extend_from_slice(&mut self, slice: &[Span<MasmOp>]) {
73        self.ops.extend_from_slice(slice);
74    }
75
76    /// Appends instructions from `slice` to the end of this block
77    #[inline]
78    pub fn extend(&mut self, ops: impl IntoIterator<Item = Span<MasmOp>>) {
79        self.ops.extend(ops);
80    }
81
82    /// Appends instructions from `other` to the end of this block
83    #[inline]
84    pub fn append<B>(&mut self, other: &mut SmallVec<B>)
85    where
86        B: smallvec::Array<Item = Span<MasmOp>>,
87    {
88        self.ops.append(other);
89    }
90}
91
92/// This enum represents the Miden Assembly (MASM) instruction set.
93///
94/// Not all MASM instructions are necessarily represented here, only those we
95/// actually use, or intend to use, when compiling from Miden IR.
96#[derive(Debug, Copy, Clone, PartialEq, Eq)]
97pub enum MasmOp {
98    /// Pushes a null word on the stack, i.e. four 0 values
99    Padw,
100    /// Pushes the given field element constant on top of the stack
101    Push(Felt),
102    /// Pushes a pair of field elements on top of the stack
103    Push2([Felt; 2]),
104    /// Pushes the given word constant on top of the stack
105    Pushw([Felt; 4]),
106    /// Pushes the given 8-bit constant on top of the stack
107    PushU8(u8),
108    /// Pushes the given 16-bit constant on top of the stack
109    PushU16(u16),
110    /// Pushes the given 32-bit constant on top of the stack
111    PushU32(u32),
112    /// Removes the item on the top of the stack
113    Drop,
114    /// Removes the top 4 items on the stack
115    Dropw,
116    /// Copies the `n`th item on the stack to the top of stack
117    ///
118    /// * `Dup(0)` duplicates the item on top of the stack
119    Dup(u8),
120    /// Copies the `n`th word on the stack, to the top of the stack
121    ///
122    /// The only values of `n` which are valid, are 0, 1, 2, 3; or
123    /// in other words, the 4 words which make up the top 16 elements
124    /// of the stack.
125    Dupw(u8),
126    /// Swaps the 1st and `n`th items on the stack
127    ///
128    /// * `Swap(1)` swaps the top two elements of the stack
129    Swap(u8),
130    /// Swaps the 1st and `n`th words on the stack
131    ///
132    /// The only values of `n` which are valid, are 1, 2, 3; or
133    /// in other words, the 3 words which make up the last 12 elements
134    /// of the stack.
135    Swapw(u8),
136    // Swaps the two words on top of the stack, with the two words at the bottom of the stack
137    Swapdw,
138    /// Moves the `n`th stack item to top of stack
139    ///
140    /// * `Movup(1)` is equivalent to `Swap(1)`
141    Movup(u8),
142    /// Moves the `n`th stack word to the top of the stack
143    ///
144    /// The only values of `n` which are valid are 2 and 3. Use `Swapw(1)`
145    /// if you want to move the second word to the top.
146    Movupw(u8),
147    /// Moves the top of stack to the `n`th index of the stack
148    ///
149    /// * `Movdn(1)` is equivalent to `Swap(1)`
150    Movdn(u8),
151    /// Moves the top word of the stack, into position as the `n`th word on the stack.
152    ///
153    /// The only values of `n` which are valid are 2 and 3. Use `Swapw(1)`
154    /// if you want to make the top word the second word.
155    Movdnw(u8),
156    /// Pops `c, b, a` off the stack, and swaps `b` and `a` if `c` is 1, or leaves
157    /// them as-is when 0.
158    ///
159    /// Traps if `c` is > 1.
160    Cswap,
161    /// Pops `c, B, A` off the stack, where `B` and `A` are words, and swaps `B` and `A`
162    /// if `c` is 1, or leaves them as-is when 0.
163    ///
164    /// Traps if `c` is > 1.
165    Cswapw,
166    /// Pops `c, b, a` off the stack, and pushes back `b` if `c` is 1, and `a` if 0.
167    ///
168    /// Traps if `c` is > 1.
169    Cdrop,
170    /// Pops `c, B, A` off the stack, where `B` and `A` are words, and pushes back `B`
171    /// if `c` is 1, and `A` if 0.
172    ///
173    /// Traps if `c` is > 1.
174    Cdropw,
175    /// Pops a value off the stack and asserts that it is equal to 1
176    Assert,
177    /// Pops a value off the stack and asserts that it is equal to 1, raising the given error code
178    AssertWithError(u32),
179    /// Pops a value off the stack and asserts that it is equal to 0
180    Assertz,
181    /// Pops a value off the stack and asserts that it is equal to 0, raising the given error code
182    AssertzWithError(u32),
183    /// Pops two values off the stack and asserts that they are equal
184    AssertEq,
185    /// Pops two values off the stack and asserts that they are equal, raising the given error code
186    AssertEqWithError(u32),
187    /// Pops two words off the stack and asserts that they are equal
188    AssertEqw,
189    /// Pops two words off the stack and asserts that they are equal, raising the given error code
190    AssertEqwWithError(u32),
191    /// Places the memory address of the given local index on top of the stack
192    LocAddr(LocalId),
193    /// Writes a value to the first element of the word at the address corresponding to the given
194    /// local index
195    LocStore(LocalId),
196    /// Writes a word to the address corresponding to the given local index
197    LocStorew(LocalId),
198    /// Reads a value from the first element of the word at the address corresponding to the given
199    /// local index
200    LocLoad(LocalId),
201    /// Reads a word from the address corresponding to the given local index
202    LocLoadw(LocalId),
203    /// Pops `a`, representing a memory address, from the top of the stack, then loads the
204    /// first element of the word starting at that address, placing it on top of the stack.
205    ///
206    /// Traps if `a` >= 2^32
207    MemLoad,
208    /// Same as above, but the address is given as an immediate
209    MemLoadImm(u32),
210    /// Pops `a`, representing a memory address, from the top of the stack, then overwrites
211    /// the top word of the stack with the word starting at that address.
212    ///
213    /// Traps if `a` >= 2^32
214    MemLoadw,
215    /// Same as above, but the address is given as an immediate
216    MemLoadwImm(u32),
217    /// Pops `a, v` from the stack, where `a` represents a memory address, and `v` the value
218    /// to be stored, and stores `v` as the element as the first element of the word starting
219    /// at that address. The remaining elements of the word are not modified.
220    ///
221    /// Traps if `a` >= 2^32
222    MemStore,
223    /// Same as above, but the address is given as an immediate
224    MemStoreImm(u32),
225    /// Pops `a, V` from the stack, where `a` represents a memory address, and `V` is a word to be
226    /// stored at that location, and overwrites the word located at `a`.
227    ///
228    /// Traps if `a` >= 2^32
229    MemStorew,
230    /// Same as above, but the address is given as an immediate
231    MemStorewImm(u32),
232    /// Read two sequential words from memory starting at `a`, overwriting the first two words on
233    /// the stack, and advancing `a` to the next address following the two that were loaded
234    /// [C, B, A, a] <- [*a, *(a + 1), A, a + 2]
235    MemStream,
236    /// Pops the next two words from the advice stack, overwrites the
237    /// top of the operand stack with them, and also writes these words
238    /// into memory at `a` and `a + 1`
239    ///
240    /// [C, B, A, a] <- [*a, *(a + 1), A, a + 2]
241    AdvPipe,
242    /// Pops `n` elements from the advice stack, and pushes them on the operand stack
243    ///
244    /// Fails if less than `n` elements are available.
245    ///
246    /// Valid values of `n` fall in the range 1..=16
247    AdvPush(u8),
248    /// Pop the next word from the advice stack and overwrite the word on top of the operand stack
249    /// with it.
250    ///
251    /// Fails if the advice stack does not have at least one word.
252    AdvLoadw,
253    /// Push the result of u64 division on the advice stack
254    ///
255    /// ```text,ignore
256    /// [b_hi, b_lo, a_hi, a_lo]
257    /// ```
258    AdvInjectPushU64Div,
259    /// Pushes a list of field elements on the advice stack.
260    ///
261    /// The list is looked up in the advice map using the word on top of the operand stack.
262    ///
263    /// ```text,ignore
264    /// [K]
265    /// ```
266    AdvInjectPushMapVal,
267    /// Pushes a list of field elements on the advice stack.
268    ///
269    /// The list is looked up in the advice map using the word starting at `index` on the operand
270    /// stack.
271    ///
272    /// ```text,ignore
273    /// [K]
274    /// ```
275    AdvInjectPushMapValImm(u8),
276    /// Pushes a list of field elements, along with the number of elements on the advice stack.
277    ///
278    /// The list is looked up in the advice map using the word on top of the operand stack.
279    ///
280    /// ```text,ignore
281    /// [K]
282    /// ```
283    AdvInjectPushMapValN,
284    /// Pushes a list of field elements, along with the number of elements on the advice stack.
285    ///
286    /// The list is looked up in the advice map using the word starting at `index` on the operand
287    /// stack.
288    ///
289    /// ```text,ignore
290    /// [K]
291    /// ```
292    AdvInjectPushMapValNImm(u8),
293    /// Pushes a node of a Merkle tree with root `R` at depth `d` and index `i` from the Merkle
294    /// store onto the advice stack
295    ///
296    /// ```text,ignore
297    /// [d, i, R]
298    /// ```
299    AdvInjectPushMTreeNode,
300    /// Reads words `mem[a]..mem[b]` from memory, and saves the data into the advice map under `K`
301    ///
302    /// ```text,ignore
303    /// [K, a, b]
304    /// ```
305    AdvInjectInsertMem,
306    /// Reads the top two words from the stack, and computes a key `K` as `hash(A || B, 0)`.
307    ///
308    /// The two words that were hashed are then saved into the advice map under `K`.
309    ///
310    /// ```text,ignore
311    /// [B, A]
312    /// ```
313    AdvInjectInsertHdword,
314    /// Reads the top two words from the stack, and computes a key `K` as `hash(A || B, d)`.
315    ///
316    /// `d` is a domain value which can be in the range 0..=255
317    ///
318    /// The two words that were hashed are then saved into the advice map under `K` as `[A, B]`.
319    ///
320    /// ```text,ignore
321    /// [B, A]
322    /// ```
323    AdvInjectInsertHdwordImm(u8),
324    /// Reads the top three words from the stack, and computes a key `K` as `permute(C, A,
325    /// B).digest`.
326    ///
327    /// The words `A` and `B` are saved into the advice map under `K` as `[A, B]`
328    ///
329    /// ```text,ignore
330    /// [B, A, C]
331    /// ```
332    AdvInjectInsertHperm,
333    /// TODO
334    AdvInjectPushSignature(miden_assembly::ast::SignatureKind),
335    /// Compute the Rescue Prime Optimized (RPO) hash of the word on top of the operand stack.
336    ///
337    /// The resulting hash of one word is placed on the operand stack.
338    ///
339    /// The input operand is consumed.
340    Hash,
341    /// Computes a 2-to-1 RPO hash of the two words on top of the operand stack.
342    ///
343    /// The resulting hash of one word is placed on the operand stack.
344    ///
345    /// The input operands are consumed.
346    Hmerge,
347    /// Compute an RPO permutation on the top 3 words of the operand stack, where the top 2 words
348    /// (C and B) are the rate, and the last word (A) is the capacity.
349    ///
350    /// The digest output is the word E.
351    ///
352    /// ```text,ignore
353    /// [C, B, A] => [F, E, D]
354    /// ```
355    Hperm,
356    /// Fetches the value `V` of the Merkle tree with root `R`, at depth `d`, and index `i` from
357    /// the advice provider, and runs a verification equivalent to `mtree_verify`, returning
358    /// the value if successful.
359    ///
360    /// ```text,ignore
361    /// [d, i, R] => [V, R]
362    /// ```
363    MtreeGet,
364    /// Sets the value to `V'` of the Merkle tree with root `R`, at depth `d`, and index `i`.
365    ///
366    /// `R'` is the Merkle root of the new tree, and `V` is the old value of the node.
367    ///
368    /// Requires that a Merkle tree with root `R` is present in the advice provider, otherwise it
369    /// fails.
370    ///
371    /// Both trees are in the advice provider upon return.
372    ///
373    /// ```text,ignore
374    /// [d, i, R, V'] => [V, R']
375    /// ```
376    MtreeSet,
377    /// Create a new Merkle tree root `M`, that joins two other Merkle trees, `R` and `L`.
378    ///
379    /// Both the new tree and the input trees are in the advice provider upon return.
380    ///
381    /// ```text,ignore
382    /// [R, L] => [M]
383    /// ```
384    MtreeMerge,
385    /// Verifies that a Merkle tree with root `R` opens to node `V` at depth `d` and index `i`.
386    ///
387    /// The Merkle tree with root `R` must be present in the advice provider or the operation
388    /// fails.
389    ///
390    /// ```text,ignore
391    /// [V, d, i, R] => [V, d, i, R]
392    /// ```
393    MtreeVerify,
394    /// Verifies that a Merkle tree with root `R` opens to node `V` at depth `d` and index `i`.
395    ///
396    /// The Merkle tree with root `R` must be present in the advice provider or the operation
397    /// fails.
398    ///
399    /// ```text,ignore
400    /// [V, d, i, R] => [V, d, i, R]
401    /// ```
402    /// Raise the given error code if the verification fails
403    MtreeVerifyWithError(u32),
404    /// Performs FRI layer folding by a factor of 4 for FRI protocol executed in a degree 2
405    /// extension of the base field. Additionally, performs several computations which simplify
406    /// FRI verification procedure.
407    ///
408    /// * Folds 4 query values: `(v0, v1)`, `(v2, v3)`, `(v4, v5)`, and `(v6, v7)` into a single
409    ///   value `(ne0, ne1)`
410    /// * Computes new value of the domain generator power: `poe' = poe^4`
411    /// * Increments layer pointer (`cptr`) by 2
412    /// * Shifts the stack left to move an item from the overflow table to bottom of stack
413    ///
414    /// ```text,ignore
415    /// [v7, v6, v5, v4, v3, v2, v1, v0, f_pos, d_seg, poe, pe1, pe0, a1, a0, cptr]
416    /// => [t1, t0, s1, s0, df3, df2, df1, df0, poe^2, f_tau, cptr+2, poe^4, f_pos, ne1, ne0, eptr]
417    /// ```
418    ///
419    /// Above, `eptr` is moved from the overflow table and is expected to be the address of the
420    /// final FRI layer.
421    FriExt2Fold4,
422    /// Perform a single step of a random linear combination defining the DEEP composition
423    /// polynomial, i.e. the input to the FRI protocol.
424    ///
425    /// ```text,ignore
426    /// [t7, t6, t5, t4, t3, t2, t1, t0, p1, p0, r1, r0, x_addr, z_addr, a_addr]
427    /// => [t0, t7, t6, t5, t4, t3, t2, t1, p1', p0', r1', r0', x_addr, z_addr+1, a_addr+1]
428    /// ```
429    ///
430    /// Where:
431    ///
432    /// * `tN` stands for the value of the `N`th trace polynomial for the current query, i.e.
433    ///   `tN(x)`
434    /// * `p0` and `p1` stand for an extension field element accumulating the values for the
435    ///   quotients with common denominator `x - z`
436    /// * `r0` and `r1` stand for an extension field element accumulating the values for the
437    ///   quotients with common denominator `x - gz`
438    /// * `x_addr` is the memory address from which we are loading the `tN`s using the `mem_stream`
439    ///   instruction
440    /// * `z_addr` is the memory address to the `N`th OOD evaluations at `z` and `gz`
441    /// * `a_addr` is the memory address of the `N`th random element `alpha_i` used in batching the
442    ///   trace polynomial quotients
443    RCombBase,
444    /// [b1, b0, a1, a0] => [c1, c0]
445    ///
446    /// c1 = (a1 + b1) mod p
447    /// c0 = (a0 + b0) mod p
448    Ext2add,
449    /// [b1, b0, a1, a0] => [c1, c0]
450    ///
451    /// c1 = (a1 - b1) mod p
452    /// c0 = (a0 - b0) mod p
453    Ext2sub,
454    /// [b1, b0, a1, a0] => [c1, c0]
455    ///
456    /// c1 = ((a0 + a1) * (b0 + b1)) mod p
457    /// c0 = ((a0 * b0) - 2(a1 * b1)) mod p
458    Ext2mul,
459    /// [a1, a0] => [a1', a0']
460    ///
461    /// a1' = -a1
462    /// a0' = -a0
463    Ext2neg,
464    /// [a1, a0] => [a1', a0']
465    ///
466    /// a' = a^-1 mod q (where `q` is the extension field prime)
467    ///
468    /// Fails if `a` = 0.
469    Ext2inv,
470    /// [b1, b0, a1, a0] => [c1, c0]
471    ///
472    /// c = a * b^-1
473    ///
474    /// Fails if `b` is 0. Multiplication and inversion are defined by the ops above.
475    Ext2div,
476    /// Pops the top of the stack, and evaluates the ops in
477    /// the block of code corresponding to the branch taken.
478    ///
479    /// If the value is `1`, corresponding to `true`, the first block
480    /// is evaluated. Otherwise, the value must be `0`, corresponding to
481    /// `false`, and the second block is evaluated.
482    If(MasmBlockId, MasmBlockId),
483    /// Pops the top of the stack, and evaluates the given block of
484    /// code if the value is `1`, corresponding to `true`.
485    ///
486    /// Otherwise, the value must be `0`, corresponding to `false`,
487    /// and the block is skipped.
488    While(MasmBlockId),
489    /// Repeatedly evaluates the given block, `n` times.
490    Repeat(u16, MasmBlockId),
491    /// Pops `N` args off the stack, executes the procedure, results will be placed on the stack
492    Exec(FunctionIdent),
493    /// Pops `N` args off the stack, executes the procedure in the root context, results will be
494    /// placed on the stack
495    Syscall(FunctionIdent),
496    /// Pops `N` args off the stack, executes the procedure in a new context, results will be
497    /// placed on the stack
498    Call(FunctionIdent),
499    /// Pops the address (MAST root hash) of a callee off the stack, and dynamically `exec` the
500    /// function
501    DynExec,
502    /// TODO
503    DynCall,
504    /// Pushes the address (MAST root hash) of the given function on the stack, to be used by
505    /// `dynexec` or `dyncall`
506    ProcRef(FunctionIdent),
507    /// Pops `b, a` off the stack, and places the result of `(a + b) mod p` on the stack
508    Add,
509    /// Same as above, but the immediate is used for `b`
510    AddImm(Felt),
511    /// Pops `b, a` off the stack, and places the result of `(a - b) mod p` on the stack
512    Sub,
513    /// Same as above, but the immediate is used for `b`
514    SubImm(Felt),
515    /// Pops `b, a` off the stack, and places the result of `(a * b) mod p` on the stack
516    Mul,
517    /// Same as above, but the immediate is used for `b`
518    MulImm(Felt),
519    /// Pops `b, a` off the stack, and places the result of `(a * b^-1) mod p` on the stack
520    ///
521    /// NOTE: `b` must not be 0
522    Div,
523    /// Same as above, but the immediate is used for `b`
524    DivImm(Felt),
525    /// Pops `a` off the stack, and places the result of `-a mod p` on the stack
526    Neg,
527    /// Pops `a` off the stack, and places the result of `a^-1 mod p` on the stack
528    ///
529    /// NOTE: `a` must not be equal to 0
530    Inv,
531    /// Pops `a` off the stack, and places the result of incrementing it by 1 back on the stack
532    Incr,
533    /// Computes the base 2 logarithm of `a`, rounded down, and places it on the advice stack.
534    Ilog2,
535    /// Pops `a` off the stack, and places the result of `2^a` on the stack
536    ///
537    /// NOTE: `a` must not be > 63
538    Pow2,
539    /// Pops `a` and `b` off the stack, and places the result of `a^b` on the stack
540    ///
541    /// NOTE: `b` must not be > 63
542    Exp,
543    /// Pops `a` off the stack, and places the result of `a^<imm>` on the stack
544    ///
545    /// NOTE: `imm` must not be > 63
546    ExpImm(u8),
547    ExpBitLength(u8),
548    /// Pops `a` off the stack, and places the result of `1 - a` on the stack
549    ///
550    /// NOTE: `a` must be boolean
551    Not,
552    /// Pops `b, a` off the stack, and places the result of `a * b` on the stack
553    ///
554    /// NOTE: `a` must be boolean
555    And,
556    /// Same as above, but `a` is taken from the stack, and `b` is the immediate.
557    ///
558    /// NOTE: `a` must be boolean
559    AndImm(bool),
560    /// Pops `b, a` off the stack, and places the result of `a + b - a * b` on the stack
561    ///
562    /// NOTE: `a` must be boolean
563    Or,
564    /// Same as above, but `a` is taken from the stack, and `b` is the immediate.
565    ///
566    /// NOTE: `a` must be boolean
567    OrImm(bool),
568    /// Pops `b, a` off the stack, and places the result of `a + b - 2 * a * b` on the stack
569    ///
570    /// NOTE: `a` and `b` must be boolean
571    Xor,
572    /// Same as above, but `a` is taken from the stack, and `b` is the immediate.
573    ///
574    /// NOTE: `a` must be boolean
575    XorImm(bool),
576    /// Pops `b, a` off the stack, and places the result of `a == b` on the stack
577    Eq,
578    /// Same as above, but `b` is provided by the immediate
579    EqImm(Felt),
580    /// Pops `b, a` off the stack, and places the result of `a != b` on the stack
581    Neq,
582    /// Same as above, but `b` is provided by the immediate
583    NeqImm(Felt),
584    /// Pops `b, a` off the stack, and places the result of `a > b` on the stack
585    Gt,
586    /// Same as above, but `b` is provided by the immediate
587    GtImm(Felt),
588    /// Pops `b, a` off the stack, and places the result of `a >= b` on the stack
589    Gte,
590    /// Same as above, but `b` is provided by the immediate
591    GteImm(Felt),
592    /// Pops `b, a` off the stack, and places the result of `a < b` on the stack
593    Lt,
594    /// Same as above, but `b` is provided by the immediate
595    LtImm(Felt),
596    /// Pops `b, a` off the stack, and places the result of `a <= b` on the stack
597    Lte,
598    /// Same as above, but `b` is provided by the immediate
599    LteImm(Felt),
600    /// Pops `a` off the stack, and places the 1 on the stack if `a` is odd, else 0
601    IsOdd,
602    /// Pops `B, A` off the stack, and places the result of `A == B` on the stack,
603    /// where the uppercase variables here represent words, rather than field elements.
604    ///
605    /// The comparison works by comparing pairs of elements from each word
606    Eqw,
607    /// Pushes the current depth of the operand stack, on the stack
608    Sdepth,
609    /// When the current procedure is called via `syscall`, this pushes the hash of the caller's
610    /// MAST root on the stack
611    Caller,
612    /// Pushes the current value of the cycle counter (clock) on the stack
613    Clk,
614    /// Peeks `a` from the top of the stack, and places the 1 on the stack if `a < 2^32`, else 0
615    U32Test,
616    /// Peeks `A` from the top of the stack, and places the 1 on the stack if `forall a : A, a <
617    /// 2^32`, else 0
618    U32Testw,
619    /// Peeks `a` from the top of the stack, and traps if `a >= 2^32`
620    U32Assert,
621    /// Peeks `a` from the top of the stack, and traps if `a >= 2^32`, raising the given error code
622    U32AssertWithError(u32),
623    /// Peeks `b, a` from the top of the stack, and traps if either `a` or `b` is >= 2^32
624    U32Assert2,
625    /// Peeks `b, a` from the top of the stack, and traps if either `a` or `b` is >= 2^32, raising
626    /// the given error code
627    U32Assert2WithError(u32),
628    /// Peeks `A` from the top of the stack, and traps unless `forall a : A, a < 2^32`, else 0
629    U32Assertw,
630    /// Peeks `A` from the top of the stack, and traps unless `forall a : A, a < 2^32`, else 0,
631    /// raising the given error code
632    U32AssertwWithError(u32),
633    /// Pops `a` from the top of the stack, and places the result of `a mod 2^32` on the stack
634    ///
635    /// This is used to cast a field element to the u32 range
636    U32Cast,
637    /// Pops `a` from the top of the stack, and splits it into upper and lower 32-bit values,
638    /// placing them back on the stack. The lower part is calculated as `a mod 2^32`,
639    /// and the higher part as `a / 2^32`. The higher part will be on top of the stack after.
640    U32Split,
641    /// Pops `b, a` from the stack, and places the result of `(a + b) mod 2^32` on the stack,
642    /// followed by 1 if `(a + b) >= 2^32`, else 0. Thus the first item on the stack will be
643    /// a boolean indicating whether the arithmetic overflowed, and the second will be the
644    /// result of the addition.
645    ///
646    /// The behavior is undefined if either `b` or `a` are >= 2^32
647    U32OverflowingAdd,
648    /// Same as above, but with `b` provided by the immediate
649    U32OverflowingAddImm(u32),
650    /// Pops `b, a` from the stack, and places the result of `(a + b) mod 2^32` on the stack.
651    ///
652    /// The behavior is undefined if either `b` or `a` are >= 2^32
653    U32WrappingAdd,
654    /// Same as above, but with `b` provided by the immediate
655    U32WrappingAddImm(u32),
656    /// Pops `c, b, a` from the stack, adds them together, and splits the result into higher
657    /// and lower parts. The lower part is calculated as `(a + b + c) mod 2^32`,
658    /// the higher part as `(a + b + c) / 2^32`.
659    ///
660    /// The behavior is undefined if any of `c`, `b` or `a` are >= 2^32
661    U32OverflowingAdd3,
662    /// Pops `c, b, a` from the stack, adds them together, and splits the result into higher
663    /// and lower parts. The lower part is calculated as `(a + b + c) mod 2^32`,
664    /// the higher part as `(a + b + c) / 2^32`.
665    ///
666    /// The behavior is undefined if any of `c`, `b` or `a` are >= 2^32
667    U32WrappingAdd3,
668    /// Pops `b, a` from the stack, and places the result of `(a - b) mod 2^32` on the stack,
669    /// followed by 1 if `a < b`, else 0. Thus the first item on the stack will be
670    /// a boolean indicating whether the arithmetic underflowed, and the second will be the
671    /// result of the subtraction.
672    ///
673    /// The behavior is undefined if either `b` or `a` are >= 2^32
674    U32OverflowingSub,
675    /// Same as above, but with `b` provided by the immediate
676    U32OverflowingSubImm(u32),
677    /// Pops `b, a` from the stack, and places the result of `(a - b) mod 2^32` on the stack.
678    ///
679    /// The behavior is undefined if either `b` or `a` are >= 2^32
680    U32WrappingSub,
681    /// Same as above, but with `b` provided by the immediate
682    U32WrappingSubImm(u32),
683    /// Pops `b, a` from the stack, and places the result of `(a * b) mod 2^32` on the stack,
684    /// followed by `(a * b) / 2^32`. Thus the first item on the stack will be the number
685    /// of times the multiplication overflowed, followed by the result.
686    ///
687    /// The behavior is undefined if either `b` or `a` are >= 2^32
688    U32OverflowingMul,
689    /// Same as above, but with `b` provided by the immediate
690    U32OverflowingMulImm(u32),
691    /// Pops `b, a` from the stack, and places the result of `(a * b) mod 2^32` on the stack.
692    ///
693    /// The behavior is undefined if either `b` or `a` are >= 2^32
694    U32WrappingMul,
695    /// Same as above, but with `b` provided by the immediate
696    U32WrappingMulImm(u32),
697    /// Pops `c, b, a` off the stack, and calculates `d = c * b + a`, then splits the result
698    /// into higher and lower parts, the lower given by `d mod 2^32`, the higher by `d / 2^32`,
699    /// and pushes them back on the stack, with the higher part on top of the stack at the end.
700    ///
701    /// Behavior is undefined if any of `a`, `b`, or `c` are >= 2^32
702    U32OverflowingMadd,
703    /// Pops `c, b, a` off the stack, and pushes `(c * a + b) mod 2^32` on the stack.
704    ///
705    /// Behavior is undefined if any of `a`, `b`, or `c` are >= 2^32
706    U32WrappingMadd,
707    /// Pops `b, a` off the stack, and pushes `a / b` on the stack.
708    ///
709    /// This operation traps if `b` is zero.
710    ///
711    /// This operation is unchecked, so the result is undefined if the operands are not valid u32
712    U32Div,
713    /// Same as above, except `b` is provided by the immediate
714    U32DivImm(u32),
715    /// Pops `b, a` off the stack, and pushes `a mod b` on the stack.
716    ///
717    /// This operation traps if `b` is zero.
718    ///
719    /// This operation is unchecked, so the result is undefined if the operands are not valid u32
720    U32Mod,
721    /// Same as above, except `b` is provided by the immediate
722    U32ModImm(u32),
723    /// Pops `b, a` off the stack, and first pushes `a / b` on the stack, followed by `a mod b`.
724    ///
725    /// This operation traps if `b` is zero.
726    ///
727    /// This operation is unchecked, so the result is undefined if the operands are not valid u32
728    U32DivMod,
729    /// Same as above, except `b` is provided by the immediate
730    U32DivModImm(u32),
731    /// Pops `b, a` off the stack, and places the bitwise AND of `a` and `b` on the stack.
732    ///
733    /// Traps if either `a` or `b` >= 2^32
734    U32And,
735    /// Pops `b, a` off the stack, and places the bitwise OR of `a` and `b` on the stack.
736    ///
737    /// Traps if either `a` or `b` >= 2^32
738    U32Or,
739    /// Pops `b, a` off the stack, and places the bitwise XOR of `a` and `b` on the stack.
740    ///
741    /// Traps if either `a` or `b` >= 2^32
742    U32Xor,
743    /// Pops `a` off the stack, and places the bitwise NOT of `a` on the stack.
744    ///
745    /// Traps if `a >= 2^32`
746    U32Not,
747    /// Pops `b, a` off the stack, and places the result of `(a * 2^b) mod 2^32` on the stack.
748    ///
749    /// Truncates if the shift would cause overflow.
750    ///
751    /// This operation is unchecked, so the result is undefined if the operands are not valid u32
752    U32Shl,
753    /// Same as above, except `b` is provided by the immediate
754    U32ShlImm(u32),
755    /// Pops `b, a` off the stack, and places the result of `a / 2^b` on the stack.
756    ///
757    /// Truncates if the shift would cause overflow.
758    ///
759    /// This operation is unchecked, so the result is undefined if the operands are not valid u32
760    U32Shr,
761    /// Same as above, except `b` is provided by the immediate
762    U32ShrImm(u32),
763    /// Pops `b, a` off the stack, and places the result of rotating the 32-bit
764    /// representation of `a` to the left by `b` bits.
765    ///
766    /// This operation is unchecked, so the result is undefined if the operands are not valid u32
767    U32Rotl,
768    /// Same as above, except `b` is provided by the immediate
769    U32RotlImm(u32),
770    /// Pops `b, a` off the stack, and places the result of rotating the 32-bit
771    /// representation of `a` to the right by `b` bits.
772    ///
773    /// This operation is unchecked, so the result is undefined if the operands are not valid u32
774    U32Rotr,
775    /// Same as above, except `b` is provided by the immediate
776    U32RotrImm(u32),
777    /// Pops `a` off the stack, and places the number of set bits in `a` (it's hamming weight).
778    ///
779    /// This operation is unchecked, so the result is undefined if the operands are not valid u32
780    U32Popcnt,
781    /// Computes the number of leading zero bits in `a`, and places it on the advice stack
782    ///
783    /// This operation is unchecked, so the result is undefined if the operands are not valid u32
784    U32Clz,
785    /// Computes the number of trailing zero bits in `a`, and places it on the advice stack
786    ///
787    /// This operation is unchecked, so the result is undefined if the operands are not valid u32
788    U32Ctz,
789    /// Computes the number of leading one bits in `a`, and places it on the advice stack
790    ///
791    /// This operation is unchecked, so the result is undefined if the operands are not valid u32
792    U32Clo,
793    /// Computes the number of trailing one bits in `a`, and places it on the advice stack
794    ///
795    /// This operation is unchecked, so the result is undefined if the operands are not valid u32
796    U32Cto,
797    /// Pops `b, a` from the stack, and places 1 on the stack if `a < b`, else 0
798    ///
799    /// This operation is unchecked, so the result is undefined if the operands are not valid u32
800    U32Lt,
801    /// Same as above, but `b` is provided by the immediate
802    U32LtImm(u32),
803    /// Pops `b, a` from the stack, and places 1 on the stack if `a <= b`, else 0
804    ///
805    /// This operation is unchecked, so the result is undefined if the operands are not valid u32
806    U32Lte,
807    /// Same as above, but `b` is provided by the immediate
808    U32LteImm(u32),
809    /// Pops `b, a` from the stack, and places 1 on the stack if `a > b`, else 0
810    ///
811    /// This operation is unchecked, so the result is undefined if the operands are not valid u32
812    U32Gt,
813    /// Same as above, but `b` is provided by the immediate
814    U32GtImm(u32),
815    /// Pops `b, a` from the stack, and places 1 on the stack if `a >= b`, else 0
816    ///
817    /// This operation is unchecked, so the result is undefined if the operands are not valid u32
818    U32Gte,
819    /// Same as above, but `b` is provided by the immediate
820    U32GteImm(u32),
821    /// Pops `b, a` from the stack, and places `a` back on the stack if `a < b`, else `b`
822    ///
823    /// This operation is unchecked, so the result is undefined if the operands are not valid u32
824    U32Min,
825    /// Same as above, but `b` is provided by the immediate
826    U32MinImm(u32),
827    /// Pops `b, a` from the stack, and places `a` back on the stack if `a > b`, else `b`
828    ///
829    /// This operation is unchecked, so the result is undefined if the operands are not valid u32
830    U32Max,
831    /// Same as above, but `b` is provided by the immediate
832    U32MaxImm(u32),
833    /// Trigger a breakpoint when this instruction is reached
834    Breakpoint,
835    /// Print out the contents of the stack
836    DebugStack,
837    /// Print out the top `n` contents of the stack
838    DebugStackN(u8),
839    /// Print out the entire contents of RAM
840    DebugMemory,
841    /// Print out the contents of RAM starting at address `n`
842    DebugMemoryAt(u32),
843    /// Print out the contents of RAM in the range `n..=m`
844    DebugMemoryRange(u32, u32),
845    /// Print out the local memory for the current procedure
846    DebugFrame,
847    /// Print out the local memory for the current procedure starting at index `n`
848    DebugFrameAt(u16),
849    /// Print out the local memory for the current procedure for indices in the range `n..=m`
850    DebugFrameRange(u16, u16),
851    /// Emit an event with the given event code
852    Emit(u32),
853    /// Emit a trace event with the given code
854    Trace(u32),
855    /// No operation
856    Nop,
857}
858
859macro_rules! unwrap_imm {
860    ($imm:ident) => {{
861        match $imm {
862            miden_assembly::ast::Immediate::Value(imm) => imm.into_inner(),
863            miden_assembly::ast::Immediate::Constant(id) => {
864                panic!("invalid reference to constant definition: '{id}'")
865            }
866        }
867    }};
868}
869
870macro_rules! unwrap_u32 {
871    ($imm:ident) => {{
872        match $imm {
873            miden_assembly::ast::Immediate::Value(imm) => imm.into_inner(),
874            miden_assembly::ast::Immediate::Constant(id) => {
875                panic!("invalid reference to constant definition: '{id}'")
876            }
877        }
878    }};
879}
880
881macro_rules! unwrap_u16 {
882    ($imm:ident) => {{
883        match $imm {
884            miden_assembly::ast::Immediate::Value(imm) => imm.into_inner(),
885            miden_assembly::ast::Immediate::Constant(id) => {
886                panic!("invalid reference to constant definition: '{id}'")
887            }
888        }
889    }};
890}
891
892macro_rules! unwrap_u8 {
893    ($imm:ident) => {{
894        match $imm {
895            miden_assembly::ast::Immediate::Value(imm) => imm.into_inner(),
896            miden_assembly::ast::Immediate::Constant(id) => {
897                panic!("invalid reference to constant definition: '{id}'")
898            }
899        }
900    }};
901}
902
903impl MasmOp {
904    pub fn has_regions(&self) -> bool {
905        matches!(self, Self::If(_, _) | Self::While(_) | Self::Repeat(_, _))
906    }
907
908    /// The cost of this instruction in cycles
909    pub fn cost(&self) -> usize {
910        match self {
911            Self::Padw => 4,
912            Self::Push(_) | Self::PushU8(_) | Self::PushU16(_) | Self::PushU32(_) => 1,
913            Self::Push2(_) => 2,
914            Self::Pushw(_) => 4,
915            Self::Drop => 1,
916            Self::Dropw => 4,
917            Self::Dup(8) | Self::Dup(10) | Self::Dup(12) | Self::Dup(14) => 3,
918            Self::Dup(_) => 1,
919            Self::Dupw(_) => 4,
920            Self::Swap(1) => 1,
921            Self::Swap(2..=8) => 2,
922            Self::Swap(_) => 6,
923            Self::Swapw(_) | Self::Swapdw => 1,
924            Self::Movup(2..=8) => 1,
925            Self::Movup(_) => 4,
926            Self::Movupw(2) => 2,
927            Self::Movupw(_) => 3,
928            Self::Movdn(2..=8) => 1,
929            Self::Movdn(_) => 4,
930            Self::Movdnw(2) => 2,
931            Self::Movdnw(_) => 3,
932            Self::Cswap => 1,
933            Self::Cswapw => 1,
934            Self::Cdrop => 2,
935            Self::Cdropw => 5,
936            Self::Assert | Self::AssertWithError(_) => 1,
937            Self::Assertz | Self::AssertzWithError(_) => 2,
938            Self::AssertEq | Self::AssertEqWithError(_) => 2,
939            Self::AssertEqw | Self::AssertEqwWithError(_) => 11,
940            Self::LocAddr(_) => 2,
941            Self::LocStore(id) if id.as_usize() == 1 => 5,
942            Self::LocStore(_) => 4,
943            Self::LocStorew(id) if id.as_usize() == 1 => 4,
944            Self::LocStorew(_) => 3,
945            Self::LocLoad(id) | Self::LocLoadw(id) if id.as_usize() == 1 => 4,
946            Self::LocLoad(_) | Self::LocLoadw(_) => 3,
947            Self::MemLoad | Self::MemLoadw => 1,
948            Self::MemLoadImm(_) | Self::MemLoadwImm(_) => 2,
949            Self::MemStore => 2,
950            Self::MemStoreImm(1) => 4,
951            Self::MemStoreImm(_) => 3,
952            Self::MemStorew => 1,
953            Self::MemStorewImm(1) => 3,
954            Self::MemStorewImm(_) => 2,
955            Self::MemStream => 1,
956            Self::AdvPipe => 1,
957            Self::AdvPush(n) => *n as usize,
958            Self::AdvLoadw => 1,
959            // This is based on cycle counts gathered from a simple program that compares a
960            // cdrop-based conditional select to an if-based one, where the only
961            // difference is the `cdrop` and `if` instructions. The `cdrop` solution
962            // was 39 cycles, the `if` solution was 49, with `cdrop` taking 2 cycles,
963            // this gives us a difference of 10 cycles, hence 12 for our cost.
964            Self::If(..) => 12,
965            // The cost for `while` appears to be the same as `if`, however comparisons are tricky
966            // as we can only really compare to `repeat`, which has no apparent cost
967            Self::While(_) => 12,
968            // Comparing a small program with `repeat.1` vs without the `repeat.1` (simply using the
969            // body of the `repeat` instead), there is no apparent cycle cost. We give
970            // it a cost of 0 to reflect that using `repeat` is no different than
971            // copying its body `N` times.
972            Self::Repeat(..) => 0,
973            Self::ProcRef(_) => 4,
974            Self::Exec(_) => 2,
975            // A `call` appears to have the same overhead as `if` and `while`
976            Self::Call(_) | Self::Syscall(_) => 12,
977            // A `dynexec` appears to be 8 cycles, based on comparisons against `exec`, with an
978            // extra `dropw` in the callee that we deduct from the cycle count
979            Self::DynExec => 8,
980            // A `dyncall` requires an additional 8 cycles compared to `dynexec`
981            Self::DynCall => 16,
982            Self::Add | Self::Sub | Self::Mul => 1,
983            Self::AddImm(imm) => match imm.as_int() {
984                0 => 0,
985                1 => 1,
986                _ => 2,
987            },
988            Self::SubImm(imm) | Self::MulImm(imm) => match imm.as_int() {
989                0 => 0,
990                _ => 2,
991            },
992            Self::Div => 2,
993            Self::DivImm(imm) => match imm.as_int() {
994                1 => 0,
995                _ => 2,
996            },
997            Self::Neg | Self::Inv | Self::Incr => 1,
998            Self::Ilog2 => 44,
999            Self::Pow2 => 16,
1000            // The cost of this instruction is 9 + log2(b), but we don't know `b`, so we use a value
1001            // of 32 to estimate average cost
1002            Self::Exp => 9 + 32usize.ilog2() as usize,
1003            Self::ExpImm(0) => 3,
1004            Self::ExpImm(1) => 1,
1005            Self::ExpImm(2) => 2,
1006            Self::ExpImm(3) => 4,
1007            Self::ExpImm(4) => 6,
1008            Self::ExpImm(5) => 8,
1009            Self::ExpImm(6) => 10,
1010            Self::ExpImm(7) => 12,
1011            Self::ExpImm(imm) | Self::ExpBitLength(imm) => {
1012                9 + unsafe { f64::from(*imm).log2().ceil().to_int_unchecked::<usize>() }
1013            }
1014            Self::Not | Self::And | Self::Or => 1,
1015            Self::AndImm(_) | Self::OrImm(_) => 2,
1016            Self::Xor => 7,
1017            Self::XorImm(_) => 8,
1018            Self::Eq => 1,
1019            Self::EqImm(imm) => match imm.as_int() {
1020                0 => 1,
1021                _ => 2,
1022            },
1023            Self::Neq => 2,
1024            Self::NeqImm(imm) => match imm.as_int() {
1025                0 => 1,
1026                _ => 3,
1027            },
1028            Self::Gt => 15,
1029            Self::GtImm(_) => 16,
1030            Self::Gte => 16,
1031            Self::GteImm(_) => 17,
1032            Self::Lt => 14,
1033            Self::LtImm(_) => 15,
1034            Self::Lte => 15,
1035            Self::LteImm(_) => 16,
1036            Self::IsOdd => 5,
1037            Self::Eqw => 15,
1038            Self::Hash => 20,
1039            Self::Hmerge => 16,
1040            Self::Hperm => 1,
1041            Self::MtreeGet => 9,
1042            Self::MtreeSet => 29,
1043            Self::MtreeMerge => 16,
1044            Self::MtreeVerify | Self::MtreeVerifyWithError(_) => 1,
1045            // This hasn't been measured, just a random guess due to the complexity
1046            Self::FriExt2Fold4 | Self::RCombBase => 50,
1047            Self::Ext2add => 5,
1048            Self::Ext2sub => 7,
1049            Self::Ext2mul => 3,
1050            Self::Ext2neg => 4,
1051            Self::Ext2inv => 8,
1052            Self::Ext2div => 11,
1053            Self::Clk | Self::Caller | Self::Sdepth => 1,
1054            Self::U32Test => 5,
1055            Self::U32Testw => 23,
1056            Self::U32Assert | Self::U32AssertWithError(_) => 3,
1057            Self::U32Assert2 | Self::U32Assert2WithError(_) => 1,
1058            Self::U32Assertw | Self::U32AssertwWithError(_) => 6,
1059            Self::U32Cast => 2,
1060            Self::U32Split => 1,
1061            Self::U32OverflowingAdd => 1,
1062            Self::U32OverflowingAddImm(_) => 2,
1063            Self::U32WrappingAdd => 2,
1064            Self::U32WrappingAddImm(_) => 3,
1065            Self::U32OverflowingAdd3 => 1,
1066            Self::U32WrappingAdd3 => 2,
1067            Self::U32OverflowingSub => 1,
1068            Self::U32OverflowingSubImm(_) => 2,
1069            Self::U32WrappingSub => 2,
1070            Self::U32WrappingSubImm(_) => 3,
1071            Self::U32OverflowingMul => 1,
1072            Self::U32OverflowingMulImm(_) => 2,
1073            Self::U32WrappingMul => 2,
1074            Self::U32WrappingMulImm(_) => 3,
1075            Self::U32OverflowingMadd => 1,
1076            Self::U32WrappingMadd => 2,
1077            Self::U32Div => 2,
1078            Self::U32DivImm(_) => 3,
1079            Self::U32Mod => 3,
1080            Self::U32ModImm(_) => 4,
1081            Self::U32DivMod => 1,
1082            Self::U32DivModImm(_) => 2,
1083            Self::U32And => 1,
1084            Self::U32Or => 6,
1085            Self::U32Xor => 1,
1086            Self::U32Not => 5,
1087            Self::U32Shl => 18,
1088            Self::U32ShlImm(0) => 0,
1089            Self::U32ShlImm(_) => 3,
1090            Self::U32Shr => 18,
1091            Self::U32ShrImm(0) => 0,
1092            Self::U32ShrImm(_) => 3,
1093            Self::U32Rotl => 18,
1094            Self::U32RotlImm(0) => 0,
1095            Self::U32RotlImm(_) => 3,
1096            Self::U32Rotr => 22,
1097            Self::U32RotrImm(0) => 0,
1098            Self::U32RotrImm(_) => 3,
1099            Self::U32Popcnt => 33,
1100            Self::U32Clz => 37,
1101            Self::U32Ctz => 34,
1102            Self::U32Clo => 36,
1103            Self::U32Cto => 33,
1104            Self::U32Lt => 3,
1105            Self::U32LtImm(_) => 4,
1106            Self::U32Lte => 5,
1107            Self::U32LteImm(_) => 6,
1108            Self::U32Gt => 4,
1109            Self::U32GtImm(_) => 5,
1110            Self::U32Gte => 4,
1111            Self::U32GteImm(_) => 5,
1112            Self::U32Min => 8,
1113            Self::U32MinImm(_) => 9,
1114            Self::U32Max => 9,
1115            Self::U32MaxImm(_) => 10,
1116            // These instructions do not modify the VM state, so we place set their cost at 0 for
1117            // now
1118            Self::Emit(_)
1119            | Self::Trace(_)
1120            | Self::AdvInjectPushU64Div
1121            | Self::AdvInjectPushMapVal
1122            | Self::AdvInjectPushMapValImm(_)
1123            | Self::AdvInjectPushMapValN
1124            | Self::AdvInjectPushMapValNImm(_)
1125            | Self::AdvInjectPushMTreeNode
1126            | Self::AdvInjectInsertMem
1127            | Self::AdvInjectInsertHdword
1128            | Self::AdvInjectInsertHdwordImm(_)
1129            | Self::AdvInjectInsertHperm
1130            | Self::AdvInjectPushSignature(_)
1131            | Self::DebugStack
1132            | Self::DebugStackN(_)
1133            | Self::DebugMemory
1134            | Self::DebugMemoryAt(_)
1135            | Self::DebugMemoryRange(..)
1136            | Self::DebugFrame
1137            | Self::DebugFrameAt(_)
1138            | Self::DebugFrameRange(..)
1139            | Self::Breakpoint
1140            | Self::Nop => 0,
1141        }
1142    }
1143
1144    pub fn from_masm(
1145        current_module: Ident,
1146        ix: miden_assembly::ast::Instruction,
1147    ) -> SmallVec<[Self; 2]> {
1148        use miden_assembly::ast::{Instruction, InvocationTarget};
1149
1150        use crate::Symbol;
1151
1152        let op = match ix {
1153            Instruction::Assert => Self::Assert,
1154            Instruction::AssertWithError(code) => Self::AssertWithError(unwrap_u32!(code)),
1155            Instruction::AssertEq => Self::AssertEq,
1156            Instruction::AssertEqWithError(code) => Self::AssertEqWithError(unwrap_u32!(code)),
1157            Instruction::AssertEqw => Self::AssertEqw,
1158            Instruction::AssertEqwWithError(code) => Self::AssertEqwWithError(unwrap_u32!(code)),
1159            Instruction::Assertz => Self::Assertz,
1160            Instruction::AssertzWithError(code) => Self::AssertzWithError(unwrap_u32!(code)),
1161            Instruction::Add => Self::Add,
1162            Instruction::AddImm(imm) => Self::AddImm(unwrap_imm!(imm)),
1163            Instruction::Sub => Self::Sub,
1164            Instruction::SubImm(imm) => Self::SubImm(unwrap_imm!(imm)),
1165            Instruction::Mul => Self::Mul,
1166            Instruction::MulImm(imm) => Self::MulImm(unwrap_imm!(imm)),
1167            Instruction::Div => Self::Div,
1168            Instruction::DivImm(imm) => Self::DivImm(unwrap_imm!(imm)),
1169            Instruction::Neg => Self::Neg,
1170            Instruction::Inv => Self::Inv,
1171            Instruction::Incr => Self::Incr,
1172            Instruction::ILog2 => Self::Ilog2,
1173            Instruction::Pow2 => Self::Pow2,
1174            Instruction::Exp => Self::Exp,
1175            Instruction::ExpImm(imm) => {
1176                Self::ExpImm(unwrap_imm!(imm).as_int().try_into().expect("invalid exponent"))
1177            }
1178            Instruction::ExpBitLength(imm) => Self::ExpBitLength(imm),
1179            Instruction::Not => Self::Not,
1180            Instruction::And => Self::And,
1181            Instruction::Or => Self::Or,
1182            Instruction::Xor => Self::Xor,
1183            Instruction::Eq => Self::Eq,
1184            Instruction::EqImm(imm) => Self::EqImm(unwrap_imm!(imm)),
1185            Instruction::Neq => Self::Neq,
1186            Instruction::NeqImm(imm) => Self::NeqImm(unwrap_imm!(imm)),
1187            Instruction::Eqw => Self::Eqw,
1188            Instruction::Lt => Self::Lt,
1189            Instruction::Lte => Self::Lte,
1190            Instruction::Gt => Self::Gt,
1191            Instruction::Gte => Self::Gte,
1192            Instruction::IsOdd => Self::IsOdd,
1193            Instruction::Hash => Self::Hash,
1194            Instruction::HMerge => Self::Hmerge,
1195            Instruction::HPerm => Self::Hperm,
1196            Instruction::MTreeGet => Self::MtreeGet,
1197            Instruction::MTreeSet => Self::MtreeSet,
1198            Instruction::MTreeMerge => Self::MtreeMerge,
1199            Instruction::MTreeVerify => Self::MtreeVerify,
1200            Instruction::MTreeVerifyWithError(code) => {
1201                Self::MtreeVerifyWithError(unwrap_u32!(code))
1202            }
1203            Instruction::Ext2Add => Self::Ext2add,
1204            Instruction::Ext2Sub => Self::Ext2sub,
1205            Instruction::Ext2Mul => Self::Ext2mul,
1206            Instruction::Ext2Div => Self::Ext2div,
1207            Instruction::Ext2Neg => Self::Ext2neg,
1208            Instruction::Ext2Inv => Self::Ext2inv,
1209            Instruction::FriExt2Fold4 => Self::FriExt2Fold4,
1210            Instruction::RCombBase => Self::RCombBase,
1211            Instruction::U32Test => Self::U32Test,
1212            Instruction::U32TestW => Self::U32Testw,
1213            Instruction::U32Assert => Self::U32Assert,
1214            Instruction::U32AssertWithError(code) => Self::U32AssertWithError(unwrap_u32!(code)),
1215            Instruction::U32Assert2 => Self::U32Assert2,
1216            Instruction::U32Assert2WithError(code) => Self::U32Assert2WithError(unwrap_u32!(code)),
1217            Instruction::U32AssertW => Self::U32Assertw,
1218            Instruction::U32AssertWWithError(code) => Self::U32AssertwWithError(unwrap_u32!(code)),
1219            Instruction::U32Split => Self::U32Split,
1220            Instruction::U32Cast => Self::U32Cast,
1221            Instruction::U32WrappingAdd => Self::U32WrappingAdd,
1222            Instruction::U32WrappingAddImm(imm) => Self::U32WrappingAddImm(unwrap_u32!(imm)),
1223            Instruction::U32OverflowingAdd => Self::U32OverflowingAdd,
1224            Instruction::U32OverflowingAddImm(imm) => Self::U32OverflowingAddImm(unwrap_u32!(imm)),
1225            Instruction::U32OverflowingAdd3 => Self::U32OverflowingAdd3,
1226            Instruction::U32WrappingAdd3 => Self::U32WrappingAdd3,
1227            Instruction::U32WrappingSub => Self::U32WrappingSub,
1228            Instruction::U32WrappingSubImm(imm) => Self::U32WrappingSubImm(unwrap_u32!(imm)),
1229            Instruction::U32OverflowingSub => Self::U32OverflowingSub,
1230            Instruction::U32OverflowingSubImm(imm) => Self::U32OverflowingSubImm(unwrap_u32!(imm)),
1231            Instruction::U32WrappingMul => Self::U32WrappingMul,
1232            Instruction::U32WrappingMulImm(imm) => Self::U32WrappingMulImm(unwrap_u32!(imm)),
1233            Instruction::U32OverflowingMul => Self::U32OverflowingMul,
1234            Instruction::U32OverflowingMulImm(imm) => Self::U32OverflowingMulImm(unwrap_u32!(imm)),
1235            Instruction::U32OverflowingMadd => Self::U32OverflowingMadd,
1236            Instruction::U32WrappingMadd => Self::U32WrappingMadd,
1237            Instruction::U32Div => Self::U32Div,
1238            Instruction::U32DivImm(imm) => Self::U32DivImm(unwrap_u32!(imm)),
1239            Instruction::U32Mod => Self::U32Mod,
1240            Instruction::U32ModImm(imm) => Self::U32ModImm(unwrap_u32!(imm)),
1241            Instruction::U32DivMod => Self::U32DivMod,
1242            Instruction::U32DivModImm(imm) => Self::U32DivModImm(unwrap_u32!(imm)),
1243            Instruction::U32And => Self::U32And,
1244            Instruction::U32Or => Self::U32Or,
1245            Instruction::U32Xor => Self::U32Xor,
1246            Instruction::U32Not => Self::U32Not,
1247            Instruction::U32Shr => Self::U32Shr,
1248            Instruction::U32ShrImm(imm) => Self::U32ShrImm(unwrap_u8!(imm) as u32),
1249            Instruction::U32Shl => Self::U32Shl,
1250            Instruction::U32ShlImm(imm) => Self::U32ShlImm(unwrap_u8!(imm) as u32),
1251            Instruction::U32Rotr => Self::U32Rotr,
1252            Instruction::U32RotrImm(imm) => Self::U32RotrImm(unwrap_u8!(imm) as u32),
1253            Instruction::U32Rotl => Self::U32Rotl,
1254            Instruction::U32RotlImm(imm) => Self::U32RotlImm(unwrap_u8!(imm) as u32),
1255            Instruction::U32Popcnt => Self::U32Popcnt,
1256            Instruction::U32Clz => Self::U32Clz,
1257            Instruction::U32Ctz => Self::U32Ctz,
1258            Instruction::U32Clo => Self::U32Clo,
1259            Instruction::U32Cto => Self::U32Cto,
1260            Instruction::U32Lt => Self::U32Lt,
1261            Instruction::U32Lte => Self::U32Lte,
1262            Instruction::U32Gt => Self::U32Gt,
1263            Instruction::U32Gte => Self::U32Gte,
1264            Instruction::U32Min => Self::U32Min,
1265            Instruction::U32Max => Self::U32Max,
1266            Instruction::Drop => Self::Drop,
1267            Instruction::DropW => Self::Dropw,
1268            Instruction::PadW => Self::Padw,
1269            Instruction::Dup0 => Self::Dup(0),
1270            Instruction::Dup1 => Self::Dup(1),
1271            Instruction::Dup2 => Self::Dup(2),
1272            Instruction::Dup3 => Self::Dup(3),
1273            Instruction::Dup4 => Self::Dup(4),
1274            Instruction::Dup5 => Self::Dup(5),
1275            Instruction::Dup6 => Self::Dup(6),
1276            Instruction::Dup7 => Self::Dup(7),
1277            Instruction::Dup8 => Self::Dup(8),
1278            Instruction::Dup9 => Self::Dup(9),
1279            Instruction::Dup10 => Self::Dup(10),
1280            Instruction::Dup11 => Self::Dup(11),
1281            Instruction::Dup12 => Self::Dup(12),
1282            Instruction::Dup13 => Self::Dup(13),
1283            Instruction::Dup14 => Self::Dup(14),
1284            Instruction::Dup15 => Self::Dup(15),
1285            Instruction::DupW0 => Self::Dupw(0),
1286            Instruction::DupW1 => Self::Dupw(1),
1287            Instruction::DupW2 => Self::Dupw(2),
1288            Instruction::DupW3 => Self::Dupw(3),
1289            Instruction::Swap1 => Self::Swap(1),
1290            Instruction::Swap2 => Self::Swap(2),
1291            Instruction::Swap3 => Self::Swap(3),
1292            Instruction::Swap4 => Self::Swap(4),
1293            Instruction::Swap5 => Self::Swap(5),
1294            Instruction::Swap6 => Self::Swap(6),
1295            Instruction::Swap7 => Self::Swap(7),
1296            Instruction::Swap8 => Self::Swap(8),
1297            Instruction::Swap9 => Self::Swap(9),
1298            Instruction::Swap10 => Self::Swap(10),
1299            Instruction::Swap11 => Self::Swap(11),
1300            Instruction::Swap12 => Self::Swap(12),
1301            Instruction::Swap13 => Self::Swap(13),
1302            Instruction::Swap14 => Self::Swap(14),
1303            Instruction::Swap15 => Self::Swap(15),
1304            Instruction::SwapW1 => Self::Swapw(1),
1305            Instruction::SwapW2 => Self::Swapw(2),
1306            Instruction::SwapW3 => Self::Swapw(3),
1307            Instruction::SwapDw => Self::Swapdw,
1308            Instruction::MovUp2 => Self::Movup(2),
1309            Instruction::MovUp3 => Self::Movup(3),
1310            Instruction::MovUp4 => Self::Movup(4),
1311            Instruction::MovUp5 => Self::Movup(5),
1312            Instruction::MovUp6 => Self::Movup(6),
1313            Instruction::MovUp7 => Self::Movup(7),
1314            Instruction::MovUp8 => Self::Movup(8),
1315            Instruction::MovUp9 => Self::Movup(9),
1316            Instruction::MovUp10 => Self::Movup(10),
1317            Instruction::MovUp11 => Self::Movup(11),
1318            Instruction::MovUp12 => Self::Movup(12),
1319            Instruction::MovUp13 => Self::Movup(13),
1320            Instruction::MovUp14 => Self::Movup(14),
1321            Instruction::MovUp15 => Self::Movup(15),
1322            Instruction::MovUpW2 => Self::Movupw(2),
1323            Instruction::MovUpW3 => Self::Movupw(3),
1324            Instruction::MovDn2 => Self::Movdn(2),
1325            Instruction::MovDn3 => Self::Movdn(3),
1326            Instruction::MovDn4 => Self::Movdn(4),
1327            Instruction::MovDn5 => Self::Movdn(5),
1328            Instruction::MovDn6 => Self::Movdn(6),
1329            Instruction::MovDn7 => Self::Movdn(7),
1330            Instruction::MovDn8 => Self::Movdn(8),
1331            Instruction::MovDn9 => Self::Movdn(9),
1332            Instruction::MovDn10 => Self::Movdn(10),
1333            Instruction::MovDn11 => Self::Movdn(11),
1334            Instruction::MovDn12 => Self::Movdn(12),
1335            Instruction::MovDn13 => Self::Movdn(13),
1336            Instruction::MovDn14 => Self::Movdn(14),
1337            Instruction::MovDn15 => Self::Movdn(15),
1338            Instruction::MovDnW2 => Self::Movdnw(2),
1339            Instruction::MovDnW3 => Self::Movdnw(3),
1340            Instruction::CSwap => Self::Cswap,
1341            Instruction::CSwapW => Self::Cswapw,
1342            Instruction::CDrop => Self::Cdrop,
1343            Instruction::CDropW => Self::Cdropw,
1344            Instruction::Push(elem) => Self::Push(unwrap_imm!(elem)),
1345            Instruction::PushU8(elem) => Self::PushU8(elem),
1346            Instruction::PushU16(elem) => Self::PushU16(elem),
1347            Instruction::PushU32(elem) => Self::PushU32(elem),
1348            Instruction::PushFelt(elem) => Self::Push(elem),
1349            Instruction::PushWord(word) => Self::Pushw(word),
1350            Instruction::PushU8List(u8s) => return u8s.into_iter().map(Self::PushU8).collect(),
1351            Instruction::PushU16List(u16s) => return u16s.into_iter().map(Self::PushU16).collect(),
1352            Instruction::PushU32List(u32s) => return u32s.into_iter().map(Self::PushU32).collect(),
1353            Instruction::PushFeltList(felts) => return felts.into_iter().map(Self::Push).collect(),
1354            Instruction::Locaddr(id) => Self::LocAddr(LocalId::from_u16(unwrap_u16!(id))),
1355            Instruction::LocStore(id) => Self::LocStore(LocalId::from_u16(unwrap_u16!(id))),
1356            Instruction::LocStoreW(id) => Self::LocStorew(LocalId::from_u16(unwrap_u16!(id))),
1357            Instruction::Clk => Self::Clk,
1358            Instruction::MemLoad => Self::MemLoad,
1359            Instruction::MemLoadImm(addr) => Self::MemLoadImm(unwrap_u32!(addr)),
1360            Instruction::MemLoadW => Self::MemLoadw,
1361            Instruction::MemLoadWImm(addr) => Self::MemLoadwImm(unwrap_u32!(addr)),
1362            Instruction::MemStore => Self::MemStore,
1363            Instruction::MemStoreImm(addr) => Self::MemStoreImm(unwrap_u32!(addr)),
1364            Instruction::MemStoreW => Self::MemStorew,
1365            Instruction::MemStoreWImm(addr) => Self::MemStorewImm(unwrap_u32!(addr)),
1366            Instruction::LocLoad(imm) => Self::LocLoad(LocalId::from_u16(unwrap_u16!(imm))),
1367            Instruction::LocLoadW(imm) => Self::LocLoadw(LocalId::from_u16(unwrap_u16!(imm))),
1368            Instruction::MemStream => Self::MemStream,
1369            Instruction::AdvPipe => Self::AdvPipe,
1370            Instruction::AdvPush(byte) => Self::AdvPush(unwrap_u8!(byte)),
1371            Instruction::AdvLoadW => Self::AdvLoadw,
1372            Instruction::AdvInject(AdviceInjectorNode::InsertMem) => Self::AdvInjectInsertMem,
1373            Instruction::AdvInject(AdviceInjectorNode::InsertHperm) => Self::AdvInjectInsertHperm,
1374            Instruction::AdvInject(AdviceInjectorNode::InsertHdword) => Self::AdvInjectInsertHdword,
1375            Instruction::AdvInject(AdviceInjectorNode::InsertHdwordImm { domain }) => {
1376                Self::AdvInjectInsertHdwordImm(unwrap_u8!(domain))
1377            }
1378            Instruction::AdvInject(AdviceInjectorNode::PushU64Div) => Self::AdvInjectPushU64Div,
1379            Instruction::AdvInject(AdviceInjectorNode::PushMtNode) => Self::AdvInjectPushMTreeNode,
1380            Instruction::AdvInject(AdviceInjectorNode::PushMapVal) => Self::AdvInjectPushMapVal,
1381            Instruction::AdvInject(AdviceInjectorNode::PushMapValImm { offset }) => {
1382                Self::AdvInjectPushMapValImm(unwrap_u8!(offset))
1383            }
1384            Instruction::AdvInject(AdviceInjectorNode::PushMapValN) => Self::AdvInjectPushMapValN,
1385            Instruction::AdvInject(AdviceInjectorNode::PushMapValNImm { offset }) => {
1386                Self::AdvInjectPushMapValNImm(unwrap_u8!(offset))
1387            }
1388            Instruction::AdvInject(AdviceInjectorNode::PushSignature { kind }) => {
1389                Self::AdvInjectPushSignature(kind)
1390            }
1391            Instruction::AdvInject(injector) => {
1392                unimplemented!("unsupported advice injector: {injector:?}")
1393            }
1394            ref ix @ (Instruction::Exec(ref target)
1395            | Instruction::SysCall(ref target)
1396            | Instruction::Call(ref target)
1397            | Instruction::ProcRef(ref target)) => {
1398                let id = match target {
1399                    InvocationTarget::AbsoluteProcedurePath { name, path } => {
1400                        let name: &str = name.as_ref();
1401                        let function = Ident::with_empty_span(Symbol::intern(name));
1402                        let module = Ident::with_empty_span(Symbol::intern(path.to_string()));
1403                        FunctionIdent { module, function }
1404                    }
1405                    InvocationTarget::ProcedurePath { name, module } => {
1406                        let name: &str = name.as_ref();
1407                        let function = Ident::with_empty_span(Symbol::intern(name));
1408                        let module = Ident::with_empty_span(Symbol::intern(module.as_str()));
1409                        FunctionIdent { module, function }
1410                    }
1411                    InvocationTarget::ProcedureName(name) => {
1412                        let name: &str = name.as_ref();
1413                        let function = Ident::with_empty_span(Symbol::intern(name));
1414                        FunctionIdent {
1415                            module: current_module,
1416                            function,
1417                        }
1418                    }
1419                    InvocationTarget::MastRoot(_root) => {
1420                        todo!("support for referencing mast roots is not yet implemented")
1421                    }
1422                };
1423                match ix {
1424                    Instruction::Exec(_) => Self::Exec(id),
1425                    Instruction::SysCall(_) => Self::Syscall(id),
1426                    Instruction::Call(_) => Self::Call(id),
1427                    Instruction::ProcRef(_) => Self::ProcRef(id),
1428                    _ => unreachable!(),
1429                }
1430            }
1431            Instruction::DynExec => Self::DynExec,
1432            Instruction::DynCall => Self::DynCall,
1433            Instruction::Caller => Self::Caller,
1434            Instruction::Sdepth => Self::Sdepth,
1435            Instruction::Breakpoint => Self::Breakpoint,
1436            Instruction::Emit(event) => Self::Emit(unwrap_u32!(event)),
1437            Instruction::Trace(event) => Self::Trace(unwrap_u32!(event)),
1438            Instruction::Debug(DebugOptions::StackAll) => Self::DebugStack,
1439            Instruction::Debug(DebugOptions::StackTop(n)) => Self::DebugStackN(unwrap_u8!(n)),
1440            Instruction::Debug(DebugOptions::MemAll) => Self::DebugMemory,
1441            Instruction::Debug(DebugOptions::MemInterval(start, end)) => {
1442                Self::DebugMemoryRange(unwrap_u32!(start), unwrap_u32!(end))
1443            }
1444            Instruction::Debug(DebugOptions::LocalAll) => Self::DebugFrame,
1445            Instruction::Debug(DebugOptions::LocalRangeFrom(start)) => {
1446                Self::DebugFrameAt(unwrap_u16!(start))
1447            }
1448            Instruction::Debug(DebugOptions::LocalInterval(start, end)) => {
1449                Self::DebugFrameRange(unwrap_u16!(start), unwrap_u16!(end))
1450            }
1451            Instruction::Nop => Self::Nop,
1452        };
1453        smallvec![op]
1454    }
1455
1456    pub fn into_masm(
1457        self,
1458        imports: &super::ModuleImportInfo,
1459        locals: &BTreeSet<FunctionIdent>,
1460    ) -> SmallVec<[miden_assembly::ast::Instruction; 2]> {
1461        use miden_assembly::{
1462            ast::{Instruction, InvocationTarget, ProcedureName},
1463            LibraryPath,
1464        };
1465        let inst = match self {
1466            Self::Padw => Instruction::PadW,
1467            Self::Push(v) => Instruction::PushFelt(v),
1468            Self::Push2([a, b]) => Instruction::PushFeltList(vec![a, b]),
1469            Self::Pushw(word) => Instruction::PushWord(word),
1470            Self::PushU8(v) => Instruction::PushU8(v),
1471            Self::PushU16(v) => Instruction::PushU16(v),
1472            Self::PushU32(v) => Instruction::PushU32(v),
1473            Self::Drop => Instruction::Drop,
1474            Self::Dropw => Instruction::DropW,
1475            Self::Dup(0) => Instruction::Dup0,
1476            Self::Dup(1) => Instruction::Dup1,
1477            Self::Dup(2) => Instruction::Dup2,
1478            Self::Dup(3) => Instruction::Dup3,
1479            Self::Dup(4) => Instruction::Dup4,
1480            Self::Dup(5) => Instruction::Dup5,
1481            Self::Dup(6) => Instruction::Dup6,
1482            Self::Dup(7) => Instruction::Dup7,
1483            Self::Dup(8) => Instruction::Dup8,
1484            Self::Dup(9) => Instruction::Dup9,
1485            Self::Dup(10) => Instruction::Dup10,
1486            Self::Dup(11) => Instruction::Dup11,
1487            Self::Dup(12) => Instruction::Dup12,
1488            Self::Dup(13) => Instruction::Dup13,
1489            Self::Dup(14) => Instruction::Dup14,
1490            Self::Dup(15) => Instruction::Dup15,
1491            Self::Dup(n) => {
1492                panic!("invalid dup instruction, valid index range is 0..=15, got {n}")
1493            }
1494            Self::Dupw(0) => Instruction::DupW0,
1495            Self::Dupw(1) => Instruction::DupW1,
1496            Self::Dupw(2) => Instruction::DupW2,
1497            Self::Dupw(3) => Instruction::DupW3,
1498            Self::Dupw(n) => {
1499                panic!("invalid dupw instruction, valid index range is 0..=3, got {n}")
1500            }
1501            Self::Swap(1) => Instruction::Swap1,
1502            Self::Swap(2) => Instruction::Swap2,
1503            Self::Swap(3) => Instruction::Swap3,
1504            Self::Swap(4) => Instruction::Swap4,
1505            Self::Swap(5) => Instruction::Swap5,
1506            Self::Swap(6) => Instruction::Swap6,
1507            Self::Swap(7) => Instruction::Swap7,
1508            Self::Swap(8) => Instruction::Swap8,
1509            Self::Swap(9) => Instruction::Swap9,
1510            Self::Swap(10) => Instruction::Swap10,
1511            Self::Swap(11) => Instruction::Swap11,
1512            Self::Swap(12) => Instruction::Swap12,
1513            Self::Swap(13) => Instruction::Swap13,
1514            Self::Swap(14) => Instruction::Swap14,
1515            Self::Swap(15) => Instruction::Swap15,
1516            Self::Swap(n) => {
1517                panic!("invalid swap instruction, valid index range is 1..=15, got {n}")
1518            }
1519            Self::Swapw(1) => Instruction::SwapW1,
1520            Self::Swapw(2) => Instruction::SwapW2,
1521            Self::Swapw(3) => Instruction::SwapW3,
1522            Self::Swapw(n) => {
1523                panic!("invalid swapw instruction, valid index range is 1..=3, got {n}")
1524            }
1525            Self::Swapdw => Instruction::SwapDw,
1526            Self::Movup(2) => Instruction::MovUp2,
1527            Self::Movup(3) => Instruction::MovUp3,
1528            Self::Movup(4) => Instruction::MovUp4,
1529            Self::Movup(5) => Instruction::MovUp5,
1530            Self::Movup(6) => Instruction::MovUp6,
1531            Self::Movup(7) => Instruction::MovUp7,
1532            Self::Movup(8) => Instruction::MovUp8,
1533            Self::Movup(9) => Instruction::MovUp9,
1534            Self::Movup(10) => Instruction::MovUp10,
1535            Self::Movup(11) => Instruction::MovUp11,
1536            Self::Movup(12) => Instruction::MovUp12,
1537            Self::Movup(13) => Instruction::MovUp13,
1538            Self::Movup(14) => Instruction::MovUp14,
1539            Self::Movup(15) => Instruction::MovUp15,
1540            Self::Movup(n) => {
1541                panic!("invalid movup instruction, valid index range is 2..=15, got {n}")
1542            }
1543            Self::Movupw(2) => Instruction::MovUpW2,
1544            Self::Movupw(3) => Instruction::MovUpW3,
1545            Self::Movupw(n) => {
1546                panic!("invalid movupw instruction, valid index range is 2..=3, got {n}")
1547            }
1548            Self::Movdn(2) => Instruction::MovDn2,
1549            Self::Movdn(3) => Instruction::MovDn3,
1550            Self::Movdn(4) => Instruction::MovDn4,
1551            Self::Movdn(5) => Instruction::MovDn5,
1552            Self::Movdn(6) => Instruction::MovDn6,
1553            Self::Movdn(7) => Instruction::MovDn7,
1554            Self::Movdn(8) => Instruction::MovDn8,
1555            Self::Movdn(9) => Instruction::MovDn9,
1556            Self::Movdn(10) => Instruction::MovDn10,
1557            Self::Movdn(11) => Instruction::MovDn11,
1558            Self::Movdn(12) => Instruction::MovDn12,
1559            Self::Movdn(13) => Instruction::MovDn13,
1560            Self::Movdn(14) => Instruction::MovDn14,
1561            Self::Movdn(15) => Instruction::MovDn15,
1562            Self::Movdn(n) => {
1563                panic!("invalid movdn instruction, valid index range is 2..=15, got {n}")
1564            }
1565            Self::Movdnw(2) => Instruction::MovDnW2,
1566            Self::Movdnw(3) => Instruction::MovDnW3,
1567            Self::Movdnw(n) => {
1568                panic!("invalid movdnw instruction, valid index range is 2..=3, got {n}")
1569            }
1570            Self::Cswap => Instruction::CSwap,
1571            Self::Cswapw => Instruction::CSwapW,
1572            Self::Cdrop => Instruction::CDrop,
1573            Self::Cdropw => Instruction::CDropW,
1574            Self::Assert => Instruction::Assert,
1575            Self::AssertWithError(code) => Instruction::AssertWithError(code.into()),
1576            Self::Assertz => Instruction::Assertz,
1577            Self::AssertzWithError(code) => Instruction::AssertzWithError(code.into()),
1578            Self::AssertEq => Instruction::AssertEq,
1579            Self::AssertEqWithError(code) => Instruction::AssertEqWithError(code.into()),
1580            Self::AssertEqw => Instruction::AssertEqw,
1581            Self::AssertEqwWithError(code) => Instruction::AssertEqwWithError(code.into()),
1582            Self::LocAddr(id) => Instruction::Locaddr(id.into()),
1583            Self::LocLoad(id) => Instruction::LocLoad(id.into()),
1584            Self::LocLoadw(id) => Instruction::LocLoadW(id.into()),
1585            Self::LocStore(id) => Instruction::LocStore(id.into()),
1586            Self::LocStorew(id) => Instruction::LocStoreW(id.into()),
1587            Self::MemLoad => Instruction::MemLoad,
1588            Self::MemLoadImm(addr) => Instruction::MemLoadImm(addr.into()),
1589            Self::MemLoadw => Instruction::MemLoadW,
1590            Self::MemLoadwImm(addr) => Instruction::MemLoadWImm(addr.into()),
1591            Self::MemStore => Instruction::MemStore,
1592            Self::MemStoreImm(addr) => Instruction::MemStoreImm(addr.into()),
1593            Self::MemStorew => Instruction::MemStoreW,
1594            Self::MemStorewImm(addr) => Instruction::MemStoreWImm(addr.into()),
1595            Self::MemStream => Instruction::MemStream,
1596            Self::AdvPipe => Instruction::AdvPipe,
1597            Self::AdvPush(n) => Instruction::AdvPush(n.into()),
1598            Self::AdvLoadw => Instruction::AdvLoadW,
1599            Self::AdvInjectPushU64Div => Instruction::AdvInject(AdviceInjectorNode::PushU64Div),
1600            Self::AdvInjectPushMTreeNode => Instruction::AdvInject(AdviceInjectorNode::PushMtNode),
1601            Self::AdvInjectPushMapVal => Instruction::AdvInject(AdviceInjectorNode::PushMapVal),
1602            Self::AdvInjectPushMapValImm(n) => {
1603                Instruction::AdvInject(AdviceInjectorNode::PushMapValImm { offset: n.into() })
1604            }
1605            Self::AdvInjectPushMapValN => Instruction::AdvInject(AdviceInjectorNode::PushMapValN),
1606            Self::AdvInjectPushMapValNImm(n) => {
1607                Instruction::AdvInject(AdviceInjectorNode::PushMapValNImm { offset: n.into() })
1608            }
1609            Self::AdvInjectInsertMem => Instruction::AdvInject(AdviceInjectorNode::InsertMem),
1610            Self::AdvInjectInsertHperm => Instruction::AdvInject(AdviceInjectorNode::InsertHperm),
1611            Self::AdvInjectInsertHdword => Instruction::AdvInject(AdviceInjectorNode::InsertHdword),
1612            Self::AdvInjectInsertHdwordImm(domain) => {
1613                Instruction::AdvInject(AdviceInjectorNode::InsertHdwordImm {
1614                    domain: domain.into(),
1615                })
1616            }
1617            Self::AdvInjectPushSignature(kind) => {
1618                Instruction::AdvInject(AdviceInjectorNode::PushSignature { kind })
1619            }
1620            Self::If(..) | Self::While(_) | Self::Repeat(..) => {
1621                panic!("control flow instructions are meant to be handled specially by the caller")
1622            }
1623            op @ (Self::Exec(ref callee)
1624            | Self::Call(ref callee)
1625            | Self::Syscall(ref callee)
1626            | Self::ProcRef(ref callee)) => {
1627                let target = if locals.contains(callee) {
1628                    let callee = ProcedureName::new_unchecked(super::utils::translate_ident(
1629                        callee.function,
1630                    ));
1631                    InvocationTarget::ProcedureName(callee)
1632                } else if let Some(alias) = imports.alias(&callee.module) {
1633                    let alias = super::utils::translate_ident(alias);
1634                    let name = ProcedureName::new_unchecked(super::utils::translate_ident(
1635                        callee.function,
1636                    ));
1637                    InvocationTarget::ProcedurePath {
1638                        name,
1639                        module: alias,
1640                    }
1641                } else {
1642                    let name = ProcedureName::new_unchecked(super::utils::translate_ident(
1643                        callee.function,
1644                    ));
1645                    let path =
1646                        LibraryPath::new(callee.module.as_str()).expect("invalid procedure path");
1647                    InvocationTarget::AbsoluteProcedurePath { name, path }
1648                };
1649                match op {
1650                    Self::Exec(_) => Instruction::Exec(target),
1651                    Self::Call(_) => Instruction::Call(target),
1652                    Self::Syscall(_) => Instruction::SysCall(target),
1653                    Self::ProcRef(_) => Instruction::ProcRef(target),
1654                    _ => unreachable!(),
1655                }
1656            }
1657            Self::DynExec => Instruction::DynExec,
1658            Self::DynCall => Instruction::DynCall,
1659            Self::Add => Instruction::Add,
1660            Self::AddImm(imm) => Instruction::AddImm(imm.into()),
1661            Self::Sub => Instruction::Sub,
1662            Self::SubImm(imm) => Instruction::SubImm(imm.into()),
1663            Self::Mul => Instruction::Mul,
1664            Self::MulImm(imm) => Instruction::MulImm(imm.into()),
1665            Self::Div => Instruction::Div,
1666            Self::DivImm(imm) => Instruction::DivImm(imm.into()),
1667            Self::Neg => Instruction::Neg,
1668            Self::Inv => Instruction::Inv,
1669            Self::Incr => Instruction::Incr,
1670            Self::Ilog2 => Instruction::ILog2,
1671            Self::Pow2 => Instruction::Pow2,
1672            Self::Exp => Instruction::Exp,
1673            Self::ExpImm(imm) => Instruction::ExpImm(Felt::new(imm as u64).into()),
1674            Self::ExpBitLength(imm) => Instruction::ExpBitLength(imm),
1675            Self::Not => Instruction::Not,
1676            Self::And => Instruction::And,
1677            Self::AndImm(imm) => {
1678                return smallvec![Instruction::PushU8(imm as u8), Instruction::And]
1679            }
1680            Self::Or => Instruction::Or,
1681            Self::OrImm(imm) => return smallvec![Instruction::PushU8(imm as u8), Instruction::Or],
1682            Self::Xor => Instruction::Xor,
1683            Self::XorImm(imm) => {
1684                return smallvec![Instruction::PushU8(imm as u8), Instruction::Xor]
1685            }
1686            Self::Eq => Instruction::Eq,
1687            Self::EqImm(imm) => Instruction::EqImm(imm.into()),
1688            Self::Neq => Instruction::Neq,
1689            Self::NeqImm(imm) => Instruction::NeqImm(imm.into()),
1690            Self::Gt => Instruction::Gt,
1691            Self::GtImm(imm) => return smallvec![Instruction::PushFelt(imm), Instruction::Gt],
1692            Self::Gte => Instruction::Gte,
1693            Self::GteImm(imm) => return smallvec![Instruction::PushFelt(imm), Instruction::Gte],
1694            Self::Lt => Instruction::Lt,
1695            Self::LtImm(imm) => return smallvec![Instruction::PushFelt(imm), Instruction::Lt],
1696            Self::Lte => Instruction::Lte,
1697            Self::LteImm(imm) => return smallvec![Instruction::PushFelt(imm), Instruction::Lte],
1698            Self::IsOdd => Instruction::IsOdd,
1699            Self::Eqw => Instruction::Eqw,
1700            Self::Ext2add => Instruction::Ext2Add,
1701            Self::Ext2sub => Instruction::Ext2Sub,
1702            Self::Ext2mul => Instruction::Ext2Mul,
1703            Self::Ext2div => Instruction::Ext2Div,
1704            Self::Ext2neg => Instruction::Ext2Neg,
1705            Self::Ext2inv => Instruction::Ext2Inv,
1706            Self::Clk => Instruction::Clk,
1707            Self::Caller => Instruction::Caller,
1708            Self::Sdepth => Instruction::Sdepth,
1709            Self::Hash => Instruction::Hash,
1710            Self::Hperm => Instruction::HPerm,
1711            Self::Hmerge => Instruction::HMerge,
1712            Self::MtreeGet => Instruction::MTreeGet,
1713            Self::MtreeSet => Instruction::MTreeSet,
1714            Self::MtreeMerge => Instruction::MTreeMerge,
1715            Self::MtreeVerify => Instruction::MTreeVerify,
1716            Self::MtreeVerifyWithError(code) => Instruction::MTreeVerifyWithError(code.into()),
1717            Self::FriExt2Fold4 => Instruction::FriExt2Fold4,
1718            Self::RCombBase => Instruction::RCombBase,
1719            Self::U32Test => Instruction::U32Test,
1720            Self::U32Testw => Instruction::U32TestW,
1721            Self::U32Assert => Instruction::U32Assert,
1722            Self::U32AssertWithError(code) => Instruction::U32AssertWithError(code.into()),
1723            Self::U32Assert2 => Instruction::U32Assert2,
1724            Self::U32Assert2WithError(code) => Instruction::U32Assert2WithError(code.into()),
1725            Self::U32Assertw => Instruction::U32AssertW,
1726            Self::U32AssertwWithError(code) => Instruction::U32AssertWWithError(code.into()),
1727            Self::U32Cast => Instruction::U32Cast,
1728            Self::U32Split => Instruction::U32Split,
1729            Self::U32OverflowingAdd => Instruction::U32OverflowingAdd,
1730            Self::U32OverflowingAddImm(imm) => Instruction::U32OverflowingAddImm(imm.into()),
1731            Self::U32WrappingAdd => Instruction::U32WrappingAdd,
1732            Self::U32WrappingAddImm(imm) => Instruction::U32WrappingAddImm(imm.into()),
1733            Self::U32OverflowingAdd3 => Instruction::U32OverflowingAdd3,
1734            Self::U32WrappingAdd3 => Instruction::U32WrappingAdd3,
1735            Self::U32OverflowingSub => Instruction::U32OverflowingSub,
1736            Self::U32OverflowingSubImm(imm) => Instruction::U32OverflowingSubImm(imm.into()),
1737            Self::U32WrappingSub => Instruction::U32WrappingSub,
1738            Self::U32WrappingSubImm(imm) => Instruction::U32WrappingSubImm(imm.into()),
1739            Self::U32OverflowingMul => Instruction::U32OverflowingMul,
1740            Self::U32OverflowingMulImm(imm) => Instruction::U32OverflowingMulImm(imm.into()),
1741            Self::U32WrappingMul => Instruction::U32WrappingMul,
1742            Self::U32WrappingMulImm(imm) => Instruction::U32WrappingMulImm(imm.into()),
1743            Self::U32OverflowingMadd => Instruction::U32OverflowingMadd,
1744            Self::U32WrappingMadd => Instruction::U32WrappingMadd,
1745            Self::U32Div => Instruction::U32Div,
1746            Self::U32DivImm(imm) => Instruction::U32DivImm(imm.into()),
1747            Self::U32Mod => Instruction::U32Mod,
1748            Self::U32ModImm(imm) => Instruction::U32ModImm(imm.into()),
1749            Self::U32DivMod => Instruction::U32DivMod,
1750            Self::U32DivModImm(imm) => Instruction::U32DivModImm(imm.into()),
1751            Self::U32And => Instruction::U32And,
1752            Self::U32Or => Instruction::U32Or,
1753            Self::U32Xor => Instruction::U32Xor,
1754            Self::U32Not => Instruction::U32Not,
1755            Self::U32Shl => Instruction::U32Shl,
1756            Self::U32ShlImm(imm) => {
1757                let shift = u8::try_from(imm).expect("invalid shift");
1758                Instruction::U32ShlImm(shift.into())
1759            }
1760            Self::U32Shr => Instruction::U32Shr,
1761            Self::U32ShrImm(imm) => {
1762                let shift = u8::try_from(imm).expect("invalid shift");
1763                Instruction::U32ShrImm(shift.into())
1764            }
1765            Self::U32Rotl => Instruction::U32Rotl,
1766            Self::U32RotlImm(imm) => {
1767                let rotate = u8::try_from(imm).expect("invalid rotation");
1768                Instruction::U32RotlImm(rotate.into())
1769            }
1770            Self::U32Rotr => Instruction::U32Rotr,
1771            Self::U32RotrImm(imm) => {
1772                let rotate = u8::try_from(imm).expect("invalid rotation");
1773                Instruction::U32RotrImm(rotate.into())
1774            }
1775            Self::U32Popcnt => Instruction::U32Popcnt,
1776            Self::U32Clz => Instruction::U32Clz,
1777            Self::U32Ctz => Instruction::U32Ctz,
1778            Self::U32Clo => Instruction::U32Clo,
1779            Self::U32Cto => Instruction::U32Cto,
1780            Self::U32Lt => Instruction::U32Lt,
1781            Self::U32LtImm(imm) => return smallvec![Instruction::PushU32(imm), Instruction::U32Lt],
1782            Self::U32Lte => Instruction::U32Lte,
1783            Self::U32LteImm(imm) => {
1784                return smallvec![Instruction::PushU32(imm), Instruction::U32Lte]
1785            }
1786            Self::U32Gt => Instruction::U32Gt,
1787            Self::U32GtImm(imm) => return smallvec![Instruction::PushU32(imm), Instruction::U32Gt],
1788            Self::U32Gte => Instruction::U32Gte,
1789            Self::U32GteImm(imm) => {
1790                return smallvec![Instruction::PushU32(imm), Instruction::U32Gte];
1791            }
1792            Self::U32Min => Instruction::U32Min,
1793            Self::U32MinImm(imm) => {
1794                return smallvec![Instruction::PushU32(imm), Instruction::U32Min];
1795            }
1796            Self::U32Max => Instruction::U32Max,
1797            Self::U32MaxImm(imm) => {
1798                return smallvec![Instruction::PushU32(imm), Instruction::U32Max];
1799            }
1800            Self::Breakpoint => Instruction::Breakpoint,
1801            Self::DebugStack => Instruction::Debug(DebugOptions::StackAll),
1802            Self::DebugStackN(n) => Instruction::Debug(DebugOptions::StackTop(n.into())),
1803            Self::DebugMemory => Instruction::Debug(DebugOptions::MemAll),
1804            Self::DebugMemoryAt(start) => {
1805                Instruction::Debug(DebugOptions::MemInterval(start.into(), u32::MAX.into()))
1806            }
1807            Self::DebugMemoryRange(start, end) => {
1808                Instruction::Debug(DebugOptions::MemInterval(start.into(), end.into()))
1809            }
1810            Self::DebugFrame => Instruction::Debug(DebugOptions::LocalAll),
1811            Self::DebugFrameAt(start) => {
1812                Instruction::Debug(DebugOptions::LocalRangeFrom(start.into()))
1813            }
1814            Self::DebugFrameRange(start, end) => {
1815                Instruction::Debug(DebugOptions::LocalInterval(start.into(), end.into()))
1816            }
1817            Self::Emit(ev) => Instruction::Emit(ev.into()),
1818            Self::Trace(ev) => Instruction::Trace(ev.into()),
1819            Self::Nop => Instruction::Nop,
1820        };
1821        smallvec![inst]
1822    }
1823}
1824
1825/// This implementation displays the opcode name for the given [MasmOp]
1826impl fmt::Display for MasmOp {
1827    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1828        match self {
1829            Self::Padw => f.write_str("padw"),
1830            Self::Push(_)
1831            | Self::Push2(_)
1832            | Self::Pushw(_)
1833            | Self::PushU8(_)
1834            | Self::PushU16(_)
1835            | Self::PushU32(_) => f.write_str("push"),
1836            Self::Drop => f.write_str("drop"),
1837            Self::Dropw => f.write_str("dropw"),
1838            Self::Dup(_) => f.write_str("dup"),
1839            Self::Dupw(_) => f.write_str("dupw"),
1840            Self::Swap(_) => f.write_str("swap"),
1841            Self::Swapw(_) => f.write_str("swapw"),
1842            Self::Swapdw => f.write_str("swapdw"),
1843            Self::Movup(_) => f.write_str("movup"),
1844            Self::Movupw(_) => f.write_str("movupw"),
1845            Self::Movdn(_) => f.write_str("movdn"),
1846            Self::Movdnw(_) => f.write_str("movdnw"),
1847            Self::Cswap => f.write_str("cswap"),
1848            Self::Cswapw => f.write_str("cswapw"),
1849            Self::Cdrop => f.write_str("cdrop"),
1850            Self::Cdropw => f.write_str("cdropw"),
1851            Self::Assert => f.write_str("assert"),
1852            Self::AssertWithError(code) => write!(f, "assert.err={code}"),
1853            Self::Assertz => f.write_str("assertz"),
1854            Self::AssertzWithError(code) => write!(f, "assertz.err={code}"),
1855            Self::AssertEq => f.write_str("assert_eq"),
1856            Self::AssertEqWithError(code) => write!(f, "assert_eq.err={code}"),
1857            Self::AssertEqw => f.write_str("assert_eqw"),
1858            Self::AssertEqwWithError(code) => write!(f, "assert_eqw.err={code}"),
1859            Self::LocAddr(_) => f.write_str("locaddr"),
1860            Self::LocLoad(_) => f.write_str("loc_load"),
1861            Self::LocLoadw(_) => f.write_str("loc_loadw"),
1862            Self::LocStore(_) => f.write_str("loc_store"),
1863            Self::LocStorew(_) => f.write_str("loc_storew"),
1864            Self::MemLoad | Self::MemLoadImm(_) => f.write_str("mem_load"),
1865            Self::MemLoadw | Self::MemLoadwImm(_) => f.write_str("mem_loadw"),
1866            Self::MemStore | Self::MemStoreImm(_) => f.write_str("mem_store"),
1867            Self::MemStorew | Self::MemStorewImm(_) => f.write_str("mem_storew"),
1868            Self::MemStream => f.write_str("mem_stream"),
1869            Self::AdvPipe => f.write_str("adv_pipe"),
1870            Self::AdvPush(_) => f.write_str("adv_push"),
1871            Self::AdvLoadw => f.write_str("adv_loadw"),
1872            Self::AdvInjectPushU64Div => f.write_str("adv.push_u64div"),
1873            Self::AdvInjectPushMTreeNode => f.write_str("adv.push_mtnode"),
1874            Self::AdvInjectPushMapVal | Self::AdvInjectPushMapValImm(_) => {
1875                f.write_str("adv.push_mapval")
1876            }
1877            Self::AdvInjectPushMapValN | Self::AdvInjectPushMapValNImm(_) => {
1878                f.write_str("adv.push_mapvaln")
1879            }
1880            Self::AdvInjectInsertMem => f.write_str("adv.insert_mem"),
1881            Self::AdvInjectInsertHperm => f.write_str("adv.insert_hperm"),
1882            Self::AdvInjectInsertHdword | Self::AdvInjectInsertHdwordImm(_) => {
1883                f.write_str("adv.insert_hdword")
1884            }
1885            Self::AdvInjectPushSignature(kind) => write!(f, "adv.push_sig.{kind}"),
1886            Self::If(..) => f.write_str("if.true"),
1887            Self::While(_) => f.write_str("while.true"),
1888            Self::Repeat(..) => f.write_str("repeat"),
1889            Self::Exec(_) => f.write_str("exec"),
1890            Self::Syscall(_) => f.write_str("syscall"),
1891            Self::Call(_) => f.write_str("call"),
1892            Self::DynExec => f.write_str("dynexec"),
1893            Self::DynCall => f.write_str("dyncall"),
1894            Self::ProcRef(_) => f.write_str("procref"),
1895            Self::Add | Self::AddImm(_) => f.write_str("add"),
1896            Self::Sub | Self::SubImm(_) => f.write_str("sub"),
1897            Self::Mul | Self::MulImm(_) => f.write_str("mul"),
1898            Self::Div | Self::DivImm(_) => f.write_str("div"),
1899            Self::Neg => f.write_str("neg"),
1900            Self::Inv => f.write_str("inv"),
1901            Self::Incr => f.write_str("add.1"),
1902            Self::Ilog2 => f.write_str("ilog2"),
1903            Self::Pow2 => f.write_str("pow2"),
1904            Self::Exp => f.write_str("exp"),
1905            Self::ExpImm(imm) => write!(f, "exp.{imm}"),
1906            Self::ExpBitLength(imm) => write!(f, "exp.u{imm}"),
1907            Self::Not => f.write_str("not"),
1908            Self::And | Self::AndImm(_) => f.write_str("and"),
1909            Self::Or | Self::OrImm(_) => f.write_str("or"),
1910            Self::Xor | Self::XorImm(_) => f.write_str("xor"),
1911            Self::Eq | Self::EqImm(_) => f.write_str("eq"),
1912            Self::Neq | Self::NeqImm(_) => f.write_str("neq"),
1913            Self::Gt | Self::GtImm(_) => f.write_str("gt"),
1914            Self::Gte | Self::GteImm(_) => f.write_str("gte"),
1915            Self::Lt | Self::LtImm(_) => f.write_str("lt"),
1916            Self::Lte | Self::LteImm(_) => f.write_str("lte"),
1917            Self::IsOdd => f.write_str("is_odd"),
1918            Self::Eqw => f.write_str("eqw"),
1919            Self::Ext2add => f.write_str("ext2add"),
1920            Self::Ext2sub => f.write_str("ext2sub"),
1921            Self::Ext2mul => f.write_str("ext2mul"),
1922            Self::Ext2div => f.write_str("ext2div"),
1923            Self::Ext2neg => f.write_str("ext2neg"),
1924            Self::Ext2inv => f.write_str("ext2inv"),
1925            Self::Clk => f.write_str("clk"),
1926            Self::Caller => f.write_str("caller"),
1927            Self::Sdepth => f.write_str("sdepth"),
1928            Self::Hash => f.write_str("hash"),
1929            Self::Hperm => f.write_str("hperm"),
1930            Self::Hmerge => f.write_str("hmerge"),
1931            Self::MtreeGet => f.write_str("mtree_get"),
1932            Self::MtreeSet => f.write_str("mtree_set"),
1933            Self::MtreeMerge => f.write_str("mtree_merge"),
1934            Self::MtreeVerify => f.write_str("mtree_verify"),
1935            Self::MtreeVerifyWithError(code) => write!(f, "mtree_verify.err={code}"),
1936            Self::FriExt2Fold4 => f.write_str("fri_ext2fold4"),
1937            Self::RCombBase => f.write_str("rcomb_base"),
1938            Self::U32Test => f.write_str("u32test"),
1939            Self::U32Testw => f.write_str("u32testw"),
1940            Self::U32Assert => f.write_str("u32assert"),
1941            Self::U32AssertWithError(code) => write!(f, "u32assert.err={code}"),
1942            Self::U32Assert2 => f.write_str("u32assert2"),
1943            Self::U32Assert2WithError(code) => write!(f, "u32assert2.err={code}"),
1944            Self::U32Assertw => f.write_str("u32assertw"),
1945            Self::U32AssertwWithError(code) => write!(f, "u32assertw.err={code}"),
1946            Self::U32Cast => f.write_str("u32cast"),
1947            Self::U32Split => f.write_str("u32split"),
1948            Self::U32OverflowingAdd | Self::U32OverflowingAddImm(_) => {
1949                f.write_str("u32overflowing_add")
1950            }
1951            Self::U32WrappingAdd | Self::U32WrappingAddImm(_) => f.write_str("u32wrapping_add"),
1952            Self::U32OverflowingAdd3 => f.write_str("u32overflowing_add3"),
1953            Self::U32WrappingAdd3 => f.write_str("u32wrapping_add3"),
1954            Self::U32OverflowingSub | Self::U32OverflowingSubImm(_) => {
1955                f.write_str("u32overflowing_sub")
1956            }
1957            Self::U32WrappingSub | Self::U32WrappingSubImm(_) => f.write_str("u32wrapping_sub"),
1958            Self::U32OverflowingMul | Self::U32OverflowingMulImm(_) => {
1959                f.write_str("u32overflowing_mul")
1960            }
1961            Self::U32WrappingMul | Self::U32WrappingMulImm(_) => f.write_str("u32wrapping_mul"),
1962            Self::U32OverflowingMadd => f.write_str("u32overflowing_madd"),
1963            Self::U32WrappingMadd => f.write_str("u32wrapping_madd"),
1964            Self::U32Div | Self::U32DivImm(_) => f.write_str("u32div"),
1965            Self::U32Mod | Self::U32ModImm(_) => f.write_str("u32mod"),
1966            Self::U32DivMod | Self::U32DivModImm(_) => f.write_str("u32divmod"),
1967            Self::U32And => f.write_str("u32and"),
1968            Self::U32Or => f.write_str("u32or"),
1969            Self::U32Xor => f.write_str("u32xor"),
1970            Self::U32Not => f.write_str("u32not"),
1971            Self::U32Shl | Self::U32ShlImm(_) => f.write_str("u32shl"),
1972            Self::U32Shr | Self::U32ShrImm(_) => f.write_str("u32shr"),
1973            Self::U32Rotl | Self::U32RotlImm(_) => f.write_str("u32rotl"),
1974            Self::U32Rotr | Self::U32RotrImm(_) => f.write_str("u32rotr"),
1975            Self::U32Popcnt => f.write_str("u32popcnt"),
1976            Self::U32Clz => f.write_str("u32clz"),
1977            Self::U32Ctz => f.write_str("u32ctz"),
1978            Self::U32Clo => f.write_str("u32clo"),
1979            Self::U32Cto => f.write_str("u32cto"),
1980            Self::U32Lt | Self::U32LtImm(_) => f.write_str("u32lt"),
1981            Self::U32Lte | Self::U32LteImm(_) => f.write_str("u32lte"),
1982            Self::U32Gt | Self::U32GtImm(_) => f.write_str("u32gt"),
1983            Self::U32Gte | Self::U32GteImm(_) => f.write_str("u32gte"),
1984            Self::U32Min | Self::U32MinImm(_) => f.write_str("u32min"),
1985            Self::U32Max | Self::U32MaxImm(_) => f.write_str("u32max"),
1986            Self::Breakpoint => f.write_str("breakpoint"),
1987            Self::DebugStack | Self::DebugStackN(_) => f.write_str("debug.stack"),
1988            Self::DebugMemory | Self::DebugMemoryAt(_) | Self::DebugMemoryRange(..) => {
1989                f.write_str("debug.mem")
1990            }
1991            Self::DebugFrame | Self::DebugFrameAt(_) | Self::DebugFrameRange(..) => {
1992                f.write_str("debug.local")
1993            }
1994            Self::Emit(_) => f.write_str("emit"),
1995            Self::Trace(_) => f.write_str("trace"),
1996            Self::Nop => f.write_str("nop"),
1997        }
1998    }
1999}