MatchBranchSimplification: Consider empty-unreachable otherwise branch

This commit is contained in:
clubby789 2024-10-04 20:26:41 +00:00
parent 11f7e302e1
commit e32ec45c02
7 changed files with 81 additions and 48 deletions

View file

@ -7,6 +7,7 @@ use rustc_middle::mir::*;
use rustc_middle::ty::layout::{IntegerExt, TyAndLayout};
use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
use rustc_type_ir::TyKind::*;
use tracing::instrument;
use super::simplify::simplify_cfg;
@ -51,7 +52,7 @@ impl<'tcx> crate::MirPass<'tcx> for MatchBranchSimplification {
}
trait SimplifyMatch<'tcx> {
/// Simplifies a match statement, returning true if the simplification succeeds, false
/// Simplifies a match statement, returning `Some` if the simplification succeeds, `None`
/// otherwise. Generic code is written here, and we generally don't need a custom
/// implementation.
fn simplify(
@ -159,6 +160,7 @@ struct SimplifyToIf;
/// }
/// ```
impl<'tcx> SimplifyMatch<'tcx> for SimplifyToIf {
#[instrument(level = "debug", skip(self, tcx), ret)]
fn can_simplify(
&mut self,
tcx: TyCtxt<'tcx>,
@ -167,12 +169,15 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToIf {
bbs: &IndexSlice<BasicBlock, BasicBlockData<'tcx>>,
_discr_ty: Ty<'tcx>,
) -> Option<()> {
if targets.iter().len() != 1 {
return None;
}
let (first, second) = match targets.all_targets() {
&[first, otherwise] => (first, otherwise),
&[first, second, otherwise] if bbs[otherwise].is_empty_unreachable() => (first, second),
_ => {
return None;
}
};
// We require that the possible target blocks all be distinct.
let (_, first) = targets.iter().next().unwrap();
let second = targets.otherwise();
if first == second {
return None;
}
@ -221,8 +226,14 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToIf {
discr_local: Local,
discr_ty: Ty<'tcx>,
) {
let (val, first) = targets.iter().next().unwrap();
let second = targets.otherwise();
let ((val, first), second) = match (targets.all_targets(), targets.all_values()) {
(&[first, otherwise], &[val]) => ((val, first), otherwise),
(&[first, second, otherwise], &[val, _]) if bbs[otherwise].is_empty_unreachable() => {
((val, first), second)
}
_ => unreachable!(),
};
// We already checked that first and second are different blocks,
// and bb_idx has a different terminator from both of them.
let first = &bbs[first];
@ -297,7 +308,7 @@ struct SimplifyToExp {
transform_kinds: Vec<TransformKind>,
}
#[derive(Clone, Copy)]
#[derive(Clone, Copy, Debug)]
enum ExpectedTransformKind<'a, 'tcx> {
/// Identical statements.
Same(&'a StatementKind<'tcx>),
@ -362,6 +373,7 @@ impl From<ExpectedTransformKind<'_, '_>> for TransformKind {
/// }
/// ```
impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp {
#[instrument(level = "debug", skip(self, tcx), ret)]
fn can_simplify(
&mut self,
tcx: TyCtxt<'tcx>,