Skip to main content

cairo_lang_lowering/optimizations/
strategy.rs

1use cairo_lang_diagnostics::Maybe;
2use cairo_lang_utils::{Intern, LookupIntern, define_short_id};
3
4use super::dedup_blocks::dedup_blocks;
5use super::early_unsafe_panic::early_unsafe_panic;
6use super::gas_redeposit::gas_redeposit;
7use super::trim_unreachable::trim_unreachable;
8use super::validate::validate;
9use crate::Lowered;
10use crate::db::LoweringGroup;
11use crate::ids::ConcreteFunctionWithBodyId;
12use crate::implicits::lower_implicits;
13use crate::inline::apply_inlining;
14use crate::optimizations::branch_inversion::branch_inversion;
15use crate::optimizations::cancel_ops::cancel_ops;
16use crate::optimizations::const_folding::const_folding;
17use crate::optimizations::match_optimizer::optimize_matches;
18use crate::optimizations::remappings::optimize_remappings;
19use crate::optimizations::reorder_statements::reorder_statements;
20use crate::optimizations::return_optimization::return_optimization;
21use crate::optimizations::split_structs::split_structs;
22use crate::reorganize_blocks::reorganize_blocks;
23
24/// Enum of the optimization phases that can be used in a strategy.
25#[derive(Clone, Debug, Eq, Hash, PartialEq)]
26pub enum OptimizationPhase {
27    ApplyInlining {
28        enable_const_folding: bool,
29    },
30    BranchInversion,
31    CancelOps,
32    ConstFolding,
33    DedupBlocks,
34    EarlyUnsafePanic,
35    OptimizeMatches,
36    OptimizeRemappings,
37    ReorderStatements,
38    ReorganizeBlocks,
39    ReturnOptimization,
40    SplitStructs,
41    TrimUnreachable,
42    GasRedeposit,
43    /// The following is not really an optimization but we want to apply optimizations before and
44    /// after it, so it is convenient to treat it as an optimization.
45    LowerImplicits,
46    /// A validation phase that checks the lowering is valid. Used for debugging purposes.
47    Validate,
48    /// A phase that iteratively a set of optimizations to the lowering.
49    /// Stops after a certain number of iterations, or when no more changes are made.
50    SubStrategy {
51        /// The id of the optimization strategy to apply.
52        strategy: OptimizationStrategyId,
53        /// The number of times to apply the strategy.
54        iterations: usize,
55    },
56}
57
58impl OptimizationPhase {
59    /// Applies the optimization phase to the lowering.
60    ///
61    /// Assumes `lowered` is a lowering of `function`.
62    pub fn apply(
63        self,
64        db: &dyn LoweringGroup,
65        function: ConcreteFunctionWithBodyId,
66        lowered: &mut Lowered,
67    ) -> Maybe<()> {
68        match self {
69            OptimizationPhase::ApplyInlining { enable_const_folding } => {
70                apply_inlining(db, function, lowered, enable_const_folding)?
71            }
72            OptimizationPhase::BranchInversion => branch_inversion(db, lowered),
73            OptimizationPhase::CancelOps => cancel_ops(lowered),
74            OptimizationPhase::ConstFolding => const_folding(db, function, lowered),
75            OptimizationPhase::EarlyUnsafePanic => early_unsafe_panic(db, lowered),
76            OptimizationPhase::DedupBlocks => dedup_blocks(lowered),
77            OptimizationPhase::OptimizeMatches => optimize_matches(lowered),
78            OptimizationPhase::OptimizeRemappings => optimize_remappings(lowered),
79            OptimizationPhase::ReorderStatements => reorder_statements(db, lowered),
80            OptimizationPhase::ReorganizeBlocks => reorganize_blocks(lowered),
81            OptimizationPhase::ReturnOptimization => return_optimization(db, lowered),
82            OptimizationPhase::SplitStructs => split_structs(lowered),
83            OptimizationPhase::TrimUnreachable => trim_unreachable(db, lowered),
84            OptimizationPhase::LowerImplicits => lower_implicits(db, function, lowered),
85            OptimizationPhase::GasRedeposit => gas_redeposit(db, function, lowered),
86            OptimizationPhase::Validate => validate(lowered)
87                .unwrap_or_else(|err| panic!("Failed validation: {:?}", err.to_message())),
88            OptimizationPhase::SubStrategy { strategy, iterations } => {
89                for _ in 1..iterations {
90                    let before = lowered.clone();
91                    strategy.apply_strategy(db, function, lowered)?;
92                    if *lowered == before {
93                        return Ok(());
94                    }
95                }
96                strategy.apply_strategy(db, function, lowered)?
97            }
98        }
99        Ok(())
100    }
101}
102
103define_short_id!(
104    OptimizationStrategyId,
105    OptimizationStrategy,
106    LoweringGroup,
107    lookup_intern_strategy,
108    intern_strategy
109);
110
111/// A strategy is a sequence of optimization phases.
112#[derive(Clone, Debug, Eq, Hash, PartialEq)]
113pub struct OptimizationStrategy(pub Vec<OptimizationPhase>);
114
115impl OptimizationStrategyId {
116    /// Applies the optimization strategy phase to the lowering.
117    ///
118    /// Assumes `lowered` is a lowering of `function`.
119    pub fn apply_strategy(
120        self,
121        db: &dyn LoweringGroup,
122        function: ConcreteFunctionWithBodyId,
123        lowered: &mut Lowered,
124    ) -> Maybe<()> {
125        for phase in self.lookup_intern(db).0 {
126            phase.apply(db, function, lowered)?;
127        }
128
129        Ok(())
130    }
131}
132
133/// Query implementation of [crate::db::LoweringGroup::baseline_optimization_strategy].
134pub fn baseline_optimization_strategy(db: &dyn LoweringGroup) -> OptimizationStrategyId {
135    OptimizationStrategy(vec![
136        // Must be right before inlining.
137        OptimizationPhase::ReorganizeBlocks,
138        OptimizationPhase::ApplyInlining { enable_const_folding: true },
139        OptimizationPhase::ReturnOptimization,
140        OptimizationPhase::ReorganizeBlocks,
141        OptimizationPhase::ReorderStatements,
142        OptimizationPhase::BranchInversion,
143        OptimizationPhase::CancelOps,
144        // Must be right before const folding.
145        OptimizationPhase::ReorganizeBlocks,
146        OptimizationPhase::ConstFolding,
147        OptimizationPhase::OptimizeMatches,
148        OptimizationPhase::SplitStructs,
149        OptimizationPhase::ReorganizeBlocks,
150        OptimizationPhase::ReorderStatements,
151        OptimizationPhase::OptimizeMatches,
152        OptimizationPhase::ReorganizeBlocks,
153        OptimizationPhase::CancelOps,
154        OptimizationPhase::ReorganizeBlocks,
155        OptimizationPhase::DedupBlocks,
156        // Re-run ReturnOptimization to eliminate harmful merges introduced by DedupBlocks.
157        OptimizationPhase::ReturnOptimization,
158        OptimizationPhase::ReorderStatements,
159        OptimizationPhase::ReorganizeBlocks,
160    ])
161    .intern(db)
162}
163
164/// Query implementation of [crate::db::LoweringGroup::final_optimization_strategy].
165pub fn final_optimization_strategy(db: &dyn LoweringGroup) -> OptimizationStrategyId {
166    OptimizationStrategy(vec![
167        OptimizationPhase::GasRedeposit,
168        OptimizationPhase::EarlyUnsafePanic,
169        // Apply `TrimUnreachable` here to remove unreachable `redeposit_gas` and `unsafe_panic`
170        // calls.
171        OptimizationPhase::TrimUnreachable,
172        OptimizationPhase::LowerImplicits,
173        OptimizationPhase::ReorganizeBlocks,
174    ])
175    .intern(db)
176}