Skip to main content

palladium/optimizer/
mod.rs

1//! Optimization passes for the Palladium compiler
2//!
3//! This module implements various optimization passes that improve
4//! the generated code quality without changing program semantics.
5
6use crate::ast::*;
7use crate::errors::CompileError;
8
9mod constant_folding;
10mod dead_code;
11mod simplify;
12
13pub use constant_folding::ConstantFoldingPass;
14pub use dead_code::DeadCodeEliminationPass;
15pub use simplify::SimplificationPass;
16
17/// Trait for optimization passes
18pub trait OptimizationPass {
19    /// Name of the optimization pass for debugging
20    fn name(&self) -> &str;
21
22    /// Optimize a complete program
23    fn optimize_program(&mut self, program: &mut Program) -> Result<bool, CompileError>;
24
25    /// Optimize a single function (default implementation)
26    fn optimize_function(&mut self, func: &mut Function) -> Result<bool, CompileError> {
27        let mut changed = false;
28        for stmt in &mut func.body {
29            changed |= self.optimize_statement(stmt)?;
30        }
31        Ok(changed)
32    }
33
34    /// Optimize a statement
35    fn optimize_statement(&mut self, stmt: &mut Stmt) -> Result<bool, CompileError>;
36
37    /// Optimize an expression
38    fn optimize_expression(&mut self, expr: &mut Expr) -> Result<bool, CompileError>;
39}
40
41/// Optimizer that runs multiple optimization passes
42pub struct Optimizer {
43    passes: Vec<Box<dyn OptimizationPass>>,
44    enable_logging: bool,
45}
46
47impl Default for Optimizer {
48    fn default() -> Self {
49        Self::new()
50    }
51}
52
53impl Optimizer {
54    /// Create a new optimizer with default passes
55    pub fn new() -> Self {
56        Self {
57            passes: vec![
58                Box::new(ConstantFoldingPass::new()),
59                Box::new(DeadCodeEliminationPass::new()),
60                Box::new(SimplificationPass::new()),
61            ],
62            enable_logging: false,
63        }
64    }
65
66    /// Enable optimization logging
67    pub fn with_logging(mut self) -> Self {
68        self.enable_logging = true;
69        self
70    }
71
72    /// Add a custom optimization pass
73    pub fn add_pass(&mut self, pass: Box<dyn OptimizationPass>) {
74        self.passes.push(pass);
75    }
76
77    /// Run all optimization passes on the program
78    pub fn optimize(&mut self, program: &mut Program) -> Result<(), CompileError> {
79        let mut total_changes = 0;
80        let mut iteration = 0;
81
82        // Keep running passes until no more changes occur (fixed point)
83        loop {
84            let mut changed_in_iteration = false;
85
86            for pass in &mut self.passes {
87                if self.enable_logging {
88                    println!("   Running {}", pass.name());
89                }
90
91                let changed = pass.optimize_program(program)?;
92                if changed {
93                    changed_in_iteration = true;
94                    total_changes += 1;
95                }
96            }
97
98            iteration += 1;
99
100            // Stop if no changes or max iterations reached
101            if !changed_in_iteration || iteration >= 10 {
102                break;
103            }
104        }
105
106        if self.enable_logging && total_changes > 0 {
107            println!(
108                "   Made {} optimization(s) in {} iteration(s)",
109                total_changes, iteration
110            );
111        }
112
113        Ok(())
114    }
115}
116
117/// Helper functions for optimization passes
118pub mod helpers {
119    use crate::ast::*;
120
121    /// Check if an expression is a compile-time constant
122    pub fn is_constant(expr: &Expr) -> bool {
123        match expr {
124            Expr::Integer(_) | Expr::Bool(_) | Expr::String(_) => true,
125            Expr::Binary { left, right, .. } => is_constant(left) && is_constant(right),
126            Expr::Unary { operand, .. } => is_constant(operand),
127            _ => false,
128        }
129    }
130
131    /// Evaluate a binary operation on integers at compile time
132    pub fn eval_binary_int(left: i64, op: BinOp, right: i64) -> Option<i64> {
133        match op {
134            BinOp::Add => Some(left + right),
135            BinOp::Sub => Some(left - right),
136            BinOp::Mul => Some(left * right),
137            BinOp::Div => {
138                if right != 0 {
139                    Some(left / right)
140                } else {
141                    None // Division by zero
142                }
143            }
144            BinOp::Mod => {
145                if right != 0 {
146                    Some(left % right)
147                } else {
148                    None
149                }
150            }
151            _ => None, // Comparison operators return bool, not int
152        }
153    }
154
155    /// Evaluate a comparison operation at compile time
156    pub fn eval_comparison(left: i64, op: BinOp, right: i64) -> Option<bool> {
157        match op {
158            BinOp::Eq => Some(left == right),
159            BinOp::Ne => Some(left != right),
160            BinOp::Lt => Some(left < right),
161            BinOp::Gt => Some(left > right),
162            BinOp::Le => Some(left <= right),
163            BinOp::Ge => Some(left >= right),
164            _ => None,
165        }
166    }
167
168    /// Check if a statement has side effects
169    pub fn has_side_effects(stmt: &Stmt) -> bool {
170        match stmt {
171            Stmt::Let { .. } => false,
172            Stmt::Expr(expr) => expr_has_side_effects(expr),
173            Stmt::If { .. } | Stmt::While { .. } => true,
174            Stmt::Return(_) => true,
175            Stmt::Break { .. } | Stmt::Continue { .. } => true,
176            Stmt::Assign { .. } => true,
177            _ => false,
178        }
179    }
180
181    /// Check if an expression has side effects
182    pub fn expr_has_side_effects(expr: &Expr) -> bool {
183        match expr {
184            Expr::Call { .. } => true, // Function calls might have side effects
185            Expr::Binary { left, right, .. } => {
186                expr_has_side_effects(left) || expr_has_side_effects(right)
187            }
188            Expr::Unary { operand, .. } => expr_has_side_effects(operand),
189            Expr::Index { array, index, .. } => {
190                expr_has_side_effects(array) || expr_has_side_effects(index)
191            }
192            Expr::FieldAccess { object, .. } => expr_has_side_effects(object),
193            _ => false,
194        }
195    }
196}