1use super::{
4 BlockId, Function, FunctionId, Immediate, InstId, InstKind, Instruction, MemoryRegion, MirType,
5 StorageAlias, Terminator, Value, ValueId,
6};
7use alloy_primitives::U256;
8use smallvec::SmallVec;
9
10pub struct FunctionBuilder<'a> {
12 func: &'a mut Function,
14 current_block: BlockId,
16}
17
18impl<'a> FunctionBuilder<'a> {
19 pub fn new(func: &'a mut Function) -> Self {
21 let entry = func.entry_block;
22 Self { func, current_block: entry }
23 }
24
25 #[must_use]
27 pub const fn current_block(&self) -> BlockId {
28 self.current_block
29 }
30
31 pub fn switch_to_block(&mut self, block: BlockId) {
33 self.current_block = block;
34 }
35
36 pub fn create_block(&mut self) -> BlockId {
38 self.func.alloc_block()
39 }
40
41 pub fn add_param(&mut self, ty: MirType) -> ValueId {
43 let index = self.func.params.len() as u32;
44 self.func.params.push(ty);
45 self.func.alloc_value(Value::Arg { index, ty })
46 }
47
48 pub fn add_return(&mut self, ty: MirType) {
50 self.func.returns.push(ty);
51 }
52
53 pub fn imm_u256(&mut self, value: U256) -> ValueId {
55 self.func.alloc_value(Value::Immediate(Immediate::uint256(value)))
56 }
57
58 pub fn imm_u64(&mut self, value: u64) -> ValueId {
60 self.imm_u256(U256::from(value))
61 }
62
63 pub fn imm_bool(&mut self, value: bool) -> ValueId {
65 self.func.alloc_value(Value::Immediate(Immediate::bool(value)))
66 }
67
68 pub fn undef(&mut self, ty: MirType) -> ValueId {
70 self.func.alloc_value(Value::Undef(ty))
71 }
72
73 pub fn error_value(&mut self, guar: solar_interface::diagnostics::ErrorGuaranteed) -> ValueId {
75 self.func.alloc_value(Value::Error(guar))
76 }
77
78 fn emit_inst_raw(&mut self, kind: InstKind, result_ty: Option<MirType>) -> InstId {
79 let mut inst = Instruction::new(kind, result_ty);
80 inst.metadata.set_effect(Some(inst.kind.effect_kind()));
81 inst.metadata.set_memory_region(self.memory_region_for_inst(&inst.kind));
82 inst.metadata.set_storage_alias(self.storage_alias_for_inst(&inst.kind));
83
84 let inst_id = self.func.alloc_inst(inst);
85 self.func.blocks[self.current_block].instructions.push(inst_id);
86 inst_id
87 }
88
89 fn emit_inst(&mut self, kind: InstKind, result_ty: Option<MirType>) -> ValueId {
90 debug_assert!(result_ty.is_some(), "value-producing instructions must have a result type");
91 let inst_id = self.emit_inst_raw(kind, result_ty);
92 self.func.alloc_value(Value::Inst(inst_id))
93 }
94
95 fn emit_void_inst(&mut self, kind: InstKind) {
100 self.emit_inst_raw(kind, None);
101 }
102
103 fn memory_region_for_inst(&self, kind: &InstKind) -> Option<MemoryRegion> {
104 let addr = match *kind {
105 InstKind::MLoad(addr)
106 | InstKind::MStore(addr, _)
107 | InstKind::MStore8(addr, _)
108 | InstKind::Keccak256(addr, _) => addr,
109 InstKind::MCopy(dest, _, _)
110 | InstKind::CalldataCopy(dest, _, _)
111 | InstKind::CodeCopy(dest, _, _)
112 | InstKind::ReturnDataCopy(dest, _, _)
113 | InstKind::ExtCodeCopy(_, dest, _, _) => dest,
114 _ => return None,
115 };
116 Some(self.memory_region_for_addr(addr))
117 }
118
119 fn memory_region_for_addr(&self, addr: ValueId) -> MemoryRegion {
120 match self.func.value(addr) {
121 Value::Immediate(imm)
122 if imm.as_u256().is_some_and(|value| value < U256::from(0x80)) =>
123 {
124 MemoryRegion::Scratch
125 }
126 Value::Inst(inst_id) => match self.func.instructions[*inst_id].kind {
127 InstKind::InternalFrameAddr(_) => MemoryRegion::InternalFrame,
128 InstKind::Add(lhs, rhs) if self.is_internal_frame_add(lhs, rhs) => {
129 MemoryRegion::InternalFrame
130 }
131 InstKind::Sub(lhs, rhs)
132 if self.is_internal_frame_addr(lhs) && self.is_immediate(rhs) =>
133 {
134 MemoryRegion::InternalFrame
135 }
136 _ => MemoryRegion::Unknown,
137 },
138 Value::Arg { .. } | Value::Immediate(_) | Value::Undef(_) | Value::Error(_) => {
139 MemoryRegion::Unknown
140 }
141 }
142 }
143
144 fn is_internal_frame_add(&self, lhs: ValueId, rhs: ValueId) -> bool {
145 (self.is_internal_frame_addr(lhs) && self.is_immediate(rhs))
146 || (self.is_internal_frame_addr(rhs) && self.is_immediate(lhs))
147 }
148
149 fn is_internal_frame_addr(&self, value: ValueId) -> bool {
150 matches!(
151 self.func.value(value),
152 Value::Inst(inst_id)
153 if matches!(self.func.instructions[*inst_id].kind, InstKind::InternalFrameAddr(_))
154 )
155 }
156
157 fn is_immediate(&self, value: ValueId) -> bool {
158 matches!(self.func.value(value), Value::Immediate(_))
159 }
160
161 fn storage_alias_for_inst(&self, kind: &InstKind) -> Option<StorageAlias> {
162 match *kind {
163 InstKind::SLoad(slot) | InstKind::SStore(slot, _) => Some(self.storage_alias(slot)),
164 _ => None,
165 }
166 }
167
168 fn storage_alias(&self, slot: ValueId) -> StorageAlias {
169 StorageAlias::for_value(self.func, slot)
170 }
171
172 pub fn add(&mut self, a: ValueId, b: ValueId) -> ValueId {
174 self.emit_inst(InstKind::Add(a, b), Some(MirType::uint256()))
175 }
176
177 pub fn sub(&mut self, a: ValueId, b: ValueId) -> ValueId {
179 self.emit_inst(InstKind::Sub(a, b), Some(MirType::uint256()))
180 }
181
182 pub fn mul(&mut self, a: ValueId, b: ValueId) -> ValueId {
184 self.emit_inst(InstKind::Mul(a, b), Some(MirType::uint256()))
185 }
186
187 pub fn div(&mut self, a: ValueId, b: ValueId) -> ValueId {
189 self.emit_inst(InstKind::Div(a, b), Some(MirType::uint256()))
190 }
191
192 pub fn sdiv(&mut self, a: ValueId, b: ValueId) -> ValueId {
194 self.emit_inst(InstKind::SDiv(a, b), Some(MirType::int256()))
195 }
196
197 pub fn mod_(&mut self, a: ValueId, b: ValueId) -> ValueId {
199 self.emit_inst(InstKind::Mod(a, b), Some(MirType::uint256()))
200 }
201
202 pub fn addmod(&mut self, a: ValueId, b: ValueId, n: ValueId) -> ValueId {
204 self.emit_inst(InstKind::AddMod(a, b, n), Some(MirType::uint256()))
205 }
206
207 pub fn mulmod(&mut self, a: ValueId, b: ValueId, n: ValueId) -> ValueId {
209 self.emit_inst(InstKind::MulMod(a, b, n), Some(MirType::uint256()))
210 }
211
212 pub fn smod(&mut self, a: ValueId, b: ValueId) -> ValueId {
214 self.emit_inst(InstKind::SMod(a, b), Some(MirType::int256()))
215 }
216
217 pub fn exp(&mut self, a: ValueId, b: ValueId) -> ValueId {
219 self.emit_inst(InstKind::Exp(a, b), Some(MirType::uint256()))
220 }
221
222 pub fn and(&mut self, a: ValueId, b: ValueId) -> ValueId {
224 self.emit_inst(InstKind::And(a, b), Some(MirType::uint256()))
225 }
226
227 pub fn or(&mut self, a: ValueId, b: ValueId) -> ValueId {
229 self.emit_inst(InstKind::Or(a, b), Some(MirType::uint256()))
230 }
231
232 pub fn xor(&mut self, a: ValueId, b: ValueId) -> ValueId {
234 self.emit_inst(InstKind::Xor(a, b), Some(MirType::uint256()))
235 }
236
237 pub fn not(&mut self, a: ValueId) -> ValueId {
239 self.emit_inst(InstKind::Not(a), Some(MirType::uint256()))
240 }
241
242 pub fn shl(&mut self, shift: ValueId, value: ValueId) -> ValueId {
244 self.emit_inst(InstKind::Shl(shift, value), Some(MirType::uint256()))
245 }
246
247 pub fn shr(&mut self, shift: ValueId, value: ValueId) -> ValueId {
249 self.emit_inst(InstKind::Shr(shift, value), Some(MirType::uint256()))
250 }
251
252 pub fn sar(&mut self, shift: ValueId, value: ValueId) -> ValueId {
254 self.emit_inst(InstKind::Sar(shift, value), Some(MirType::int256()))
255 }
256
257 pub fn lt(&mut self, a: ValueId, b: ValueId) -> ValueId {
259 self.emit_inst(InstKind::Lt(a, b), Some(MirType::Bool))
260 }
261
262 pub fn gt(&mut self, a: ValueId, b: ValueId) -> ValueId {
264 self.emit_inst(InstKind::Gt(a, b), Some(MirType::Bool))
265 }
266
267 pub fn slt(&mut self, a: ValueId, b: ValueId) -> ValueId {
269 self.emit_inst(InstKind::SLt(a, b), Some(MirType::Bool))
270 }
271
272 pub fn sgt(&mut self, a: ValueId, b: ValueId) -> ValueId {
274 self.emit_inst(InstKind::SGt(a, b), Some(MirType::Bool))
275 }
276
277 pub fn eq(&mut self, a: ValueId, b: ValueId) -> ValueId {
279 self.emit_inst(InstKind::Eq(a, b), Some(MirType::Bool))
280 }
281
282 pub fn iszero(&mut self, a: ValueId) -> ValueId {
284 self.emit_inst(InstKind::IsZero(a), Some(MirType::Bool))
285 }
286
287 pub fn byte(&mut self, index: ValueId, value: ValueId) -> ValueId {
289 self.emit_inst(InstKind::Byte(index, value), Some(MirType::uint256()))
290 }
291
292 pub fn signextend(&mut self, size: ValueId, value: ValueId) -> ValueId {
294 self.emit_inst(InstKind::SignExtend(size, value), Some(MirType::int256()))
295 }
296
297 pub fn mload(&mut self, offset: ValueId) -> ValueId {
299 self.emit_inst(InstKind::MLoad(offset), Some(MirType::uint256()))
300 }
301
302 pub fn mstore(&mut self, offset: ValueId, value: ValueId) {
304 self.emit_void_inst(InstKind::MStore(offset, value))
305 }
306
307 pub fn mstore8(&mut self, offset: ValueId, value: ValueId) {
309 self.emit_void_inst(InstKind::MStore8(offset, value))
310 }
311
312 pub fn msize(&mut self) -> ValueId {
314 self.emit_inst(InstKind::MSize, Some(MirType::uint256()))
315 }
316
317 pub fn mcopy(&mut self, dest: ValueId, src: ValueId, len: ValueId) {
319 self.emit_void_inst(InstKind::MCopy(dest, src, len))
320 }
321
322 pub fn sload(&mut self, slot: ValueId) -> ValueId {
324 self.emit_inst(InstKind::SLoad(slot), Some(MirType::uint256()))
325 }
326
327 pub fn sstore(&mut self, slot: ValueId, value: ValueId) {
329 self.emit_void_inst(InstKind::SStore(slot, value))
330 }
331
332 pub fn tload(&mut self, slot: ValueId) -> ValueId {
334 self.emit_inst(InstKind::TLoad(slot), Some(MirType::uint256()))
335 }
336
337 pub fn tstore(&mut self, slot: ValueId, value: ValueId) {
339 self.emit_void_inst(InstKind::TStore(slot, value))
340 }
341
342 pub fn calldataload(&mut self, offset: ValueId) -> ValueId {
344 self.emit_inst(InstKind::CalldataLoad(offset), Some(MirType::uint256()))
345 }
346
347 pub fn calldatasize(&mut self) -> ValueId {
349 self.emit_inst(InstKind::CalldataSize, Some(MirType::uint256()))
350 }
351
352 pub fn calldatacopy(&mut self, dest: ValueId, offset: ValueId, size: ValueId) {
354 self.emit_void_inst(InstKind::CalldataCopy(dest, offset, size))
355 }
356
357 pub fn codesize(&mut self) -> ValueId {
359 self.emit_inst(InstKind::CodeSize, Some(MirType::uint256()))
360 }
361
362 pub fn extcodesize(&mut self, addr: ValueId) -> ValueId {
364 self.emit_inst(InstKind::ExtCodeSize(addr), Some(MirType::uint256()))
365 }
366
367 pub fn load_immutable(&mut self, offset: u32) -> ValueId {
369 self.emit_inst(InstKind::LoadImmutable(offset), Some(MirType::uint256()))
370 }
371
372 pub fn extcodecopy(&mut self, addr: ValueId, dest: ValueId, offset: ValueId, size: ValueId) {
374 self.emit_void_inst(InstKind::ExtCodeCopy(addr, dest, offset, size))
375 }
376
377 pub fn extcodehash(&mut self, addr: ValueId) -> ValueId {
379 self.emit_inst(InstKind::ExtCodeHash(addr), Some(MirType::uint256()))
380 }
381
382 pub fn returndatasize(&mut self) -> ValueId {
384 self.emit_inst(InstKind::ReturnDataSize, Some(MirType::uint256()))
385 }
386
387 pub fn returndatacopy(&mut self, dest: ValueId, offset: ValueId, size: ValueId) {
389 self.emit_void_inst(InstKind::ReturnDataCopy(dest, offset, size))
390 }
391
392 pub fn internal_call(
394 &mut self,
395 function: FunctionId,
396 args: Vec<ValueId>,
397 result_ty: MirType,
398 returns: usize,
399 ) -> ValueId {
400 let returns = u32::try_from(returns).expect("too many internal call return values");
401 self.emit_inst(
402 InstKind::InternalCall { function, args: args.into(), returns },
403 Some(result_ty),
404 )
405 }
406
407 pub fn internal_call_void(&mut self, function: FunctionId, args: Vec<ValueId>, returns: usize) {
409 let returns = u32::try_from(returns).expect("too many internal call return values");
410 self.emit_void_inst(InstKind::InternalCall { function, args: args.into(), returns });
411 }
412
413 pub fn internal_frame_addr(&mut self, offset: u64) -> ValueId {
415 self.emit_inst(InstKind::InternalFrameAddr(offset), Some(MirType::MemPtr))
416 }
417
418 pub fn caller(&mut self) -> ValueId {
420 self.emit_inst(InstKind::Caller, Some(MirType::Address))
421 }
422
423 pub fn callvalue(&mut self) -> ValueId {
425 self.emit_inst(InstKind::CallValue, Some(MirType::uint256()))
426 }
427
428 pub fn origin(&mut self) -> ValueId {
430 self.emit_inst(InstKind::Origin, Some(MirType::Address))
431 }
432
433 pub fn gasprice(&mut self) -> ValueId {
435 self.emit_inst(InstKind::GasPrice, Some(MirType::uint256()))
436 }
437
438 pub fn blockhash(&mut self, block_num: ValueId) -> ValueId {
440 self.emit_inst(InstKind::BlockHash(block_num), Some(MirType::FixedBytes(32)))
441 }
442
443 pub fn coinbase(&mut self) -> ValueId {
445 self.emit_inst(InstKind::Coinbase, Some(MirType::Address))
446 }
447
448 pub fn timestamp(&mut self) -> ValueId {
450 self.emit_inst(InstKind::Timestamp, Some(MirType::uint256()))
451 }
452
453 pub fn number(&mut self) -> ValueId {
455 self.emit_inst(InstKind::BlockNumber, Some(MirType::uint256()))
456 }
457
458 pub fn prevrandao(&mut self) -> ValueId {
460 self.emit_inst(InstKind::PrevRandao, Some(MirType::uint256()))
461 }
462
463 pub fn gaslimit(&mut self) -> ValueId {
465 self.emit_inst(InstKind::GasLimit, Some(MirType::uint256()))
466 }
467
468 pub fn chainid(&mut self) -> ValueId {
470 self.emit_inst(InstKind::ChainId, Some(MirType::uint256()))
471 }
472
473 pub fn address(&mut self) -> ValueId {
475 self.emit_inst(InstKind::Address, Some(MirType::Address))
476 }
477
478 pub fn balance(&mut self, addr: ValueId) -> ValueId {
480 self.emit_inst(InstKind::Balance(addr), Some(MirType::uint256()))
481 }
482
483 pub fn selfbalance(&mut self) -> ValueId {
485 self.emit_inst(InstKind::SelfBalance, Some(MirType::uint256()))
486 }
487
488 pub fn gas(&mut self) -> ValueId {
490 self.emit_inst(InstKind::Gas, Some(MirType::uint256()))
491 }
492
493 pub fn keccak256(&mut self, offset: ValueId, size: ValueId) -> ValueId {
495 self.emit_inst(InstKind::Keccak256(offset, size), Some(MirType::bytes32()))
496 }
497
498 pub fn basefee(&mut self) -> ValueId {
500 self.emit_inst(InstKind::BaseFee, Some(MirType::uint256()))
501 }
502
503 pub fn blobbasefee(&mut self) -> ValueId {
505 self.emit_inst(InstKind::BlobBaseFee, Some(MirType::uint256()))
506 }
507
508 pub fn blobhash(&mut self, index: ValueId) -> ValueId {
510 self.emit_inst(InstKind::BlobHash(index), Some(MirType::FixedBytes(32)))
511 }
512
513 #[allow(clippy::too_many_arguments)]
515 pub fn call(
516 &mut self,
517 gas: ValueId,
518 addr: ValueId,
519 value: ValueId,
520 args_offset: ValueId,
521 args_size: ValueId,
522 ret_offset: ValueId,
523 ret_size: ValueId,
524 ) -> ValueId {
525 self.emit_inst(
526 InstKind::Call { gas, addr, value, args_offset, args_size, ret_offset, ret_size },
527 Some(MirType::uint256()),
528 )
529 }
530
531 pub fn staticcall(
533 &mut self,
534 gas: ValueId,
535 addr: ValueId,
536 args_offset: ValueId,
537 args_size: ValueId,
538 ret_offset: ValueId,
539 ret_size: ValueId,
540 ) -> ValueId {
541 self.emit_inst(
542 InstKind::StaticCall { gas, addr, args_offset, args_size, ret_offset, ret_size },
543 Some(MirType::uint256()),
544 )
545 }
546
547 pub fn delegatecall(
549 &mut self,
550 gas: ValueId,
551 addr: ValueId,
552 args_offset: ValueId,
553 args_size: ValueId,
554 ret_offset: ValueId,
555 ret_size: ValueId,
556 ) -> ValueId {
557 self.emit_inst(
558 InstKind::DelegateCall { gas, addr, args_offset, args_size, ret_offset, ret_size },
559 Some(MirType::uint256()),
560 )
561 }
562
563 pub fn create(&mut self, value: ValueId, offset: ValueId, size: ValueId) -> ValueId {
565 self.emit_inst(InstKind::Create(value, offset, size), Some(MirType::Address))
566 }
567
568 pub fn create2(
570 &mut self,
571 value: ValueId,
572 offset: ValueId,
573 size: ValueId,
574 salt: ValueId,
575 ) -> ValueId {
576 self.emit_inst(InstKind::Create2(value, offset, size, salt), Some(MirType::Address))
577 }
578
579 pub fn codecopy(&mut self, dest: ValueId, offset: ValueId, size: ValueId) {
581 self.emit_void_inst(InstKind::CodeCopy(dest, offset, size))
582 }
583
584 pub fn log0(&mut self, offset: ValueId, size: ValueId) {
586 self.emit_void_inst(InstKind::Log0(offset, size));
587 }
588
589 pub fn log1(&mut self, offset: ValueId, size: ValueId, topic1: ValueId) {
591 self.emit_void_inst(InstKind::Log1(offset, size, topic1));
592 }
593
594 pub fn log2(&mut self, offset: ValueId, size: ValueId, topic1: ValueId, topic2: ValueId) {
596 self.emit_void_inst(InstKind::Log2(offset, size, topic1, topic2));
597 }
598
599 pub fn log3(
601 &mut self,
602 offset: ValueId,
603 size: ValueId,
604 topic1: ValueId,
605 topic2: ValueId,
606 topic3: ValueId,
607 ) {
608 self.emit_void_inst(InstKind::Log3(offset, size, topic1, topic2, topic3));
609 }
610
611 pub fn log4(
613 &mut self,
614 offset: ValueId,
615 size: ValueId,
616 topic1: ValueId,
617 topic2: ValueId,
618 topic3: ValueId,
619 topic4: ValueId,
620 ) {
621 self.emit_void_inst(InstKind::Log4(offset, size, topic1, topic2, topic3, topic4));
622 }
623
624 pub fn select(&mut self, cond: ValueId, then_val: ValueId, else_val: ValueId) -> ValueId {
626 self.emit_inst(InstKind::Select(cond, then_val, else_val), Some(MirType::uint256()))
627 }
628
629 pub fn phi(&mut self, incoming: Vec<(BlockId, ValueId)>) -> ValueId {
633 self.emit_inst(InstKind::Phi(incoming), Some(MirType::uint256()))
634 }
635
636 pub fn add_phi_incoming(&mut self, phi: ValueId, block: BlockId, value: ValueId) {
644 let Value::Inst(inst_id) = *self.func.value(phi) else {
645 panic!("add_phi_incoming: value is not an instruction result");
646 };
647 let InstKind::Phi(incoming) = &mut self.func.instructions[inst_id].kind else {
648 panic!("add_phi_incoming: instruction is not a phi");
649 };
650 incoming.push((block, value));
651 }
652
653 pub fn jump(&mut self, target: BlockId) {
655 let block = &mut self.func.blocks[self.current_block];
656 block.terminator = Some(Terminator::Jump(target));
657 self.func.blocks[target].predecessors.push(self.current_block);
658 }
659
660 pub fn branch(&mut self, condition: ValueId, then_block: BlockId, else_block: BlockId) {
662 let block = &mut self.func.blocks[self.current_block];
663 block.terminator = Some(Terminator::Branch { condition, then_block, else_block });
664 self.func.blocks[then_block].predecessors.push(self.current_block);
665 self.func.blocks[else_block].predecessors.push(self.current_block);
666 }
667
668 pub fn switch(&mut self, value: ValueId, default: BlockId, cases: Vec<(ValueId, BlockId)>) {
670 let current = self.current_block;
671 self.func.blocks[current].terminator =
672 Some(Terminator::Switch { value, default, cases: cases.clone() });
673 self.func.blocks[default].predecessors.push(current);
674 for (_, case_block) in cases {
675 self.func.blocks[case_block].predecessors.push(current);
676 }
677 }
678
679 pub fn ret(&mut self, values: impl IntoIterator<Item = ValueId>) {
681 let values: SmallVec<[ValueId; 2]> = values.into_iter().collect();
682 self.func.blocks[self.current_block].terminator = Some(Terminator::Return { values });
683 }
684
685 pub fn revert(&mut self, offset: ValueId, size: ValueId) {
687 self.func.blocks[self.current_block].terminator = Some(Terminator::Revert { offset, size });
688 }
689
690 pub fn ret_data(&mut self, offset: ValueId, size: ValueId) {
692 self.func.blocks[self.current_block].terminator =
693 Some(Terminator::ReturnData { offset, size });
694 }
695
696 pub fn stop(&mut self) {
698 self.func.blocks[self.current_block].terminator = Some(Terminator::Stop);
699 }
700
701 pub fn invalid(&mut self) {
703 self.func.blocks[self.current_block].terminator = Some(Terminator::Invalid);
704 }
705
706 pub fn selfdestruct(&mut self, recipient: ValueId) {
708 self.func.blocks[self.current_block].terminator =
709 Some(Terminator::SelfDestruct { recipient });
710 }
711
712 #[must_use]
714 pub fn func(&self) -> &Function {
715 self.func
716 }
717
718 pub fn func_mut(&mut self) -> &mut Function {
720 self.func
721 }
722}