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