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