1use core::ops::RangeBounds;
2
3use vm_core::{Decorator, ONE, WORD_SIZE, ZERO, debuginfo::Spanned, mast::MastNodeId};
4
5use super::{Assembler, BasicBlockBuilder, Felt, Operation, ProcedureContext, ast::InvokeKind};
6use crate::{AssemblyError, Span, ast::Instruction, report, utils::bound_into_included_u64};
7
8mod adv_ops;
9mod crypto_ops;
10mod env_ops;
11mod ext2_ops;
12mod field_ops;
13mod mem_ops;
14mod procedures;
15mod u32_ops;
16
17use self::u32_ops::U32OpMode::*;
18
19impl Assembler {
21 pub(super) fn compile_instruction(
22 &self,
23 instruction: &Span<Instruction>,
24 block_builder: &mut BasicBlockBuilder,
25 proc_ctx: &mut ProcedureContext,
26 ) -> Result<Option<MastNodeId>, AssemblyError> {
27 if self.in_debug_mode() {
31 block_builder.track_instruction(instruction, proc_ctx)?;
32 }
33
34 let new_node_id = self.compile_instruction_impl(instruction, block_builder, proc_ctx)?;
35
36 if self.in_debug_mode() {
37 let maybe_asm_op_id = block_builder.set_instruction_cycle_count();
39
40 if let Some(node_id) = new_node_id {
41 if !matches!(instruction.inner(), &Instruction::Exec(_)) {
48 let asm_op_id = maybe_asm_op_id.expect("no asmop decorator");
49
50 {
52 let assembly_op = &mut block_builder.mast_forest_builder_mut()[asm_op_id];
53 if let Decorator::AsmOp(assembly_op) = assembly_op {
54 assembly_op.set_num_cycles(1);
55 } else {
56 panic!("expected AsmOp decorator");
57 }
58 }
59
60 block_builder
61 .mast_forest_builder_mut()
62 .append_before_enter(node_id, &[asm_op_id]);
63 }
64 }
65 }
66
67 Ok(new_node_id)
68 }
69
70 fn compile_instruction_impl(
71 &self,
72 instruction: &Span<Instruction>,
73 block_builder: &mut BasicBlockBuilder,
74 proc_ctx: &mut ProcedureContext,
75 ) -> Result<Option<MastNodeId>, AssemblyError> {
76 use Operation::*;
77
78 match &**instruction {
79 Instruction::Nop => block_builder.push_op(Noop),
80 Instruction::Assert => block_builder.push_op(Assert(ZERO)),
81 Instruction::AssertWithError(err_msg) => {
82 let error_code = block_builder.register_error(err_msg.expect_string());
83 block_builder.push_op(Assert(error_code))
84 },
85 Instruction::AssertEq => block_builder.push_ops([Eq, Assert(ZERO)]),
86 Instruction::AssertEqWithError(err_msg) => {
87 let error_code = block_builder.register_error(err_msg.expect_string());
88 block_builder.push_ops([Eq, Assert(error_code)])
89 },
90 Instruction::AssertEqw => field_ops::assertw(block_builder, ZERO),
91 Instruction::AssertEqwWithError(err_msg) => {
92 let error_code = block_builder.register_error(err_msg.expect_string());
93 field_ops::assertw(block_builder, error_code)
94 },
95 Instruction::Assertz => block_builder.push_ops([Eqz, Assert(ZERO)]),
96 Instruction::AssertzWithError(err_msg) => {
97 let error_code = block_builder.register_error(err_msg.expect_string());
98 block_builder.push_ops([Eqz, Assert(error_code)])
99 },
100
101 Instruction::Add => block_builder.push_op(Add),
102 Instruction::AddImm(imm) => field_ops::add_imm(block_builder, imm.expect_value()),
103 Instruction::Sub => block_builder.push_ops([Neg, Add]),
104 Instruction::SubImm(imm) => field_ops::sub_imm(block_builder, imm.expect_value()),
105 Instruction::Mul => block_builder.push_op(Mul),
106 Instruction::MulImm(imm) => field_ops::mul_imm(block_builder, imm.expect_value()),
107 Instruction::Div => block_builder.push_ops([Inv, Mul]),
108 Instruction::DivImm(imm) => {
109 field_ops::div_imm(block_builder, proc_ctx, imm.expect_spanned_value())?;
110 },
111 Instruction::Neg => block_builder.push_op(Neg),
112 Instruction::Inv => block_builder.push_op(Inv),
113 Instruction::Incr => block_builder.push_op(Incr),
114
115 Instruction::Pow2 => field_ops::pow2(block_builder),
116 Instruction::Exp => field_ops::exp(block_builder, 64)?,
117 Instruction::ExpImm(pow) => field_ops::exp_imm(block_builder, pow.expect_value())?,
118 Instruction::ExpBitLength(num_pow_bits) => {
119 field_ops::exp(block_builder, *num_pow_bits)?
120 },
121 Instruction::ILog2 => field_ops::ilog2(block_builder),
122
123 Instruction::Not => block_builder.push_op(Not),
124 Instruction::And => block_builder.push_op(And),
125 Instruction::Or => block_builder.push_op(Or),
126 Instruction::Xor => block_builder.push_ops([Dup0, Dup2, Or, MovDn2, And, Not, And]),
127
128 Instruction::Eq => block_builder.push_op(Eq),
129 Instruction::EqImm(imm) => field_ops::eq_imm(block_builder, imm.expect_value()),
130 Instruction::Eqw => field_ops::eqw(block_builder),
131 Instruction::Neq => block_builder.push_ops([Eq, Not]),
132 Instruction::NeqImm(imm) => field_ops::neq_imm(block_builder, imm.expect_value()),
133 Instruction::Lt => field_ops::lt(block_builder),
134 Instruction::Lte => field_ops::lte(block_builder),
135 Instruction::Gt => field_ops::gt(block_builder),
136 Instruction::Gte => field_ops::gte(block_builder),
137 Instruction::IsOdd => field_ops::is_odd(block_builder),
138
139 Instruction::Ext2Add => ext2_ops::ext2_add(block_builder),
141 Instruction::Ext2Sub => ext2_ops::ext2_sub(block_builder),
142 Instruction::Ext2Mul => ext2_ops::ext2_mul(block_builder),
143 Instruction::Ext2Div => ext2_ops::ext2_div(block_builder),
144 Instruction::Ext2Neg => ext2_ops::ext2_neg(block_builder),
145 Instruction::Ext2Inv => ext2_ops::ext2_inv(block_builder)?,
146
147 Instruction::U32Test => block_builder.push_ops([Dup0, U32split, Swap, Drop, Eqz]),
149 Instruction::U32TestW => u32_ops::u32testw(block_builder),
150 Instruction::U32Assert => block_builder.push_ops([Pad, U32assert2(ZERO), Drop]),
151 Instruction::U32AssertWithError(err_msg) => {
152 let error_code = block_builder.register_error(err_msg.expect_string());
153 block_builder.push_ops([Pad, U32assert2(error_code), Drop])
154 },
155 Instruction::U32Assert2 => block_builder.push_op(U32assert2(ZERO)),
156 Instruction::U32Assert2WithError(err_msg) => {
157 let error_code = block_builder.register_error(err_msg.expect_string());
158 block_builder.push_op(U32assert2(error_code))
159 },
160 Instruction::U32AssertW => u32_ops::u32assertw(block_builder, ZERO),
161 Instruction::U32AssertWWithError(err_msg) => {
162 let error_code = block_builder.register_error(err_msg.expect_string());
163 u32_ops::u32assertw(block_builder, error_code)
164 },
165
166 Instruction::U32Cast => block_builder.push_ops([U32split, Drop]),
167 Instruction::U32Split => block_builder.push_op(U32split),
168
169 Instruction::U32OverflowingAdd => u32_ops::u32add(block_builder, Overflowing, None),
170 Instruction::U32OverflowingAddImm(v) => {
171 u32_ops::u32add(block_builder, Overflowing, Some(v.expect_value()))
172 },
173 Instruction::U32WrappingAdd => u32_ops::u32add(block_builder, Wrapping, None),
174 Instruction::U32WrappingAddImm(v) => {
175 u32_ops::u32add(block_builder, Wrapping, Some(v.expect_value()))
176 },
177 Instruction::U32OverflowingAdd3 => block_builder.push_op(U32add3),
178 Instruction::U32WrappingAdd3 => block_builder.push_ops([U32add3, Drop]),
179
180 Instruction::U32OverflowingSub => u32_ops::u32sub(block_builder, Overflowing, None),
181 Instruction::U32OverflowingSubImm(v) => {
182 u32_ops::u32sub(block_builder, Overflowing, Some(v.expect_value()))
183 },
184 Instruction::U32WrappingSub => u32_ops::u32sub(block_builder, Wrapping, None),
185 Instruction::U32WrappingSubImm(v) => {
186 u32_ops::u32sub(block_builder, Wrapping, Some(v.expect_value()))
187 },
188
189 Instruction::U32OverflowingMul => u32_ops::u32mul(block_builder, Overflowing, None),
190 Instruction::U32OverflowingMulImm(v) => {
191 u32_ops::u32mul(block_builder, Overflowing, Some(v.expect_value()))
192 },
193 Instruction::U32WrappingMul => u32_ops::u32mul(block_builder, Wrapping, None),
194 Instruction::U32WrappingMulImm(v) => {
195 u32_ops::u32mul(block_builder, Wrapping, Some(v.expect_value()))
196 },
197 Instruction::U32OverflowingMadd => block_builder.push_op(U32madd),
198 Instruction::U32WrappingMadd => block_builder.push_ops([U32madd, Drop]),
199
200 Instruction::U32Div => u32_ops::u32div(block_builder, proc_ctx, None)?,
201 Instruction::U32DivImm(v) => {
202 u32_ops::u32div(block_builder, proc_ctx, Some(v.expect_spanned_value()))?
203 },
204 Instruction::U32Mod => u32_ops::u32mod(block_builder, proc_ctx, None)?,
205 Instruction::U32ModImm(v) => {
206 u32_ops::u32mod(block_builder, proc_ctx, Some(v.expect_spanned_value()))?
207 },
208 Instruction::U32DivMod => u32_ops::u32divmod(block_builder, proc_ctx, None)?,
209 Instruction::U32DivModImm(v) => {
210 u32_ops::u32divmod(block_builder, proc_ctx, Some(v.expect_spanned_value()))?
211 },
212 Instruction::U32And => block_builder.push_op(U32and),
213 Instruction::U32Or => block_builder.push_ops([Dup1, Dup1, U32and, Neg, Add, Add]),
214 Instruction::U32Xor => block_builder.push_op(U32xor),
215 Instruction::U32Not => u32_ops::u32not(block_builder),
216 Instruction::U32Shl => u32_ops::u32shl(block_builder, None)?,
217 Instruction::U32ShlImm(v) => u32_ops::u32shl(block_builder, Some(v.expect_value()))?,
218 Instruction::U32Shr => u32_ops::u32shr(block_builder, None)?,
219 Instruction::U32ShrImm(v) => u32_ops::u32shr(block_builder, Some(v.expect_value()))?,
220 Instruction::U32Rotl => u32_ops::u32rotl(block_builder, None)?,
221 Instruction::U32RotlImm(v) => u32_ops::u32rotl(block_builder, Some(v.expect_value()))?,
222 Instruction::U32Rotr => u32_ops::u32rotr(block_builder, None)?,
223 Instruction::U32RotrImm(v) => u32_ops::u32rotr(block_builder, Some(v.expect_value()))?,
224 Instruction::U32Popcnt => u32_ops::u32popcnt(block_builder),
225 Instruction::U32Clz => u32_ops::u32clz(block_builder),
226 Instruction::U32Ctz => u32_ops::u32ctz(block_builder),
227 Instruction::U32Clo => u32_ops::u32clo(block_builder),
228 Instruction::U32Cto => u32_ops::u32cto(block_builder),
229 Instruction::U32Lt => u32_ops::u32lt(block_builder),
230 Instruction::U32Lte => u32_ops::u32lte(block_builder),
231 Instruction::U32Gt => u32_ops::u32gt(block_builder),
232 Instruction::U32Gte => u32_ops::u32gte(block_builder),
233 Instruction::U32Min => u32_ops::u32min(block_builder),
234 Instruction::U32Max => u32_ops::u32max(block_builder),
235
236 Instruction::Drop => block_builder.push_op(Drop),
238 Instruction::DropW => block_builder.push_ops([Drop; 4]),
239 Instruction::PadW => block_builder.push_ops([Pad; 4]),
240 Instruction::Dup0 => block_builder.push_op(Dup0),
241 Instruction::Dup1 => block_builder.push_op(Dup1),
242 Instruction::Dup2 => block_builder.push_op(Dup2),
243 Instruction::Dup3 => block_builder.push_op(Dup3),
244 Instruction::Dup4 => block_builder.push_op(Dup4),
245 Instruction::Dup5 => block_builder.push_op(Dup5),
246 Instruction::Dup6 => block_builder.push_op(Dup6),
247 Instruction::Dup7 => block_builder.push_op(Dup7),
248 Instruction::Dup8 => block_builder.push_ops([Pad, Dup9, Add]),
249 Instruction::Dup9 => block_builder.push_op(Dup9),
250 Instruction::Dup10 => block_builder.push_ops([Pad, Dup11, Add]),
251 Instruction::Dup11 => block_builder.push_op(Dup11),
252 Instruction::Dup12 => block_builder.push_ops([Pad, Dup13, Add]),
253 Instruction::Dup13 => block_builder.push_op(Dup13),
254 Instruction::Dup14 => block_builder.push_ops([Pad, Dup15, Add]),
255 Instruction::Dup15 => block_builder.push_op(Dup15),
256 Instruction::DupW0 => block_builder.push_ops([Dup3; 4]),
257 Instruction::DupW1 => block_builder.push_ops([Dup7; 4]),
258 Instruction::DupW2 => block_builder.push_ops([Dup11; 4]),
259 Instruction::DupW3 => block_builder.push_ops([Dup15; 4]),
260 Instruction::Swap1 => block_builder.push_op(Swap),
261 Instruction::Swap2 => block_builder.push_ops([Swap, MovUp2]),
262 Instruction::Swap3 => block_builder.push_ops([MovDn2, MovUp3]),
263 Instruction::Swap4 => block_builder.push_ops([MovDn3, MovUp4]),
264 Instruction::Swap5 => block_builder.push_ops([MovDn4, MovUp5]),
265 Instruction::Swap6 => block_builder.push_ops([MovDn5, MovUp6]),
266 Instruction::Swap7 => block_builder.push_ops([MovDn6, MovUp7]),
267 Instruction::Swap8 => block_builder.push_ops([MovDn7, MovUp8]),
268 Instruction::Swap9 => block_builder.push_ops([MovDn8, SwapDW, Swap, SwapDW, MovUp8]),
269 Instruction::Swap10 => {
270 block_builder.push_ops([MovDn8, SwapDW, Swap, MovUp2, SwapDW, MovUp8])
271 },
272 Instruction::Swap11 => {
273 block_builder.push_ops([MovDn8, SwapDW, MovDn2, MovUp3, SwapDW, MovUp8])
274 },
275 Instruction::Swap12 => {
276 block_builder.push_ops([MovDn8, SwapDW, MovDn3, MovUp4, SwapDW, MovUp8])
277 },
278 Instruction::Swap13 => {
279 block_builder.push_ops([MovDn8, SwapDW, MovDn4, MovUp5, SwapDW, MovUp8])
280 },
281 Instruction::Swap14 => {
282 block_builder.push_ops([MovDn8, SwapDW, MovDn5, MovUp6, SwapDW, MovUp8])
283 },
284 Instruction::Swap15 => {
285 block_builder.push_ops([MovDn8, SwapDW, MovDn6, MovUp7, SwapDW, MovUp8])
286 },
287 Instruction::SwapW1 => block_builder.push_op(SwapW),
288 Instruction::SwapW2 => block_builder.push_op(SwapW2),
289 Instruction::SwapW3 => block_builder.push_op(SwapW3),
290 Instruction::SwapDw => block_builder.push_op(SwapDW),
291 Instruction::MovUp2 => block_builder.push_op(MovUp2),
292 Instruction::MovUp3 => block_builder.push_op(MovUp3),
293 Instruction::MovUp4 => block_builder.push_op(MovUp4),
294 Instruction::MovUp5 => block_builder.push_op(MovUp5),
295 Instruction::MovUp6 => block_builder.push_op(MovUp6),
296 Instruction::MovUp7 => block_builder.push_op(MovUp7),
297 Instruction::MovUp8 => block_builder.push_op(MovUp8),
298 Instruction::MovUp9 => block_builder.push_ops([SwapDW, Swap, SwapDW, MovUp8]),
299 Instruction::MovUp10 => block_builder.push_ops([SwapDW, MovUp2, SwapDW, MovUp8]),
300 Instruction::MovUp11 => block_builder.push_ops([SwapDW, MovUp3, SwapDW, MovUp8]),
301 Instruction::MovUp12 => block_builder.push_ops([SwapDW, MovUp4, SwapDW, MovUp8]),
302 Instruction::MovUp13 => block_builder.push_ops([SwapDW, MovUp5, SwapDW, MovUp8]),
303 Instruction::MovUp14 => block_builder.push_ops([SwapDW, MovUp6, SwapDW, MovUp8]),
304 Instruction::MovUp15 => block_builder.push_ops([SwapDW, MovUp7, SwapDW, MovUp8]),
305 Instruction::MovUpW2 => block_builder.push_ops([SwapW, SwapW2]),
306 Instruction::MovUpW3 => block_builder.push_ops([SwapW, SwapW2, SwapW3]),
307 Instruction::MovDn2 => block_builder.push_op(MovDn2),
308 Instruction::MovDn3 => block_builder.push_op(MovDn3),
309 Instruction::MovDn4 => block_builder.push_op(MovDn4),
310 Instruction::MovDn5 => block_builder.push_op(MovDn5),
311 Instruction::MovDn6 => block_builder.push_op(MovDn6),
312 Instruction::MovDn7 => block_builder.push_op(MovDn7),
313 Instruction::MovDn8 => block_builder.push_op(MovDn8),
314 Instruction::MovDn9 => block_builder.push_ops([MovDn8, SwapDW, Swap, SwapDW]),
315 Instruction::MovDn10 => block_builder.push_ops([MovDn8, SwapDW, MovDn2, SwapDW]),
316 Instruction::MovDn11 => block_builder.push_ops([MovDn8, SwapDW, MovDn3, SwapDW]),
317 Instruction::MovDn12 => block_builder.push_ops([MovDn8, SwapDW, MovDn4, SwapDW]),
318 Instruction::MovDn13 => block_builder.push_ops([MovDn8, SwapDW, MovDn5, SwapDW]),
319 Instruction::MovDn14 => block_builder.push_ops([MovDn8, SwapDW, MovDn6, SwapDW]),
320 Instruction::MovDn15 => block_builder.push_ops([MovDn8, SwapDW, MovDn7, SwapDW]),
321 Instruction::MovDnW2 => block_builder.push_ops([SwapW2, SwapW]),
322 Instruction::MovDnW3 => block_builder.push_ops([SwapW3, SwapW2, SwapW]),
323
324 Instruction::CSwap => block_builder.push_op(CSwap),
325 Instruction::CSwapW => block_builder.push_op(CSwapW),
326 Instruction::CDrop => block_builder.push_ops([CSwap, Drop]),
327 Instruction::CDropW => block_builder.push_ops([CSwapW, Drop, Drop, Drop, Drop]),
328
329 Instruction::Push(imm) => env_ops::push_one(imm.expect_value(), block_builder),
331 Instruction::PushU8(imm) => env_ops::push_one(*imm, block_builder),
332 Instruction::PushU16(imm) => env_ops::push_one(*imm, block_builder),
333 Instruction::PushU32(imm) => env_ops::push_one(*imm, block_builder),
334 Instruction::PushFelt(imm) => env_ops::push_one(*imm, block_builder),
335 Instruction::PushWord(imms) => env_ops::push_many(imms, block_builder),
336 Instruction::PushU8List(imms) => env_ops::push_many(imms, block_builder),
337 Instruction::PushU16List(imms) => env_ops::push_many(imms, block_builder),
338 Instruction::PushU32List(imms) => env_ops::push_many(imms, block_builder),
339 Instruction::PushFeltList(imms) => env_ops::push_many(imms, block_builder),
340 Instruction::Sdepth => block_builder.push_op(SDepth),
341 Instruction::Caller => env_ops::caller(block_builder, proc_ctx, instruction.span())?,
342 Instruction::Clk => block_builder.push_op(Clk),
343 Instruction::AdvPipe => block_builder.push_op(Pipe),
344 Instruction::AdvPush(n) => adv_ops::adv_push(block_builder, n.expect_value())?,
345 Instruction::AdvLoadW => block_builder.push_op(AdvPopW),
346
347 Instruction::MemStream => block_builder.push_op(MStream),
348 Instruction::Locaddr(v) => env_ops::locaddr(block_builder, v.expect_value(), proc_ctx)?,
349 Instruction::MemLoad => mem_ops::mem_read(block_builder, proc_ctx, None, false, true)?,
350 Instruction::MemLoadImm(v) => {
351 mem_ops::mem_read(block_builder, proc_ctx, Some(v.expect_value()), false, true)?
352 },
353 Instruction::MemLoadW => {
354 mem_ops::mem_read(block_builder, proc_ctx, None, false, false)?
355 },
356 Instruction::MemLoadWImm(v) => {
357 mem_ops::mem_read(block_builder, proc_ctx, Some(v.expect_value()), false, false)?
358 },
359 Instruction::LocLoad(v) => mem_ops::mem_read(
360 block_builder,
361 proc_ctx,
362 Some(v.expect_value() as u32),
363 true,
364 true,
365 )?,
366 Instruction::LocLoadW(v) => {
367 let local_addr = v.expect_value();
368 if local_addr % WORD_SIZE as u16 != 0 {
369 return Err(AssemblyError::InvalidLocalWordIndex {
370 span: instruction.span(),
371 source_file: proc_ctx
372 .source_manager()
373 .get(proc_ctx.span().source_id())
374 .ok(),
375 local_addr,
376 });
377 }
378
379 mem_ops::mem_read(block_builder, proc_ctx, Some(local_addr as u32), true, false)?
380 },
381 Instruction::MemStore => block_builder.push_ops([MStore, Drop]),
382 Instruction::MemStoreW => block_builder.push_ops([MStoreW]),
383 Instruction::MemStoreImm(v) => {
384 mem_ops::mem_write_imm(block_builder, proc_ctx, v.expect_value(), false, true)?
385 },
386 Instruction::MemStoreWImm(v) => {
387 mem_ops::mem_write_imm(block_builder, proc_ctx, v.expect_value(), false, false)?
388 },
389 Instruction::LocStore(v) => mem_ops::mem_write_imm(
390 block_builder,
391 proc_ctx,
392 v.expect_value() as u32,
393 true,
394 true,
395 )?,
396 Instruction::LocStoreW(v) => {
397 let local_addr = v.expect_value();
398 if local_addr % WORD_SIZE as u16 != 0 {
399 return Err(AssemblyError::InvalidLocalWordIndex {
400 span: instruction.span(),
401 source_file: proc_ctx
402 .source_manager()
403 .get(proc_ctx.span().source_id())
404 .ok(),
405 local_addr,
406 });
407 }
408
409 mem_ops::mem_write_imm(block_builder, proc_ctx, local_addr as u32, true, false)?
410 },
411 Instruction::SysEvent(system_event) => {
412 block_builder.push_system_event(system_event.into())
413 },
414
415 Instruction::Hash => crypto_ops::hash(block_builder),
417 Instruction::HPerm => block_builder.push_op(HPerm),
418 Instruction::HMerge => crypto_ops::hmerge(block_builder),
419 Instruction::MTreeGet => crypto_ops::mtree_get(block_builder),
420 Instruction::MTreeSet => crypto_ops::mtree_set(block_builder)?,
421 Instruction::MTreeMerge => crypto_ops::mtree_merge(block_builder),
422 Instruction::MTreeVerify => block_builder.push_op(MpVerify(ZERO)),
423 Instruction::MTreeVerifyWithError(err_msg) => {
424 let error_code = block_builder.register_error(err_msg.expect_string());
425 block_builder.push_op(MpVerify(error_code))
426 },
427
428 Instruction::FriExt2Fold4 => block_builder.push_op(FriE2F4),
430 Instruction::HornerBase => block_builder.push_op(HornerBase),
431 Instruction::HornerExt => block_builder.push_op(HornerExt),
432 Instruction::ArithmeticCircuitEval => {
433 block_builder.push_op(Operation::ArithmeticCircuitEval);
434 },
435
436 Instruction::Exec(callee) => {
438 return self
439 .invoke(
440 InvokeKind::Exec,
441 callee,
442 proc_ctx,
443 block_builder.mast_forest_builder_mut(),
444 )
445 .map(Into::into);
446 },
447 Instruction::Call(callee) => {
448 return self
449 .invoke(
450 InvokeKind::Call,
451 callee,
452 proc_ctx,
453 block_builder.mast_forest_builder_mut(),
454 )
455 .map(Into::into);
456 },
457 Instruction::SysCall(callee) => {
458 return self
459 .invoke(
460 InvokeKind::SysCall,
461 callee,
462 proc_ctx,
463 block_builder.mast_forest_builder_mut(),
464 )
465 .map(Into::into);
466 },
467 Instruction::DynExec => return self.dynexec(block_builder.mast_forest_builder_mut()),
468 Instruction::DynCall => return self.dyncall(block_builder.mast_forest_builder_mut()),
469 Instruction::ProcRef(callee) => self.procref(callee, proc_ctx, block_builder)?,
470
471 Instruction::Breakpoint => {
473 if self.in_debug_mode() {
474 block_builder.push_op(Noop);
475 block_builder.track_instruction(instruction, proc_ctx)?;
476 }
477 },
478
479 Instruction::Debug(options) => {
480 if self.in_debug_mode() {
481 block_builder.push_decorator(Decorator::Debug(
482 options.clone().try_into().expect("unresolved constant"),
483 ))?;
484 }
485 },
486
487 Instruction::Emit(event_id) => {
489 block_builder.push_op(Operation::Emit(event_id.expect_value()));
490 },
491
492 Instruction::Trace(trace_id) => {
494 block_builder.push_decorator(Decorator::Trace(trace_id.expect_value()))?;
495 },
496 }
497
498 Ok(None)
499 }
500}
501
502fn push_u32_value(span_builder: &mut BasicBlockBuilder, value: u32) {
511 use Operation::*;
512
513 if value == 0 {
514 span_builder.push_op(Pad);
515 } else if value == 1 {
516 span_builder.push_op(Pad);
517 span_builder.push_op(Incr);
518 } else {
519 span_builder.push_op(Push(Felt::from(value)));
520 }
521}
522
523fn push_felt(span_builder: &mut BasicBlockBuilder, value: Felt) {
529 use Operation::*;
530
531 if value == ZERO {
532 span_builder.push_op(Pad);
533 } else if value == ONE {
534 span_builder.push_op(Pad);
535 span_builder.push_op(Incr);
536 } else {
537 span_builder.push_op(Push(value));
538 }
539}
540
541fn validate_param<I, R>(value: I, range: R) -> Result<(), AssemblyError>
544where
545 I: Ord + Clone + Into<u64>,
546 R: RangeBounds<I>,
547{
548 range.contains(&value).then_some(()).ok_or_else(|| {
549 let value: u64 = value.into();
550 let min = bound_into_included_u64(range.start_bound(), true);
551 let max = bound_into_included_u64(range.end_bound(), false);
552 AssemblyError::Other(
553 report!(
554 "parameter value must be greater than or equal to {min} and \
555 less than or equal to {max}, but was {value}",
556 )
557 .into(),
558 )
559 })
560}