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