sway_ir/
optimize.rs

1//! A collection of optimization passes.
2//!
3//! Each of these modules are a collection of typical code optimisation passes.
4//!
5//! Currently there is no pass manager, as there are only a couple of passes, but this is something
6//! which will be added in the future.
7//!
8//! So each of the functions under this module will return a boolean indicating whether a
9//! modification to the IR was made.  Typically the passes will be just re-run until they no longer
10//! make any such modifications, implying they've optimized as much possible.
11//!
12//! When writing passes one should keep in mind that when a modification is made then any iterators
13//! over blocks or instructions can be invalidated, and starting over is a safer option than trying
14//! to attempt multiple changes at once.
15
16pub mod arg_demotion;
17pub use arg_demotion::*;
18pub mod arg_mutability_tagger;
19pub use arg_mutability_tagger::*;
20pub mod const_demotion;
21pub use const_demotion::*;
22pub mod constants;
23pub use constants::*;
24pub mod conditional_constprop;
25pub use conditional_constprop::*;
26pub mod cse;
27pub use cse::*;
28pub mod dce;
29pub use dce::*;
30pub mod inline;
31pub use inline::*;
32pub mod mem2reg;
33pub use mem2reg::*;
34pub mod memcpyopt;
35pub use memcpyopt::*;
36pub mod misc_demotion;
37pub use misc_demotion::*;
38pub mod ret_demotion;
39pub use ret_demotion::*;
40pub mod simplify_cfg;
41pub use simplify_cfg::*;
42pub mod sroa;
43pub use sroa::*;
44pub mod fn_dedup;
45pub use fn_dedup::*;
46
47mod target_fuel;
48
49#[cfg(test)]
50pub mod tests {
51    use crate::{Backtrace, PassGroup, PassManager};
52    use sway_features::ExperimentalFeatures;
53    use sway_types::SourceEngine;
54
55    /// This function parses the IR text representation and run the specified optimizers passes.
56    /// Then, depending on the `expected` parameter it checks if the IR was optimized or not.
57    ///
58    /// This comparison is done by capturing all instructions with metadata "!0".
59    ///
60    /// For example:
61    ///
62    /// ```rust, ignore
63    /// assert_optimization(
64    ///     &[CONST_FOLDING_NAME],
65    ///     "entry fn main() -> u64 {
66    ///        entry():
67    ///             l = const u64 1
68    ///             r = const u64 2
69    ///             result = add l, r, !0
70    ///             ret u64 result
71    ///     }",
72    ///     ["const u64 3"],
73    /// );
74    /// ```
75    pub(crate) fn assert_optimization<'a>(
76        passes: &[&'static str],
77        body: &str,
78        expected: Option<impl IntoIterator<Item = &'a str>>,
79    ) {
80        let source_engine = SourceEngine::default();
81        let mut context = crate::parse(
82            &format!(
83                "script {{
84                {body}
85            }}
86
87            !0 = \"a.sw\"
88            "
89            ),
90            &source_engine,
91            ExperimentalFeatures::default(),
92            Backtrace::default(),
93        )
94        .unwrap();
95
96        let mut pass_manager = PassManager::default();
97        crate::register_known_passes(&mut pass_manager);
98
99        let mut group = PassGroup::default();
100        for pass in passes {
101            group.append_pass(pass);
102        }
103
104        let before = context.to_string();
105        let modified = pass_manager.run(&mut context, &group).unwrap();
106        let after = context.to_string();
107
108        // print diff to help debug
109        if std::env::args().any(|x| x == "--nocapture") {
110            println!("{}", prettydiff::diff_lines(&before, &after));
111        }
112
113        assert_eq!(expected.is_some(), modified);
114
115        let Some(expected) = expected else {
116            return;
117        };
118
119        let actual = context
120            .to_string()
121            .lines()
122            .filter_map(|x| {
123                if x.contains(", !") {
124                    Some(format!("{}\n", x.trim()))
125                } else {
126                    None
127                }
128            })
129            .collect::<Vec<String>>();
130
131        assert!(!actual.is_empty());
132
133        let mut expected_matches = actual.len();
134
135        for (actual, expected) in actual.iter().zip(expected) {
136            if !actual.contains(expected) {
137                panic!("Actual: {actual:?} does not contains expected: {expected:?}. (Run with --nocapture to see a diff)");
138            } else {
139                expected_matches -= 1;
140            }
141        }
142
143        assert_eq!(expected_matches, 0);
144    }
145}