palladium/optimizer/
dead_code.rs1use crate::ast::*;
6use crate::errors::CompileError;
7use crate::optimizer::{helpers, OptimizationPass};
8
9pub struct DeadCodeEliminationPass {
10 changes_made: usize,
11}
12
13impl Default for DeadCodeEliminationPass {
14 fn default() -> Self {
15 Self::new()
16 }
17}
18
19impl DeadCodeEliminationPass {
20 pub fn new() -> Self {
21 Self { changes_made: 0 }
22 }
23
24 #[allow(clippy::only_used_in_recursion)]
26 fn can_continue_after(&self, stmt: &Stmt) -> bool {
27 match stmt {
28 Stmt::Return(_) | Stmt::Break { .. } | Stmt::Continue { .. } => false,
29 Stmt::If {
30 then_branch,
31 else_branch,
32 ..
33 } => {
34 let then_can_continue =
36 then_branch.is_empty() || self.can_continue_after(then_branch.last().unwrap());
37
38 let else_can_continue = else_branch.as_ref().is_none_or(|branch| {
39 branch.is_empty() || self.can_continue_after(branch.last().unwrap())
40 });
41
42 then_can_continue || else_can_continue
43 }
44 _ => true,
45 }
46 }
47}
48
49impl OptimizationPass for DeadCodeEliminationPass {
50 fn name(&self) -> &str {
51 "Dead Code Elimination"
52 }
53
54 fn optimize_program(&mut self, program: &mut Program) -> Result<bool, CompileError> {
55 self.changes_made = 0;
56
57 for item in &mut program.items {
58 if let Item::Function(func) = item {
59 self.optimize_function(func)?;
60 }
61 }
62
63 Ok(self.changes_made > 0)
64 }
65
66 fn optimize_function(&mut self, func: &mut Function) -> Result<bool, CompileError> {
67 self.eliminate_dead_code_in_vec(&mut func.body)
68 }
69
70 fn optimize_statement(&mut self, stmt: &mut Stmt) -> Result<bool, CompileError> {
71 match stmt {
72 Stmt::If {
73 condition,
74 then_branch,
75 else_branch,
76 ..
77 } => {
78 if let Expr::Bool(_val) = condition {
80 self.changes_made += 1;
86 }
87
88 self.eliminate_dead_code_in_vec(then_branch)?;
89
90 if let Some(else_branch) = else_branch {
91 self.eliminate_dead_code_in_vec(else_branch)?;
92 }
93 }
94 Stmt::While {
95 condition, body, ..
96 } => {
97 if let Expr::Bool(false) = condition {
99 self.changes_made += 1;
103 }
104
105 self.eliminate_dead_code_in_vec(body)?;
106 }
107 Stmt::Expr(expr) => {
108 if !helpers::expr_has_side_effects(expr) {
110 self.changes_made += 1;
113 return Ok(true);
114 }
115 }
116 _ => {}
117 }
118
119 Ok(false)
120 }
121
122 fn optimize_expression(&mut self, _expr: &mut Expr) -> Result<bool, CompileError> {
123 Ok(false)
125 }
126}
127
128impl DeadCodeEliminationPass {
129 fn eliminate_dead_code_in_vec(
131 &mut self,
132 statements: &mut Vec<Stmt>,
133 ) -> Result<bool, CompileError> {
134 let mut i = 0;
135 let mut found_terminator = false;
136
137 while i < statements.len() {
138 let stmt = &statements[i];
139
140 if found_terminator {
141 statements.truncate(i);
143 self.changes_made += 1;
144 return Ok(true);
145 }
146
147 if !self.can_continue_after(stmt) {
149 found_terminator = true;
150 }
151
152 self.optimize_statement(&mut statements[i])?;
154
155 i += 1;
156 }
157
158 Ok(false)
159 }
160}