MatchBranchSimplification: Consider empty-unreachable otherwise branch
This commit is contained in:
parent
11f7e302e1
commit
e32ec45c02
7 changed files with 81 additions and 48 deletions
|
@ -18,6 +18,13 @@ impl Pu128 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Pu128> for u128 {
|
||||||
|
#[inline]
|
||||||
|
fn from(value: Pu128) -> Self {
|
||||||
|
value.get()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<u128> for Pu128 {
|
impl From<u128> for Pu128 {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(value: u128) -> Self {
|
fn from(value: u128) -> Self {
|
||||||
|
|
|
@ -67,6 +67,17 @@ impl SwitchTargets {
|
||||||
&mut self.targets
|
&mut self.targets
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a slice with all considered values (not including the fallback).
|
||||||
|
#[inline]
|
||||||
|
pub fn all_values(&self) -> &[Pu128] {
|
||||||
|
&self.values
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn all_values_mut(&mut self) -> &mut [Pu128] {
|
||||||
|
&mut self.values
|
||||||
|
}
|
||||||
|
|
||||||
/// Finds the `BasicBlock` to which this `SwitchInt` will branch given the
|
/// Finds the `BasicBlock` to which this `SwitchInt` will branch given the
|
||||||
/// specific value. This cannot fail, as it'll return the `otherwise`
|
/// specific value. This cannot fail, as it'll return the `otherwise`
|
||||||
/// branch if there's not a specific match for the value.
|
/// branch if there's not a specific match for the value.
|
||||||
|
|
|
@ -7,6 +7,7 @@ use rustc_middle::mir::*;
|
||||||
use rustc_middle::ty::layout::{IntegerExt, TyAndLayout};
|
use rustc_middle::ty::layout::{IntegerExt, TyAndLayout};
|
||||||
use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
|
use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
|
||||||
use rustc_type_ir::TyKind::*;
|
use rustc_type_ir::TyKind::*;
|
||||||
|
use tracing::instrument;
|
||||||
|
|
||||||
use super::simplify::simplify_cfg;
|
use super::simplify::simplify_cfg;
|
||||||
|
|
||||||
|
@ -51,7 +52,7 @@ impl<'tcx> crate::MirPass<'tcx> for MatchBranchSimplification {
|
||||||
}
|
}
|
||||||
|
|
||||||
trait SimplifyMatch<'tcx> {
|
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
|
/// otherwise. Generic code is written here, and we generally don't need a custom
|
||||||
/// implementation.
|
/// implementation.
|
||||||
fn simplify(
|
fn simplify(
|
||||||
|
@ -159,6 +160,7 @@ struct SimplifyToIf;
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
impl<'tcx> SimplifyMatch<'tcx> for SimplifyToIf {
|
impl<'tcx> SimplifyMatch<'tcx> for SimplifyToIf {
|
||||||
|
#[instrument(level = "debug", skip(self, tcx), ret)]
|
||||||
fn can_simplify(
|
fn can_simplify(
|
||||||
&mut self,
|
&mut self,
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
|
@ -167,12 +169,15 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToIf {
|
||||||
bbs: &IndexSlice<BasicBlock, BasicBlockData<'tcx>>,
|
bbs: &IndexSlice<BasicBlock, BasicBlockData<'tcx>>,
|
||||||
_discr_ty: Ty<'tcx>,
|
_discr_ty: Ty<'tcx>,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
if targets.iter().len() != 1 {
|
let (first, second) = match targets.all_targets() {
|
||||||
return None;
|
&[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.
|
// We require that the possible target blocks all be distinct.
|
||||||
let (_, first) = targets.iter().next().unwrap();
|
|
||||||
let second = targets.otherwise();
|
|
||||||
if first == second {
|
if first == second {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
@ -221,8 +226,14 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToIf {
|
||||||
discr_local: Local,
|
discr_local: Local,
|
||||||
discr_ty: Ty<'tcx>,
|
discr_ty: Ty<'tcx>,
|
||||||
) {
|
) {
|
||||||
let (val, first) = targets.iter().next().unwrap();
|
let ((val, first), second) = match (targets.all_targets(), targets.all_values()) {
|
||||||
let second = targets.otherwise();
|
(&[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,
|
// We already checked that first and second are different blocks,
|
||||||
// and bb_idx has a different terminator from both of them.
|
// and bb_idx has a different terminator from both of them.
|
||||||
let first = &bbs[first];
|
let first = &bbs[first];
|
||||||
|
@ -297,7 +308,7 @@ struct SimplifyToExp {
|
||||||
transform_kinds: Vec<TransformKind>,
|
transform_kinds: Vec<TransformKind>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
enum ExpectedTransformKind<'a, 'tcx> {
|
enum ExpectedTransformKind<'a, 'tcx> {
|
||||||
/// Identical statements.
|
/// Identical statements.
|
||||||
Same(&'a StatementKind<'tcx>),
|
Same(&'a StatementKind<'tcx>),
|
||||||
|
@ -362,6 +373,7 @@ impl From<ExpectedTransformKind<'_, '_>> for TransformKind {
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp {
|
impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp {
|
||||||
|
#[instrument(level = "debug", skip(self, tcx), ret)]
|
||||||
fn can_simplify(
|
fn can_simplify(
|
||||||
&mut self,
|
&mut self,
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
|
|
|
@ -25,12 +25,12 @@ fn num_to_digit(_1: char) -> u32 {
|
||||||
bb1: {
|
bb1: {
|
||||||
StorageLive(_3);
|
StorageLive(_3);
|
||||||
_3 = discriminant(_2);
|
_3 = discriminant(_2);
|
||||||
switchInt(move _3) -> [1: bb2, 0: bb6, otherwise: bb8];
|
StorageDead(_2);
|
||||||
|
switchInt(move _3) -> [1: bb2, otherwise: bb7];
|
||||||
}
|
}
|
||||||
|
|
||||||
bb2: {
|
bb2: {
|
||||||
StorageDead(_3);
|
StorageDead(_3);
|
||||||
StorageDead(_2);
|
|
||||||
StorageLive(_4);
|
StorageLive(_4);
|
||||||
_4 = char::methods::<impl char>::to_digit(move _1, const 8_u32) -> [return: bb3, unwind unreachable];
|
_4 = char::methods::<impl char>::to_digit(move _1, const 8_u32) -> [return: bb3, unwind unreachable];
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ fn num_to_digit(_1: char) -> u32 {
|
||||||
bb3: {
|
bb3: {
|
||||||
StorageLive(_5);
|
StorageLive(_5);
|
||||||
_5 = discriminant(_4);
|
_5 = discriminant(_4);
|
||||||
switchInt(move _5) -> [0: bb4, 1: bb5, otherwise: bb8];
|
switchInt(move _5) -> [0: bb4, 1: bb5, otherwise: bb6];
|
||||||
}
|
}
|
||||||
|
|
||||||
bb4: {
|
bb4: {
|
||||||
|
@ -49,21 +49,20 @@ fn num_to_digit(_1: char) -> u32 {
|
||||||
_0 = move ((_4 as Some).0: u32);
|
_0 = move ((_4 as Some).0: u32);
|
||||||
StorageDead(_5);
|
StorageDead(_5);
|
||||||
StorageDead(_4);
|
StorageDead(_4);
|
||||||
goto -> bb7;
|
goto -> bb8;
|
||||||
}
|
}
|
||||||
|
|
||||||
bb6: {
|
bb6: {
|
||||||
StorageDead(_3);
|
unreachable;
|
||||||
StorageDead(_2);
|
|
||||||
_0 = const 0_u32;
|
|
||||||
goto -> bb7;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bb7: {
|
bb7: {
|
||||||
return;
|
StorageDead(_3);
|
||||||
|
_0 = const 0_u32;
|
||||||
|
goto -> bb8;
|
||||||
}
|
}
|
||||||
|
|
||||||
bb8: {
|
bb8: {
|
||||||
unreachable;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,12 +25,12 @@ fn num_to_digit(_1: char) -> u32 {
|
||||||
bb1: {
|
bb1: {
|
||||||
StorageLive(_3);
|
StorageLive(_3);
|
||||||
_3 = discriminant(_2);
|
_3 = discriminant(_2);
|
||||||
switchInt(move _3) -> [1: bb2, 0: bb6, otherwise: bb8];
|
StorageDead(_2);
|
||||||
|
switchInt(move _3) -> [1: bb2, otherwise: bb7];
|
||||||
}
|
}
|
||||||
|
|
||||||
bb2: {
|
bb2: {
|
||||||
StorageDead(_3);
|
StorageDead(_3);
|
||||||
StorageDead(_2);
|
|
||||||
StorageLive(_4);
|
StorageLive(_4);
|
||||||
_4 = char::methods::<impl char>::to_digit(move _1, const 8_u32) -> [return: bb3, unwind continue];
|
_4 = char::methods::<impl char>::to_digit(move _1, const 8_u32) -> [return: bb3, unwind continue];
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ fn num_to_digit(_1: char) -> u32 {
|
||||||
bb3: {
|
bb3: {
|
||||||
StorageLive(_5);
|
StorageLive(_5);
|
||||||
_5 = discriminant(_4);
|
_5 = discriminant(_4);
|
||||||
switchInt(move _5) -> [0: bb4, 1: bb5, otherwise: bb8];
|
switchInt(move _5) -> [0: bb4, 1: bb5, otherwise: bb6];
|
||||||
}
|
}
|
||||||
|
|
||||||
bb4: {
|
bb4: {
|
||||||
|
@ -49,21 +49,20 @@ fn num_to_digit(_1: char) -> u32 {
|
||||||
_0 = move ((_4 as Some).0: u32);
|
_0 = move ((_4 as Some).0: u32);
|
||||||
StorageDead(_5);
|
StorageDead(_5);
|
||||||
StorageDead(_4);
|
StorageDead(_4);
|
||||||
goto -> bb7;
|
goto -> bb8;
|
||||||
}
|
}
|
||||||
|
|
||||||
bb6: {
|
bb6: {
|
||||||
StorageDead(_3);
|
unreachable;
|
||||||
StorageDead(_2);
|
|
||||||
_0 = const 0_u32;
|
|
||||||
goto -> bb7;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bb7: {
|
bb7: {
|
||||||
return;
|
StorageDead(_3);
|
||||||
|
_0 = const 0_u32;
|
||||||
|
goto -> bb8;
|
||||||
}
|
}
|
||||||
|
|
||||||
bb8: {
|
bb8: {
|
||||||
unreachable;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,27 +5,32 @@
|
||||||
debug bar => _1;
|
debug bar => _1;
|
||||||
let mut _0: bool;
|
let mut _0: bool;
|
||||||
let mut _2: isize;
|
let mut _2: isize;
|
||||||
|
+ let mut _3: isize;
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
_2 = discriminant(_1);
|
_2 = discriminant(_1);
|
||||||
switchInt(move _2) -> [0: bb2, 1: bb3, otherwise: bb1];
|
- switchInt(move _2) -> [0: bb2, 1: bb3, otherwise: bb1];
|
||||||
}
|
- }
|
||||||
|
-
|
||||||
bb1: {
|
- bb1: {
|
||||||
unreachable;
|
- unreachable;
|
||||||
}
|
- }
|
||||||
|
-
|
||||||
bb2: {
|
- bb2: {
|
||||||
_0 = const false;
|
- _0 = const false;
|
||||||
goto -> bb4;
|
- goto -> bb4;
|
||||||
}
|
- }
|
||||||
|
-
|
||||||
bb3: {
|
- bb3: {
|
||||||
_0 = const true;
|
- _0 = const true;
|
||||||
goto -> bb4;
|
- goto -> bb4;
|
||||||
}
|
- }
|
||||||
|
-
|
||||||
bb4: {
|
- bb4: {
|
||||||
|
+ StorageLive(_3);
|
||||||
|
+ _3 = move _2;
|
||||||
|
+ _0 = Ne(copy _3, const 0_isize);
|
||||||
|
+ StorageDead(_3);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ fn foo(bar: Option<()>) {
|
||||||
// Test for #131219.
|
// Test for #131219.
|
||||||
fn my_is_some(bar: Option<()>) -> bool {
|
fn my_is_some(bar: Option<()>) -> bool {
|
||||||
// CHECK-LABEL: fn my_is_some(
|
// CHECK-LABEL: fn my_is_some(
|
||||||
// CHECK: switchInt
|
// CHECK: = Ne
|
||||||
// CHECK: return
|
// CHECK: return
|
||||||
match bar {
|
match bar {
|
||||||
Some(_) => true,
|
Some(_) => true,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue