cairo_lang_lowering/optimizations/
strategy.rs1use cairo_lang_debug::DebugWithDb;
2use cairo_lang_diagnostics::Maybe;
3use cairo_lang_proc_macros::HeapSize;
4use cairo_lang_utils::{Intern, define_short_id};
5use salsa::Database;
6
7use super::cse::cse;
8use super::dedup_blocks::dedup_blocks;
9use super::early_unsafe_panic::early_unsafe_panic;
10use super::gas_redeposit::gas_redeposit;
11use super::reboxing::apply_reboxing;
12use super::trim_unreachable::trim_unreachable;
13use super::validate::validate;
14use crate::Lowered;
15use crate::db::LoweringGroup;
16use crate::ids::ConcreteFunctionWithBodyId;
17use crate::implicits::lower_implicits;
18use crate::inline::apply_inlining;
19use crate::optimizations::branch_inversion::branch_inversion;
20use crate::optimizations::config::Optimizations;
21use crate::optimizations::const_folding::const_folding;
22use crate::optimizations::match_optimizer::optimize_matches;
23use crate::optimizations::remappings::optimize_remappings;
24use crate::optimizations::reorder_statements::reorder_statements;
25use crate::optimizations::return_optimization::return_optimization;
26use crate::optimizations::split_structs::split_structs;
27use crate::optimizations::variable_forwarding::variable_forwarding;
28use crate::reorganize_blocks::reorganize_blocks;
29
30#[derive(Clone, Debug, Eq, Hash, PartialEq, salsa::Update, HeapSize)]
32pub enum OptimizationPhase<'db> {
33 ApplyInlining {
34 enable_const_folding: bool,
35 },
36 BranchInversion,
37 ConstFolding,
38 Cse,
39 DedupBlocks,
40 EarlyUnsafePanic,
41 OptimizeMatches,
42 OptimizeRemappings,
43 Reboxing,
44 ReorderStatements,
45 ReorganizeBlocks,
46 ReturnOptimization,
47 SplitStructs,
48 TrimUnreachable,
49 VariableForwarding,
50 GasRedeposit,
51 LowerImplicits,
54 Validate,
56 SubStrategy {
59 strategy: OptimizationStrategyId<'db>,
61 iterations: usize,
63 },
64}
65
66pub trait ApplyOptimization<'db> {
68 fn apply(
72 &self,
73 db: &'db dyn Database,
74 function: ConcreteFunctionWithBodyId<'db>,
75 lowered: &mut Lowered<'db>,
76 ) -> Maybe<()>;
77}
78
79impl<'db> ApplyOptimization<'db> for OptimizationPhase<'db> {
80 fn apply(
81 &self,
82 db: &'db dyn Database,
83 function: ConcreteFunctionWithBodyId<'db>,
84 lowered: &mut Lowered<'db>,
85 ) -> Maybe<()> {
86 debug!("Applying optimization: {self:?}");
87
88 match self {
89 OptimizationPhase::ApplyInlining { enable_const_folding } => {
90 apply_inlining(db, function, lowered, *enable_const_folding)?
91 }
92 OptimizationPhase::BranchInversion => branch_inversion(db, lowered),
93 OptimizationPhase::ConstFolding => const_folding(db, function, lowered),
94 OptimizationPhase::Cse => cse(lowered),
95 OptimizationPhase::EarlyUnsafePanic => early_unsafe_panic(db, lowered),
96 OptimizationPhase::DedupBlocks => dedup_blocks(lowered),
97 OptimizationPhase::OptimizeMatches => optimize_matches(db, lowered),
98 OptimizationPhase::OptimizeRemappings => optimize_remappings(lowered),
99 OptimizationPhase::Reboxing => apply_reboxing(db, lowered)?,
100 OptimizationPhase::ReorderStatements => reorder_statements(db, lowered),
101 OptimizationPhase::ReorganizeBlocks => reorganize_blocks(lowered),
102 OptimizationPhase::ReturnOptimization => return_optimization(db, lowered),
103 OptimizationPhase::SplitStructs => split_structs(lowered),
104 OptimizationPhase::TrimUnreachable => trim_unreachable(db, lowered),
105 OptimizationPhase::VariableForwarding => variable_forwarding(db, lowered),
106 OptimizationPhase::LowerImplicits => lower_implicits(db, function, lowered),
107 OptimizationPhase::GasRedeposit => gas_redeposit(db, function, lowered),
108 OptimizationPhase::Validate => validate(lowered).unwrap_or_else(|err| {
109 panic!(
110 "Failed validation for function {}: {:?}",
111 function.full_path(db),
112 err.to_message()
113 )
114 }),
115 OptimizationPhase::SubStrategy { strategy, iterations } => {
116 for _ in 1..*iterations {
117 let before = lowered.clone();
118 strategy.apply(db, function, lowered)?;
119 if *lowered == before {
120 return Ok(());
121 }
122 }
123 strategy.apply(db, function, lowered)?
124 }
125 }
126 Ok(())
127 }
128}
129
130define_short_id!(OptimizationStrategyId, OptimizationStrategy<'db>);
131
132#[derive(Clone, Debug, Eq, Hash, PartialEq, salsa::Update, HeapSize)]
134pub struct OptimizationStrategy<'db>(pub Vec<OptimizationPhase<'db>>);
135
136impl<'db> ApplyOptimization<'db> for [OptimizationPhase<'db>] {
137 fn apply(
138 &self,
139 db: &'db dyn Database,
140 function: ConcreteFunctionWithBodyId<'db>,
141 lowered: &mut Lowered<'db>,
142 ) -> Maybe<()> {
143 let fmt = crate::fmt::LoweredFormatter::new(db, &lowered.variables);
144 tracing::trace!(
145 target: "optimization_dump",
146 "({})\nInitial:\n{:?}",
147 function.full_path(db),
148 lowered.debug(&fmt)
149 );
150
151 for phase in self {
152 phase.apply(db, function, lowered)?;
153 let fmt = crate::fmt::LoweredFormatter::new(db, &lowered.variables);
154 tracing::trace!(
155 target: "optimization_dump",
156 "({})\nAfter {phase:?}:\n{:?}",
157 function.full_path(db),
158 lowered.debug(&fmt)
159 );
160 }
161 Ok(())
162 }
163}
164
165impl<'db> ApplyOptimization<'db> for OptimizationStrategyId<'db> {
166 fn apply(
170 &self,
171 db: &'db dyn Database,
172 function: ConcreteFunctionWithBodyId<'db>,
173 lowered: &mut Lowered<'db>,
174 ) -> Maybe<()> {
175 self.long(db).0.apply(db, function, lowered)
176 }
177}
178
179#[salsa::tracked]
181pub fn baseline_optimization_strategy<'db>(db: &'db dyn Database) -> OptimizationStrategyId<'db> {
182 match db.optimizations() {
183 Optimizations::Enabled(_) => {
184 OptimizationStrategy(vec![
185 OptimizationPhase::ReorganizeBlocks,
187 OptimizationPhase::ApplyInlining { enable_const_folding: true },
188 OptimizationPhase::ReturnOptimization,
189 OptimizationPhase::ReorganizeBlocks,
190 OptimizationPhase::ReorderStatements,
191 OptimizationPhase::BranchInversion,
192 OptimizationPhase::ReorderStatements,
193 OptimizationPhase::VariableForwarding,
194 OptimizationPhase::ReorderStatements,
195 OptimizationPhase::ReorganizeBlocks,
196 OptimizationPhase::OptimizeMatches,
197 OptimizationPhase::ReorderStatements,
198 OptimizationPhase::ReorganizeBlocks,
200 OptimizationPhase::ConstFolding,
201 OptimizationPhase::OptimizeMatches,
202 OptimizationPhase::SplitStructs,
203 OptimizationPhase::ReorganizeBlocks,
204 OptimizationPhase::ReorderStatements,
205 OptimizationPhase::OptimizeMatches,
206 OptimizationPhase::ReorganizeBlocks,
207 OptimizationPhase::Reboxing,
208 OptimizationPhase::ReorderStatements,
209 OptimizationPhase::VariableForwarding,
210 OptimizationPhase::ReorderStatements,
211 OptimizationPhase::ReorganizeBlocks,
212 OptimizationPhase::Cse,
215 OptimizationPhase::DedupBlocks,
216 OptimizationPhase::ReturnOptimization,
218 OptimizationPhase::ReorderStatements,
219 OptimizationPhase::ReorganizeBlocks,
220 ])
221 }
222 Optimizations::Disabled => OptimizationStrategy(vec![OptimizationPhase::ApplyInlining {
223 enable_const_folding: false,
224 }]),
225 }
226 .intern(db)
227}
228
229#[salsa::tracked]
231pub fn final_optimization_strategy<'db>(db: &'db dyn Database) -> OptimizationStrategyId<'db> {
232 match db.optimizations() {
233 Optimizations::Enabled(_) => {
234 OptimizationStrategy(vec![
235 OptimizationPhase::GasRedeposit,
236 OptimizationPhase::EarlyUnsafePanic,
237 OptimizationPhase::TrimUnreachable,
240 OptimizationPhase::LowerImplicits,
241 OptimizationPhase::ReorganizeBlocks,
242 ])
243 }
244 Optimizations::Disabled => OptimizationStrategy(vec![
245 OptimizationPhase::LowerImplicits,
246 OptimizationPhase::ReorganizeBlocks,
247 ]),
248 }
249 .intern(db)
250}