cairo_lang_lowering/optimizations/
strategy.rs1use cairo_lang_diagnostics::Maybe;
2use cairo_lang_utils::{Intern, define_short_id};
3use salsa::Database;
4
5use super::cse::cse;
6use super::dedup_blocks::dedup_blocks;
7use super::early_unsafe_panic::early_unsafe_panic;
8use super::gas_redeposit::gas_redeposit;
9use super::trim_unreachable::trim_unreachable;
10use super::validate::validate;
11use crate::Lowered;
12use crate::db::LoweringGroup;
13use crate::ids::ConcreteFunctionWithBodyId;
14use crate::implicits::lower_implicits;
15use crate::inline::apply_inlining;
16use crate::optimizations::branch_inversion::branch_inversion;
17use crate::optimizations::cancel_ops::cancel_ops;
18use crate::optimizations::config::Optimizations;
19use crate::optimizations::const_folding::const_folding;
20use crate::optimizations::match_optimizer::optimize_matches;
21use crate::optimizations::remappings::optimize_remappings;
22use crate::optimizations::reorder_statements::reorder_statements;
23use crate::optimizations::return_optimization::return_optimization;
24use crate::optimizations::split_structs::split_structs;
25use crate::reorganize_blocks::reorganize_blocks;
26
27#[derive(Clone, Debug, Eq, Hash, PartialEq)]
29pub enum OptimizationPhase<'db> {
30 ApplyInlining {
31 enable_const_folding: bool,
32 },
33 BranchInversion,
34 CancelOps,
35 ConstFolding,
36 Cse,
37 DedupBlocks,
38 EarlyUnsafePanic,
39 OptimizeMatches,
40 OptimizeRemappings,
41 ReorderStatements,
42 ReorganizeBlocks,
43 ReturnOptimization,
44 SplitStructs,
45 TrimUnreachable,
46 GasRedeposit,
47 LowerImplicits,
50 Validate,
52 SubStrategy {
55 strategy: OptimizationStrategyId<'db>,
57 iterations: usize,
59 },
60}
61
62impl<'db> OptimizationPhase<'db> {
63 pub fn apply(
67 self,
68 db: &'db dyn Database,
69 function: ConcreteFunctionWithBodyId<'db>,
70 lowered: &mut Lowered<'db>,
71 ) -> Maybe<()> {
72 match self {
73 OptimizationPhase::ApplyInlining { enable_const_folding } => {
74 apply_inlining(db, function, lowered, enable_const_folding)?
75 }
76 OptimizationPhase::BranchInversion => branch_inversion(db, lowered),
77 OptimizationPhase::CancelOps => cancel_ops(lowered),
78 OptimizationPhase::ConstFolding => const_folding(db, function, lowered),
79 OptimizationPhase::Cse => cse(lowered),
80 OptimizationPhase::EarlyUnsafePanic => early_unsafe_panic(db, lowered),
81 OptimizationPhase::DedupBlocks => dedup_blocks(lowered),
82 OptimizationPhase::OptimizeMatches => optimize_matches(lowered),
83 OptimizationPhase::OptimizeRemappings => optimize_remappings(lowered),
84 OptimizationPhase::ReorderStatements => reorder_statements(db, lowered),
85 OptimizationPhase::ReorganizeBlocks => reorganize_blocks(lowered),
86 OptimizationPhase::ReturnOptimization => return_optimization(db, lowered),
87 OptimizationPhase::SplitStructs => split_structs(lowered),
88 OptimizationPhase::TrimUnreachable => trim_unreachable(db, lowered),
89 OptimizationPhase::LowerImplicits => lower_implicits(db, function, lowered),
90 OptimizationPhase::GasRedeposit => gas_redeposit(db, function, lowered),
91 OptimizationPhase::Validate => validate(lowered).unwrap_or_else(|err| {
92 panic!(
93 "Failed validation for function {}: {:?}",
94 function.full_path(db),
95 err.to_message()
96 )
97 }),
98 OptimizationPhase::SubStrategy { strategy, iterations } => {
99 for _ in 1..iterations {
100 let before = lowered.clone();
101 strategy.apply_strategy(db, function, lowered)?;
102 if *lowered == before {
103 return Ok(());
104 }
105 }
106 strategy.apply_strategy(db, function, lowered)?
107 }
108 }
109 Ok(())
110 }
111}
112
113define_short_id!(OptimizationStrategyId, OptimizationStrategy<'db>);
114
115#[derive(Clone, Debug, Eq, Hash, PartialEq)]
117pub struct OptimizationStrategy<'db>(pub Vec<OptimizationPhase<'db>>);
118
119impl<'db> OptimizationStrategyId<'db> {
120 pub fn apply_strategy(
124 self,
125 db: &'db dyn Database,
126 function: ConcreteFunctionWithBodyId<'db>,
127 lowered: &mut Lowered<'db>,
128 ) -> Maybe<()> {
129 for phase in self.long(db).0.clone() {
130 phase.apply(db, function, lowered)?;
131 }
132
133 Ok(())
134 }
135}
136
137#[salsa::tracked]
139pub fn baseline_optimization_strategy<'db>(db: &'db dyn Database) -> OptimizationStrategyId<'db> {
140 match db.optimizations() {
141 Optimizations::Enabled(_) => {
142 OptimizationStrategy(vec![
143 OptimizationPhase::ReorganizeBlocks,
145 OptimizationPhase::ApplyInlining { enable_const_folding: true },
146 OptimizationPhase::ReturnOptimization,
147 OptimizationPhase::ReorganizeBlocks,
148 OptimizationPhase::ReorderStatements,
149 OptimizationPhase::BranchInversion,
150 OptimizationPhase::CancelOps,
151 OptimizationPhase::ReorganizeBlocks,
153 OptimizationPhase::ConstFolding,
154 OptimizationPhase::OptimizeMatches,
155 OptimizationPhase::SplitStructs,
156 OptimizationPhase::ReorganizeBlocks,
157 OptimizationPhase::ReorderStatements,
158 OptimizationPhase::OptimizeMatches,
159 OptimizationPhase::ReorganizeBlocks,
160 OptimizationPhase::CancelOps,
161 OptimizationPhase::ReorganizeBlocks,
162 OptimizationPhase::Cse,
165 OptimizationPhase::DedupBlocks,
166 OptimizationPhase::ReturnOptimization,
168 OptimizationPhase::ReorderStatements,
169 OptimizationPhase::ReorganizeBlocks,
170 ])
171 }
172 Optimizations::Disabled => OptimizationStrategy(vec![OptimizationPhase::ApplyInlining {
173 enable_const_folding: false,
174 }]),
175 }
176 .intern(db)
177}
178
179#[salsa::tracked]
181pub fn final_optimization_strategy<'db>(db: &'db dyn Database) -> OptimizationStrategyId<'db> {
182 match db.optimizations() {
183 Optimizations::Enabled(_) => {
184 OptimizationStrategy(vec![
185 OptimizationPhase::GasRedeposit,
186 OptimizationPhase::EarlyUnsafePanic,
187 OptimizationPhase::TrimUnreachable,
190 OptimizationPhase::LowerImplicits,
191 OptimizationPhase::ReorganizeBlocks,
192 ])
193 }
194 Optimizations::Disabled => OptimizationStrategy(vec![
195 OptimizationPhase::LowerImplicits,
196 OptimizationPhase::ReorganizeBlocks,
197 ]),
198 }
199 .intern(db)
200}