cairo_lang_lowering/optimizations/
config.rs

1use std::sync::Arc;
2
3use cairo_lang_semantic::corelib;
4use cairo_lang_semantic::db::SemanticGroup;
5use cairo_lang_utils::Intern;
6use cairo_lang_utils::unordered_hash_set::UnorderedHashSet;
7
8use crate::db::LoweringGroup;
9use crate::ids::{FunctionId, FunctionLongId};
10use crate::utils::InliningStrategy;
11
12/// The default threshold for inlining small functions. Decided according to sample contracts
13/// profiling.
14// TODO(Gil): Expose this as a configuration in the project toml.
15const DEFAULT_INLINE_SMALL_FUNCTIONS_THRESHOLD: usize = 24;
16
17/// A configuration struct that controls the behavior of the optimization passes.
18#[derive(Debug, Eq, PartialEq, Clone)]
19pub struct OptimizationConfig {
20    /// A list of functions that can be moved during the reorder_statements optimization.
21    pub moveable_functions: Vec<String>,
22    /// The size of functions (in lowering statements) below which they are marked as
23    /// `should_inline`.
24    pub inline_small_functions_threshold: usize,
25    /// Determines whether inlining is disabled.
26    pub inlining_strategy: InliningStrategy,
27    /// Should const folding be skipped.
28    pub skip_const_folding: bool,
29}
30
31impl OptimizationConfig {
32    /// Sets the list of moveable functions.
33    pub fn with_moveable_functions(mut self, moveable_functions: Vec<String>) -> Self {
34        self.moveable_functions = moveable_functions;
35        self
36    }
37    /// Sets the list of moveable functions to a minimal set, useful for testing.
38    pub fn with_minimal_movable_functions(self) -> Self {
39        self.with_moveable_functions(vec!["felt252_sub".into()])
40    }
41    /// Sets the threshold for inlining small functions.
42    pub fn with_inline_small_functions_threshold(
43        mut self,
44        inline_small_functions_threshold: usize,
45    ) -> Self {
46        self.inline_small_functions_threshold = inline_small_functions_threshold;
47        self
48    }
49    /// Sets the `inlining_strategy` flag.
50    pub fn with_inlining_strategy(mut self, inlining_strategy: InliningStrategy) -> Self {
51        self.inlining_strategy = inlining_strategy;
52        self
53    }
54    /// Sets the `skip_const_folding` flag.
55    pub fn with_skip_const_folding(mut self, skip_const_folding: bool) -> Self {
56        self.skip_const_folding = skip_const_folding;
57        self
58    }
59}
60
61impl Default for OptimizationConfig {
62    fn default() -> Self {
63        Self {
64            moveable_functions: vec![],
65            inline_small_functions_threshold: DEFAULT_INLINE_SMALL_FUNCTIONS_THRESHOLD,
66            inlining_strategy: InliningStrategy::Default,
67            skip_const_folding: false,
68        }
69    }
70}
71
72pub fn priv_movable_function_ids(db: &dyn LoweringGroup) -> Arc<UnorderedHashSet<FunctionId>> {
73    let semantic_db: &dyn SemanticGroup = db.elongate();
74    let libfunc_by_name = |name: &String| {
75        let mut path_iter = name.split("::");
76
77        let mut module = db.core_module();
78
79        let mut next = path_iter.next();
80        while let Some(path_item) = next {
81            next = path_iter.next();
82            if next.is_some() {
83                module = corelib::get_submodule(semantic_db, module, path_item)
84                    .unwrap_or_else(|| panic!("module not found: {}", path_item));
85                continue;
86            }
87
88            return FunctionLongId::Semantic(corelib::get_function_id(
89                semantic_db,
90                module,
91                path_item.into(),
92                vec![],
93            ))
94            .intern(db);
95        }
96
97        panic!("Got empty string as movable_function");
98    };
99
100    Arc::new(db.optimization_config().moveable_functions.iter().map(libfunc_by_name).collect())
101}