palladium/optimizer/
mod.rs1use 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
17pub trait OptimizationPass {
19 fn name(&self) -> &str;
21
22 fn optimize_program(&mut self, program: &mut Program) -> Result<bool, CompileError>;
24
25 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 fn optimize_statement(&mut self, stmt: &mut Stmt) -> Result<bool, CompileError>;
36
37 fn optimize_expression(&mut self, expr: &mut Expr) -> Result<bool, CompileError>;
39}
40
41pub 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 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 pub fn with_logging(mut self) -> Self {
68 self.enable_logging = true;
69 self
70 }
71
72 pub fn add_pass(&mut self, pass: Box<dyn OptimizationPass>) {
74 self.passes.push(pass);
75 }
76
77 pub fn optimize(&mut self, program: &mut Program) -> Result<(), CompileError> {
79 let mut total_changes = 0;
80 let mut iteration = 0;
81
82 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 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
117pub mod helpers {
119 use crate::ast::*;
120
121 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 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 }
143 }
144 BinOp::Mod => {
145 if right != 0 {
146 Some(left % right)
147 } else {
148 None
149 }
150 }
151 _ => None, }
153 }
154
155 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 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 pub fn expr_has_side_effects(expr: &Expr) -> bool {
183 match expr {
184 Expr::Call { .. } => true, 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}