Skip to main content

gruel_codegen_llvm/
opt_level.rs

1//! Optimization level configuration.
2//!
3//! Per ADR-0034, optimization is handled entirely by LLVM's mid-end pipeline
4//! (`default<OX>`), invoked when generating object code or LLVM IR at `-O1` and
5//! above. `OptLevel` is the user-facing knob that controls which pipeline (if
6//! any) runs.
7
8/// Optimization level, following standard compiler conventions.
9///
10/// Maps to `inkwell::OptimizationLevel` when building the `TargetMachine` and
11/// selects the `default<OX>` pass pipeline run before emission. At `-O0` no
12/// LLVM passes are run.
13#[derive(
14    Debug, Clone, Copy, PartialEq, Eq, Default, strum::Display, strum::EnumString, strum::EnumIter,
15)]
16pub enum OptLevel {
17    /// No optimization (`-O0`).
18    #[default]
19    #[strum(to_string = "0", serialize = "O0")]
20    O0,
21
22    /// Basic optimizations (`-O1`).
23    #[strum(to_string = "1", serialize = "O1")]
24    O1,
25
26    /// Standard optimizations (`-O2`).
27    #[strum(to_string = "2", serialize = "O2")]
28    O2,
29
30    /// Aggressive optimizations (`-O3`).
31    #[strum(to_string = "3", serialize = "O3")]
32    O3,
33}
34
35impl OptLevel {
36    /// Returns all available optimization levels.
37    pub fn all() -> Vec<OptLevel> {
38        use strum::IntoEnumIterator;
39        OptLevel::iter().collect()
40    }
41
42    /// Returns a comma-separated string of all level names (for help text).
43    pub fn all_names() -> String {
44        Self::all()
45            .iter()
46            .map(|l| l.to_string())
47            .collect::<Vec<_>>()
48            .join(", ")
49    }
50}
51
52#[cfg(test)]
53mod tests {
54    use super::*;
55
56    #[test]
57    fn test_opt_level_from_str() {
58        // Numeric form (canonical for --opt-level=N)
59        assert_eq!("0".parse::<OptLevel>().unwrap(), OptLevel::O0);
60        assert_eq!("1".parse::<OptLevel>().unwrap(), OptLevel::O1);
61        assert_eq!("2".parse::<OptLevel>().unwrap(), OptLevel::O2);
62        assert_eq!("3".parse::<OptLevel>().unwrap(), OptLevel::O3);
63
64        // O-prefixed form is still accepted for compatibility.
65        assert_eq!("O0".parse::<OptLevel>().unwrap(), OptLevel::O0);
66        assert_eq!("O3".parse::<OptLevel>().unwrap(), OptLevel::O3);
67
68        // Invalid
69        assert!("4".parse::<OptLevel>().is_err());
70        assert!("fast".parse::<OptLevel>().is_err());
71    }
72
73    #[test]
74    fn test_opt_level_display() {
75        assert_eq!(format!("{}", OptLevel::O0), "0");
76        assert_eq!(format!("{}", OptLevel::O3), "3");
77    }
78
79    #[test]
80    fn test_opt_level_default() {
81        assert_eq!(OptLevel::default(), OptLevel::O0);
82    }
83}