Only emit !=
assumptions if the otherwise target is reachable.
This commit is contained in:
parent
096196d5b0
commit
cb918904fe
11 changed files with 148 additions and 58 deletions
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue