fe_codegen/yul/runtime/
mod.rs

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    /// Copy data from `src` to `dst`.
99    /// NOTE: src and dst must be aligned by 32 when a ptr is storage ptr.
100    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    // TODO: The all functions below will be reimplemented in `std`.
171    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        // Handle unit enum variant.
378        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    /// # Panics
753    /// Panics if a number of arguments doesn't match the definition.
754    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    /// Remove this when `yultsur::function_definition!` becomes to return
764    /// `FunctionDefinition`.
765    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        // Bigint is variable length integer, so we need special handling for `not`
792        // operation.
793        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}