1mod abi;
2mod contract;
3mod data;
4mod emit;
5mod revert;
6mod safe_math;
7
8use std::fmt::Write;
9
10use fe_abi::types::AbiType;
11use fe_analyzer::namespace::items::ContractId;
12use fe_mir::ir::{types::ArrayDef, FunctionId, TypeId, TypeKind};
13use indexmap::IndexMap;
14use yultsur::*;
15
16use num_bigint::BigInt;
17
18use crate::{db::CodegenDb, yul::slot_size::SLOT_SIZE};
19
20use super::slot_size::yul_primitive_type;
21
22pub trait RuntimeProvider {
23 fn collect_definitions(&self) -> Vec<yul::FunctionDefinition>;
24
25 fn alloc(&mut self, db: &dyn CodegenDb, size: yul::Expression) -> yul::Expression;
26
27 fn avail(&mut self, db: &dyn CodegenDb) -> yul::Expression;
28
29 fn create(
30 &mut self,
31 db: &dyn CodegenDb,
32 contract: ContractId,
33 value: yul::Expression,
34 ) -> yul::Expression;
35
36 fn create2(
37 &mut self,
38 db: &dyn CodegenDb,
39 contract: ContractId,
40 value: yul::Expression,
41 salt: yul::Expression,
42 ) -> yul::Expression;
43
44 fn emit(
45 &mut self,
46 db: &dyn CodegenDb,
47 event: yul::Expression,
48 event_ty: TypeId,
49 ) -> yul::Expression;
50
51 fn revert(
52 &mut self,
53 db: &dyn CodegenDb,
54 arg: Option<yul::Expression>,
55 arg_name: &str,
56 arg_ty: TypeId,
57 ) -> yul::Expression;
58
59 fn external_call(
60 &mut self,
61 db: &dyn CodegenDb,
62 function: FunctionId,
63 args: Vec<yul::Expression>,
64 ) -> yul::Expression;
65
66 fn map_value_ptr(
67 &mut self,
68 db: &dyn CodegenDb,
69 map_ptr: yul::Expression,
70 key: yul::Expression,
71 key_ty: TypeId,
72 ) -> yul::Expression;
73
74 fn aggregate_init(
75 &mut self,
76 db: &dyn CodegenDb,
77 ptr: yul::Expression,
78 args: Vec<yul::Expression>,
79 ptr_ty: TypeId,
80 arg_tys: Vec<TypeId>,
81 ) -> yul::Expression;
82
83 fn string_copy(
84 &mut self,
85 db: &dyn CodegenDb,
86 dst: yul::Expression,
87 data: &str,
88 is_dst_storage: bool,
89 ) -> yul::Expression;
90
91 fn string_construct(
92 &mut self,
93 db: &dyn CodegenDb,
94 data: &str,
95 string_len: usize,
96 ) -> yul::Expression;
97
98 fn ptr_copy(
101 &mut self,
102 db: &dyn CodegenDb,
103 src: yul::Expression,
104 dst: yul::Expression,
105 size: yul::Expression,
106 is_src_storage: bool,
107 is_dst_storage: bool,
108 ) -> yul::Expression;
109
110 fn ptr_store(
111 &mut self,
112 db: &dyn CodegenDb,
113 ptr: yul::Expression,
114 imm: yul::Expression,
115 ptr_ty: TypeId,
116 ) -> yul::Expression;
117
118 fn ptr_load(
119 &mut self,
120 db: &dyn CodegenDb,
121 ptr: yul::Expression,
122 ptr_ty: TypeId,
123 ) -> yul::Expression;
124
125 fn abi_encode(
126 &mut self,
127 db: &dyn CodegenDb,
128 src: yul::Expression,
129 dst: yul::Expression,
130 src_ty: TypeId,
131 is_dst_storage: bool,
132 ) -> yul::Expression;
133
134 fn abi_encode_seq(
135 &mut self,
136 db: &dyn CodegenDb,
137 src: &[yul::Expression],
138 dst: yul::Expression,
139 src_tys: &[TypeId],
140 is_dst_storage: bool,
141 ) -> yul::Expression;
142
143 fn abi_decode(
144 &mut self,
145 db: &dyn CodegenDb,
146 src: yul::Expression,
147 size: yul::Expression,
148 types: &[TypeId],
149 abi_loc: AbiSrcLocation,
150 ) -> yul::Expression;
151
152 fn primitive_cast(
153 &mut self,
154 db: &dyn CodegenDb,
155 value: yul::Expression,
156 from_ty: TypeId,
157 ) -> yul::Expression {
158 debug_assert!(from_ty.is_primitive(db.upcast()));
159 let from_size = from_ty.size_of(db.upcast(), SLOT_SIZE);
160
161 if from_ty.is_signed(db.upcast()) {
162 let significant = literal_expression! {(from_size-1)};
163 expression! { signextend([significant], [value]) }
164 } else {
165 let mask = BitMask::new(from_size);
166 expression! { and([value], [mask.as_expr()]) }
167 }
168 }
169
170 fn safe_add(
172 &mut self,
173 db: &dyn CodegenDb,
174 lhs: yul::Expression,
175 rhs: yul::Expression,
176 ty: TypeId,
177 ) -> yul::Expression;
178
179 fn safe_sub(
180 &mut self,
181 db: &dyn CodegenDb,
182 lhs: yul::Expression,
183 rhs: yul::Expression,
184 ty: TypeId,
185 ) -> yul::Expression;
186
187 fn safe_mul(
188 &mut self,
189 db: &dyn CodegenDb,
190 lhs: yul::Expression,
191 rhs: yul::Expression,
192 ty: TypeId,
193 ) -> yul::Expression;
194
195 fn safe_div(
196 &mut self,
197 db: &dyn CodegenDb,
198 lhs: yul::Expression,
199 rhs: yul::Expression,
200 ty: TypeId,
201 ) -> yul::Expression;
202
203 fn safe_mod(
204 &mut self,
205 db: &dyn CodegenDb,
206 lhs: yul::Expression,
207 rhs: yul::Expression,
208 ty: TypeId,
209 ) -> yul::Expression;
210
211 fn safe_pow(
212 &mut self,
213 db: &dyn CodegenDb,
214 lhs: yul::Expression,
215 rhs: yul::Expression,
216 ty: TypeId,
217 ) -> yul::Expression;
218}
219
220#[derive(Clone, Copy, Debug)]
221pub enum AbiSrcLocation {
222 CallData,
223 Memory,
224}
225
226#[derive(Debug, Default)]
227pub struct DefaultRuntimeProvider {
228 functions: IndexMap<String, RuntimeFunction>,
229}
230
231impl DefaultRuntimeProvider {
232 fn create_then_call<F>(
233 &mut self,
234 name: &str,
235 args: Vec<yul::Expression>,
236 func_builder: F,
237 ) -> yul::Expression
238 where
239 F: FnOnce(&mut Self) -> RuntimeFunction,
240 {
241 if let Some(func) = self.functions.get(name) {
242 func.call(args)
243 } else {
244 let func = func_builder(self);
245 let result = func.call(args);
246 self.functions.insert(name.to_string(), func);
247 result
248 }
249 }
250}
251
252impl RuntimeProvider for DefaultRuntimeProvider {
253 fn collect_definitions(&self) -> Vec<yul::FunctionDefinition> {
254 self.functions
255 .values()
256 .map(RuntimeFunction::definition)
257 .collect()
258 }
259
260 fn alloc(&mut self, _db: &dyn CodegenDb, bytes: yul::Expression) -> yul::Expression {
261 let name = "$alloc";
262 let arg = vec![bytes];
263 self.create_then_call(name, arg, |_| data::make_alloc(name))
264 }
265
266 fn avail(&mut self, _db: &dyn CodegenDb) -> yul::Expression {
267 let name = "$avail";
268 let arg = vec![];
269 self.create_then_call(name, arg, |_| data::make_avail(name))
270 }
271
272 fn create(
273 &mut self,
274 db: &dyn CodegenDb,
275 contract: ContractId,
276 value: yul::Expression,
277 ) -> yul::Expression {
278 let name = format!("$create_{}", db.codegen_contract_symbol_name(contract));
279 let arg = vec![value];
280 self.create_then_call(&name, arg, |provider| {
281 contract::make_create(provider, db, &name, contract)
282 })
283 }
284
285 fn create2(
286 &mut self,
287 db: &dyn CodegenDb,
288 contract: ContractId,
289 value: yul::Expression,
290 salt: yul::Expression,
291 ) -> yul::Expression {
292 let name = format!("$create2_{}", db.codegen_contract_symbol_name(contract));
293 let arg = vec![value, salt];
294 self.create_then_call(&name, arg, |provider| {
295 contract::make_create2(provider, db, &name, contract)
296 })
297 }
298
299 fn emit(
300 &mut self,
301 db: &dyn CodegenDb,
302 event: yul::Expression,
303 event_ty: TypeId,
304 ) -> yul::Expression {
305 let name = format!("$emit_{}", event_ty.0);
306 let legalized_ty = db.codegen_legalized_type(event_ty);
307 self.create_then_call(&name, vec![event], |provider| {
308 emit::make_emit(provider, db, &name, legalized_ty)
309 })
310 }
311
312 fn revert(
313 &mut self,
314 db: &dyn CodegenDb,
315 arg: Option<yul::Expression>,
316 arg_name: &str,
317 arg_ty: TypeId,
318 ) -> yul::Expression {
319 let func_name = format! {"$revert_{}_{}", arg_name, arg_ty.0};
320 let args = match arg {
321 Some(arg) => vec![arg],
322 None => vec![],
323 };
324 self.create_then_call(&func_name, args, |provider| {
325 revert::make_revert(provider, db, &func_name, arg_name, arg_ty)
326 })
327 }
328
329 fn external_call(
330 &mut self,
331 db: &dyn CodegenDb,
332 function: FunctionId,
333 args: Vec<yul::Expression>,
334 ) -> yul::Expression {
335 let name = format!(
336 "$call_external__{}",
337 db.codegen_function_symbol_name(function)
338 );
339 self.create_then_call(&name, args, |provider| {
340 contract::make_external_call(provider, db, &name, function)
341 })
342 }
343
344 fn map_value_ptr(
345 &mut self,
346 db: &dyn CodegenDb,
347 map_ptr: yul::Expression,
348 key: yul::Expression,
349 key_ty: TypeId,
350 ) -> yul::Expression {
351 if key_ty.is_primitive(db.upcast()) {
352 let name = "$map_value_ptr_with_primitive_key";
353 self.create_then_call(name, vec![map_ptr, key], |provider| {
354 data::make_map_value_ptr_with_primitive_key(provider, db, name, key_ty)
355 })
356 } else if key_ty.is_mptr(db.upcast()) {
357 let name = "$map_value_ptr_with_ptr_key";
358 self.create_then_call(name, vec![map_ptr, key], |provider| {
359 data::make_map_value_ptr_with_ptr_key(provider, db, name, key_ty)
360 })
361 } else {
362 unreachable!()
363 }
364 }
365
366 fn aggregate_init(
367 &mut self,
368 db: &dyn CodegenDb,
369 ptr: yul::Expression,
370 mut args: Vec<yul::Expression>,
371 ptr_ty: TypeId,
372 arg_tys: Vec<TypeId>,
373 ) -> yul::Expression {
374 debug_assert!(ptr_ty.is_ptr(db.upcast()));
375 let deref_ty = ptr_ty.deref(db.upcast());
376
377 if args.len() == 1 && deref_ty.is_enum(db.upcast()) {
379 let tag = args.pop().unwrap();
380 let tag_ty = arg_tys[0];
381 let is_sptr = ptr_ty.is_sptr(db.upcast());
382 return self.ptr_store(db, ptr, tag, make_ptr(db, tag_ty, is_sptr));
383 }
384
385 let deref_ty = ptr_ty.deref(db.upcast());
386 let args = std::iter::once(ptr).chain(args).collect();
387 let legalized_ty = db.codegen_legalized_type(ptr_ty);
388 if deref_ty.is_enum(db.upcast()) {
389 let mut name = format!("enum_init_{}", ptr_ty.0);
390 for ty in &arg_tys {
391 write!(&mut name, "_{}", ty.0).unwrap();
392 }
393 self.create_then_call(&name, args, |provider| {
394 data::make_enum_init(provider, db, &name, legalized_ty, arg_tys)
395 })
396 } else {
397 let name = format!("$aggregate_init_{}", ptr_ty.0);
398 self.create_then_call(&name, args, |provider| {
399 data::make_aggregate_init(provider, db, &name, legalized_ty, arg_tys)
400 })
401 }
402 }
403
404 fn string_copy(
405 &mut self,
406 db: &dyn CodegenDb,
407 dst: yul::Expression,
408 data: &str,
409 is_dst_storage: bool,
410 ) -> yul::Expression {
411 debug_assert!(data.is_ascii());
412 let symbol_name = db.codegen_constant_string_symbol_name(data.to_string());
413
414 let name = if is_dst_storage {
415 format!("$string_copy_{symbol_name}_storage")
416 } else {
417 format!("$string_copy_{symbol_name}_memory")
418 };
419
420 self.create_then_call(&name, vec![dst], |provider| {
421 data::make_string_copy(provider, db, &name, data, is_dst_storage)
422 })
423 }
424
425 fn string_construct(
426 &mut self,
427 db: &dyn CodegenDb,
428 data: &str,
429 string_len: usize,
430 ) -> yul::Expression {
431 debug_assert!(data.is_ascii());
432 debug_assert!(string_len >= data.len());
433 let symbol_name = db.codegen_constant_string_symbol_name(data.to_string());
434
435 let name = format!("$string_construct_{symbol_name}");
436 let arg = literal_expression!((32 + string_len));
437 self.create_then_call(&name, vec![arg], |provider| {
438 data::make_string_construct(provider, db, &name, data)
439 })
440 }
441
442 fn ptr_copy(
443 &mut self,
444 _db: &dyn CodegenDb,
445 src: yul::Expression,
446 dst: yul::Expression,
447 size: yul::Expression,
448 is_src_storage: bool,
449 is_dst_storage: bool,
450 ) -> yul::Expression {
451 let args = vec![src, dst, size];
452 match (is_src_storage, is_dst_storage) {
453 (true, true) => {
454 let name = "scopys";
455 self.create_then_call(name, args, |_| data::make_scopys(name))
456 }
457 (true, false) => {
458 let name = "scopym";
459 self.create_then_call(name, args, |_| data::make_scopym(name))
460 }
461 (false, true) => {
462 let name = "mcopys";
463 self.create_then_call(name, args, |_| data::make_mcopys(name))
464 }
465 (false, false) => {
466 let name = "mcopym";
467 self.create_then_call(name, args, |_| data::make_mcopym(name))
468 }
469 }
470 }
471
472 fn ptr_store(
473 &mut self,
474 db: &dyn CodegenDb,
475 ptr: yul::Expression,
476 imm: yul::Expression,
477 ptr_ty: TypeId,
478 ) -> yul::Expression {
479 debug_assert!(ptr_ty.is_ptr(db.upcast()));
480 let size = ptr_ty.deref(db.upcast()).size_of(db.upcast(), SLOT_SIZE);
481 debug_assert!(size <= 32);
482
483 let size_bits = size * 8;
484 if ptr_ty.is_sptr(db.upcast()) {
485 let name = "$sptr_store";
486 let args = vec![ptr, imm, literal_expression! {(size_bits)}];
487 self.create_then_call(name, args, |_| data::make_sptr_store(name))
488 } else if ptr_ty.is_mptr(db.upcast()) {
489 let name = "$mptr_store";
490 let shift_num = literal_expression! {(256 - size_bits)};
491 let mask = BitMask::new(32 - size);
492 let args = vec![ptr, imm, shift_num, mask.as_expr()];
493 self.create_then_call(name, args, |_| data::make_mptr_store(name))
494 } else {
495 unreachable!()
496 }
497 }
498
499 fn ptr_load(
500 &mut self,
501 db: &dyn CodegenDb,
502 ptr: yul::Expression,
503 ptr_ty: TypeId,
504 ) -> yul::Expression {
505 debug_assert!(ptr_ty.is_ptr(db.upcast()));
506 let size = ptr_ty.deref(db.upcast()).size_of(db.upcast(), SLOT_SIZE);
507 debug_assert!(size <= 32);
508
509 let size_bits = size * 8;
510 if ptr_ty.is_sptr(db.upcast()) {
511 let name = "$sptr_load";
512 let args = vec![ptr, literal_expression! {(size_bits)}];
513 self.create_then_call(name, args, |_| data::make_sptr_load(name))
514 } else if ptr_ty.is_mptr(db.upcast()) {
515 let name = "$mptr_load";
516 let shift_num = literal_expression! {(256 - size_bits)};
517 let args = vec![ptr, shift_num];
518 self.create_then_call(name, args, |_| data::make_mptr_load(name))
519 } else {
520 unreachable!()
521 }
522 }
523
524 fn abi_encode(
525 &mut self,
526 db: &dyn CodegenDb,
527 src: yul::Expression,
528 dst: yul::Expression,
529 src_ty: TypeId,
530 is_dst_storage: bool,
531 ) -> yul::Expression {
532 let legalized_ty = db.codegen_legalized_type(src_ty);
533 let args = vec![src.clone(), dst.clone()];
534
535 let func_name_postfix = if is_dst_storage { "storage" } else { "memory" };
536
537 if legalized_ty.is_primitive(db.upcast()) {
538 let name = format!(
539 "$abi_encode_primitive_type_{}_to_{}",
540 src_ty.0, func_name_postfix
541 );
542 return self.create_then_call(&name, args, |provider| {
543 abi::make_abi_encode_primitive_type(
544 provider,
545 db,
546 &name,
547 legalized_ty,
548 is_dst_storage,
549 )
550 });
551 }
552
553 let deref_ty = legalized_ty.deref(db.upcast());
554 let abi_ty = db.codegen_abi_type(deref_ty);
555 match abi_ty {
556 AbiType::UInt(_) | AbiType::Int(_) | AbiType::Bool | AbiType::Address => {
557 let value = self.ptr_load(db, src, src_ty);
558 let extended_value = self.primitive_cast(db, value, deref_ty);
559 self.abi_encode(db, extended_value, dst, deref_ty, is_dst_storage)
560 }
561 AbiType::Array { elem_ty, .. } => {
562 if elem_ty.is_static() {
563 let name = format!(
564 "$abi_encode_static_array_type_{}_to_{}",
565 src_ty.0, func_name_postfix
566 );
567 self.create_then_call(&name, args, |provider| {
568 abi::make_abi_encode_static_array_type(provider, db, &name, legalized_ty)
569 })
570 } else {
571 let name = format! {
572 "$abi_encode_dynamic_array_type{}_to_{}", src_ty.0, func_name_postfix
573 };
574 self.create_then_call(&name, args, |provider| {
575 abi::make_abi_encode_dynamic_array_type(provider, db, &name, legalized_ty)
576 })
577 }
578 }
579 AbiType::Tuple(_) => {
580 if abi_ty.is_static() {
581 let name = format!(
582 "$abi_encode_static_aggregate_type_{}_to_{}",
583 src_ty.0, func_name_postfix
584 );
585 self.create_then_call(&name, args, |provider| {
586 abi::make_abi_encode_static_aggregate_type(
587 provider,
588 db,
589 &name,
590 legalized_ty,
591 is_dst_storage,
592 )
593 })
594 } else {
595 let name = format!(
596 "$abi_encode_dynamic_aggregate_type_{}_to_{}",
597 src_ty.0, func_name_postfix
598 );
599 self.create_then_call(&name, args, |provider| {
600 abi::make_abi_encode_dynamic_aggregate_type(
601 provider,
602 db,
603 &name,
604 legalized_ty,
605 is_dst_storage,
606 )
607 })
608 }
609 }
610 AbiType::Bytes => {
611 let len = match &deref_ty.data(db.upcast()).kind {
612 TypeKind::Array(ArrayDef { len, .. }) => *len,
613 _ => unreachable!(),
614 };
615 let name = format! {"$abi_encode_bytes{len}_type_to_{func_name_postfix}"};
616 self.create_then_call(&name, args, |provider| {
617 abi::make_abi_encode_bytes_type(provider, db, &name, len, is_dst_storage)
618 })
619 }
620 AbiType::String => {
621 let name = format! {"$abi_encode_string_type_to_{func_name_postfix}"};
622 self.create_then_call(&name, args, |provider| {
623 abi::make_abi_encode_string_type(provider, db, &name, is_dst_storage)
624 })
625 }
626 AbiType::Function => unreachable!(),
627 }
628 }
629
630 fn abi_encode_seq(
631 &mut self,
632 db: &dyn CodegenDb,
633 src: &[yul::Expression],
634 dst: yul::Expression,
635 src_tys: &[TypeId],
636 is_dst_storage: bool,
637 ) -> yul::Expression {
638 let mut name = "$abi_encode_value_seq".to_string();
639 for ty in src_tys {
640 write!(&mut name, "_{}", ty.0).unwrap();
641 }
642
643 let mut args = vec![dst];
644 args.extend(src.iter().cloned());
645 self.create_then_call(&name, args, |provider| {
646 abi::make_abi_encode_seq(provider, db, &name, src_tys, is_dst_storage)
647 })
648 }
649
650 fn abi_decode(
651 &mut self,
652 db: &dyn CodegenDb,
653 src: yul::Expression,
654 size: yul::Expression,
655 types: &[TypeId],
656 abi_loc: AbiSrcLocation,
657 ) -> yul::Expression {
658 let mut name = "$abi_decode".to_string();
659 for ty in types {
660 write!(name, "_{}", ty.0).unwrap();
661 }
662
663 match abi_loc {
664 AbiSrcLocation::CallData => write!(name, "_from_calldata").unwrap(),
665 AbiSrcLocation::Memory => write!(name, "_from_memory").unwrap(),
666 };
667
668 self.create_then_call(&name, vec![src, size], |provider| {
669 abi::make_abi_decode(provider, db, &name, types, abi_loc)
670 })
671 }
672
673 fn safe_add(
674 &mut self,
675 db: &dyn CodegenDb,
676 lhs: yul::Expression,
677 rhs: yul::Expression,
678 ty: TypeId,
679 ) -> yul::Expression {
680 debug_assert!(ty.is_integral(db.upcast()));
681 safe_math::dispatch_safe_add(self, db, lhs, rhs, ty)
682 }
683
684 fn safe_sub(
685 &mut self,
686 db: &dyn CodegenDb,
687 lhs: yul::Expression,
688 rhs: yul::Expression,
689 ty: TypeId,
690 ) -> yul::Expression {
691 debug_assert!(ty.is_integral(db.upcast()));
692 safe_math::dispatch_safe_sub(self, db, lhs, rhs, ty)
693 }
694
695 fn safe_mul(
696 &mut self,
697 db: &dyn CodegenDb,
698 lhs: yul::Expression,
699 rhs: yul::Expression,
700 ty: TypeId,
701 ) -> yul::Expression {
702 debug_assert!(ty.is_integral(db.upcast()));
703 safe_math::dispatch_safe_mul(self, db, lhs, rhs, ty)
704 }
705
706 fn safe_div(
707 &mut self,
708 db: &dyn CodegenDb,
709 lhs: yul::Expression,
710 rhs: yul::Expression,
711 ty: TypeId,
712 ) -> yul::Expression {
713 debug_assert!(ty.is_integral(db.upcast()));
714 safe_math::dispatch_safe_div(self, db, lhs, rhs, ty)
715 }
716
717 fn safe_mod(
718 &mut self,
719 db: &dyn CodegenDb,
720 lhs: yul::Expression,
721 rhs: yul::Expression,
722 ty: TypeId,
723 ) -> yul::Expression {
724 debug_assert!(ty.is_integral(db.upcast()));
725 safe_math::dispatch_safe_mod(self, db, lhs, rhs, ty)
726 }
727
728 fn safe_pow(
729 &mut self,
730 db: &dyn CodegenDb,
731 lhs: yul::Expression,
732 rhs: yul::Expression,
733 ty: TypeId,
734 ) -> yul::Expression {
735 debug_assert!(ty.is_integral(db.upcast()));
736 safe_math::dispatch_safe_pow(self, db, lhs, rhs, ty)
737 }
738}
739
740#[derive(Debug)]
741struct RuntimeFunction(yul::FunctionDefinition);
742
743impl RuntimeFunction {
744 fn arg_num(&self) -> usize {
745 self.0.parameters.len()
746 }
747
748 fn definition(&self) -> yul::FunctionDefinition {
749 self.0.clone()
750 }
751
752 fn call(&self, args: Vec<yul::Expression>) -> yul::Expression {
755 debug_assert_eq!(self.arg_num(), args.len());
756
757 yul::Expression::FunctionCall(yul::FunctionCall {
758 identifier: self.0.name.clone(),
759 arguments: args,
760 })
761 }
762
763 fn from_statement(func: yul::Statement) -> Self {
766 match func {
767 yul::Statement::FunctionDefinition(def) => Self(def),
768 _ => unreachable!(),
769 }
770 }
771}
772
773fn make_ptr(db: &dyn CodegenDb, inner: TypeId, is_sptr: bool) -> TypeId {
774 if is_sptr {
775 inner.make_sptr(db.upcast())
776 } else {
777 inner.make_mptr(db.upcast())
778 }
779}
780
781struct BitMask(BigInt);
782
783impl BitMask {
784 fn new(byte_size: usize) -> Self {
785 debug_assert!(byte_size <= 32);
786 let one: BigInt = 1usize.into();
787 Self((one << (byte_size * 8)) - 1)
788 }
789
790 fn not(&self) -> Self {
791 let one: BigInt = 1usize.into();
794 let u256_max = (one << 256) - 1;
795 Self(u256_max ^ &self.0)
796 }
797
798 fn as_expr(&self) -> yul::Expression {
799 let mask = format!("{:#x}", self.0);
800 literal_expression! {(mask)}
801 }
802}
803
804pub(super) fn error_revert_numeric(
805 provider: &mut dyn RuntimeProvider,
806 db: &dyn CodegenDb,
807 error_code: yul::Expression,
808) -> yul::Statement {
809 yul::Statement::Expression(provider.revert(
810 db,
811 Some(error_code),
812 "Error",
813 yul_primitive_type(db),
814 ))
815}
816
817pub(super) fn panic_revert_numeric(
818 provider: &mut dyn RuntimeProvider,
819 db: &dyn CodegenDb,
820 error_code: yul::Expression,
821) -> yul::Statement {
822 yul::Statement::Expression(provider.revert(
823 db,
824 Some(error_code),
825 "Panic",
826 yul_primitive_type(db),
827 ))
828}