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::gas_redeposit::gas_redeposit;
6use super::validate::validate;
7use crate::FlatLowered;
8use crate::db::LoweringGroup;
9use crate::ids::ConcreteFunctionWithBodyId;
10use crate::implicits::lower_implicits;
11use crate::inline::apply_inlining;
12use crate::optimizations::branch_inversion::branch_inversion;
13use crate::optimizations::cancel_ops::cancel_ops;
14use crate::optimizations::const_folding::const_folding;
15use crate::optimizations::match_optimizer::optimize_matches;
16use crate::optimizations::remappings::optimize_remappings;
17use crate::optimizations::reorder_statements::reorder_statements;
18use crate::optimizations::return_optimization::return_optimization;
19use crate::optimizations::split_structs::split_structs;
20use crate::reorganize_blocks::reorganize_blocks;
21
22/// Enum of the optimization phases that can be used in a strategy.
23#[derive(Clone, Debug, Eq, Hash, PartialEq)]
24pub enum OptimizationPhase {
25    ApplyInlining,
26    BranchInversion,
27    CancelOps,
28    ConstFolding,
29    DedupBlocks,
30    OptimizeMatches,
31    OptimizeRemappings,
32    ReorderStatements,
33    ReorganizeBlocks,
34    ReturnOptimization,
35    SplitStructs,
36    GasRedeposit,
37    /// The following is not really an optimization but we want to apply optimizations before and
38    /// after it, so it is convenient to treat it as an optimization.
39    LowerImplicits,
40    /// A validation phase that checks the lowering is valid. Used for debugging purposes.
41    Validate,
42}
43
44impl OptimizationPhase {
45    /// Applies the optimization phase to the lowering.
46    ///
47    /// Assumes `lowered` is a lowering of `function`.
48    pub fn apply(
49        self,
50        db: &dyn LoweringGroup,
51        function: ConcreteFunctionWithBodyId,
52        lowered: &mut FlatLowered,
53    ) -> Maybe<()> {
54        match self {
55            OptimizationPhase::ApplyInlining => apply_inlining(db, function, lowered)?,
56            OptimizationPhase::BranchInversion => branch_inversion(db, lowered),
57            OptimizationPhase::CancelOps => cancel_ops(lowered),
58            OptimizationPhase::ConstFolding => const_folding(db, lowered),
59            OptimizationPhase::DedupBlocks => dedup_blocks(lowered),
60            OptimizationPhase::OptimizeMatches => optimize_matches(lowered),
61            OptimizationPhase::OptimizeRemappings => optimize_remappings(lowered),
62            OptimizationPhase::ReorderStatements => reorder_statements(db, lowered),
63            OptimizationPhase::ReorganizeBlocks => reorganize_blocks(lowered),
64            OptimizationPhase::ReturnOptimization => return_optimization(db, function, lowered),
65            OptimizationPhase::SplitStructs => split_structs(lowered),
66            OptimizationPhase::LowerImplicits => lower_implicits(db, function, lowered),
67            OptimizationPhase::GasRedeposit => gas_redeposit(db, function, lowered),
68            OptimizationPhase::Validate => validate(lowered)
69                .unwrap_or_else(|err| panic!("Failed validation: {:?}", err.to_message())),
70        }
71        Ok(())
72    }
73}
74
75define_short_id!(
76    OptimizationStrategyId,
77    OptimizationStrategy,
78    LoweringGroup,
79    lookup_intern_strategy,
80    intern_strategy
81);
82
83/// A strategy is a sequence of optimization phases.
84#[derive(Clone, Debug, Eq, Hash, PartialEq)]
85pub struct OptimizationStrategy(pub Vec<OptimizationPhase>);
86
87impl OptimizationStrategyId {
88    /// Applies the optimization strategy phase to the lowering.
89    ///
90    /// Assumes `lowered` is a lowering of `function`.
91    pub fn apply_strategy(
92        self,
93        db: &dyn LoweringGroup,
94        function: ConcreteFunctionWithBodyId,
95        lowered: &mut FlatLowered,
96    ) -> Maybe<()> {
97        for phase in self.lookup_intern(db).0 {
98            phase.apply(db, function, lowered)?;
99        }
100
101        Ok(())
102    }
103}
104
105/// Query implementation of [crate::db::LoweringGroup::baseline_optimization_strategy].
106pub fn baseline_optimization_strategy(db: &dyn LoweringGroup) -> OptimizationStrategyId {
107    OptimizationStrategy(vec![
108        OptimizationPhase::ApplyInlining,
109        OptimizationPhase::ReturnOptimization,
110        OptimizationPhase::ReorganizeBlocks,
111        // The call to `reorder_statements` before and after `branch_inversion` is intentional.
112        // See description of `branch_inversion` for more details.
113        OptimizationPhase::ReorderStatements,
114        OptimizationPhase::BranchInversion,
115        OptimizationPhase::ReorderStatements,
116        OptimizationPhase::CancelOps,
117        // Must be right before const folding.
118        OptimizationPhase::ReorganizeBlocks,
119        OptimizationPhase::ConstFolding,
120        OptimizationPhase::OptimizeMatches,
121        OptimizationPhase::SplitStructs,
122        OptimizationPhase::ReorganizeBlocks,
123        OptimizationPhase::ReorderStatements,
124        OptimizationPhase::OptimizeMatches,
125        OptimizationPhase::ReorganizeBlocks,
126        OptimizationPhase::CancelOps,
127        OptimizationPhase::ReorderStatements,
128        OptimizationPhase::ReorganizeBlocks,
129        OptimizationPhase::DedupBlocks,
130        OptimizationPhase::ReorganizeBlocks,
131    ])
132    .intern(db)
133}
134
135/// Query implementation of [crate::db::LoweringGroup::final_optimization_strategy].
136pub fn final_optimization_strategy(db: &dyn LoweringGroup) -> OptimizationStrategyId {
137    OptimizationStrategy(vec![
138        OptimizationPhase::GasRedeposit,
139        OptimizationPhase::LowerImplicits,
140        OptimizationPhase::ReorganizeBlocks,
141        OptimizationPhase::CancelOps,
142        OptimizationPhase::ReorderStatements,
143        OptimizationPhase::ReorganizeBlocks,
144        OptimizationPhase::DedupBlocks,
145        OptimizationPhase::ReorganizeBlocks,
146    ])
147    .intern(db)
148}