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