Only emit != assumptions if the otherwise target is reachable.

This commit is contained in:
Camille GILLOT 2023-09-24 08:27:42 +00:00
parent 096196d5b0
commit cb918904fe
11 changed files with 148 additions and 58 deletions

View file

@ -116,22 +116,21 @@ fn remove_successors_from_switch<'tcx>(
patch.add_statement(location, StatementKind::Intrinsic(Box::new(assume))); patch.add_statement(location, StatementKind::Intrinsic(Box::new(assume)));
}; };
let otherwise = targets.otherwise();
let otherwise_unreachable = is_unreachable(otherwise);
let reachable_iter = targets.iter().filter(|&(value, bb)| { let reachable_iter = targets.iter().filter(|&(value, bb)| {
let is_unreachable = is_unreachable(bb); let is_unreachable = is_unreachable(bb);
if is_unreachable {
// We remove this target from the switch, so record the inequality using `Assume`. // We remove this target from the switch, so record the inequality using `Assume`.
if is_unreachable && !otherwise_unreachable {
add_assumption(BinOp::Ne, value); add_assumption(BinOp::Ne, value);
false
} else {
true
} }
!is_unreachable
}); });
let otherwise = targets.otherwise();
let new_targets = SwitchTargets::new(reachable_iter, otherwise); let new_targets = SwitchTargets::new(reachable_iter, otherwise);
let num_targets = new_targets.all_targets().len(); let num_targets = new_targets.all_targets().len();
let otherwise_unreachable = is_unreachable(otherwise);
let fully_unreachable = num_targets == 1 && otherwise_unreachable; let fully_unreachable = num_targets == 1 && otherwise_unreachable;
let terminator = match (num_targets, otherwise_unreachable) { let terminator = match (num_targets, otherwise_unreachable) {

View file

@ -10,7 +10,6 @@
+ let mut _3: &std::option::Option<T>; + let mut _3: &std::option::Option<T>;
+ let mut _4: isize; + let mut _4: isize;
+ let mut _5: bool; + let mut _5: bool;
+ let mut _6: bool;
+ scope 2 { + scope 2 {
+ debug val => _0; + debug val => _0;
+ } + }
@ -37,14 +36,10 @@
+ StorageLive(_3); + StorageLive(_3);
+ StorageLive(_4); + StorageLive(_4);
+ StorageLive(_5); + StorageLive(_5);
+ StorageLive(_6);
+ _4 = discriminant(_2); + _4 = discriminant(_2);
+ _5 = Ne(_4, const 0_isize); + _5 = Eq(_4, const 1_isize);
+ assume(move _5); + assume(move _5);
+ _6 = Eq(_4, const 1_isize);
+ assume(move _6);
+ _0 = move ((_2 as Some).0: T); + _0 = move ((_2 as Some).0: T);
+ StorageDead(_6);
+ StorageDead(_5); + StorageDead(_5);
+ StorageDead(_4); + StorageDead(_4);
+ StorageDead(_3); + StorageDead(_3);

View file

@ -10,7 +10,6 @@
+ let mut _3: &std::option::Option<T>; + let mut _3: &std::option::Option<T>;
+ let mut _4: isize; + let mut _4: isize;
+ let mut _5: bool; + let mut _5: bool;
+ let mut _6: bool;
+ scope 2 { + scope 2 {
+ debug val => _0; + debug val => _0;
+ } + }
@ -37,14 +36,10 @@
+ StorageLive(_3); + StorageLive(_3);
+ StorageLive(_4); + StorageLive(_4);
+ StorageLive(_5); + StorageLive(_5);
+ StorageLive(_6);
+ _4 = discriminant(_2); + _4 = discriminant(_2);
+ _5 = Ne(_4, const 0_isize); + _5 = Eq(_4, const 1_isize);
+ assume(move _5); + assume(move _5);
+ _6 = Eq(_4, const 1_isize);
+ assume(move _6);
+ _0 = move ((_2 as Some).0: T); + _0 = move ((_2 as Some).0: T);
+ StorageDead(_6);
+ StorageDead(_5); + StorageDead(_5);
+ StorageDead(_4); + StorageDead(_4);
+ StorageDead(_3); + StorageDead(_3);

View file

@ -7,8 +7,7 @@ fn unwrap_unchecked(_1: Option<T>) -> T {
debug self => _1; debug self => _1;
let mut _2: isize; let mut _2: isize;
let mut _3: bool; let mut _3: bool;
let mut _4: bool; let mut _4: &std::option::Option<T>;
let mut _5: &std::option::Option<T>;
scope 2 { scope 2 {
debug val => _0; debug val => _0;
} }
@ -21,25 +20,21 @@ fn unwrap_unchecked(_1: Option<T>) -> T {
} }
} }
scope 4 (inlined Option::<T>::is_some) { scope 4 (inlined Option::<T>::is_some) {
debug self => _5; debug self => _4;
} }
} }
bb0: { bb0: {
StorageLive(_5); StorageLive(_4);
StorageLive(_2); StorageLive(_2);
StorageLive(_3); StorageLive(_3);
StorageLive(_4);
_2 = discriminant(_1); _2 = discriminant(_1);
_3 = Ne(_2, const 0_isize); _3 = Eq(_2, const 1_isize);
assume(move _3); assume(move _3);
_4 = Eq(_2, const 1_isize);
assume(move _4);
_0 = move ((_1 as Some).0: T); _0 = move ((_1 as Some).0: T);
StorageDead(_4);
StorageDead(_3); StorageDead(_3);
StorageDead(_2); StorageDead(_2);
StorageDead(_5); StorageDead(_4);
return; return;
} }
} }

View file

@ -7,8 +7,7 @@ fn unwrap_unchecked(_1: Option<T>) -> T {
debug self => _1; debug self => _1;
let mut _2: isize; let mut _2: isize;
let mut _3: bool; let mut _3: bool;
let mut _4: bool; let mut _4: &std::option::Option<T>;
let mut _5: &std::option::Option<T>;
scope 2 { scope 2 {
debug val => _0; debug val => _0;
} }
@ -21,25 +20,21 @@ fn unwrap_unchecked(_1: Option<T>) -> T {
} }
} }
scope 4 (inlined Option::<T>::is_some) { scope 4 (inlined Option::<T>::is_some) {
debug self => _5; debug self => _4;
} }
} }
bb0: { bb0: {
StorageLive(_5); StorageLive(_4);
StorageLive(_2); StorageLive(_2);
StorageLive(_3); StorageLive(_3);
StorageLive(_4);
_2 = discriminant(_1); _2 = discriminant(_1);
_3 = Ne(_2, const 0_isize); _3 = Eq(_2, const 1_isize);
assume(move _3); assume(move _3);
_4 = Eq(_2, const 1_isize);
assume(move _4);
_0 = move ((_1 as Some).0: T); _0 = move ((_1 as Some).0: T);
StorageDead(_4);
StorageDead(_3); StorageDead(_3);
StorageDead(_2); StorageDead(_2);
StorageDead(_5); StorageDead(_4);
return; return;
} }
} }

View file

