Add case alternatives for switch.
This commit is contained in:
133
src/optimizer.rs
133
src/optimizer.rs
@@ -525,6 +525,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
||||
let (
|
||||
match_expr,
|
||||
SwitchCases {
|
||||
blocks: blocks_list,
|
||||
cases,
|
||||
ranges,
|
||||
def_case,
|
||||
@@ -537,34 +538,30 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
||||
let hash = hasher.finish();
|
||||
|
||||
// First check hashes
|
||||
if let Some(block) = cases.get_mut(&hash) {
|
||||
match mem::take(&mut block.condition) {
|
||||
if let Some(block) = cases.remove(&hash) {
|
||||
let mut block = mem::take(&mut blocks_list[block]);
|
||||
cases.clear();
|
||||
|
||||
match block.condition {
|
||||
Expr::BoolConstant(true, ..) => {
|
||||
// Promote the matched case
|
||||
let statements = optimize_stmt_block(
|
||||
mem::take(&mut block.statements),
|
||||
state,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
);
|
||||
let statements: StmtBlockContainer = mem::take(&mut block.statements);
|
||||
let statements = optimize_stmt_block(statements, state, true, true, false);
|
||||
*stmt = (statements, block.statements.span()).into();
|
||||
}
|
||||
mut condition => {
|
||||
ref mut condition => {
|
||||
// switch const { case if condition => stmt, _ => def } => if condition { stmt } else { def }
|
||||
optimize_expr(&mut condition, state, false);
|
||||
|
||||
let def_stmt =
|
||||
optimize_stmt_block(mem::take(def_case), state, true, true, false);
|
||||
optimize_expr(condition, state, false);
|
||||
|
||||
let def_case = &mut blocks_list[*def_case].statements;
|
||||
let def_span = def_case.span_or_else(*pos, Position::NONE);
|
||||
let def_case: StmtBlockContainer = mem::take(def_case);
|
||||
let def_stmt = optimize_stmt_block(def_case, state, true, true, false);
|
||||
*stmt = Stmt::If(
|
||||
(
|
||||
condition,
|
||||
mem::take(condition),
|
||||
mem::take(&mut block.statements),
|
||||
StmtBlock::new_with_span(
|
||||
def_stmt,
|
||||
def_case.span_or_else(*pos, Position::NONE),
|
||||
),
|
||||
StmtBlock::new_with_span(def_stmt, def_span),
|
||||
)
|
||||
.into(),
|
||||
match_expr.start_position(),
|
||||
@@ -582,21 +579,20 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
||||
|
||||
// Only one range or all ranges without conditions
|
||||
if ranges.len() == 1
|
||||
|| ranges
|
||||
.iter()
|
||||
.all(|(.., c)| matches!(c.condition, Expr::BoolConstant(true, ..)))
|
||||
|| ranges.iter().all(|r| {
|
||||
matches!(
|
||||
blocks_list[r.index()].condition,
|
||||
Expr::BoolConstant(true, ..)
|
||||
)
|
||||
})
|
||||
{
|
||||
for (.., block) in
|
||||
ranges
|
||||
.iter_mut()
|
||||
.filter(|&&mut (start, end, inclusive, ..)| {
|
||||
(!inclusive && (start..end).contains(&value))
|
||||
|| (inclusive && (start..=end).contains(&value))
|
||||
})
|
||||
{
|
||||
match mem::take(&mut block.condition) {
|
||||
for r in ranges.iter().filter(|r| r.contains(value)) {
|
||||
let condition = mem::take(&mut blocks_list[r.index()].condition);
|
||||
|
||||
match condition {
|
||||
Expr::BoolConstant(true, ..) => {
|
||||
// Promote the matched case
|
||||
let block = &mut blocks_list[r.index()];
|
||||
let statements = mem::take(&mut *block.statements);
|
||||
let statements =
|
||||
optimize_stmt_block(statements, state, true, true, false);
|
||||
@@ -606,21 +602,19 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
||||
// switch const { range if condition => stmt, _ => def } => if condition { stmt } else { def }
|
||||
optimize_expr(&mut condition, state, false);
|
||||
|
||||
let def_stmt = optimize_stmt_block(
|
||||
mem::take(def_case),
|
||||
state,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
);
|
||||
let def_case = &mut blocks_list[*def_case].statements;
|
||||
let def_span = def_case.span_or_else(*pos, Position::NONE);
|
||||
let def_case: StmtBlockContainer = mem::take(def_case);
|
||||
let def_stmt =
|
||||
optimize_stmt_block(def_case, state, true, true, false);
|
||||
|
||||
let statements = mem::take(&mut blocks_list[r.index()].statements);
|
||||
|
||||
*stmt = Stmt::If(
|
||||
(
|
||||
condition,
|
||||
mem::take(&mut block.statements),
|
||||
StmtBlock::new_with_span(
|
||||
def_stmt,
|
||||
def_case.span_or_else(*pos, Position::NONE),
|
||||
),
|
||||
statements,
|
||||
StmtBlock::new_with_span(def_stmt, def_span),
|
||||
)
|
||||
.into(),
|
||||
match_expr.start_position(),
|
||||
@@ -640,16 +634,14 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
||||
|
||||
let old_ranges_len = ranges.len();
|
||||
|
||||
ranges.retain(|&mut (start, end, inclusive, ..)| {
|
||||
(!inclusive && (start..end).contains(&value))
|
||||
|| (inclusive && (start..=end).contains(&value))
|
||||
});
|
||||
ranges.retain(|r| r.contains(value));
|
||||
|
||||
if ranges.len() != old_ranges_len {
|
||||
state.set_dirty();
|
||||
}
|
||||
|
||||
for (.., block) in ranges.iter_mut() {
|
||||
for r in ranges.iter() {
|
||||
let block = &mut blocks_list[r.index()];
|
||||
let statements = mem::take(&mut *block.statements);
|
||||
*block.statements =
|
||||
optimize_stmt_block(statements, state, preserve_result, true, false);
|
||||
@@ -670,14 +662,18 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
||||
|
||||
// Promote the default case
|
||||
state.set_dirty();
|
||||
let def_stmt = optimize_stmt_block(mem::take(def_case), state, true, true, false);
|
||||
*stmt = (def_stmt, def_case.span_or_else(*pos, Position::NONE)).into();
|
||||
let def_case = &mut blocks_list[*def_case].statements;
|
||||
let def_span = def_case.span_or_else(*pos, Position::NONE);
|
||||
let def_case: StmtBlockContainer = mem::take(def_case);
|
||||
let def_stmt = optimize_stmt_block(def_case, state, true, true, false);
|
||||
*stmt = (def_stmt, def_span).into();
|
||||
}
|
||||
// switch
|
||||
Stmt::Switch(x, ..) => {
|
||||
let (
|
||||
match_expr,
|
||||
SwitchCases {
|
||||
blocks: blocks_list,
|
||||
cases,
|
||||
ranges,
|
||||
def_case,
|
||||
@@ -687,8 +683,8 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
||||
|
||||
optimize_expr(match_expr, state, false);
|
||||
|
||||
// Optimize cases
|
||||
for block in cases.values_mut() {
|
||||
// Optimize blocks
|
||||
for block in blocks_list.iter_mut() {
|
||||
let statements = mem::take(&mut *block.statements);
|
||||
*block.statements =
|
||||
optimize_stmt_block(statements, state, preserve_result, true, false);
|
||||
@@ -700,38 +696,26 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
||||
block.condition = Expr::BoolConstant(true, pos);
|
||||
state.set_dirty();
|
||||
}
|
||||
Expr::BoolConstant(false, ..) => {
|
||||
if !block.statements.is_empty() {
|
||||
block.statements = StmtBlock::NONE;
|
||||
state.set_dirty();
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
// Remove false cases
|
||||
cases.retain(|_, block| match block.condition {
|
||||
cases.retain(|_, &mut block| match blocks_list[block].condition {
|
||||
Expr::BoolConstant(false, ..) => {
|
||||
state.set_dirty();
|
||||
false
|
||||
}
|
||||
_ => true,
|
||||
});
|
||||
|
||||
// Optimize ranges
|
||||
for (.., block) in ranges.iter_mut() {
|
||||
let statements = mem::take(&mut *block.statements);
|
||||
*block.statements =
|
||||
optimize_stmt_block(statements, state, preserve_result, true, false);
|
||||
|
||||
optimize_expr(&mut block.condition, state, false);
|
||||
|
||||
match block.condition {
|
||||
Expr::Unit(pos) => {
|
||||
block.condition = Expr::BoolConstant(true, pos);
|
||||
state.set_dirty();
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
// Remove false ranges
|
||||
ranges.retain(|(.., block)| match block.condition {
|
||||
ranges.retain(|r| match blocks_list[r.index()].condition {
|
||||
Expr::BoolConstant(false, ..) => {
|
||||
state.set_dirty();
|
||||
false
|
||||
@@ -739,8 +723,9 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
||||
_ => true,
|
||||
});
|
||||
|
||||
let def_block = mem::take(&mut ***def_case);
|
||||
***def_case = optimize_stmt_block(def_block, state, preserve_result, true, false);
|
||||
let def_case = &mut blocks_list[*def_case].statements;
|
||||
let def_block = mem::take(&mut **def_case);
|
||||
**def_case = optimize_stmt_block(def_block, state, preserve_result, true, false);
|
||||
}
|
||||
|
||||
// while false { block } -> Noop
|
||||
|
Reference in New Issue
Block a user