cairo_lang_lowering/optimizations/
config.rs1use cairo_lang_defs::ids::ExternFunctionId;
2use cairo_lang_semantic::helper::ModuleHelper;
3use cairo_lang_utils::unordered_hash_set::UnorderedHashSet;
4use itertools::chain;
5use salsa::Database;
6
7use crate::db::LoweringGroup;
8use crate::utils::InliningStrategy;
9
10#[derive(Debug, Eq, PartialEq, Clone)]
12pub enum Optimizations {
13 Disabled,
14 Enabled(OptimizationConfig),
15}
16
17#[derive(Default, Debug, Eq, PartialEq, Clone)]
19pub struct OptimizationConfig {
20 pub(crate) moveable_functions: Vec<String>,
22 pub(crate) inlining_strategy: InliningStrategy,
24 pub(crate) skip_const_folding: bool,
26}
27
28impl OptimizationConfig {
29 pub fn with_skip_const_folding(mut self, skip_const_folding: bool) -> Self {
30 self.skip_const_folding = skip_const_folding;
31 self
32 }
33}
34
35impl Optimizations {
36 pub fn enabled_with_default_movable_functions(inlining_strategy: InliningStrategy) -> Self {
39 Self::Enabled(OptimizationConfig {
40 moveable_functions: default_moveable_functions(),
41 inlining_strategy,
42 skip_const_folding: false,
43 })
44 }
45
46 pub fn enabled_with_minimal_movable_functions() -> Self {
49 Self::Enabled(OptimizationConfig {
50 moveable_functions: vec!["felt252_sub".to_string()],
51 inlining_strategy: Default::default(),
52 skip_const_folding: false,
53 })
54 }
55
56 pub fn moveable_functions(&self) -> &[String] {
59 if let Self::Enabled(config) = self { &config.moveable_functions } else { &[] }
60 }
61
62 pub fn inlining_strategy(&self) -> InliningStrategy {
65 if let Self::Enabled(config) = self {
66 config.inlining_strategy
67 } else {
68 InliningStrategy::Avoid
69 }
70 }
71
72 pub fn skip_const_folding(&self) -> bool {
74 if let Self::Enabled(config) = self { config.skip_const_folding } else { true }
75 }
76}
77
78#[salsa::tracked(returns(ref))]
79pub fn priv_movable_function_ids<'db>(
80 db: &'db dyn Database,
81) -> UnorderedHashSet<ExternFunctionId<'db>> {
82 db.optimizations()
83 .moveable_functions()
84 .iter()
85 .map(|name: &String| {
86 let mut path_iter = name.split("::");
87
88 let mut module = ModuleHelper::core(db);
89
90 let mut next = path_iter.next();
91 while let Some(path_item) = next {
92 next = path_iter.next();
93 if next.is_some() {
94 module = module.submodule(path_item);
95 continue;
96 }
97 return module.extern_function_id(path_item);
98 }
99
100 panic!("Got empty string as movable_function");
101 })
102 .collect()
103}
104
105fn default_moveable_functions() -> Vec<String> {
107 let mut moveable_functions: Vec<String> = chain!(
108 ["bool_not_impl"],
109 ["felt252_add", "felt252_sub", "felt252_mul", "felt252_div"],
110 ["array::array_new", "array::array_append"],
111 ["box::unbox", "box::box_forward_snapshot", "box::into_box"],
112 )
113 .map(|s| s.to_string())
114 .collect();
115
116 for ty in ["i8", "i16", "i32", "i64", "u8", "u16", "u32", "u64"] {
117 moveable_functions.push(format!("integer::{ty}_wide_mul"));
118 }
119 moveable_functions
120}