@ -5,7 +5,6 @@ fn ub_if_b(_1: Thing) -> Thing {
let mut _0: Thing; let mut _0: Thing;
let mut _2: isize; let mut _2: isize;
let mut _3: bool; let mut _3: bool;
let mut _4: bool;
scope 1 (inlined unreachable_unchecked) { scope 1 (inlined unreachable_unchecked) {
scope 2 { scope 2 {
scope 3 (inlined unreachable_unchecked::runtime) { scope 3 (inlined unreachable_unchecked::runtime) {
@ -15,10 +14,8 @@ fn ub_if_b(_1: Thing) -> Thing {
bb0: { bb0: {
_2 = discriminant(_1); _2 = discriminant(_1);
_3 = Ne(_2, const 1_isize); _3 = Eq(_2, const 0_isize);
assume(move _3); assume(move _3);
_4 = Eq(_2, const 0_isize);
assume(move _4);
_0 = move _1; _0 = move _1;
return; return;
} }

View file

@ -0,0 +1,45 @@
- // MIR for `as_match` before UnreachablePropagation
+ // MIR for `as_match` after UnreachablePropagation
fn as_match() -> () {
let mut _0: ();
let mut _1: std::option::Option<Empty>;
let mut _2: isize;
let _3: Empty;
let mut _4: !;
+ let mut _5: bool;
scope 1 {
debug _x => _3;
}
bb0: {
StorageLive(_1);
_1 = empty() -> [return: bb1, unwind unreachable];
}
bb1: {
_2 = discriminant(_1);
- switchInt(move _2) -> [0: bb4, 1: bb2, otherwise: bb3];
+ _5 = Eq(_2, const 0_isize);
+ assume(move _5);
+ goto -> bb4;
}
bb2: {
- StorageLive(_3);
- _3 = move ((_1 as Some).0: Empty);
- StorageLive(_4);
unreachable;
}
bb3: {
unreachable;
}
bb4: {
_0 = const ();
StorageDead(_1);
return;
}
}

View file

@ -0,0 +1,45 @@
- // MIR for `as_match` before UnreachablePropagation
+ // MIR for `as_match` after UnreachablePropagation
fn as_match() -> () {
let mut _0: ();
let mut _1: std::option::Option<Empty>;
let mut _2: isize;
let _3: Empty;
let mut _4: !;
+ let mut _5: bool;
scope 1 {
debug _x => _3;
}
bb0: {
StorageLive(_1);
_1 = empty() -> [return: bb1, unwind continue];
}
bb1: {
_2 = discriminant(_1);
- switchInt(move _2) -> [0: bb4, 1: bb2, otherwise: bb3];
+ _5 = Eq(_2, const 0_isize);
+ assume(move _5);
+ goto -> bb4;
}
bb2: {
- StorageLive(_3);
- _3 = move ((_1 as Some).0: Empty);
- StorageLive(_4);
unreachable;
}
bb3: {
unreachable;
}
bb4: {
_0 = const ();
StorageDead(_1);
return;
}
}

View file

@ -1,7 +1,7 @@
- // MIR for `main` before UnreachablePropagation - // MIR for `if_let` before UnreachablePropagation
+ // MIR for `main` after UnreachablePropagation + // MIR for `if_let` after UnreachablePropagation
fn main() -> () { fn if_let() -> () {
let mut _0: (); let mut _0: ();
let mut _1: std::option::Option<Empty>; let mut _1: std::option::Option<Empty>;
let mut _2: isize; let mut _2: isize;
@ -9,7 +9,6 @@
let mut _6: bool; let mut _6: bool;
let mut _7: !; let mut _7: !;
+ let mut _8: bool; + let mut _8: bool;
+ let mut _9: bool;
scope 1 { scope 1 {
debug _x => _3; debug _x => _3;
let _3: Empty; let _3: Empty;
@ -27,8 +26,8 @@
bb1: { bb1: {
_2 = discriminant(_1); _2 = discriminant(_1);
- switchInt(move _2) -> [1: bb2, otherwise: bb6]; - switchInt(move _2) -> [1: bb2, otherwise: bb6];
+ _9 = Ne(_2, const 1_isize); + _8 = Ne(_2, const 1_isize);
+ assume(move _9); + assume(move _8);
+ goto -> bb6; + goto -> bb6;
} }

View file

@ -1,7 +1,7 @@
- // MIR for `main` before UnreachablePropagation - // MIR for `if_let` before UnreachablePropagation
+ // MIR for `main` after UnreachablePropagation + // MIR for `if_let` after UnreachablePropagation
fn main() -> () { fn if_let() -> () {
let mut _0: (); let mut _0: ();
let mut _1: std::option::Option<Empty>; let mut _1: std::option::Option<Empty>;
let mut _2: isize; let mut _2: isize;
@ -9,7 +9,6 @@
let mut _6: bool; let mut _6: bool;
let mut _7: !; let mut _7: !;
+ let mut _8: bool; + let mut _8: bool;
+ let mut _9: bool;
scope 1 { scope 1 {
debug _x => _3; debug _x => _3;
let _3: Empty; let _3: Empty;
@ -27,8 +26,8 @@
bb1: { bb1: {
_2 = discriminant(_1); _2 = discriminant(_1);
- switchInt(move _2) -> [1: bb2, otherwise: bb6]; - switchInt(move _2) -> [1: bb2, otherwise: bb6];
+ _9 = Ne(_2, const 1_isize); + _8 = Ne(_2, const 1_isize);
+ assume(move _9); + assume(move _8);
+ goto -> bb6; + goto -> bb6;
} }

View file

@ -7,9 +7,9 @@ fn empty() -> Option<Empty> {
None None
} }
// EMIT_MIR unreachable.main.UnreachablePropagation.diff // EMIT_MIR unreachable.if_let.UnreachablePropagation.diff
fn main() { fn if_let() {
// CHECK-LABEL: fn main( // CHECK-LABEL: fn if_let(
// CHECK: bb0: { // CHECK: bb0: {
// CHECK: {{_.*}} = empty() // CHECK: {{_.*}} = empty()
// CHECK: bb1: { // CHECK: bb1: {
@ -38,3 +38,29 @@ fn main() {
match _x { } match _x { }
} }
} }
// EMIT_MIR unreachable.as_match.UnreachablePropagation.diff
fn as_match() {
// CHECK-LABEL: fn as_match(
// CHECK: bb0: {
// CHECK: {{_.*}} = empty()
// CHECK: bb1: {
// CHECK: [[eq:_.*]] = Eq({{.*}}, const 0_isize);
// CHECK-NEXT: assume(move [[eq]]);
// CHECK-NEXT: goto -> bb4;
// CHECK: bb2: {
// CHECK-NEXT: unreachable;
// CHECK: bb3: {
// CHECK-NEXT: unreachable;
// CHECK: bb4: {
// CHECK: return;
match empty() {
None => {}
Some(_x) => match _x {}
}
}
fn main() {
if_let();
as_match();
}