Minor improvements to the optimizer.

This commit is contained in:
Stephen Chung 2020-03-12 23:46:52 +08:00
parent 91317c0d3e
commit 9bd66c7db3
2 changed files with 38 additions and 3 deletions

View File

@ -3,6 +3,26 @@ use crate::parser::{Expr, Stmt};
fn optimize_stmt(stmt: Stmt, changed: &mut bool, preserve_result: bool) -> Stmt {
match stmt {
Stmt::IfElse(expr, stmt1, None) if stmt1.is_noop() => {
*changed = true;
let pos = expr.position();
let expr = optimize_expr(*expr, changed);
match expr {
Expr::False(_) | Expr::True(_) => Stmt::Noop(stmt1.position()),
expr => {
let stmt = Stmt::Expr(Box::new(expr));
if preserve_result {
Stmt::Block(vec![stmt, *stmt1], pos)
} else {
stmt
}
}
}
}
Stmt::IfElse(expr, stmt1, None) => match *expr {
Expr::False(pos) => {
*changed = true;
@ -22,7 +42,10 @@ fn optimize_stmt(stmt: Stmt, changed: &mut bool, preserve_result: bool) -> Stmt
expr => Stmt::IfElse(
Box::new(optimize_expr(expr, changed)),
Box::new(optimize_stmt(*stmt1, changed, true)),
Some(Box::new(optimize_stmt(*stmt2, changed, true))),
match optimize_stmt(*stmt2, changed, true) {
stmt if stmt.is_noop() => None,
stmt => Some(Box::new(stmt)),
},
),
},
@ -274,10 +297,14 @@ pub(crate) fn optimize(statements: Vec<Stmt>) -> Vec<Stmt> {
}
}
// Eliminate No-op's but always keep the last statement
// Eliminate code that is pure but always keep the last statement
let last_stmt = result.pop();
result.retain(Stmt::is_op); // Remove all No-op's
// Remove all pure statements at top level
result.retain(|stmt| match stmt {
Stmt::Expr(expr) if expr.is_pure() => false,
_ => true,
});
if let Some(stmt) = last_stmt {
result.push(stmt); // Add back the last statement

View File

@ -186,6 +186,13 @@ pub enum Stmt {
}
impl Stmt {
pub fn is_noop(&self) -> bool {
match self {
Stmt::Noop(_) => true,
_ => false,
}
}
pub fn is_op(&self) -> bool {
match self {
Stmt::Noop(_) => false,
@ -265,6 +272,7 @@ impl Expr {
pub fn is_pure(&self) -> bool {
match self {
Expr::Array(expressions, _) => expressions.iter().all(Expr::is_pure),
Expr::And(x, y) | Expr::Or(x, y) | Expr::Index(x, y, _) => x.is_pure() && y.is_pure(),
expr => expr.is_constant() || expr.is_identifier(),
}
}