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