1use miden_assembly_syntax::{
2 ast::{ImmU16, Instruction},
3 debuginfo::{Span, Spanned},
4 diagnostics::{RelatedLabel, Report},
5 parser::{IntValue, PushValue},
6};
7use miden_core::{
8 Felt, WORD_SIZE, ZERO,
9 events::SystemEvent,
10 operations::{AssemblyOp, Operation},
11};
12
13use crate::{
14 Assembler, ProcedureContext, ast::InvokeKind, basic_block_builder::BasicBlockBuilder,
15 mast_forest_builder::MastNodeUse, push_value_ops,
16};
17
18mod crypto_ops;
19mod env_ops;
20mod ext2_ops;
21mod field_ops;
22mod mem_ops;
23mod procedures;
24mod u32_ops;
25
26use self::u32_ops::U32OpMode::*;
27
28impl Assembler {
30 pub(super) fn compile_instruction(
31 &self,
32 instruction: &Span<Instruction>,
33 block_builder: &mut BasicBlockBuilder,
34 proc_ctx: &mut ProcedureContext,
35 ) -> Result<Option<MastNodeUse>, Report> {
36 let can_create_node = matches!(
38 instruction.inner(),
39 Instruction::Call(_)
40 | Instruction::SysCall(_)
41 | Instruction::DynExec
42 | Instruction::DynCall
43 );
44
45 block_builder.track_instruction(instruction, proc_ctx);
49
50 let pending_node_asm_op = if can_create_node {
53 block_builder.set_instruction_cycle_count().map(|mut asm_op| {
56 asm_op.set_num_cycles(1);
57 asm_op
58 })
59 } else {
60 None
61 };
62
63 let opt_new_node_id = self.compile_instruction_impl(
65 instruction,
66 block_builder,
67 proc_ctx,
68 pending_node_asm_op,
69 )?;
70
71 if !can_create_node {
73 let _ = block_builder.set_instruction_cycle_count();
74 }
75
76 Ok(opt_new_node_id)
77 }
78
79 fn compile_instruction_impl(
80 &self,
81 instruction: &Span<Instruction>,
82 block_builder: &mut BasicBlockBuilder,
83 proc_ctx: &mut ProcedureContext,
84 node_asm_op: Option<AssemblyOp>,
85 ) -> Result<Option<MastNodeUse>, Report> {
86 use Operation::*;
87
88 let span = instruction.span();
89 match &**instruction {
90 Instruction::Nop => block_builder.push_op(Noop),
91 Instruction::Assert => block_builder.push_op(Assert(ZERO)),
92 Instruction::AssertWithError(err_msg) => {
93 let error_code = block_builder.register_error(err_msg.expect_string());
94 block_builder.push_op(Assert(error_code))
95 },
96 Instruction::AssertEq => block_builder.push_ops([Eq, Assert(ZERO)]),
97 Instruction::AssertEqWithError(err_msg) => {
98 let error_code = block_builder.register_error(err_msg.expect_string());
99 block_builder.push_ops([Eq, Assert(error_code)])
100 },
101 Instruction::AssertEqw => field_ops::assertw(block_builder, ZERO),
102 Instruction::AssertEqwWithError(err_msg) => {
103 let error_code = block_builder.register_error(err_msg.expect_string());
104 field_ops::assertw(block_builder, error_code)
105 },
106 Instruction::Assertz => block_builder.push_ops([Eqz, Assert(ZERO)]),
107 Instruction::AssertzWithError(err_msg) => {
108 let error_code = block_builder.register_error(err_msg.expect_string());
109 block_builder.push_ops([Eqz, Assert(error_code)])
110 },
111
112 Instruction::Add => block_builder.push_op(Add),
113 Instruction::AddImm(imm) => field_ops::add_imm(block_builder, imm.expect_value()),
114 Instruction::Sub => block_builder.push_ops([Neg, Add]),
115 Instruction::SubImm(imm) => field_ops::sub_imm(block_builder, imm.expect_value()),
116 Instruction::Mul => block_builder.push_op(Mul),
117 Instruction::MulImm(imm) => field_ops::mul_imm(block_builder, imm.expect_value()),
118 Instruction::Div => block_builder.push_ops([Inv, Mul]),
119 Instruction::DivImm(imm) => {
120 field_ops::div_imm(block_builder, proc_ctx, imm.expect_spanned_value())?;
121 },
122 Instruction::Neg => block_builder.push_op(Neg),
123 Instruction::Inv => block_builder.push_op(Inv),
124 Instruction::Incr => block_builder.push_op(Incr),
125
126 Instruction::Pow2 => field_ops::pow2(block_builder),
127 Instruction::Exp => {
128 field_ops::exp(block_builder, proc_ctx, crate::MAX_DYNAMIC_EXP_BITS, span)?
129 },
130
131 Instruction::ExpImm(pow) => field_ops::exp_imm(block_builder, pow.expect_value()),
132 Instruction::ExpBitLength(num_pow_bits) => {
133 field_ops::exp(block_builder, proc_ctx, *num_pow_bits, span)?
134 },
135 Instruction::ILog2 => field_ops::ilog2(block_builder),
136
137 Instruction::Not => block_builder.push_op(Not),
138 Instruction::And => block_builder.push_op(And),
139 Instruction::Or => block_builder.push_op(Or),
140 Instruction::Xor => block_builder.push_ops([Dup0, Dup2, Or, MovDn2, And, Not, And]),
141
142 Instruction::Eq => block_builder.push_op(Eq),
143 Instruction::EqImm(imm) => field_ops::eq_imm(block_builder, imm.expect_value()),
144 Instruction::Eqw => field_ops::eqw(block_builder),
145 Instruction::Neq => block_builder.push_ops([Eq, Not]),
146 Instruction::NeqImm(imm) => field_ops::neq_imm(block_builder, imm.expect_value()),
147 Instruction::Lt => field_ops::lt(block_builder),
148 Instruction::LtImm(imm) => field_ops::lt_imm(block_builder, imm.expect_value()),
149 Instruction::Lte => field_ops::lte(block_builder),
150 Instruction::LteImm(imm) => field_ops::lte_imm(block_builder, imm.expect_value()),
151 Instruction::Gt => field_ops::gt(block_builder),
152 Instruction::GtImm(imm) => field_ops::gt_imm(block_builder, imm.expect_value()),
153 Instruction::Gte => field_ops::gte(block_builder),
154 Instruction::GteImm(imm) => field_ops::gte_imm(block_builder, imm.expect_value()),
155 Instruction::IsOdd => field_ops::is_odd(block_builder),
156
157 Instruction::Ext2Add => ext2_ops::ext2_add(block_builder),
159 Instruction::Ext2Sub => ext2_ops::ext2_sub(block_builder),
160 Instruction::Ext2Mul => ext2_ops::ext2_mul(block_builder),
161 Instruction::Ext2Div => ext2_ops::ext2_div(block_builder),
162 Instruction::Ext2Neg => ext2_ops::ext2_neg(block_builder),
163 Instruction::Ext2Inv => ext2_ops::ext2_inv(block_builder),
164
165 Instruction::U32Test => block_builder.push_ops([Dup0, U32split, Drop, Eqz]),
167 Instruction::U32TestW => u32_ops::u32testw(block_builder),
168 Instruction::U32Assert => block_builder.push_ops([Pad, U32assert2(ZERO), Drop]),
169 Instruction::U32AssertWithError(err_msg) => {
170 let error_code = block_builder.register_error(err_msg.expect_string());
171 block_builder.push_ops([Pad, U32assert2(error_code), Drop])
172 },
173 Instruction::U32Assert2 => block_builder.push_op(U32assert2(ZERO)),
174 Instruction::U32Assert2WithError(err_msg) => {
175 let error_code = block_builder.register_error(err_msg.expect_string());
176 block_builder.push_op(U32assert2(error_code))
177 },
178 Instruction::U32AssertW => u32_ops::u32assertw(block_builder, ZERO),
179 Instruction::U32AssertWWithError(err_msg) => {
180 let error_code = block_builder.register_error(err_msg.expect_string());
181 u32_ops::u32assertw(block_builder, error_code)
182 },
183
184 Instruction::U32Cast => block_builder.push_ops([U32split, Swap, Drop]),
185 Instruction::U32Split => block_builder.push_op(U32split),
186
187 Instruction::U32OverflowingAdd => u32_ops::u32overflowing_add(block_builder, None),
188 Instruction::U32OverflowingAddImm(v) => {
189 u32_ops::u32overflowing_add(block_builder, Some(v.expect_value()))
190 },
191 Instruction::U32WideningAdd => u32_ops::u32widening_add(block_builder, None),
192 Instruction::U32WideningAddImm(v) => {
193 u32_ops::u32widening_add(block_builder, Some(v.expect_value()))
194 },
195 Instruction::U32WrappingAdd => u32_ops::u32add(block_builder, Wrapping, None),
196 Instruction::U32WrappingAddImm(v) => {
197 u32_ops::u32add(block_builder, Wrapping, Some(v.expect_value()))
198 },
199 Instruction::U32OverflowingAdd3 => u32_ops::u32overflowing_add3(block_builder),
200 Instruction::U32WideningAdd3 => u32_ops::u32widening_add3(block_builder),
201 Instruction::U32WrappingAdd3 => u32_ops::u32wrapping_add3(block_builder),
202
203 Instruction::U32OverflowingSub => u32_ops::u32sub(block_builder, Overflowing, None),
204 Instruction::U32OverflowingSubImm(v) => {
205 u32_ops::u32sub(block_builder, Overflowing, Some(v.expect_value()))
206 },
207 Instruction::U32WrappingSub => u32_ops::u32sub(block_builder, Wrapping, None),
208 Instruction::U32WrappingSubImm(v) => {
209 u32_ops::u32sub(block_builder, Wrapping, Some(v.expect_value()))
210 },
211
212 Instruction::U32WideningMul => u32_ops::u32mul(block_builder, Overflowing, None),
213 Instruction::U32WideningMulImm(v) => {
214 u32_ops::u32mul(block_builder, Overflowing, Some(v.expect_value()))
215 },
216 Instruction::U32WrappingMul => u32_ops::u32mul(block_builder, Wrapping, None),
217 Instruction::U32WrappingMulImm(v) => {
218 u32_ops::u32mul(block_builder, Wrapping, Some(v.expect_value()))
219 },
220 Instruction::U32WideningMadd => block_builder.push_op(U32madd),
221 Instruction::U32WrappingMadd => block_builder.push_ops([U32madd, Swap, Drop]),
222
223 Instruction::U32Div => u32_ops::u32div(block_builder, proc_ctx, None)?,
224 Instruction::U32DivImm(v) => {
225 u32_ops::u32div(block_builder, proc_ctx, Some(v.expect_spanned_value()))?
226 },
227 Instruction::U32Mod => u32_ops::u32mod(block_builder, proc_ctx, None)?,
228 Instruction::U32ModImm(v) => {
229 u32_ops::u32mod(block_builder, proc_ctx, Some(v.expect_spanned_value()))?
230 },
231 Instruction::U32DivMod => u32_ops::u32divmod(block_builder, proc_ctx, None)?,
232 Instruction::U32DivModImm(v) => {
233 u32_ops::u32divmod(block_builder, proc_ctx, Some(v.expect_spanned_value()))?
234 },
235 Instruction::U32And => block_builder.push_op(U32and),
236 Instruction::U32Or => block_builder.push_ops([Dup1, Dup1, U32and, Neg, Add, Add]),
237 Instruction::U32Xor => block_builder.push_op(U32xor),
238 Instruction::U32Not => u32_ops::u32not(block_builder),
239 Instruction::U32Shl => u32_ops::u32shl(block_builder, proc_ctx, None, span)?,
240 Instruction::U32ShlImm(v) => {
241 u32_ops::u32shl(block_builder, proc_ctx, Some(v.expect_value()), span)?
242 },
243 Instruction::U32Shr => u32_ops::u32shr(block_builder, proc_ctx, None, span)?,
244 Instruction::U32ShrImm(v) => {
245 u32_ops::u32shr(block_builder, proc_ctx, Some(v.expect_value()), v.span())?
246 },
247 Instruction::U32Rotl => u32_ops::u32rotl(block_builder, proc_ctx, None, span)?,
248 Instruction::U32RotlImm(v) => {
249 u32_ops::u32rotl(block_builder, proc_ctx, Some(v.expect_value()), v.span())?
250 },
251 Instruction::U32Rotr => u32_ops::u32rotr(block_builder, proc_ctx, None, span)?,
252 Instruction::U32RotrImm(v) => {
253 u32_ops::u32rotr(block_builder, proc_ctx, Some(v.expect_value()), v.span())?
254 },
255 Instruction::U32Popcnt => u32_ops::u32popcnt(block_builder),
256 Instruction::U32Clz => u32_ops::u32clz(block_builder),
257 Instruction::U32Ctz => u32_ops::u32ctz(block_builder),
258 Instruction::U32Clo => u32_ops::u32clo(block_builder),
259 Instruction::U32Cto => u32_ops::u32cto(block_builder),
260 Instruction::U32Lt => u32_ops::u32lt(block_builder),
261 Instruction::U32Lte => u32_ops::u32lte(block_builder),
262 Instruction::U32Gt => u32_ops::u32gt(block_builder),
263 Instruction::U32Gte => u32_ops::u32gte(block_builder),
264 Instruction::U32Min => u32_ops::u32min(block_builder),
265 Instruction::U32Max => u32_ops::u32max(block_builder),
266
267 Instruction::Drop => block_builder.push_op(Drop),
269 Instruction::DropW => block_builder.push_ops([Drop; 4]),
270 Instruction::PadW => block_builder.push_ops([Pad; 4]),
271 Instruction::Dup0 => block_builder.push_op(Dup0),
272 Instruction::Dup1 => block_builder.push_op(Dup1),
273 Instruction::Dup2 => block_builder.push_op(Dup2),
274 Instruction::Dup3 => block_builder.push_op(Dup3),
275 Instruction::Dup4 => block_builder.push_op(Dup4),
276 Instruction::Dup5 => block_builder.push_op(Dup5),
277 Instruction::Dup6 => block_builder.push_op(Dup6),
278 Instruction::Dup7 => block_builder.push_op(Dup7),
279 Instruction::Dup8 => block_builder.push_ops([Pad, Dup9, Add]),
280 Instruction::Dup9 => block_builder.push_op(Dup9),
281 Instruction::Dup10 => block_builder.push_ops([Pad, Dup11, Add]),
282 Instruction::Dup11 => block_builder.push_op(Dup11),
283 Instruction::Dup12 => block_builder.push_ops([Pad, Dup13, Add]),
284 Instruction::Dup13 => block_builder.push_op(Dup13),
285 Instruction::Dup14 => block_builder.push_ops([Pad, Dup15, Add]),
286 Instruction::Dup15 => block_builder.push_op(Dup15),
287 Instruction::DupW0 => block_builder.push_ops([Dup3; 4]),
288 Instruction::DupW1 => block_builder.push_ops([Dup7; 4]),
289 Instruction::DupW2 => block_builder.push_ops([Dup11; 4]),
290 Instruction::DupW3 => block_builder.push_ops([Dup15; 4]),
291 Instruction::Swap1 => block_builder.push_op(Swap),
292 Instruction::Swap2 => block_builder.push_ops([Swap, MovUp2]),
293 Instruction::Swap3 => block_builder.push_ops([MovDn2, MovUp3]),
294 Instruction::Swap4 => block_builder.push_ops([MovDn3, MovUp4]),
295 Instruction::Swap5 => block_builder.push_ops([MovDn4, MovUp5]),
296 Instruction::Swap6 => block_builder.push_ops([MovDn5, MovUp6]),
297 Instruction::Swap7 => block_builder.push_ops([MovDn6, MovUp7]),
298 Instruction::Swap8 => block_builder.push_ops([MovDn7, MovUp8]),
299 Instruction::Swap9 => block_builder.push_ops([MovDn8, SwapDW, Swap, SwapDW, MovUp8]),
300 Instruction::Swap10 => {
301 block_builder.push_ops([MovDn8, SwapDW, Swap, MovUp2, SwapDW, MovUp8])
302 },
303 Instruction::Swap11 => {
304 block_builder.push_ops([MovDn8, SwapDW, MovDn2, MovUp3, SwapDW, MovUp8])
305 },
306 Instruction::Swap12 => {
307 block_builder.push_ops([MovDn8, SwapDW, MovDn3, MovUp4, SwapDW, MovUp8])
308 },
309 Instruction::Swap13 => {
310 block_builder.push_ops([MovDn8, SwapDW, MovDn4, MovUp5, SwapDW, MovUp8])
311 },
312 Instruction::Swap14 => {
313 block_builder.push_ops([MovDn8, SwapDW, MovDn5, MovUp6, SwapDW, MovUp8])
314 },
315 Instruction::Swap15 => {
316 block_builder.push_ops([MovDn8, SwapDW, MovDn6, MovUp7, SwapDW, MovUp8])
317 },
318 Instruction::SwapW1 => block_builder.push_op(SwapW),
319 Instruction::SwapW2 => block_builder.push_op(SwapW2),
320 Instruction::SwapW3 => block_builder.push_op(SwapW3),
321 Instruction::SwapDw => block_builder.push_op(SwapDW),
322 Instruction::MovUp2 => block_builder.push_op(MovUp2),
323 Instruction::MovUp3 => block_builder.push_op(MovUp3),
324 Instruction::MovUp4 => block_builder.push_op(MovUp4),
325 Instruction::MovUp5 => block_builder.push_op(MovUp5),
326 Instruction::MovUp6 => block_builder.push_op(MovUp6),
327 Instruction::MovUp7 => block_builder.push_op(MovUp7),
328 Instruction::MovUp8 => block_builder.push_op(MovUp8),
329 Instruction::MovUp9 => block_builder.push_ops([SwapDW, Swap, SwapDW, MovUp8]),
330 Instruction::MovUp10 => block_builder.push_ops([SwapDW, MovUp2, SwapDW, MovUp8]),
331 Instruction::MovUp11 => block_builder.push_ops([SwapDW, MovUp3, SwapDW, MovUp8]),
332 Instruction::MovUp12 => block_builder.push_ops([SwapDW, MovUp4, SwapDW, MovUp8]),
333 Instruction::MovUp13 => block_builder.push_ops([SwapDW, MovUp5, SwapDW, MovUp8]),
334 Instruction::MovUp14 => block_builder.push_ops([SwapDW, MovUp6, SwapDW, MovUp8]),
335 Instruction::MovUp15 => block_builder.push_ops([SwapDW, MovUp7, SwapDW, MovUp8]),
336 Instruction::MovUpW2 => block_builder.push_ops([SwapW, SwapW2]),
337 Instruction::MovUpW3 => block_builder.push_ops([SwapW, SwapW2, SwapW3]),
338 Instruction::MovDn2 => block_builder.push_op(MovDn2),
339 Instruction::MovDn3 => block_builder.push_op(MovDn3),
340 Instruction::MovDn4 => block_builder.push_op(MovDn4),
341 Instruction::MovDn5 => block_builder.push_op(MovDn5),
342 Instruction::MovDn6 => block_builder.push_op(MovDn6),
343 Instruction::MovDn7 => block_builder.push_op(MovDn7),
344 Instruction::MovDn8 => block_builder.push_op(MovDn8),
345 Instruction::MovDn9 => block_builder.push_ops([MovDn8, SwapDW, Swap, SwapDW]),
346 Instruction::MovDn10 => block_builder.push_ops([MovDn8, SwapDW, MovDn2, SwapDW]),
347 Instruction::MovDn11 => block_builder.push_ops([MovDn8, SwapDW, MovDn3, SwapDW]),
348 Instruction::MovDn12 => block_builder.push_ops([MovDn8, SwapDW, MovDn4, SwapDW]),
349 Instruction::MovDn13 => block_builder.push_ops([MovDn8, SwapDW, MovDn5, SwapDW]),
350 Instruction::MovDn14 => block_builder.push_ops([MovDn8, SwapDW, MovDn6, SwapDW]),
351 Instruction::MovDn15 => block_builder.push_ops([MovDn8, SwapDW, MovDn7, SwapDW]),
352 Instruction::MovDnW2 => block_builder.push_ops([SwapW2, SwapW]),
353 Instruction::MovDnW3 => block_builder.push_ops([SwapW3, SwapW2, SwapW]),
354 Instruction::Reversew => push_reversew(block_builder),
355 Instruction::Reversedw => {
356 push_reversew(block_builder);
357 block_builder.push_op(SwapW);
358 push_reversew(block_builder);
359 },
360
361 Instruction::CSwap => block_builder.push_op(CSwap),
362 Instruction::CSwapW => block_builder.push_op(CSwapW),
363 Instruction::CDrop => block_builder.push_ops([CSwap, Drop]),
364 Instruction::CDropW => block_builder.push_ops([CSwapW, Drop, Drop, Drop, Drop]),
365
366 Instruction::Push(imm) => match (*imm).expect_value() {
368 PushValue::Int(value) => match value {
369 IntValue::U8(v) => env_ops::push_one(Felt::from_u8(v), block_builder),
370 IntValue::U16(v) => env_ops::push_one(Felt::from_u16(v), block_builder),
371 IntValue::U32(v) => env_ops::push_one(Felt::from_u32(v), block_builder),
372 IntValue::Felt(v) => env_ops::push_one(v, block_builder),
373 },
374 PushValue::Word(v) => env_ops::push_word(&v.0, block_builder),
375 },
376 Instruction::PushSlice(imm, range) => {
377 env_ops::push_word_slice(imm, range, block_builder)?
378 },
379 Instruction::PushFeltList(imms) => env_ops::push_many(imms, block_builder),
380 Instruction::Sdepth => block_builder.push_op(SDepth),
381 Instruction::Caller => env_ops::caller(block_builder),
382 Instruction::Clk => block_builder.push_op(Clk),
383 Instruction::AdvPipe => block_builder.push_op(Pipe),
384 Instruction::AdvPush => block_builder.push_op(AdvPop),
385 Instruction::AdvPushW => {
386 block_builder.push_ops([Pad; 4]);
387 block_builder.push_op(AdvPopW);
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::LogDeferred => block_builder.push_op(LogDeferred),
542
543 Instruction::Exec(callee) => {
545 let inline_calls = block_builder.active_inline_call_rows(0);
546 return self
547 .invoke(
548 InvokeKind::Exec,
549 callee,
550 proc_ctx.id(),
551 block_builder.mast_forest_builder_mut(),
552 None,
553 inline_calls,
554 )
555 .map(Into::into);
556 },
557 Instruction::Call(callee) => {
558 let inline_calls = block_builder.active_inline_call_rows(0);
559 return self
560 .invoke(
561 InvokeKind::Call,
562 callee,
563 proc_ctx.id(),
564 block_builder.mast_forest_builder_mut(),
565 Some(node_asm_op.expect("call instructions must provide an AssemblyOp")),
566 inline_calls,
567 )
568 .map(Into::into);
569 },
570 Instruction::SysCall(callee) => {
571 let inline_calls = block_builder.active_inline_call_rows(0);
572 return self
573 .invoke(
574 InvokeKind::SysCall,
575 callee,
576 proc_ctx.id(),
577 block_builder.mast_forest_builder_mut(),
578 Some(node_asm_op.expect("syscall instructions must provide an AssemblyOp")),
579 inline_calls,
580 )
581 .map(Into::into);
582 },
583 Instruction::DynExec => {
584 let inline_calls = block_builder.active_inline_call_rows(0);
585 return self.dynexec(
586 block_builder.mast_forest_builder_mut(),
587 node_asm_op.expect("dynexec instructions must provide an AssemblyOp"),
588 inline_calls,
589 );
590 },
591 Instruction::DynCall => {
592 let inline_calls = block_builder.active_inline_call_rows(0);
593 return self.dyncall(
594 block_builder.mast_forest_builder_mut(),
595 node_asm_op.expect("dyncall instructions must provide an AssemblyOp"),
596 inline_calls,
597 );
598 },
599 Instruction::ProcRef(callee) => self.procref(callee, proc_ctx.id(), block_builder)?,
600
601 Instruction::DebugVar(debug_var_info) => {
602 block_builder.push_debug_var(debug_var_info.clone())?;
603 },
604 Instruction::DebugInlineCall(inline_call) => {
605 block_builder.push_debug_inline_call(inline_call, proc_ctx.source_manager());
606 },
607 Instruction::DebugInlineCallClear => {
608 block_builder.clear_debug_inline_calls();
609 },
610
611 Instruction::Emit => {
614 block_builder.push_ops([Emit]);
615 },
616 Instruction::EmitImm(event_id) => {
618 let event_id_value = event_id.expect_value();
619 block_builder.push_ops([Push(event_id_value), Emit, Drop]);
620 },
621
622 Instruction::Trace => {
625 let sys_event_id = SystemEvent::TraceEvent.event_id().as_felt();
628 block_builder.push_ops([Push(sys_event_id), Emit, Drop]);
629 },
630 Instruction::TraceImm(trace_id) => {
633 let trace_id_value = trace_id.expect_value();
634 let sys_event_id = SystemEvent::TraceEvent.event_id().as_felt();
635 block_builder.push_ops([
636 Push(trace_id_value),
637 Push(sys_event_id),
638 Emit,
639 Drop,
640 Drop,
641 ]);
642 },
643 }
644
645 Ok(None)
646 }
647}
648
649fn push_u32_value(span_builder: &mut BasicBlockBuilder, value: u32) {
658 use Operation::*;
659
660 if value == 0 {
661 span_builder.push_op(Pad);
662 } else if value == 1 {
663 span_builder.push_op(Pad);
664 span_builder.push_op(Incr);
665 } else {
666 span_builder.push_op(Push(Felt::from_u32(value)));
667 }
668}
669
670fn push_felt(span_builder: &mut BasicBlockBuilder, value: Felt) {
676 span_builder.push_ops(push_value_ops(value));
677}
678
679fn push_reversew(block_builder: &mut BasicBlockBuilder) {
685 use Operation::*;
686
687 block_builder.push_ops([MovDn3, Swap, MovUp2]);
688}
689
690fn validate_local_word_alignment(
694 local_addr: &ImmU16,
695 proc_ctx: &ProcedureContext,
696) -> Result<u32, Report> {
697 let addr = local_addr.expect_value();
698 if !addr.is_multiple_of(WORD_SIZE as u16) {
699 return Err(RelatedLabel::error("invalid local word index")
700 .with_help("the index to a local word must be a multiple of 4")
701 .with_labeled_span(local_addr.span(), "this index is not word-aligned")
702 .with_source_file(proc_ctx.source_manager().get(proc_ctx.span().source_id()).ok())
703 .into());
704 }
705 Ok(addr as u32)
706}