Refine optimizer.

This commit is contained in:
Stephen Chung 2020-03-10 11:22:41 +08:00
parent feaad4e0da
commit 2d80ee2f18
2 changed files with 41 additions and 10 deletions

View File

@ -8,8 +8,8 @@ fn optimize_stmt(stmt: Stmt, changed: &mut bool) -> Stmt {
Stmt::Noop(pos) Stmt::Noop(pos)
} }
Expr::True(_) => optimize_stmt(*stmt1, changed), Expr::True(_) => optimize_stmt(*stmt1, changed),
_ => Stmt::IfElse( expr => Stmt::IfElse(
Box::new(optimize_expr(*expr, changed)), Box::new(optimize_expr(expr, changed)),
Box::new(optimize_stmt(*stmt1, changed)), Box::new(optimize_stmt(*stmt1, changed)),
None, None,
), ),
@ -18,8 +18,8 @@ fn optimize_stmt(stmt: Stmt, changed: &mut bool) -> Stmt {
Stmt::IfElse(expr, stmt1, Some(stmt2)) => match *expr { Stmt::IfElse(expr, stmt1, Some(stmt2)) => match *expr {
Expr::False(_) => optimize_stmt(*stmt2, changed), Expr::False(_) => optimize_stmt(*stmt2, changed),
Expr::True(_) => optimize_stmt(*stmt1, changed), Expr::True(_) => optimize_stmt(*stmt1, changed),
_ => Stmt::IfElse( expr => Stmt::IfElse(
Box::new(optimize_expr(*expr, changed)), Box::new(optimize_expr(expr, changed)),
Box::new(optimize_stmt(*stmt1, changed)), Box::new(optimize_stmt(*stmt1, changed)),
Some(Box::new(optimize_stmt(*stmt2, changed))), Some(Box::new(optimize_stmt(*stmt2, changed))),
), ),
@ -31,8 +31,8 @@ fn optimize_stmt(stmt: Stmt, changed: &mut bool) -> Stmt {
Stmt::Noop(pos) Stmt::Noop(pos)
} }
Expr::True(_) => Stmt::Loop(Box::new(optimize_stmt(*stmt, changed))), Expr::True(_) => Stmt::Loop(Box::new(optimize_stmt(*stmt, changed))),
_ => Stmt::While( expr => Stmt::While(
Box::new(optimize_expr(*expr, changed)), Box::new(optimize_expr(expr, changed)),
Box::new(optimize_stmt(*stmt, changed)), Box::new(optimize_stmt(*stmt, changed)),
), ),
}, },
@ -57,6 +57,17 @@ fn optimize_stmt(stmt: Stmt, changed: &mut bool) -> Stmt {
.filter(Stmt::is_op) // Remove no-op's .filter(Stmt::is_op) // Remove no-op's
.collect(); .collect();
if let Some(last_stmt) = result.pop() {
// Remove all raw expression statements that evaluate to constants
// except for the very last statement
result.retain(|stmt| match stmt {
Stmt::Expr(expr) if expr.is_constant() => false,
_ => true,
});
result.push(last_stmt);
}
*changed = *changed || original_len != result.len(); *changed = *changed || original_len != result.len();
match result[..] { match result[..] {
@ -65,14 +76,19 @@ fn optimize_stmt(stmt: Stmt, changed: &mut bool) -> Stmt {
*changed = true; *changed = true;
Stmt::Noop(pos) Stmt::Noop(pos)
} }
[Stmt::Let(_, _, _)] => { [Stmt::Let(_, None, _)] => {
// Only one empty variable declaration - change to No-op
*changed = true;
Stmt::Noop(pos)
}
[Stmt::Let(_, Some(_), _)] => {
// Only one let statement, but cannot promote // Only one let statement, but cannot promote
// (otherwise the variable gets declared in the scope above) // (otherwise the variable gets declared in the scope above)
// and still need to run just in case there are side effects // and still need to run just in case there are side effects
Stmt::Block(result, pos) Stmt::Block(result, pos)
} }
[_] => { [_] => {
// No statements in block - change to No-op // Only one statement - promote
*changed = true; *changed = true;
result.remove(0) result.remove(0)
} }
@ -87,9 +103,9 @@ fn optimize_stmt(stmt: Stmt, changed: &mut bool) -> Stmt {
is_return, is_return,
pos, pos,
), ),
Stmt::ReturnWithVal(None, _, _) => stmt, stmt @ Stmt::ReturnWithVal(None, _, _) => stmt,
Stmt::Noop(_) | Stmt::Break(_) => stmt, stmt @ Stmt::Noop(_) | stmt @ Stmt::Break(_) => stmt,
} }
} }

View File

@ -198,6 +198,21 @@ impl Expr {
| Expr::Or(e, _) => e.position(), | Expr::Or(e, _) => e.position(),
} }
} }
pub fn is_constant(&self) -> bool {
match self {
Expr::IntegerConstant(_, _)
| Expr::FloatConstant(_, _)
| Expr::Identifier(_, _)
| Expr::CharConstant(_, _)
| Expr::StringConstant(_, _)
| Expr::True(_)
| Expr::False(_)
| Expr::Unit(_) => true,
_ => false,
}
}
} }
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]