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